land-complex-change / references/worked-landing.md
A worked landing
A reference shipped with the skill · 1,291 words
A worked landing
One migration-shaped change, end to end: the map, the budget, the ladder, a mid-run discovery that stopped the work, the extension that followed, and the surface that stayed unguarded. Names are generic; the sequence, including the discovery, is the ordinary one.
The change: drop the status column from the jobs table. It has been superseded by a
state enum written by the same code path for two releases.
1. Shape and band
Shape: migration. Two halves — the readers stop reading status, then the column is
dropped — an ordering between them, and one irreversible act.
The rubric is scored with investigate-codebase. Cost-of-being-wrong is 2 by this skill's
one rule: the plan contains applying a migration. Total lands at normal on its own; the floor
rule would have raised it there anyway. Announced before anything is dispatched:
land-complex-change · normal band — migration shape; cost-of-being-wrong 2 (plan applies a
migration) forces the floor. Map required, budget derived, one gate per affected surface,
act gates armed. Attended.
2. The map, read blindspots first
The mapping skill returns nine surfaces with content and two empty. Read in the order that matters:
- What it could not see: resolution is name-based; the repository has no compiler-resolved index. Data-resident references were queried — a single table of saved report definitions. Runtime-only edges: one job dispatches handlers by a key built at runtime.
- Callers: four, all in one package,
compilebreak. - Data contracts: two readers plus one deriver — a nightly rollup computing a count
grouped by
status. Break timesilent: with the column gone the group collapses and the number simply changes. - Jobs: the nightly rollup, above.
runtimeat first dispatch. - Docs and data-resident: one saved report definition names the column in a stored SQL
string.
silent, always. - Deploy ordering: code-first. The schema half would break readers that are live now, so the readers stop reading, old instances drain, then the column goes.
- External consumers: an analytics warehouse job in another repository, not readable from here — recorded as a blindspot with a probe: ask its owners for a column-level search.
3. The budget, before the first edit
BUDGET drop jobs.status base 4f2ab19 band normal shape migration
map: blast map of the same base; blindspots read
ALLOWED
src/jobs/read-status.ts edit callers switch four call sites to state
src/reports/rollup-nightly.ts edit data-contracts group by state; deriver
src/jobs/__tests__/rollup.test.ts edit tests-and-guards rung-1 guard for the deriver
migrations/<version>_drop_status add data-contracts FILE ONLY — not applied
EXPECTED EFFECT
callers four call sites take state compile
data-contracts rollup groups by state, same totals silent
jobs nightly rollup keeps running runtime
docs-and-data-resident one saved report definition updated silent
ui none — searched, control fired none
external-consumers UNKNOWN — warehouse job unreadable unknown
OUT OF BOUNDS
the four standing classes, plus:
- the enum definition itself: widening it is a different change
- the report-definition table beyond the single row named above
ON BREACH
stop → re-enter the mapping skill → extend | split | abandon
The migrations/... row is the distinction the whole shape turns on: the file is allowed,
applying it is not.
4. The ladder, armed before any edit
| Surface | Guard | Rung | Fail-before |
|---|---|---|---|
| callers | typecheck | 1 | run first: four errors, one per call site — quoted |
| data-contracts (deriver) | rollup test asserting the grouped totals | 1 | edited the test to expect state; run: fails on the old code, correct reason |
| jobs | registration assertion + one execution test | 2 | additive; mutation: removed the registry key, watched the assertion fail, restored |
| tests-and-guards | the mutation above is itself the check | 2 | recorded |
| docs-and-data-resident | a query counting rows whose SQL names status |
1 | returns 1 before; must return 0 after |
| deploy-ordering | rehearsed on a disposable database | 3 | written procedure, before-value recorded |
| ui | — | 4 | unguarded: no view renders the column; a search with a fired control found nothing, and nothing would catch a future one |
| external-consumers | — | 4 | unguarded: the warehouse job is in another repository. Guarding it needs a column-level search by its owners — asked, answer pending |
Two rung-4 rows, both visible in the deliverable. The second is the honest one: this change cannot see the consumer that is most likely to break, and the reviewer needs to know that before approving, not after.
5. The breach
Four call sites edited, typecheck green. While editing the rollup, a SELECT built from a
string literal appears in a second report path that the map did not list — an export
routine assembling its query from a template, in a package the search's pathspec excluded.
The work stops there. Not after finishing the rollup edit: the discovery is evidence that the map's method missed a class of thing, so every clean result from the same method is now weaker evidence than it was.
Re-entering the mapping skill with the new fact returns what stopping bought: three more string-built queries, not one. Two name the column; the third names a different column and is irrelevant. The original pathspec had excluded an entire package.
Disposition: extend. The two new sites belong to this change — same surface, same break time, no new shape. The budget is re-declared with the extra rows, the extension is announced with the re-scored band (still normal), and the ladder gains a rung-1 guard for the export path: a test asserting the exported header set, which fails before and passes after.
Absorbing the two edits quietly would have produced a diff with two extra files and no record of why — and, worse, would have left the third string-built query undiscovered, because nobody would have gone looking for a class of thing they had already fixed twice.
6. Landing, in the map's order
Code-first, in separately revertible steps: callers and rollup, then the export path, then the saved report definition row, then the migration file. Four commits, each revertible alone.
At the act gate:
ABOUT TO: apply the pending migration to the production database
IT TOUCHES: one table, one column
CANNOT UNDO: the column's values. A revert restores the shape, not the data.
IF I DO NOT: nothing else is blocked. The readers already stopped reading it.
Consent given, naming this act. The applied-migration record is updated in the same change — the record is part of the act, and a repository whose history disagrees with production breaks the next clean deploy rather than this one.
7. Closing
Ladder re-run: every rung-1 gate passed having failed first; both rung-2 gates passed with
their mutations recorded; the rehearsal at rung 3 matched its expected value. Nothing was
recorded unproven.
Residual risks, from the map's silent items and the two rung-4 rows:
- The warehouse job in another repository. Probe: a column-level search by its owners; asked, pending. This is the most likely break in the whole change.
- Any report definition added to the datastore between the query and the deploy. Probe: re-run the counting query immediately before the act — done, still 0.
- Undo: a revert restores the schema shape and the four commits. It does not restore the column's values, and it does not un-write rows the new code wrote in the window.
Handed to review: the diff, the budget with its one recorded extension, the ladder including both unguarded rows, and the three residuals. The reviewer's first question was about the warehouse job — which is the point. It was on the page.