chore(spec): re-classify the field.conditionalRequired liveness entry dead (#13043) — the last line citation, counter to 0 - #13069
Merged
Conversation
… dead (#13043) The entry was ledgered `live` on a FieldSchema `.transform` lowering conditionalRequired -> requiredWhen and dropping the alias. No such transform exists: field.zod.ts has ZERO `.transform` calls, and its two occurrences of the token are comments recording that `.overwrite()` was chosen instead (#6926). The note's second leg - that objectql rule-validator.ts keeps a `requiredWhen ?? conditionalRequired` fallback on purpose - was retired by #3903, which replays the ADR-0087 conversion chain at rehydration so a stored pre-17 row arrives already lowered; its absence is pinned by that module's own test. Status flips to `dead` with the ROW STAYING - the rls.priority precedent, a retiredKey tombstone keeps the key in the walked shape. The falsified `evidence` goes, the #3754 / #3713 lowering history is preserved in the note. This was the LAST `path:NNN` citation in any ledger. The gate's line-citation counter goes 1 -> 0, which is the end of the #13003 anchor-adoption worklist and the trigger for the delete-at-zero instruction the two non-vacuity floors carried in their own guard comments: both floors, both guard comments and both named companions (`outOfRange`; the equality check) are deleted here. The two sibling floors on non-draining populations (`local` paths, `evidence paths`) stay at `> 100`, verified by grep. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LpRNHxWZgSUgVnFT9mQQo4
Contributor
📓 Docs Drift Check
What this run could not see
Coarse fallback — 126 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
This was referenced Aug 29, 2026
os-trump
marked this pull request as ready for review
August 29, 2026 03:05
os-trump
enabled auto-merge
August 29, 2026 03:05
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #13043
Fixes #13003
The second one is the worklist's ruled closure, not a rider. The line-citation counter reaches 0 here, which is the event ruling 5458356183 named as the moment both non-vacuity floors are deleted, and the endgame wiring recorded in ACCEPT 5459233103: "#13043 stays HELD in the serial queue … its landing is the counter-to-0 event that deletes the floors per ruling 5458356183".
Two related cards, cross-referenced and deliberately kept away from any closing keyword: #13042 is the recorded remainder and remains open; #13041 (the
planned/experimentalevidence-scan gap) is the held follow-on, blocked behind these same two test files, and remains open.Verified at
21b610d73. Authored by Claude Code, sessionhttps://claude.ai/code/session_01LpRNHxWZgSUgVnFT9mQQo4— recorded here in prose as well as in the footer, because a body edit rewrites the footer's session form back to the bare one, and because on this PR the first edit dropped the footer line outright (measured, twice; see the note at the bottom).Notation, forced by a measured GitHub sanitizer behaviour.
BANG1andBANG2below stand for the first and second regex capture read through a TypeScript non-null assertion — in the source, the identifierm, then an exclamation mark, then the bracketed index. Written literally, GitHub's body sanitizer deletes the exclamation mark before the bracket, silently, in inline code spans and inside fenced blocks. Measured on this very PR: the first revision of this body was read back twice — through the API and through the rendered page — and both came back with the operator gone from all four quoted assertions, while the files on disk are unchanged. Quoting an assertion wrongly is precisely the "looks precise, is not" failure this ledger governs, so the operator is spelled out rather than left corrupted. The assertions in the repository are unaffected.The flip
packages/spec/liveness/field.json, propconditionalRequired.Before (2 keys + status):
status: "live"evidence: "packages/spec/src/data/field.zod.ts:639 — the FieldSchema .transform lowers conditionalRequired -> requiredWhen and DROPS the alias, so authoring it changes what the validator enforces"note:the [P2]field.conditionalRequiredis the same alias-drift shape #3713 just fixed — and the spec pins the alias to SURVIVE parse #3754 lowering story, ending "objectql rule-validator.ts keeps itsrequiredWhen ?? conditionalRequiredfallback on purpose … Removal of the input key is still the endgame."After (
status/verifiedAt/note, the measured house style):status: "dead",verifiedAt: "2026-08-29"evidencekey — measured on this tree, not recalled: of 79 dead entries across the ledgers, 73 carry noevidence; the two dominant shapes are{status, verifiedAt, note}(37) and{status, evidenceScope, verifiedAt, note}(36).authorWarnappears on 0 of 79, so it is not part of this shape either.retiredKeykeeps the key in the walked shape (therls.priorityprecedent the chore(spec): re-classify the action.execute liveness entry dead (#13036) #13045 body cites); deleting it would report UNCLASSIFIED.noteinpath#symbolgrammar: the tombstonepackages/spec/src/data/field.zod.ts#conditionalRequired, the consumer-side refusalpackages/objectql/src/validation/rule-validator.ts#ConditionalFieldDef, and the case that pins the absence,does NOT read the retired conditionalRequired alias (PD #12 — no dialect fallback)inpackages/objectql/src/validation/rule-validator.test.ts.#3754/#3713lowering history is preserved in substance, because it is the argument forrequiredWhenbeing the single slot.field-conditionalRequired-to-requiredWhen, itsRETIRED_KEYS_BY_MAJORentry and D3 chain step, andauthoring-key-lint.ts's explicit "no entry forconditionalRequired".Premise re-measured on this base (all four legs held)
Base
cae2169cf=origin/mainwith #13045 merged..transformdoes not exist — stronger than the card claimed.packages/spec/src/data/field.zod.tshas zero.transform(calls. Its only two occurrences of that token are comments recording that.overwrite()was chosen instead, per the measured finding:FormViewSchema.groupsis declared as "alias to sections" but nothing folds it — every consumer reads onlysections#6926 precedent. The key isretiredKey(...)at line 1380, andgit log -Sdates that tombstone toacbf364a0, 2026-07-28, "retire the last three deprecated authorable aliases ([P3] Retire the three deprecated aliases — via the ADR-0087 D2 conversion layer, not by deleting the keys #3855) (feat(spec)!: retire the last three deprecated authorable aliases (#3855) #3883)" — the same commit that tombstonedaction.execute.rule-validator.tsnames the alias exactly once, in a comment onConditionalFieldDefdeclaringrequiredWhen"The ONLY predicate slot" and stating "PD Add comprehensive test suite for Zod schema validation #12: no consumer-side dialect fallback returns here". The absence is pinned by the named test, beside a positive case asserting the rule DOES fire onceapplyConversionsToStoredItemhas lowered the alias.livecitingfield.zod.ts:639— confirmed byte-for-byte. Line 639 today is the tail ofFieldMaskingRuleSchema, in range in a 2,132-line file that names the key five times, so existence, line bound and key-mention were all green on it.cae2169cf:line citations: 1 pointer(s) writtenpath:NNN,1 inside the cited file.Attribution measured by re-running the gate's owncheckEvidenceextractor over every ledger: sole resultfield/conditionalRequired -> packages/spec/src/data/field.zod.ts:639.The counter, 1 to 0
check:livenessis green at head. Its verdict line, quoted:state-counts.mdwas regenerated bypnpm --filter @objectstack/spec gen:liveness-counts, never by hand (the file carriesmerge=os-regenfor exactly that reason). Current line, and the totals row:Deleted-assertion inventory
Executed exactly as the two guard comments instruct — the instruction lives in the code, so this PR runs it rather than re-deriving it.
1.
packages/spec/scripts/liveness/evidence.test.ts— the guard comment, quoted:Deleted:
expect(citations).toBeGreaterThan(0);(the floor), its 22-line guard comment, and the named companionexpect(outOfRange).toEqual([]);.Those two were all the assertions the case "every local
path:NNNcitation names a line that file has" had, so the case went with them: a body that walks every ledger and asserts nothing is the vacuous shape #5623 exists to refuse. A note stands where it was, recording what was deleted, why, what still covers the bound (the arithmetic stays fully unit-tested in thecheckCitationLinesdescribe above it), and to restore a contract test if apath:NNNcitation is ever written again.2.
packages/spec/scripts/liveness/check-liveness.test.ts— the guard comment, quoted:Deleted:
expect(Number(BANG1)).toBeGreaterThan(0);(the floor), its 19-line guard comment, and the named companionexpect(BANG2).toBe(BANG1);.Here the
itsurvives, and that asymmetry is the point: its remaining assertions still measure something at a zero population — the gate must keep EMITTING theline citations:line in the shape the regex documents (expect(m, line).not.toBeNull()), on a green run (expect(status, output).toBe(0)), withoutPAST EOF. Drop that line, rename it, or collapse it to one number and this case reds. The title's "equal on a green run" clause named the deleted equality check, so it is corrected to "in the documented two-number shape".Two small consequentials of the deletion, both named here rather than left to rot: the
checkCitationLinesdescribe preamble said "a citation whose real line count matters is asserted against the real ledgers in the contract test at the bottom of this file" — corrected, since that test is gone; and the surviving case's own lead comment pointed at "the floor's own note at the assertion below" — rewritten.Minimality
Six files. In the two test files nothing outside the named assertions, their guard comments and the two prose corrections above moved — the
check-liveness.test.tshunk is a single contiguous block at lines 183-211, theevidence.test.tshunk a single contiguous block where the deleted case stood plus the preamble sentence. No change tocheck-liveness.mtsor to any scan behaviour; #13041 stays held behind this PR by design.Surviving floors, grep-verified (not intent)
The two siblings guard populations that are not draining, and they keep their constants:
Their population at head, from the gate:
evidence paths: 465 repo-local path(s) declared by 'live' entries, 465 resolved against this checkout— 466 at base, the single drop being the entry this flip retires.The two symbol-anchor floors from the anchor-grammar card also survive untouched:
evidence.test.ts:393expect(anchors).toBeGreaterThanOrEqual(2)andcheck-liveness.test.ts:306the same, over a population of 499 anchors, all naming a symbol their file contains.Tests
pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 scripts/liveness/(heavy runs serialised throughscripts/pm/os-verify-lock.sh):254 → 253: exactly one case removed, the
evidence.test.tscontract test.Reverse verification — predicted direction: RED, and only at the floors
The implementation was committed first, then the two pre-deletion test files were restored from base over it, the run measured, and the files restored to
HEAD. Both legs proved on disk, not by exit code:grep -c= 1, 1) and the post-deletion marker text absent from both (grep -c= 0, 0); the run aborts on any other reading.git diff HEADempty for both paths, and each file'sgit hash-objectcompared equal to itsHEADblob (ef2daaa44…,92d3daecd…) — an empty or mismatched hash is a hard failure, not "nothing to compare".trap restore EXIT INT TERMwith absolute paths resolved fromgit rev-parse --show-toplevel.Result — exactly the two deleted floors, and nothing else:
This is the ruling's own design claim, now measured: the
> 0floor "reds at precisely the moment the endgame decision is due". And the second half is measured too — the two named companions did NOT fail:outOfRangeand the equality check were both vacuously true at a zero population, which is exactly why the guard comments named them as deletions rather than leaving them behind.No ablation is owed for the flip itself: it introduces no new anchor mechanism, and the change is ledger data plus test deletions.
Gates
Family derived from the real change set, not from a recalled list:
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack— provenance line confirms "gate list derived from the tree of 'objectstack-ai/objectstack' at commit cae2169", change set "6 path(s)", matching the six above. 30 path-matched families plus 6 convention-triggered ones (the test-file kind). All re-run at21b610d73on a clean tree, exit codes captured before any pipe:check:liveness,check:empty-state,check:strictness-ledger,check:variant-docs,check:nul-bytes,check:cross-package-test-inputs(both the pnpm andci.ymlspellings),check:merge-driver,check:objectql-double-limit,check:objectui-changeset,check:page-declaration-shape,check:pm-governed-merges,check:published-files,check:slot-lookup,check:test-source-alias,check:type-source-resolution,check:changeset-gate-self-tests,check-adr-0087-registration,check-changeset-no-major,check-ci-filter-parity,check-comment-mask-adoption,check-empty-changeset,check-keyed-text-bounds,check-plugin-teardown-shape,check-undeclared-dep-imports,check-dev-prereqs(67/67, on the built closure),release-rehearsal-clone --self-test,docs-audit/check-affected-docs,docs-audit/check-drift-comment.check:query-options-erasure,check:type-check-coverage,check:engine-double-contract,check:where-matcher,check:cross-package-test-inputs, andcheck:type-check-debt— the last built the workspace closure first, exactly aslint.ymldoes (turbo run build --filter=./packages/* --filter=./packages/*/*, 70/70 tasks), so it is a real measurement and not a refusal: "31 ledger entr(ies) re-measured in 239.3s, 1570 raw tsc error(s) total, none above its recorded number. surplus: none".pnpm --filter @objectstack/spec typecheckgreen across all three legs, with--listFilescoverage proof rather than a green read as coverage: the scripts program (tsconfig.scripts.json) names both edited files; the base program names neither (0 and 0 of 1002 files).check:test-typecheck: "OK — @objectstack/spec's test layer compiles".eslint . --no-inline-configwas run in full rather than narrowed: 5392 files, 0 errors, 0 warnings (68s under the verify lock). No narrowing argument is needed.Census position
This is the final landing of the #13003 worklist. Line citations over live entries, by landing: 300 at the card's filing → 175 after batch 2 → 82 after batch 3 → 2 after batch 4 (#13044) → 1 after #13045 (
action.execute, #13036) → 0 here. Both of the last two were the same shape and neither was a citation repair: aliveverdict resting on a protocol-17.transformthat no longer exists, on a key that has been aretiredKeytombstone since 2026-07-28. Batch 4 correctly reported them instead of re-anchoring them, which is what left exactly these two for their own cards.Honest residual
packages/lint/src/validate-expressions.tsstill walksconditionalRequiredin its field-rule loop; its own docblock says the branch is inert on the parsed compile path because the strictFieldSchemarejects the key by name, and it gets a slot-agnostic consequence clause "rather than a fabricated fourth measurement".packages/drivers/driver-sql/src/builtin-column-collision.tslists it in a key-classification map aspresentation, which classifies a name, not a value anyone reads. Both are recorded in the ledger note so the next reader does not resurrect aliveverdict from them. Neither is touched here — that would be a scope change, and neither is a defect.fieldrow's README Notes cell said "healthy", which this flip falsifies (the type's dead column moves 0 to 1). Corrected in the spec(liveness): 9 rows of the README state table have count columns that disagree with the gate's--jsonreport #7377 shape used foractionone round ago, rather than rewritten.node scripts/pm/check-half-states.mjs(the live sweep) is NOT MEASURED here — exit 3, its own words: "PREREQUISITE NOT MET — the token in the environment is not a valid GitHub credential … Nothing was swept … It is not a clean board and it is not a dirty one — it is no reading at all." A container fact, not a fact about this change; its self-test half (pnpm check:pm-half-states) is green, and CI runs the sweep with a real credential.---plus footer line rather than downgrading it to the bare form, so the session URL is carried in prose above as the durable copy. If the footer below is absent when you read this, that is observation (2) repeating, not a missing signature.