Skip to content

Docs corpus: rewrite every published page in its Diátaxis mode (#272) - #274

Merged
simpros merged 2 commits into
mainfrom
gh-272-docs-corpus-diataxis
Oct 2, 2026
Merged

simpros merged 2 commits into
mainfrom
gh-272-docs-corpus-diataxis

Conversation

@simpros

@simpros simpros commented Oct 2, 2026

Copy link
Copy Markdown
Owner

Closes #272

Why the change

The docs corpus mixed tutorials, reference, and explanation on the same pages, so this rewrite gives every published page exactly one Diátaxis mode with facts re-checked against the code.

Special things to note

  • Every H1 and every #fragment link target is unchanged, so sidebar labels, the docs index, and external anchors keep working.
  • Only prose plus the three docsGroups description strings changed; no shell, theme, or marketing-fragment code, leaving issue 273's surface untouched.
  • Knob sweep found no stale names in the corpus (SPROUT_SWEEP_CRON was already correct); versions and commands verified against package.json and the CLI sources.

Change outline

One page, one mode (skill workflow: type → audience → goal → scope → outline → write, answered from the ticket):

  • tutorial — getting-started: one GitLab path to a first preview, no tables, no options.
  • how-to — adopting-a-repo, ci-integration, previews, operator-deploy, herdr-integration, troubleshooting: task-headed recipes, symptom → cause → fix for troubleshooting.
  • reference — cli-reference: terse command/flag tables, pedagogy moved out to links.
  • explanation — telemetry: what is sent, why, what it costs.
  • onboarding-prompt: unchanged copy-paste block, still exactly one text prompt fence.
 docs/*.md (10 pages)      # rewritten in place, one mode each
 README.md                 # front door tightened, links unchanged
 docs/site/assemble.ts     # 3 description strings (adopting, troubleshooting, telemetry)
 llms.txt                  # regenerated from the generator

Gates: bun test docs/site/ 75 pass, bun run docs:check links OK, bun run docs:typecheck clean.

Closes #272 written as plain text per the ticket: Closes #272

@simpros

simpros commented Oct 2, 2026

Copy link
Copy Markdown
Owner Author

🧊 Thermo-nuclear review (round 1) — REQUESTCHANGES · 9d6b3b53

    1. Structural: the worktree-db flag contract is now documented twice and will drift
    1. Content regression: the only seeded-manifest (health: + seed:) example was deleted, leaving two dangling references
    1. Factual regression: telemetry cost claim misstates the code
    1. Factual regression: a valid maintainer test pointer was dropped
    1. Legibility: a human tutorial now tells the reader to invoke an internal TypeScript function
  • Residual risks
  • Unverifiable from here
Full report (click to expand)

VERDICT: REQUEST CHANGES

Findings, in rubric priority order.

1. Structural: the worktree-db flag contract is now documented twice and will drift

docs/cli-reference.md:107,114-119 and docs/operator-deploy.md:766-780

The MR adds a new canonical-looking flags table to the reference page — while line 107 of the same section explicitly says "Operator detail: Operator deploy" — and then operator-deploy keeps the full bullet list of the same rules (--slug normalization/max-40, sprout_wt_ object naming and drop prefix refusal, atomic temp+rename, PGPASSWORD reuse, the canonical write set, --rename). That is two copies of one reference contract. This is the docs equivalent of duplicating a canonical helper, and it is exactly the kind of single-source rule this repo already enforces elsewhere (docs/site/assemble.ts:38-65 derives the sidebar/index/llms from one manifest, guarded by a drift test).

Remedy: keep the flag table only in docs/cli-reference.md (the reference home, which is where adopters and operators look up flags), and reduce docs/operator-deploy.md:755-780 to the how-to intent + the two command invocations + a link to cli-reference.md#worktree-db-local-provisioner. Do not leave both.

2. Content regression: the only seeded-manifest (health: + seed:) example was deleted, leaving two dangling references

docs/getting-started.md:44-45, docs/adopting-a-repo.md:158-159, docs/troubleshooting.md:17

The rewrite removed the seeded manifest block from getting started and moved seeding to a one-line pointer. But no published page now shows a health: block at all — verified by grep -rn "health:" docs/*.md, which matches only prose, while examples/adopting-repo/.sprout.yaml is the sole remaining full example. Two cross-references are now false:

  • docs/adopting-a-repo.md:158 — "Write a seeded manifest (as in the quickstart): add health: + seed:" points at a quickstart that no longer contains either.
  • docs/troubleshooting.md:17 — "Add the health: block (Getting started has the shape)" — the anchor resolves but the claim is false; the page has no health: block.

This matters because health.* is when seeding required (docs/adopting-a-repo.md:49-52) and seeding is the documented next step. The docs tests pass because the anchor exists — they do not check that the referenced content is present, so this regression is invisible to CI.

Remedy: restore a concrete seeded manifest (health: with path/interval/timeout/expect, plus seed: { dockerfile: Dockerfile.seed }) in docs/adopting-a-repo.md beside the manifest table, and repoint both references at it. Delete "as in the quickstart" / "Getting started has the shape" rather than pointing at a page that does not have it.

3. Factual regression: telemetry cost claim misstates the code

docs/telemetry.md:90-95

"two small JSON posts per deploy plus one per day" is wrong. apps/server/src/preview/async-deploy.ts:157 calls reportDeployOutcome once per deploy → buildDeployEvent once (apps/server/src/telemetry/reporter.ts:90-95) → one POST. The install event is boot + every 24h (apps/server/src/telemetry/heartbeat.ts:1-22, apps/server/src/index.ts:67), never per deploy. The old "Two events, one fixed schema" described two event kinds; the rewrite turned that into two posts per deploy.

Remedy: "one post per deploy, plus an install heartbeat at boot and every 24h".

4. Factual regression: a valid maintainer test pointer was dropped

docs/cli-reference.md:157-158

The rewrite deleted "- Send-and-read-back through Mailpit's API: e2e/mail.test.ts". e2e/mail.test.ts exists and does exactly that (test named "example app sends and Mailpit API reads back the deployment From"), so this is a loss of an accurate pointer, not a removal of stale content.

Remedy: restore the line (between forge-note.test.ts and the e2e/lifecycle.test.ts entry). If the intent was to trim, the whole "Test coverage" list should be reconsidered as a unit, not silently drop one entry.

5. Legibility: a human tutorial now tells the reader to invoke an internal TypeScript function

docs/getting-started.md:40-42

"Check the file loads with the CLI's own loader (apps/cli/src/yaml.ts, parseSproutYaml)" is unactionable for an adopter reading a getting-started tutorial — there is no CLI command that runs the manifest parser in isolation (sprout doctor hits GET /v1/doctor, not the local parser). This phrasing was borrowed from the agent-facing docs/onboarding-prompt.md:52-55, where reading source is legitimate; in a human page it leaks implementation detail and gives a step the reader cannot perform.

Remedy: drop the check, or replace it with the observable behavior: "Unknown keys are rejected (unknown key: <path>), so typos fail on the first sprout ci preview."

Residual risks

  • A reader follows step 1, adds seed: without health:, and hits health block required in .sprout.yaml when seed block is configured at deploy. Probe: grep -rn "health:" docs/*.md | grep -v "required\|when seeding" should be non-empty (a real example) after the fix.
  • A reader plans egress from the telemetry page and under-provisions: two posts per deploy vs. the real one. Probe: count sendTelemetryEvent invocations in apps/server/src/telemetry/deploy.test.ts for a single deploy (expect 1).
  • The duplicated worktree contract drifts on the next flag change: one copy updates, the other silently does not. Probe: add a CI check that the --slug / --env-file / --rename tokens appear in exactly one published doc page.
  • A user searching for the Mailpit e2e coverage finds nothing and re-checks a working test. Probe: grep -c "e2e/mail.test.ts" docs/cli-reference.md (currently 0).
  • A human reader stalls on the parseSproutYaml step and cannot verify their manifest before pushing. Probe: grep -n "apps/cli/src" docs/getting-started.md should be empty for a human tutorial.

Unverifiable from here

Could not run the CLI against a live gateway or re-render the published Pages site; I did run docs/site locally (75 pass, 0 fail), so anchors, fragments, and the checked-in llms.txt equal the generated index — those are verified, but the content-accuracy issues above are invisible to that suite.


Automated agent review (opencode) · worktree /home/sim/.herdr/worktrees/sprout/gh-272-docs-corpus-diataxis · subsequent rounds will reply in this thread.

- operator-deploy: worktree-db flag contract single-sourced to cli-reference
- adopting-a-repo: restore concrete seeded manifest (health + seed) example
- troubleshooting: repoint seed-without-health fix at adopting-a-repo
- telemetry: one post per deploy plus boot/daily heartbeat, not two per deploy
- cli-reference: restore e2e/mail.test.ts Mailpit pointer
- getting-started: drop internal parseSproutYaml loader step for human readers
@simpros

simpros commented Oct 2, 2026

Copy link
Copy Markdown
Owner Author

🧊 Thermo-nuclear review (round 2) — APPROVE · 554f1687

    1. (Structural, pre-existing) The deploy-token recipe is still authored twice, and the new cross-link claims one copy is canonical
    1. (Content accuracy) on_stop is asserted on a section the page sends GitHub readers to
    1. (Content regression) A minimum-release guard was dropped from the install snippet
  • Residual risks
  • Unverifiable from here
Full report (click to expand)

VERDICT: APPROVE

All five findings from review-report.md are resolved in 554f168, and I re-verified each against the tree and the code, not just the prose. HEAD is 554f168776af7b261c535aef10148992ff0863b3, matching the brief; the diff is docs-only plus two manifest description strings in docs/site/assemble.ts. bun test in docs/site is 75 pass / 0 fail, and the real link gate (bun run check.ts) reports docs links OK across every assembled page, so every changed fragment resolves. No file crosses 1000 lines (largest: docs/operator-deploy.md, 852). The fixes hold up:

  • docs/operator-deploy.md:766 now defers the worktree flag contract to docs/cli-reference.md#worktree-db-local-provisioner; I checked the new table against apps/cli/src/commands/worktree-db.ts, apps/cli/src/worktree-db/env-file.ts, and packages/preview-db/src/worktree-names.ts (normalization, max 40, sprout_wt_ naming, prefix refusal, PGPASSWORD reuse, canonical write set, --rename logical keys) — accurate.
  • docs/adopting-a-repo.md:165-176 restores the concrete health: + seed: manifest, and docs/troubleshooting.md:17 now points at it; the anchor lives in the same section as the block, so the pointer is true.
  • docs/telemetry.md:94 now matches the code: apps/server/src/preview/async-deploy.ts:157 → one reportDeployOutcome, and the install event is boot + 24h (apps/server/src/telemetry/heartbeat.ts:1).
  • docs/cli-reference.md:160 restores the e2e/mail.test.ts pointer; the file exists.
  • docs/getting-started.md:40 drops the internal parseSproutYaml step while docs/onboarding-prompt.md:53 legitimately keeps it for the agent-facing page.

Findings, in rubric order.

1. (Structural, pre-existing) The deploy-token recipe is still authored twice, and the new cross-link claims one copy is canonical

docs/cli-reference.md:88-102 and docs/adopting-a-repo.md:258-270

The MR added Canonical recipe: [Adopting a repo](adopting-a-repo.md#deploy-token-setup) at cli-reference.md:91, then keeps the full recipe below it, while adopting-a-repo.md also carries the full recipe. Two copies of one procedure, already diverging (--repo "https://github.com/org/repo" vs --repo "https://github.com/${GITHUB_REPOSITORY}"), is the same drift class round 1 flagged for the worktree contract. This is not a regression introduced by the MR — the duplication pre-dates it — so it does not gate, but the pointer makes the intent clear and the leftover block contradicts it.

Remedy: keep the recipe in exactly one page. Since cli-reference.md now names adopting-a-repo.md canonical, reduce the reference section to the one-line usage + link (the sprout admin token … row at cli-reference.md:22 already covers command discovery), or invert the direction and delete the duplicate from adopting-a-repo.md. Do not leave both.

2. (Content accuracy) on_stop is asserted on a section the page sends GitHub readers to

docs/getting-started.md:82

"Close / merge: sprout ci teardown runs via on_stop" — but the page intro (line 8) tells GitHub readers to branch at step 3 and rejoin at "What you get". GitHub has no on_stop; the caller workflow tears down on pull_request: closed plus the sweep (ci-integration.md:179-181). A GitHub reader who follows the rejoin instruction gets a GitLab-only mechanism stated as universal.

Remedy: qualify the line: "Close / merge: sprout ci teardown on the on_stop job (GitLab) or the closed event (GitHub) — idempotent, exit 0 when already gone."

3. (Content regression) A minimum-release guard was dropped from the install snippet

docs/ci-integration.md:196-197

The rewrite deleted TAG=v0.8.3 # pin ≥ the release that ships glibc \sprout-linux-x64``. The asset table above still guides libc selection, so this is minor, but nothing now warns that some older tag predates the glibc asset — a reader pinning an old release can get a 404 where the old comment prevented it.

Remedy: restore the constraint where it is load-bearing, e.g. a "Minimum release" note in the asset table, or the comment on TAG.

No other structural findings: the rewrite keeps the manifest contract in adopting-a-repo.md, lifecycle in previews.md, flags in cli-reference.md, and reduces the operator page to intent + invocations + links, which is the right ownership split.

Residual risks

  • The restored seeded manifest could drift from the parser the next time health.* changes, and no docs test checks that an example is valid, only that links resolve. Probe: run the example through apps/cli/src/yaml.test.ts, or sprout doctor against docs/adopting-a-repo.md:165-176.
  • The telemetry cost sentence is prose, not generated; it can silently go stale the next time reporting changes. Probe: count reportDeployOutcome invocations per deploy in apps/server/src/telemetry/deploy.test.ts (expect 1) and the heartbeat test.
  • Cross-references phrased as content claims ("shows the shape", "has the shape") can become false while the link gate stays green, which is exactly what round 1 caught. Probe: grep -n "health:" docs/adopting-a-repo.md and re-read docs/troubleshooting.md:17 after any health: edit.
  • The GitLab-first on_stop claim will re-break whenever the GitHub branch of getting-started is edited. Probe: read docs/getting-started.md:4-8 together with .github/workflows/preview.yml triggers.
  • The two deploy-token copies will drift on the next sprout admin token flag change. Probe: grep -rn "admin token create" docs/ should shrink to one how-to copy plus the operator docker exec path.

Unverifiable from here

Could not run the CLI against a live gateway, exercise a real deploy, or render the published Pages site; external http(s) links are intentionally skipped by the link gate. I did run docs/site (75 pass, 0 fail) and the real check.ts (docs links OK), and I could not verify release-tag history to confirm when the glibc sprout-linux-x64 asset first shipped, so finding 3 is a request to retain documentation, not a claim that the constraint is currently violated.

@simpros
simpros merged commit b0869db into main Oct 2, 2026
2 checks passed
@simpros
simpros deleted the gh-272-docs-corpus-diataxis branch October 2, 2026 19:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Docs corpus: rewrite every published page with the documentation-writer skill (Diátaxis)

1 participant