Canonical privacy policy: one page, retired docs library, public copy gate - #980
Merged
Conversation
One /privacy route replaces the scattering of analytics promises: what is collected, why, which processors receive it, indefinite default retention, and how to unsubscribe or request deletion. It describes categories and purposes rather than an event catalog. A published catalog goes stale the first time an event changes, and a stale one is worse than a general one; the page also avoids installation claims and absolute guarantees it cannot continuously verify. Its spec fails if any of those grow back. Also lists /privacy in the sitemap inventory and links it from the footer bottom bar. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Deletes the What we won't do section outright rather than trimming it to a smaller set of claims, and removes both its call sites. Also drops the FinalCTA trailing caption, the YesWall install/no-phone-home row, and the orphaned CSS for all three. The specs now fail if any of them return: FinalCTA renders no caption element, YesWall carries fifteen questions with no phone-home claim, and both counts stay derived from the data so the label cannot drift. Reworded Pilot-to-Prod's OpenTelemetry hooks to Distributed tracing hooks. Removing the caption prop also removes two descriptive call-site captions on the home and AG-UI pages. That is the approved scope: the surface goes, not just the promises on it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… redirects Deletes the seven dedicated files and removes the library from docsConfig, the LibraryId union, the docs home card, and the LibraryMark glyph map; navigation, search, static params, sitemap, and markdown lookup all lose it through the shared configuration. Delivered links and indexed results outlive a deletion, so all four retired route families — the public docs root and descendants, and the markdown API root and descendants — permanently redirect to /privacy. Browser tests walk each one. Two ag-ui docs tables kept documenting the sink option but lost their link to the retired library, and llms-full.txt no longer imports the deleted API JSON. Also revives next.config.spec.ts: it sits at the app root, which none of the vitest include patterns matched, so its PostHog rewrite assertions had never run. Root specs are now included. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds a public-copy scan that fails on the barred absolute claims — phone home, installation is inert, off by default, what we won't do, no telemetry is emitted, we never collect — and on narrative positioning around the word. Rewrites the three blog posts and the ag-ui, chat, langgraph, and render docs in observability and instrumentation language, and deletes the three lifecycle guides' Privacy sections outright rather than softening them: they asserted absolutes no test keeps true, and /privacy now covers the subject once. Public /api/ingest bodies become Invalid event payload, Event ingest is not configured, and Event ingest failed. The internal log prefix and type names are untouched, and a test pins that split in both directions. The scan covers hand-authored MDX only. Generated API JSON still carries the old guarantee text; the projection that cleans it is the next task, and the scan grows to cover it there. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Generated API docs are TSDoc rendered as published copy, so a claim written in a doc comment became site content without anyone reviewing it as content. Four comments asserted 'No telemetry is emitted unless this is provided' and shipped straight through. Fixes those at the source rather than only downstream: the same comment is the .d.ts and the IDE tooltip, which no website-side filter can reach. Generation now fails on the raw entries and names the offending sentence, so the author is sent back to the comment instead of the site being quietly cleaned. Adds a pure projection as the second line: it strips a barred claim from any description, keeps every name, type, and structure verbatim, and does not mutate its input. Renaming AgentRuntimeTelemetry* or a config field would make the docs disagree with the shipped types, which is the worse failure. The narrative generator now reads a six-library allowlist instead of walking the directory, so a retired library reappearing on disk cannot feed it again, and the public-copy scan covers generated JSON as well as authored MDX. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The source scan reads the repository; this reads what a visitor receives. They can disagree — a template, a generated bundle, or a response body can carry a claim no .mdx file contains — and the served side is the one that ships. Crawls every sitemap route plus an explicit registry of non-indexed public routes (AGENTS.md, CLAUDE.md, both LLM endpoints, representative markdown API output), asserts the retired routes still answer 308 to /privacy, and checks public /api/ingest error bodies. A future public route such as /connect belongs in that registry in the change that creates it, or it ships unchecked. Both the scan and the crawl now import one contract module, so the two cannot drift apart — and drift would land on the deployed side, which is harder to notice. Two things this surfaced: - NX It's time to update Nx 🎉 Your repository uses a higher version of Nx (22.5.1) than your global CLI version (21.5.2) For more information, see https://nx.dev/more-concepts/global-nx NX Cannot find configuration for task root:serve Pass --verbose to see the stacktrace. runs with dist as its cwd, and dist carries no content/, so routes reading MDX at request time served an empty list. /blog rendered zero posts. The gate would have passed against a page no visitor sees, so production mode links the content in before serving. - CI ran the website E2E only in dev mode. The gate now runs a second time against a real production build. Verified non-vacuous: injecting a claim into /about fails the crawl and names the route. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
blove
enabled auto-merge (squash)
September 3, 2026 06:02
The gate crawls every sitemap route. Against a prebuilt production server that is about two seconds; against `next dev` each route compiles on demand, and the ordinary CI e2e job timed out on it. I had only ever run the gate in production mode locally, so the dev-mode cost never showed up until CI. Both modes are now exercised before pushing. Scoped to production mode, which is also where the plan puts it: the answers that matter come from the built output, not from a dev bundle. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Contributor
blove
added a commit
that referenced
this pull request
Sep 4, 2026
…the Yes Wall main's #996 replaced the Yes wall with the reliability band: ProofStrip moves into the dark contrast slot under the logo ribbon and the Yes wall is deleted. That supersedes this branch's Task 12, so the Yes wall work is dropped rather than merged. - page.tsx: ProofStrip (dark) sits directly under LogoRibbon, ahead of RuntimeParity/ThreeSteps. YesWall is gone; Promises went with #980 and its component no longer exists on main. StackDiagramSection and HomeConceptGrid stay unmounted here (they still ship on /langgraph and /ag-ui). Metadata keeps HOME_TITLE/HOME_DESCRIPTION. - landing.css: main's proof-strip block wholesale, including its min-width:0 fix, which supersedes this branch's repeat(2, minmax(0, 1fr)) from 5b6328b. The .yes-wall-* rules and the Task 12 expander are deleted. - style-contracts.spec.ts: the .yes-wall-row[hidden] contract is removed; the rule it guarded no longer exists. - FinalCTA.tsx: keeps this branch's optional ctaId on primary/secondary and captionLink, and honours main's retirement of the promise caption — the caption prop stays, but its default is null instead of the old "Installation is inert" line, which main's e2e now asserts is absent. - analytics/events.ts + taxonomy.md: home_production_readiness_expand joins home_yes_wall_docs as retired; neither has a firing site any more. - e2e: the Yes Wall expander test is dropped from home-hero.spec.ts; website.spec.ts keeps main's dark-proof-band assertion alongside this branch's five-FeatureBlock and H1 assertions. - HomeFAQ: the branch's telemetry question made a barred absolute claim ("Installation is inert") and linked the retired /docs/telemetry library, both of which main's public-copy contract now forbids. Replaced with a reporting question answered from /privacy. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
blove
added a commit
that referenced
this pull request
Sep 4, 2026
…ialog Rebuilds the top of threadplane.ai and reorders the bottom, per docs/superpowers/specs/2026-09-02-homepage-rebuild-design.md. The demo-side /hero route this embeds shipped in #976. Rewritten: stacked category hero, InstallDialog (fake/LangGraph/AG-UI), HeroDemo (server-rendered poster as the LCP, origin-checked postMessage bridge to demo.threadplane.ai/hero, poster fallback), LogoRibbon into three labelled compatibility rows, HomeFAQ, PilotBlock, FinalCTA. New: RuntimeParity, ThreeSteps, CodingAgentQuickstart, ScopeTable, a shared Modal primitive, and a Try-without-a-backend docs page verified from a clean ng new application. All homepage copy, install commands and snippets are single-sourced in src/lib/positioning.ts behind drift guards that resolve package names and peers against libs/*/package.json, parse every snippet through the TypeScript compiler, and pin the license word and Angular range to their manifests. Adopts main's decisions where they superseded the spec: the Yes wall stays deleted and the reliability band keeps its slot and styling (#996), Promises stays unmounted, and the telemetry FAQ answer uses the privacy-policy language the public-copy contract requires (#980). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
blove
added a commit
that referenced
this pull request
Sep 4, 2026
…ialog (#997) Rebuilds the top of threadplane.ai and reorders the bottom, per docs/superpowers/specs/2026-09-02-homepage-rebuild-design.md. The demo-side /hero route this embeds shipped in #976. Rewritten: stacked category hero, InstallDialog (fake/LangGraph/AG-UI), HeroDemo (server-rendered poster as the LCP, origin-checked postMessage bridge to demo.threadplane.ai/hero, poster fallback), LogoRibbon into three labelled compatibility rows, HomeFAQ, PilotBlock, FinalCTA. New: RuntimeParity, ThreeSteps, CodingAgentQuickstart, ScopeTable, a shared Modal primitive, and a Try-without-a-backend docs page verified from a clean ng new application. All homepage copy, install commands and snippets are single-sourced in src/lib/positioning.ts behind drift guards that resolve package names and peers against libs/*/package.json, parse every snippet through the TypeScript compiler, and pin the license word and Angular range to their manifests. Adopts main's decisions where they superseded the spec: the Yes wall stays deleted and the reliability band keeps its slot and styling (#996), Promises stays unmounted, and the telemetry FAQ answer uses the privacy-policy language the public-copy contract requires (#980). Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces Threadplane's scattered analytics promises with a single
/privacypolicy, retires the dedicated telemetry docs library behind permanent redirects, and adds a gate that checks served production output rather than source.Implements
docs/superpowers/plans/2026-08-31-threadplane-canonical-privacy-policy.md, the first of the three plans the approved growth design decomposed into.What changes
One canonical policy.
/privacystates the collected categories, names every processor (Vercel, Neon, PostHog, Resend, Google, Anthropic), declares indefinite default retention, and explains deletion, opt-out, and contact. It describes categories and purposes rather than an event catalog: a published catalog goes stale the first time an event changes, and a stale one is worse than a general one. Linked from the footer on every page and listed in the sitemap.The promise surfaces are gone. The "What we won't do" section is deleted outright rather than trimmed, along with both call sites, the
FinalCTAcaption, and the YesWall install claim (16 → 15 questions, count still derived from the data). Removing the caption prop also removed two descriptive captions on the home and AG-UI pages — the surface goes, not just the promises on it.The telemetry docs library is retired. Seven files deleted and the library removed from
docsConfig, theLibraryIdunion, the docs home card, and the glyph map, so navigation, search, static params, sitemap, and markdown lookup all lose it through shared configuration. All four retired route families answer 308 to/privacy— the public docs root and descendants, and the markdown API root and descendants.Claims fixed at their source, not downstream. Four TSDoc comments asserted "No telemetry is emitted unless this is provided" and were rendered into published API docs. The same comment ships in the
.d.tsand every IDE tooltip, which no website-side filter can reach, so generation now fails on the raw TSDoc and names the offending sentence rather than quietly cleaning the website. A pure projection remains as a second line for anything phrased differently.A gate on served output.
e2e/public-copy.spec.tscrawls every sitemap route plus an explicit registry of non-indexed public routes, and runs against a real production build in CI. One shared contract module feeds both the source scan and the crawl so they cannot drift.Scope decision worth review
The plan asked that no public surface contain the word "telemetry", while also placing
AgentRuntimeTelemetrySinkout of scope. Those cannot both hold:telemetryis the literal name of a documented config field onprovideAgent(),toAgent(), and bothAgentConfigtypes.The gate therefore bars the claims and the narrative positioning, and a companion test asserts the API rows still exist — so a future cleanup cannot satisfy the bans by deleting documentation for a shipped option.
Two bugs this surfaced
next.config.spec.tshad never run. It sits at the app root, which none of the vitest include patterns matched, so its PostHog rewrite assertions had been dead since they were written. Root specs are now included; the existing assertions pass./blogserved zero posts in the production build.nx serve --configuration=productionruns withdistas its cwd anddistcarries nocontent/, so routes reading MDX at request time returned an empty list. The gate would have passed against a page no visitor sees. Production mode now links the content in before serving.Testing
/privacyprerenders as static/aboutfails the crawl and names the route; injecting one into committed API JSON fails the scan; injecting one into TSDoc aborts generation🤖 Generated with Claude Code