Site: four-intent structure, interim Supporter signing, Participate and registers, temporary Review page - #313
Conversation
Foundation for the four-intent site. - src/lib/site-config.ts holds every deployment-specific value behind a visible bracketed placeholder. A wrong-but-plausible default reads as fact and ships silently; "[controller name not set]" cannot. unsetConfigValues() is what the launch checklist reads. The reports mailbox is deliberately NOT configurable: a deployment that could repoint it could redirect a conduct or security report. - Nav becomes Principles, Specification, Build, Participate, with the Specification dropdown carrying "The specification" and, behind reviewOpen, "Review, until 1 Oct". The dropdown opens on hover AND focus-within, so it is keyboard-reachable with no open/closed state to keep in sync. - The review ticker is one link wrapping a CSS marquee: two identical tracks translated by exactly -50%, so the loop seam is invisible and the animation runs off the main thread. prefers-reduced-motion pauses it rather than hiding it, because the message still has to be readable. - sync-spec-docs parses PRINCIPLES.md into PRINCIPLES_PREAMBLE and PRINCIPLES_LIST so /principles and the home page render the six principles without a second copy in site source. It throws unless exactly six parse. - PdppConceptSection's sectionIndex becomes optional: the new site carries no ordinal numbering on section headings. - PRINCIPLES.md gains the sentence about the relying party's uncertainty. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NECjjZbYWNTzq3bu7nuiDP Signed-off-by: Art A <129354338+artvana@users.noreply.github.com>
Four of the seven routes, carrying the prototype's copy with the deltas
applied.
/principles renders the preamble and the six principles from PRINCIPLES.md
through the generated module, never from page source. The Supporters table
ships an EMPTY state, not the prototype's six example rows and "[ 247 ]"
counter: those are labelled layout-only in the design, and a page showing
invented signatories has published a false register.
/build carries the three role cards and the FAQs. Section citations are named
rather than numbered ("Source declaration" rather than "Core §5"): the § glyph
and numbered citations do not belong in site copy outside the reader and
/review, and a section number that moves leaves every citing page wrong. The
links still land on the same anchors.
/review applies all three of its copy deltas: the working-sessions channel is
gone, the comment-handling sentences are replaced, and the "one document of
nine sections" sentence is cut from the lede. It is one of only two places
that name the review period, so retiring the period is the flag plus this
page.
/privacy states controller, purposes, what is stored, what is published,
retention, the confirmation and withdrawal mechanism and a contact, all from
config so nothing legal is guessed on someone else's behalf.
The signing form is present but renders the closed notice until signingLive.
When the flag is off the form is ABSENT, not disabled: a disabled form still
ships its field names and endpoint to every reader.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NECjjZbYWNTzq3bu7nuiDP
Signed-off-by: Art A <129354338+artvana@users.noreply.github.com>
Home carries the hero, the OAuth-versus-grant comparison, the six principles, the Supporters register and the build entry point. The hero's right-hand element is the repo's own scrolling data columns rather than the grant card the prototype puts there. The design export and the build prompt both call for the columns, and the grant card already carries the comparison below: rendering it twice would spend the page's one strong artifact on decoration. The comparison is components, not an image. It is the one place the site shows the argument rather than stating it, so it has to reflow, respect the theme, be selectable and read aloud correctly. The two panels deliberately do not share a card shell: they show a consent dialog and a record, and one shell would flatten the difference the section exists to make. /specification now renders GOVERNANCE.md inline at #governance, with the four-stage diagram built from components for the same reasons. /governance 308s there and the standalone route is gone. One page carries the protocol and the programme that stewards it. The contents rail becomes Core's own nine sections as in-page anchors, then the informative documents under "Implementer guidance, informative", then Appendix A. The sections are hand-declared rather than picked from the fumadocs tree because they are anchors on this page, and the tree only knows about documents. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NECjjZbYWNTzq3bu7nuiDP Signed-off-by: Art A <129354338+artvana@users.noreply.github.com>
/participate carries the three levels, the four verification steps, the status table, both registers and the contact channels. Both registers are PR-driven JSON in this repo and hold no personal data. /register/index.json ships empty; /register/trust-registries.json holds the one recognised entry, the Data Transfer Initiative's Data Trust Registry. Both are read at build time rather than fetched: they ship in the repo, so a network hop in front of them would only add a way for the page to 500. The Operator apply button is inert with its date until operatorApplications is on. The test suite an Operator is assessed against does not exist until then, so a live button would invite an application nobody can act on. Copy delta 1 applied: the Level 1 channel list is "Discord, mailing list, comments", and the section is "Channels and contacts". Issue templates for the three roles list what to attach per GOVERNANCE.md Appendix A, each stating that the admissions check is exhaustive and that every return cites the item it failed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NECjjZbYWNTzq3bu7nuiDP Signed-off-by: Art A <129354338+artvana@users.noreply.github.com>
The signing system, all behind signingLive and none of it exercised: the KV store, the mail provider and the deploy key do not exist yet. Every seam fails closed with SigningUnavailableError rather than degrading, because a seam that degraded would accept a signature, tell the signatory it worked, and drop it. POST /api/sign rate-limits, validates against a strict schema, refuses an organisation submission that is not from an address at the organisation's own domain, writes a pending record to a TTL store and sends ONE email. Nothing is published here. A signature becomes real only when the confirmation link is used, which is what stops anyone signing in someone else's name. Single use is enforced by GETDEL on the pending record, not by the signature: an HMAC is stateless, so checking, then reading, then deleting would leave a window where two clicks both write a signatory file. The withdraw link deliberately does not expire. A signatory keeps the email and may act on it a year later, and a withdrawal that needed a person to serve it is the friction the Principles say ending should not have. The flags gate the ROUTES, not just the UI: a form hidden in the page while the endpoint still accepts posts is not switched off. docs/registers.md documents the three stores, the one-way data flow, who has access, and the handover, rotation and deletion procedure. Also here: the sitemap drops /governance (a redirect in a sitemap is a redirect a crawler must follow to learn it was one) and /review (temporary, and a page due for retirement should not be advertised), and picks up the new routes. Five sandbox files are reformatted by the repo's own formatter. They are unrelated to this change and were already failing `pnpm check` on main; fixing them is what makes this branch green. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NECjjZbYWNTzq3bu7nuiDP Signed-off-by: Art A <129354338+artvana@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
@tnunamak @annakaz — review context for all three open PRs, and the order to take them, is in one comment on #279: #279 (comment) This one is independent on the branch graph but coupled in content: |
The Vana Foundation holds the Supporter register until LF Decentralized Trust hosting is confirmed, and support@vanafoundation.org is the project's general address. Both were placeholders; they are decided, so they render as themselves. They are defaults rather than hard-coded values: a deployment can still override either through the environment, and the transfer to LFDT is one edit here. The privacy contact defaults to the general address for now. A privacy page that cannot name an address to write to is worse than one naming the same address as everything else; split them by setting the variable when a dedicated mailbox exists. The footer gains its Contact block. Reports and General are never the same address: reports is the LF Decentralized Trust mailbox fixed by GOVERNANCE.md's header, general is the project's own, and routing either to the other is the failure the separation prevents. The footer's governance link now points at /specification#governance rather than through the /governance redirect. Verified on the served build: no bracketed placeholder renders on /, /principles, /privacy or /participate, and no em-dash appears in site copy on any of the seven routes. Discord and the mailing list URL are the two values still unset. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NECjjZbYWNTzq3bu7nuiDP Signed-off-by: Art A <129354338+artvana@users.noreply.github.com>
The gate is not "is it a list", it is "would this put personal data in the private repository". Nothing that would collect a person's details is reachable until the arrangement for holding them is confirmed. A form that takes an address into a store nobody has agreed the shape of is the one thing on this site that a later edit cannot undo. Three surfaces claimed signing was open and no longer do: - The signing section keeps its place on /principles and now carries a waiting panel. It says we are not taking signatures yet, says why, and sends the reader to the specification instead, because someone who arrived wanting to support the work can still do the useful thing this week and comment on it. - /participate's Level 2 said "Open now". It now says signing opens once the register has a confirmed home, and its link goes to the Principles document rather than to a form that is not there. - The Pre stage in the governance diagram said "you can sign now". The Discord and mailing list cards no longer render an unset config value as a live link. An href of "[mailing list URL not set]" looks live and goes nowhere, which is worst at exactly the moment a reader expects to hand over an address; they show "Link to follow" until the destination is real. The mailing list opt-in needed no separate change: it lives inside the form, which is absent while signingLive is off. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NECjjZbYWNTzq3bu7nuiDP Signed-off-by: Art A <129354338+artvana@users.noreply.github.com>
|
Pushed The gate is "would this collect someone's details", not "is it a list". Three places claimed signing was open and no longer do:
Discord and the mailing list no longer render an unset config value as a live link ( Nothing here changes the conformance register, which is PR-driven and holds no personal data. Verified on the served build: no page claims signing is open, and no placeholder href renders. |
discord.gg/JmKcFYE4 for #pdp-connect. It also collapses a duplicate. The footer read DISCORD_INVITE_URL from site-facts while /participate read discordUrl from config, so the site held two Discord constants at once. That is how a site ends up publishing two different invites and only noticing when one of them expires. Config owns the value now and the footer reads the same one; the site-facts constant is retired with a note saying where it went. The previous invite (FV4bkZBdmA) is replaced, not kept as a fallback. Two live invites to the same channel is the state this change exists to remove. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NECjjZbYWNTzq3bu7nuiDP Signed-off-by: Art A <129354338+artvana@users.noreply.github.com>
Signed-off-by: Art A <129354338+artvana@users.noreply.github.com>
Signed-off-by: Tim Nunamaker <tnunamak@gmail.com> Assisted-by: AI
Rebuilds pdpp.dev around the four intents, adds the interim Supporter signing system behind a flag, ships the conformance registers, and adds a temporary Review page.
Branched off
mainatf1e8357d, after #267 merged. The design handoff is committed atdesign_handoff_pdpp_site/.Routes
//principlesPRINCIPLES.md, who can sign, the signing form, and the public register./specificationspec-core.mdin the reader, with a contents rail of Core's nine sections, the informative documents, and Appendix A.GOVERNANCE.mdrenders inline at#governance, above it the four-stage diagram./build/participate/reviewreviewOpenin the nav and ticker; the page itself always resolves./privacy/governance/specification#governance. The standalone route is gone.Nav is the four items with a Specification dropdown holding "The specification" and, behind
reviewOpen, "Review, until 1 Oct". The full-width ticker under the header is one link wrapping a CSS marquee: two identical tracks translated by exactly -50% so the loop seam is invisible, ~55s, paused rather than hidden underprefers-reduced-motion.Theme is the repo's existing
PdppThemeSwitchandThemeProvider, already keyed topdpp-theme. The wordmark is the repo's existingWordmarkIcon; fonts are the repo's own loading, not the export's Google Fonts./reviewand the reader's version strip are the only places the review period is named, so retiring it is the flag plus one page.Signing data flow
Three properties hold it together:
Single use is enforced by
GETDELon the pending record, not by the token: an HMAC is stateless, so check-then-read-then-delete would leave a window where two clicks both write a signatory file. The withdraw link deliberately never expires — a signatory keeps the email and may act on it a year later.Every seam fails closed with
SigningUnavailableErrorrather than degrading. A degrading seam would accept a signature, tell the signatory it worked, and drop it.None of the signing system has run. The KV store, the mail provider and the deploy key do not exist. Treat the request shapes as the intended contract, to be checked against each provider's documentation when provisioned.
The private store
Not created here, by agreement: it holds personal data and its settings need org-level rights I do not have. Staged at
~/Desktop/claude-projects/supporters-private-staging/, outside this repo, ready to push toPDP-Connect/supporters-private:README.md— what it holds, who may read it, handover and deletion.scripts/publish-supporters.mjs— the allowlist publisher.scripts/export-list-optins.mjs— prints opted-in addresses to stdout for a one-off manual subscribe. Sends nothing..github/workflows/publish-supporters.yml— scheduled, not signature-triggered, so a confirmation cannot make the public commit timing a side channel about when someone signed.SETTINGS-CHECKLIST.md— private, collaborators, forking off, secret scanning, branch protection, deploy key, and every Vercel secret.docs/registers.mdin this repo documents all three stores, the flow, access, and the handover procedure.Registers
/register/index.jsonships[];/register/trust-registries.jsonholds the one recognised entry, the Data Transfer Initiative's Data Trust Registry. Both are PR-driven and hold no personal data, both render on/participate. Issue templatesapply-source.md,apply-accessor.mdandapply-operator.mdlist what to attach perGOVERNANCE.mdAppendix A. The Operator button is inert with its date untiloperatorApplications.Config still needing real values
Every one renders a visible bracketed placeholder until set, so nothing guessed ships as fact.
NEXT_PUBLIC_PDPP_CONTROLLER_NAME— decided: the Vana Foundation, holding the register until LFDT hosting is confirmed. Shipped as a default, still env-overridable.NEXT_PUBLIC_PDPP_GENERAL_CONTACT— decided: support@vanafoundation.org. The footer's General contact, never the reports address.NEXT_PUBLIC_PDPP_PRIVACY_CONTACT— defaults to the general address. Split it by setting this when a dedicated mailbox exists.NEXT_PUBLIC_PDPP_FORM_ENDPOINT— where the form postsNEXT_PUBLIC_PDPP_EMAIL_PROVIDER— named in config; the route currently targets Resend's APINEXT_PUBLIC_PDPP_DISCORD_URLNEXT_PUBLIC_PDPP_MAILING_LIST_URLNEXT_PUBLIC_PDPP_REVIEW_OPEN,NEXT_PUBLIC_PDPP_SIGNING_LIVE,NEXT_PUBLIC_PDPP_OPERATOR_APPLICATIONS— all default offPDPP_SIGNING_TOKEN_SECRET,PDPP_KV_REST_API_URL,PDPP_KV_REST_API_TOKEN,PDPP_MAIL_API_KEY,PDPP_MAIL_FROM,PDPP_PRIVATE_REPO_OWNER,PDPP_PRIVATE_REPO_NAME,PDPP_PRIVATE_REPO_TOKENPDPP_PUBLIC_REPO_TOKENWhere the two sources disagreed
/build's prototype copy is built on§citations, and the brief removes section citations from site copy outside the reader and/review. Links kept as wayfinding but named ("Source declaration" rather than "Core §5"); they land on the same anchors. A grep of the built site finds zero§on/,/principles,/build,/participateand/privacy.supporters.jsonis[], and a page showing invented signatories has published a false register./review, so the clause is dropped.Copy deltas 1 to 5 are all applied.
Verification
pnpm spec:checkpasses.pnpm --dir apps/site types:check,test(202 passed, 0 failed),checkandbuildall pass, 68 pages generated.Served the production build: all seven routes 200,
/governance308s to/specification#governance, the rail renders the three groups, and the governance document renders inline.Grep of the built site finds one email address, the reports mailbox, plus
user@example.cominsidespec-collection-profile.md's own JSON example, which is pre-existing spec text on a reserved example domain.bot@pdpp.devappears in source as the git committer identity the GitHub contents API requires; it is not a mailbox. No private-store content is tracked in this repo.Five sandbox files are reformatted by the repo's own formatter. They are unrelated to this change and were already failing
pnpm checkonmain(20 errors there); fixing them is what makes this branch green.Assisted-by: AI
🤖 Generated with Claude Code
https://claude.ai/code/session_01NECjjZbYWNTzq3bu7nuiDP