docs(specs): retire S06 and repair its references
🗑️ What this does
Retires S06 (storage layer) from the tree and repairs every reference it leaves behind, following the S04-C precedent in !2879 (merged). The spec has been a 22-line landing stub since dddc6cc7 converted its content into docs/dev/storage.md and docs/dev/storage-composition.md. This MR deletes the stub, turns its index row into a retired row, and removes every S06 citation from the code: Go comments, the config proto, SQL migration comments, CI, and scripts.
🔗 ADR sync
Handbook !21252 removed the three ADR passages (ADR-007 twice, ADR-008 once) that linked docs/specs/S06-storage-layer.md, and the sync:adrs job has brought that change into main, so deleting the spec leaves no ADR link dangling.
✅ Eligibility
| Finding | Re-verified |
|---|---|
| Completed with zero implementing plans | docs/specs/README.md ## Completion and retirement names S06 and S22 as the Implemented specs whose plans were deleted before the retired-row rule existed; dddc6cc7 deleted S06's plan and settles completion. No retired plan row names S06. |
| The spec is a stub | |
| No blocking open issue | storage.md (for example #198). #615 owns the deferred blob FKs; this MR only re-points their TODO markers at it. |
| Destination carries the contract | storage.md section (table below); nothing needed authoring. |
📚 Citation to destination
| Citation in the tree | Now carried by |
|---|---|
AC#7 (Exists tri-state), AC#9 (multipart copy above 5 GB), AC#12 (signed HTTPS URLFor) |
### StorageDriver, ### Move semantics and ### S3 driver, ## Security considerations |
BlobStore AC, OpenBlob execution steps |
### BlobStore, ### Delivery mode, ### Object metadata |
Session Lifecycle AC |
### Session, ### Commit protocol |
Commit Protocol step numbers |
### Commit protocol; its list is renumbered, so these were restated, not re-pointed |
Crash-Recovery A1a to G1b, B1 |
### ResumeSession recovery branches, ### Failure scenario catalog, ### dirty as a poison pill; the ids survive without the S06 prefix |
| "Deferred DB Writes", "Canonical cleanup" | their own sections |
Data Model, Step 6 attachment FK |
## Data model, ### blob_storage_blobs, ### upload_sessions |
| "Session-to-URL binding" | ### upload_sessions and the ## Error cases row |
Error Cases, Security Considerations, Observability, Configuration |
the matching sections |
Step 22 (mandatory storage) |
storage-composition.md ### One shared store, threaded into the format tiers |
Plan-step decisions, Resolution #21, S06 Testing, PathResolver ACs |
dropped as point-in-time; the code, ## Testing and ### PathResolver state what survives |
The three ADR delegations the handbook MR removes (the metadata_sha1 rationale, the per-failure flow, and the consistency model) are all carried by ### blob_storage_blobs, ### Object metadata and ## Consistency and crash recovery.
🔍 Reference sites and how each was resolved
| Site | Resolution |
|---|---|
docs/specs/README.md index row |
Retired row naming this MR and both dev docs |
docs/specs/README.md completion paragraph |
Names S22 alone, since S06 now has a retired row |
docs/plans/README.md npm-hosted row |
Links the storage layer |
| 13 live specs, 15 live plans | Each reference links the storage.md section carrying its contract; line-pinned citations became the section link or the restated contract; references to the deleted storage-layer plan keep the step with a commit-pinned permalink. No plan Status table is touched. |
| The five relative links to the spec file | Re-pointed with the rest; they are what docs:lint would otherwise fail on |
docs/dev/observability.md |
The 18 storage metric Owner cells link storage.md#observability |
docs/dev/development-model.md |
Table and prose ids link or name the storage layer; ### S06 delivery strategy is removed, because it recorded how a finished phase was sequenced and its stub-first lesson is already stated under ### When dependencies are not yet available |
docs/dev/database-query-patterns.md |
"the S06 catalog" became "the storage query catalog" |
docs/roadmap/closed-beta.md tallies |
Recomputed from the index: Implemented 6 to 5, Retired 1 to 2, tracked 55 to 54, approved-or-better 40 to 39, closed-beta scope 40 of 50 to 39 of 49 |
docs/roadmap/closed-beta.md rows, retrospectives, owner tables |
Dated narrative; the bare id stays |
docs/roadmap/closed-beta.md mermaid nodes |
Node identifiers, untouched |
.gitlab/issue_templates/engineer_onboarding.md |
Links storage.md instead of the spec |
internal/storage/session_expiry.md |
The GCS citation links storage.md#gcs-driver; the dead plan-step pointer became the current fact that StorageConfig carries no override |
internal/remote/operations.md |
Gains ## The cache-fill tee, carrying the contracts the capped fetch.go comments could no longer hold (below) |
| Go comments, 126 files | Removed or restated per go-style.md ### Reference only what does not rot; any other spec, plan-step or AC citation in an edited block went too |
config.proto, gen/ |
Four comments fixed and regenerated |
| SQL migrations | Data-model citations cite storage.md; the five TODO(S06-Step-6) markers are TODO(blob-fk) and point at #615 |
.gitlab-ci.yml, .mise.toml, testdata, scripts/conformance/run.sh |
Banners and comments name the storage subject |
Two lines keep the literal S06 because they mean monolith/S06, a live spec.
✂️ Comment compression
Editing a comment block caps the whole block (### Comment caps), and many storage blocks were several times over cap, so the Go diff is mostly deletions. The dropped text was restatement, AC and plan-step lists, and test-first narration. Comments found untrue against the code were corrected in the same edit:
internal/storage/metrics.go: the header claimed the metrics are an unwired skeleton.internal/storage/stub/stub.go:Newclaimed the interface lands in later plan steps.internal/format/maven/upload_stream_test.go: the header claimed its cases fail.internal/metrics/cardinality.go: "above" meant "below".
Where a compressed comment carried a contract stated nowhere else, the contract moved to the package's own page instead of being lost: fetch.go's cache-fill tee states, its no-concurrent-Close rule, the detached session context, and the unbounded terminal calls tracked in #396 now live in internal/remote/operations.md.
In pg_session.go, the prose above the closeFlushFail failpoint is deleted rather than rewritten. The failpoint's injected body counts as comment lines, so any rewrite there exceeds the cap; with the directive first the block passes, as internal/accounting/emit.go already does. The injected code and the arming sites carry what the prose said.
Non-comment changes: three test assertion messages, and TestInstrumentQuery_CoversS06NameSet / s06QueryNames renamed to TestInstrumentQuery_CoversStorageNameSet / storageQueryNames. No behavior change.
📏 Size
This MR exceeds 500 reviewable lines on purpose. The deletion and the sweep are one concern: a partial sweep leaves some sites pointing at a file that still exists and others at the dev doc, and lychee forces the link repairs to land with the deletion anyway. The branch is one commit per file group, so it reads commit by commit:
| File group | Files | Added | Removed |
|---|---|---|---|
internal/storage Go |
65 | 418 | 2192 |
internal/format Go |
30 | 103 | 540 |
| Other Go (cmd, datastore, remote, server, smaller packages) | 32 | 127 | 518 |
docs/specs |
13 | 168 | 166 |
docs/plans |
16 | 166 | 153 |
docs/dev |
3 | 29 | 38 |
| Roadmap, sidecar pages, issue template | 4 | 79 | 24 |
| SQL, CI, scripts, testdata | 13 | 40 | 36 |
proto and generated gen/ |
2 | 10 | 10 |
The retirement commit itself (the stub deletion and the retired row) lands on top of these.
📋 Guardrails
- Configuration reference (guardrail 14): the
config.protochange is comment-only, with no schema or loader change, sodocs/dev/configuration-reference.mddoes not change, and it must not gain a spec identifier. - User docs (guardrail 24):
docs/user/**is unaffected; a retirement changes no customer-visible surface. - E2e catalogs: no scenario is added or affected; this changes no behavior.
- Verification:
lychee --offline --include-fragments '**/*.md'0 errors;markdownlint-cli20 issues;vale0 errors on changed files;golangci-lint run ./...0 issues; the integration-tagged lint is clean on changed lines; the unit tests pass;check-comment-caps.sh --base origin/mainpasses;git grep S06-storage-layeris empty across the tree. - Duo
spec-status-changes: the retired row has no spec file to match by design, perdocs/specs/README.md### The retired row.
Related to #1338