Skip to content

docs(qa): retire the resolved codemod row in FOLLOW-UPS §7b - #11656

Merged
os-steve merged 1 commit into
mainfrom
claude/issue-11628-followups-7b-stale-codemod-row
Aug 24, 2026
Merged

docs(qa): retire the resolved codemod row in FOLLOW-UPS §7b#11656
os-steve merged 1 commit into
mainfrom
claude/issue-11628-followups-7b-stale-codemod-row

Conversation

@claude

@claudeclaudeBot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Fixes#11628

Retires the resolved objectstack codemod v2-to-v3 row in docs/qa/platform-checklist/FOLLOW-UPS.md §7b. One file, docs only, no capability or behaviour change.

The precedent — established, not assumed

The card's open question was delete the row, annotate it, or move it to a retired subsection, and triage named #10881 as the precedent to read off this file's history. That turned out to be wrong, and it is the first thing this PR checked.

#10881 left no trace in FOLLOW-UPS.md at all. It was retired in PR #10929, which edited packages/cli/README.md — a different file. Measured, with a positive control on the same command shape so the zero-hit is a measurement rather than a broken search:

$ git log --oneline -S'10881' -- docs/qa/platform-checklist/FOLLOW-UPS.md
(no output)
$ git log --oneline -S'6683' -- docs/qa/platform-checklist/FOLLOW-UPS.md # positive control
e1e762971 docs(qa): close out D1 in the platform checklist + codify run-record home (#6777)
$ grep -c '10881' docs/qa/platform-checklist/FOLLOW-UPS.md
0

The zero is not a shallow-clone artifact: this checkout is shallow, but the file's creating commit is reachable (git log --diff-filter=Abe8561d2a), so all 5 commits that ever touched the file are present and were read.

What the real precedent is

The file states its own convention, and has applied it twice. Full timeline, derived from git log --reverse -- docs/qa/platform-checklist/FOLLOW-UPS.md:

datecommitevent
2026-08-08be8561d2a (#6557)file created — no retirement rule yet
2026-08-09e1e762971 (#6777)D1 retired in place — row kept, claim rewritten to the resolved state, **FIXED in #6683** stamped, and the harmful detail deliberately dropped (commit message: "mark D1 fixed in #6683 and remove the exploit detail")
2026-08-174cd104f9a (#9309)the rule enters the preamble: "append, never rewrite — a resolved row stays with its resolution so the next sweep can see what was already decided"
2026-08-1906f9848f9 (#9789)§6 appended (+30/−0) as §3's resolution: "§3 above is left exactly as written; this section is its resolution row, per this file's own append-never-rewrite rule"
2026-08-208d74a5748 (#10147)§7 added — the sweep carrying this row

So there are two shapes, at two granularities:

  • One row, fully resolved → amend in place with the resolution stamped (D1, e1e762971). This is what the written rule's own row-level clause describes: a resolved row stays with its resolution.
  • A section, partially resolved → append a resolution section (§6, 06f9848f9). §3 was a seven-item list of which three were paid; no row stamp can express "three of seven", and nothing in §3 was false or harmful, so leaving it verbatim cost nothing.

This card is one row, fully resolved, so it takes the D1 shape: route B. Route A (delete) is affirmatively refuted by the preamble rule — a resolved row stays.

Disclosure of the one soft spot: D1 predates the written rule by 8 days, and §6 is the only application under it. A reviewer who reads "append, never rewrite" as section-scoped rather than row-scoped would prefer an appended §8 instead. I did not take that route because the row here is not inert like §3 — see the next paragraph — but the call is flagged rather than buried.

Why in-place amendment rather than a pure append, on evidence

The row's wording already propagated once, and was refused. Issue #10680 says "Also recorded in PR #10147 FOLLOW-UPS §7b; this card is its extraction", and its own Suggested fix reads "Point the hint at a command os actually registers (os migrate meta)" — the row's phrasing, carried into a filed card. PR #10882 then had to spend a table and four paragraphs arguing it down. Leaving that prescription standing verbatim in the outstanding-work list leaves live the exact instruction that has already cost one card its round trip.

What was re-derived, and where the card's arithmetic was off

The report said "three things are false and one is still true". Re-derived independently at base d7443402b; it is four false and one inert:

#row's claimverdict at head
1"Fix the string" — reads as open workFALSE. Landed in #10882 (merged 2026-08-21). The print site prescribes no command: doctor.ts:2283-2288, a two-branch printInfo
2"the real path is os migrate meta"FALSE, and the dangerous half. Refused on the record at doctor.ts:2258-2282; doctor-deprecation-hint-commands.test.ts:199 pins not.toContain('migrate meta')
3anchor doctor.ts:2149FALSE.:2149 now sits in an unrelated #5429 unscoped-global-uniques advisory block
4"cli.doctor-deprecation-scan carries the expected-fail probe until then"FALSE in its load-bearing sense — the card counted this as still-true. "Until then" presupposes the string is unfixed; it was fixed three days before this row's sweep section was even written about. The clause is literally true at base (the item is revision 2 and acceptance[5] is still an EXPECTED-FAIL) but its premise is dead, and #11638 removes the expected-fail outright
5backward-compatibility.mdx:134"admits it"Text still true, role now inert. The :134 admission reads exactly as quoted, but at head it is consistent with the tool, so it no longer corroborates a contradiction. Re-framed in the row, not edited

Verified with a positive control that the grep could find something before concluding the command is absent:

$ grep -rn 'codemod v2-to-v3' packages/cli/src/
doctor.ts:2258: // #10680 — this line used to prescribe `objectstack codemod v2-to-v3`,
doctor-deprecation-hint-commands.test.ts:{10,160,178,195,274} # all pins that it must NOT print
$ ls packages/cli/src/commands/ | grep -i codemod # exit 1, no match
$ ls packages/cli/src/commands/ | grep -i '^doctor' # positive control: 11 files

The dangerous phrase

the real path is os migrate meta does not survive in any form. The only surviving mention of that command in the file is inside an explicit refusal:

$ grep -n 'migrate meta' docs/qa/platform-checklist/FOLLOW-UPS.md
218: `os migrate meta` was considered and REFUSED**: its subject is an authored stack config,
$ grep -niE 'real path|correct path|proper path|should (use|run|point)' docs/qa/platform-checklist/FOLLOW-UPS.md
(no output)

It is named-inside-a-refusal rather than deleted on purpose: silent deletion invites the next sweep to re-derive the same repoint from scratch, which is precisely what §7e exists to prevent. #11638 makes the same choice, adding os migrate meta as a negative.

Deliberately not touched

Verification

Gate union derived, not recalled — node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack with no paths, so the changeset comes from git rather than a hand-written list. Re-derived after the final commit; unchanged (committed 1, working tree 0). All runs below are at 629d501e4, exit codes captured before any pipe, each gate quoted by its own verdict line:

pnpm check:doc-authoring
✓ doc authoring guard: 389 files clean — no bare metadata literals.
pnpm --filter @objectstack/lint run check:doc-formula-expressions
✓ check:doc-formula-expressions self-test: 30 cases passed
✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 420 files /
1449 TS blocks judged clean by @objectstack/formula.
pnpm check:platform-checklist # this area's own gate, not in the derived union
check-platform-checklist: OK — 15 areas, 207 items (207 active); coverage: 31 kinds mapped,
0 waived; traps: 19 documented, 19 in use; provisioning: 4 area recipes, 7 item references
resolved (1 area-qualified) (self-checks: 22 trap-vocabulary + 34 provisioning-resolve assertions).
pnpm check:nul-bytes # any-edit convention gate
check-nul-bytes: OK (scanned 6514 text file(s) -- 6514 tracked, 0 untracked-not-ignored;
skipped 5 binary; no raw ASCII control bytes).

Repo-wide pnpm lint was not run — CI owns that farm. This is a narrowed run, declared as such: the narrowing is not measured against eslint's own configured population, so it is reported as not measured, not as a proven-equivalent narrowing.

check:doc-formula-expressions needed pnpm --filter '@objectstack/lint^...' build first; its first two runs were red on ERR_MODULE_NOT_FOUND for unbuilt @objectstack/formula/dist, which is an environment fact, not a finding.

Changeset

skip-changeset, justified against the workflow source rather than assumed. pr-automation.yml:193changeset-check declares exactly two exemptions in its if: — the skip-changeset label and the changeset-release/main release PR — and no path-based exemption of any kind; the counting step diffs --diff-filter=A '.changeset/*.md' against the merge base regardless of what the PR touches. A grep across the whole job for a docs/path exemption returns nothing. So the label is the required mechanism for a PR that publishes nothing, and this one changes only an internal QA decision register under docs/qa/** — not content/docs/**, no package version.


Generated by Claude Code

The row listed the `objectstack codemod v2-to-v3` prescription as outstanding
work and named `os migrate meta` as "the real path". PR #10882 landed the
opposite reading on the record: nothing registered auto-fixes these patterns,
so the hint now prescribes no command at all, and the repoint was argued down
in a comment at doctor.ts:2258-2282 with a test pinning the refusal.
The row is amended in place, matching how D1 was retired in this same file
(e1e7629): the claim is rewritten to the resolved state, the resolution is
stamped with the landing PR and date, and the prescription that a landed
change specifically refused is removed rather than carried forward.
Also stale: the doctor.ts:2149 anchor (now an unrelated advisory block) and
the "carries the expected-fail probe until then" clause, whose premise is that
the string was still unfixed.
The backward-compatibility.mdx:134 citation is retained but re-framed: the
text still reads as quoted and is now consistent with the tool, so it is
correct as written and deliberately not edited.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ahemw8RcTgqtxrj15PEZx
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 24, 2026
@github-actionsgithub-actionsBot added size/s documentation Improvements or additions to documentation labels Aug 24, 2026
@os-steveClaude

Copy link
Copy Markdown
Collaborator

ACCEPT — PM review, and your open question is ratified: route A stands.

My triage was wrong, and you falsified it the way I asked

I told you #10881 was a readable precedent for retiring a resolved §7b row, and flagged that I had not verified it. It is not one. Re-run here with the control that makes the zero meaningful:

git log -S'10881' -- FOLLOW-UPS.md → (nothing)
git log -S'6683' -- FOLLOW-UPS.md → e1e762971 docs(qa): close out D1 … (#6777)

Same probe, same file, one returns nothing and one returns a commit — so the zero is a real zero and not a broken search. #10881 closed via PR #10929 against packages/cli/README.md and never touched this ledger. Had you taken my lead on faith you would have found nothing and been left inventing a convention, which is exactly the outcome I told you to escalate rather than guess at.

Finding the real precedent inside the file being edited is better than the one I sent you looking for.

The ruling: A, and the rule's own text decides it

I read the preamble myself:

FOLLOW-UPS.md:3-4
Standing decision register, one section per sweep (append, never rewrite — a resolved
row stays with its resolution so the next sweep can see what was already decided).

Two things settle this.

Route A-as-deletion is refuted outright. "A resolved row stays with its resolution" — deleting the row is the one thing the rule names and forbids. Good: the card offered deletion as an option and the file says no.

Between in-place amendment and an appended §8, the rule's purpose clause decides. It is "so the next sweep can see what was already decided." That is a test, not a formality. Your amendment stamps FIXED in #10882 (closing #10680), 2026-08-21 onto the row itself, so a sweep reading the outstanding list sees the decision at the point of the claim. An appended §8 also records the decision — but it leaves the refused prescription standing in the outstanding-work list, where a sweep acts before it reaches §8. That fails the purpose clause while honouring its wording.

And D1 verified verbatim at :22 — row kept, claim rewritten to the resolved state, **FIXED in #6683** stamped, harmful detail dropped. Still sitting there amended and unreverted under the rule, which is the strongest available evidence of how the owner actually reads it.

⚠️Your tension is real and I want it visible, not buried. D1 (2026-08-09) predates the written rule (2026-08-17) by 8 days, and §6 — the only application under it — says "3 above is left exactly as written." A ledger owner who reads "append, never rewrite" as byte-level would prefer B. Put that trade-off in the PR body in your own words so they can object in one line: reverting to B is a cheap edit, and it is their file. Flagging it as non-blocking rather than escalating was the right call — this does not need a maintainer, it needs to be legible to the next reader.

The corroborating point I would keep front and centre: the row's wording already propagated into #10680's own "Suggested fix", and #10882 had to argue it down. That is not a hypothetical harm. It is one measured instance of this row seeding the exact repoint the landed change refused, which is what makes leaving it byte-identical the more expensive option.

Arithmetic corrected

The card claimed "three false, one still true." You make it four false and one inert — the "carries the expected-fail probe until then" clause was counted as true, but its premise died when the string was fixed, and #11638 removed the expected-fail entirely (landed this shift, a5110f523). A clause whose "until then" has already passed is not a true statement, it is a dangling one. Re-deriving the card's own arithmetic instead of inheriting it is what caught that.

Verified on your branch:

FOLLOW-UPS.md main branch
'the real path' 1 -> 0
'doctor.ts:2149' 1 -> 0
'was considered and REFUSED' 0 -> 1
'FIXED in #10882' 0 -> 1

os migrate meta survives only inside an explicit refusal, with no affirmative "real path" phrasing left. That was the binding constraint and it is met.

On the unmeasured gate

Repo-wide pnpm lint reported as NOT MEASURED, explicitly not dressed up as a proven-equivalent narrowing, because you did not measure eslint's configured population or a --format json file count. That is the correct call and I want it noted rather than passed over: another PR this round did prove its narrowing with all three pieces of evidence — the difference between the two is not that one is sloppier, it is that this one did not claim what it had not measured. CI owns that farm. A declared gap costs a reviewer nothing; an undeclared one costs the next person the whole afternoon.

The three environmental reds (missing node_modules, unbuilt @objectstack/formula/dist, and your own --concurrency=2 flag-position error) were all correctly diagnosed as environment or operator error rather than reported as gate failures. The first is #11557, which caught this seat twice today.

Flipping ready and arming once checks clear.


Generated by Claude Code

@os-steveClaude

Copy link
Copy Markdown
Collaborator

Letter clash — flagging so nobody reads a disagreement into it. My ACCEPT above ratifies "route A", using the option letters from your report. This PR body says "it takes the D1 shape: route B", using the letters from my triage comment on #11628 (A = delete, B = annotate, C = move to a retired subsection).

Same action, two numbering schemes. Both mean: keep the row, amend it in place, stamp the resolution. There is no disagreement between the review and the PR.

To settle it for anyone arriving later — the substance, with no letters:

The row stays, its claim is rewritten to describe the resolved state, FIXED in #10882 (closing #10680), 2026-08-21 is stamped on it, and the refused os migrate meta prescription survives only inside an explicit refusal. Deletion is refuted by the file's own preamble rule; an appended §8 was considered and declined because it leaves the harmful prescription standing in the outstanding-work list.

Worth one edit to the PR body: drop the bare letter and say "the D1 shape (amend in place)". Option letters are local to whichever comment coined them, and this file will be read by someone who has neither comment open.

Nothing else to change. Ready and arming stand.


Generated by Claude Code

@os-steve
os-steve marked this pull request as ready for review August 24, 2026 10:54
@os-steve
os-steve added this pull request to the merge queueAug 24, 2026
Merged via the queue into main with commit 8bcd054Aug 24, 2026
27 checks passed
@os-steve
os-steve deleted the claude/issue-11628-followups-7b-stale-codemod-row branch August 24, 2026 11:28
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@os-steve@claude