fix(metadata-protocol): refusals, hints and log lines state each decision in words instead of a tracker number (stage 2) - #20830
Conversation
…ds instead of a tracker number (stage 2, author-visible) The thrown refusals, the stored-type preflight and revert refusals, and the schedule-flow organization hint no longer send the reader to a tracker number: each says what was decided, or loses only the citation where the sentence already said it. Text only: no code, field, status or export moves. The prose-id ledger is recomputed with --census-ledger; only metadata-protocol rows move. Claude-Session: https://claude.ai/code/session_01DEvba2nBuD4tWzfq8r8NFY Co-authored-by: Claude <noreply@anthropic.com>
…each decision in words instead of a tracker number (stage 2, log lines) The kernel:ready index migrations, the seed/API tenancy repair and its receipt, the three migration-skipped warnings, and the protocol's warn and error lines no longer cite a tracker number. Where the sentence already said what was decided, only the citation goes; the three skipped warnings now say what the migration that did not run would have ensured. Two tests that pinned a number now pin the sentence. Text only. The ledger is recomputed; only metadata-protocol rows move. Claude-Session: https://claude.ai/code/session_01DEvba2nBuD4tWzfq8r8NFY Co-authored-by: Claude <noreply@anthropic.com>
…s its tracker number; changeset (stage 2) The last metadata-protocol row leaves the prose-id ledger: the testkit's isolation error already says what it guards, so only the citation goes. The ledger is recomputed with --census-ledger and holds no metadata-protocol row. Changeset: @objectstack/metadata-protocol patch. Claude-Session: https://claude.ai/code/session_01DEvba2nBuD4tWzfq8r8NFY Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 4 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 3 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 11 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 793427441801fea69c2cd1f38a9b98fc64d32086 && git checkout 793427441801fea69c2cd1f38a9b98fc64d32086
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 73155fedcacc215565c4eef6d9899977e0707010 442473234551d7cb909e2a927d1adc446a9b4e35 && git checkout -B drift-repro 73155fedcacc215565c4eef6d9899977e0707010 && git merge --no-ff 442473234551d7cb909e2a927d1adc446a9b4e35
node scripts/docs-audit/affected-docs.mjs --json 73155fedcacc215565c4eef6d9899977e0707010
|
Contract reviewServed-tier: Read-only, at tier, adversarial to the dispatch. Inputs: card #20513 (body and all 17 comments — the census 5900801368, the ruling 5902360492 「20513 A」 A / A, the lane checklist 5902678544, the stage-2 claim 5907730876, the stage-2 Check-runs on ① Derived judgmentsScope against the ruling and the claim — right. The ruling orders stages per package, all three categories, form D, Text only — right, checked line by line. All 108 changed lines in the 11 Accept-set and public surface — nothing moves — right. No schema, route, wire Ledger diff — right, exact. Nine Form D, string by string — right. Every cited card was read: 20 closed
Pins — right, 3 lines in 2 files. ② Semver level
Clause-②: no — right. Nothing an author can write is widened or narrowed; the PR body carries ③ Boundary flagsDev flags (report 5908549372), each answered:
One boundary note, not a FAIL item — a docs page quotes the old sentence. Implemented-by: VERDICT: PASS Generated by Claude Code |
Part of #20513
Clause-②: no
Stage 2 of 5 of this lane (
metadata-protocol), under the maintainer's A / A ruling on the card. The card stays open for stages 3-5, so this PR carries no closing keyword. Text only: no errorcode, field name, HTTP status, export or control flow moves. Every changed source line is a string-literal line (108 changed lines in 11.tsfiles, checked line by line against the merge base).What this does
The metadata protocol's refusals, hints and log lines sent the reader to a tracker number for the reason behind them. Each rewritten string now says that reason in words (form D, as the migration-entry rewrite and stage 1 applied it). Where the sentence already stated what was decided, only the citation goes. Where it did not, the decision is added in words:
protocol.tsinsertManyDatarefusal (thrown)insertManyis the partial-success batch insert: an outcome per row, so a bad row neither fails the whole batch nor makes the good rows run theirbeforeInserthooks twice.protocol.tsunknown metadata type refusal (400)additionalTypeswas retired because nothing ever read it.protocol.tsstored non-canonical type refusals on publish and on revert (STORED_TYPE_NOT_CANONICAL)/metaURL door now folds a type to its canonical spelling before it writes, so such a row predates that; the stored migration'sskippedreport "with that same reason" loses only its citation.runtime-authoring-gate.tsschedule-floworganization_idhintplugin.tsthe threekernel:ready"migration skipped" warningssys_settingrow identity on tenant and global rows; the adoption of untenanted seed rows and their autonumber counter.sys-metadata-repository.tshistory-counter abort (error)protocol.tspublish-closure degrade (warn)protocol.tscold-boot org-scoped audit (warn)sys_view_definitionandsys_settingindex migration messages (ADR-0120 D4 stays), the seed/API tenancy repair, its receipt and its skips, the batch-row withhold, the object-existence gate's no-registry warning, the nested-select, overlay and non-canonical-registry refusals, and the live-MySQL testkit errorEach claim was checked against today's code, not only against the cited card:
saveMetaItemfolds the request type before it persists;additionalTypesis aretiredKey()tombstone inpackages/spec; the org-scoped write refusal is live inorgScopedWriteRefusal. One cited number (10382) answers 404 and was read through its landing commitee09d2119; the testkit sentence already says what it guards.Order inside the stage
All 46 id-bearing literals (50 occurrences) fit one PR, under the stop line, so the stage lands whole, in three commits in the ordered sequence:
dc8a1a112author-visible text: 10 literals (thrown refusals, the stored-type refusals, the hint);730cbcaf6log lines: 35 literals, plus the two re-pinned tests;442473234thesrc/-shipped testkit string, and the changeset.Each commit recomputes the ledger, so every commit on the branch is green on
check:doc-authoring.Pins re-pinned: 3 assertion lines in 2 test files
migrations/view-definition-active-index.test.ts342-343 asserted the two numbers in the MySQL degradation line. They now assert the two gaps in words: "an archived view keeps occupying its name slot" and "two same-name ACTIVE shared views (owner NULL)".protocol.batch-row-driver-text.test.ts396 asserted the number in the withhold warning. It now asserts "must not be quoted back on response data", the decision itself.A one-off mutation proves each new pin can fail, run on the committed head with
scripts/ablation-replace.mjs(anchor hit once, disk-verified) under a shell trap. Changing "name slot" gives 1 failed / 27 passed. Changing "(owner NULL)" gives 1 failed / 27 passed. Changing "quoted back" gives 2 failed / 14 passed: the re-pin, and a knock-on in the next test, because the failed test never reached itsmockRestore. After each leg, the blob equals HEAD andgit diff HEADis empty. The tree is clean after the run, and no test file was left behind.No string here is compared byte for byte with a twin in another package. The consumer pins outside the package read unchanged fragments:
runtime'sbatch-row-driver-text-real-driver.integration.test.tsreads the withhold prefix,seed-tenancy-autonumber-split.integration.test.tsreads "backfill skipped", andmeta-field-overlay-lock.test.ts,objectql'sprotocol-meta.test.tsandrest'smeta-unknown-type-read-refusal.test.tsread "is not a metadata type". I ran the threeruntimefiles against the rebuiltdist/, and they passed.Ledger burn-down
scripts/doc-authoring-prose-id.baseline.jsonwas regenerated withnode scripts/check-doc-authoring.mjs --census-ledgerinto a scratch file, so the growth refusal ran against the checked-in baseline, and then copied into place. Onlymetadata-protocolrows moved, and every one of them leaves:metadata-protocol/src/protocol.tsmetadata-protocol/src/migrations/seed-tenancy-backfill.tsmetadata-protocol/src/migrations/view-definition-active-index.tsmetadata-protocol/src/migrations/overlay-index.tsmetadata-protocol/src/migrations/sys-setting-identity-index.tsmetadata-protocol/src/plugin.tsmetadata-protocol/src/migrations/live-mysql-database.testkit.tsmetadata-protocol/src/runtime-authoring-gate.tsmetadata-protocol/src/sys-metadata-repository.tsThe ledger's file count goes from 224 to 215, and other packages' rows moved: 0. The census's 40 messages reconcile with the ledger's 50 occurrences. The gate counts 46 string literals: 45 in the census population plus the testkit string, which the census filed as test-facing. The census folds a
+chain into one message, so 5 two-literal chains make 45 literals into 40 messages. Four literals carry two ids each, which makes 46 literals into 50 occurrences.Verification (head
442473234)@objectstack/runtime...(30/30), then the whole workspace (72/72), then@objectstack/metadata-protocoldirectly. The new sentences are indist/index.js, and the only citations left indist/are docblocks.@objectstack/metadata-protocoltest: Test Files 190 passed, 3 skipped (193); Tests 2792 passed, 19 skipped. The skips are the live MySQL/PostgreSQL files: this container has no server.@objectstack/metadata-protocoltypecheck: exit 0;tsc --listFilesreads 193 of 193 test files.@objectstack/runtime, the three consumer files above: 3 files, 33 tests passed.node scripts/pm/dispatch-gates.mjs --commands(no paths; 13 paths against merge base261c529f0): 70 commands, all exit 0.check:dual-build-cjs-loadsandcheck:type-check-debtfirst answered exit 3 PREREQUISITE NOT MET on the partial build. After the full build (and a direct rebuild of this package, whosedista turbo cache hit had left older than the restored sources), both exit 0;check:dts-closureandcheck:lean-entry-closurewere re-run there too.--ran: 70 derived, 70 run, 0 NOT-MEASURED, 0 UNRUN, exit 0.check:doc-authoring: sibling-package prose ids hold the baseline, no growth, no burn-down unrecorded.eslint --no-inline-config --format jsonover the 11 touched.tsfiles reports 11 files, 0 errors and 0 warnings. The resolvedparserOptionsfor these files areecmaVersionandsourceTypeonly, with noprojectorprojectService. So no type-aware rule can move an untouched file. The repo-widepnpm lintis CI's.Acceptance notes
protocol.ts. Whichever lands second mergesmainand recomputes the ledger with--census-ledger.//comments in this package still cite numbers. They are out of scope here: comments are the sanctioned home for internal anchors, and a separate card owns stale ones.Generated by Claude Code