chore(spec): re-anchor the action + object liveness ledgers to consuming symbols - #13035
Merged
Conversation
…g symbols Adoption batch 1 of the #12516 symbol-anchor citation grammar (#13003). Twenty `path:NNN` evidence citations in liveness/action.json and liveness/object.json become `path#symbol`, each re-closed by reading the code on the current tree rather than by shifting a line. Fourteen of the fifteen object.json citations were already wrong — all of them IN RANGE, so the existence check, the line bound and the key-mention check all passed on pointers that named a docblock, a neighbouring const, or (object.enable.clone) a sort normalizer ~6,700 lines from its reader. Three readers had moved package into @objectstack/spec. action.execute is NOT touched here: its cited `.transform` lowering was removed in protocol 17 and the key is now a retiredKey tombstone, so the `live` verdict is falsified. That is a re-classification under ADR-0049 and is reported on #13003 rather than executed in this PR. Part of #13003 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 28, 2026
os-trump
marked this pull request as ready for review
August 28, 2026 20:28
os-trump
enabled auto-merge
August 28, 2026 20:28
This was referenced Aug 28, 2026
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.
Part of #13003
Adoption batch 1 of the symbol-anchor citation grammar that #12516 / PR #13004 landed. Two ledger files, chosen by the card's own order:
action.json(the hot file — the only ledger citingpackages/runtime/src/action-execution.ts, 1670 lines, and the file whose two entries drifted in a day) andobject.json(the oldest dated batch,verifiedAtback to 2026-07-28).Every citation below was re-closed by reading the code on the current tree. No line number was shifted by a diff, and no existing citation was trusted. That mattered more than expected: 14 of the 15
object.jsoncitations were already pointing at the wrong place, every one of them IN RANGE and therefore invisible to all three existing checks.Per-entry table
⟳= citation was already wrong and is repointed ·== citation was accurate, grammar migration only ·✗= consumer gone, reported not executedpackages/spec/liveness/action.jsontypebody-runner.ts:385body-runner.ts#actionBodyRunnerFactory=line still accurate (repointed 08-26)typeaction-execution.ts:1309action-execution.ts#invokeBusinessAction=accuratetypedomains/actions.ts:591domains/actions.ts#handleActionsRequest=accuratetype:524:552:906#isHeadlessInvokableAction,#headlessActionTypeError,#summarizeAction⟳not citations at all — see belowbodybody-runner.ts:356body-runner.ts#actionBodyRunnerFactory=accuratebodyaction-execution.ts:525action-execution.ts#isHeadlessInvokableAction=accurateexecuteaction.zod.ts:581✗consumer gone — reported on #13003, not executed hereThe
typeentry carried a second, quieter defect the migration repaired::524,:552and:906were written as bare line suffixes with no path in front of them.PATH_REneeds a repo-rooted token, so the evidence scanner never parsed them as citations — three of that entry's six consumers were unfalsifiable prose that no check has ever resolved. They are anchors of their own now.packages/spec/liveness/object.jsondatasourceengine.ts:1147#resolveDatasourceBinding,#assertWriteAllowed⟳:1147 is a docblock about write-refusal placement (13593-line file)indexessql-driver.ts:1181#syncTableIndexes,#syncDeclaredIndexes,#initObjects⟳:1181 is a docblock oncount_distinctlowering (16289-line file)validationsrule-validator.ts:154#evaluateValidationRules,#legalNextStates,#needsPriorRecord⟳:154 is arequiredWhendocblockactionsapp-plugin.ts:929#collectBundleActions⟳:929 is the job scheduling blockmanagedByregistry.ts:208#resolveCrudAffordances,#resolveInjectedSystemColumns;#assertEngineOwnedWriteAllowed;#collectMaskedReadFields⟳:208 is the siblingindexesmerge; readers moved packageownershipregistry.ts:292#resolveInjectedSystemColumns(+#applySystemFieldsas materializer)⟳:292 is amultiTenantdocblock — and the parenthetical was false, see belowrequiredPermissionssecurity-plugin.ts:132#getObjectSecurityMeta,#normalizeRequiredPermissions,#requiredCapsForOperation,#crudBucketForOperation⟳:132 is a platform-admin docblock; real read ~6400 lines latersystemFieldssecurity-plugin.ts:3281(+ linelessregistry.ts)#resolveInjectedSystemColumns,#applySystemFields,#getObjectSecurityMeta,#loadObjectFieldNames⟳:3281 is a bootstrapcatalogSeedPasses()callsharingModelsharing-service.ts:54#effectiveSharingModel⟳:54 is a blank linepublicSharingshare-link-service.ts:48(+:170)#getPolicy,#createLink⟳both lines rottedtenancy.enabledsql-driver.ts:1081#isTenancyDisabled,#computeTenantField,#getObjectSecurityMeta,#resolveInjectedSystemColumns⟳:1081 is a withheld-filter docblock; predicate moved to spectenancy.organizationFieldrecord-organization.ts:177-180#resolveRecordOrganizationField=the one accurate citation — 248-line fileenable.searchableprotocol.ts:2967#searchAll⟳:2967 is insidenormalizeSortNodes, ~7100 lines offenable.cloneprotocol.ts:2938#cloneData⟳:2938 isnormalizeSortNodes; reader at ~:9648 — a 6700-line in-range driftisSystemsharing-service.ts:75#effectiveSharingModel⟳:75 is a neighbouringconst OWNER_FIELDThree observations the batch is worth recording for:
action.targetandaction.requiredPermissionspoint at the wrong lines one day after being repointed, and every check stays green #12516 thesis measured a second time, on a different population.object.ownershipwas falsified in prose, not just in line. Its citation readregistry.ts:292 (applySystemFields reads schema.ownership).applySystemFieldsreadsownershipnowhere in code — its nine occurrences in that function are all comments explaining a decision it delegates toresolveInjectedSystemColumnsin@objectstack/spec. The entry staysliveon stronger evidence; what it demonstrates is a line refreshed on 2026-07-30 rotting again inside the same file while the prose beside it already pointed at a reader that had changed packages.object.enable.clonehas now been repaired twice — once in 2026-07 for a cross-package move the existence check could see, and once here for a 6700-line in-file move that nothing in the gate could. It is the worked example of why the anchor exists.action.execute— consumer GONE, reported not executedPer the dispatch, a gone consumer is a re-classification under ADR-0049 and is reported on the card, not executed here. The entry is left byte-for-byte untouched.
The evidence claims
action.zod.ts:581 — the .transform lowers execute -> target and DROPS the alias. On the current tree there is no such transform:executewas removed in protocol 17 (#3855) and is aretiredKey(...)tombstone ataction.zod.ts:1040, so authoring it is atscerror and a parse error.packages/cli/src/utils/lower-callables.tsexplicitly refuses to consume it. Meanwhile:581is in range and lands on a comment about theglobal_navenum-value retirement's declaration style.The honest verdict is
dead, matching its already-tombstoned siblingsshortcutandbulkEnabledin the same file. That is a status change with its own card shape.Census position
Measured by the gate's own counters, base
c459da6bc→ heade243b3191:20 of ~300 live-entry local line citations converted, across 2 of the 24 ledger files that carry any. The card's own census framing (
117–173 of 298failing key-proximity) is a different metric and is not re-measured here. Remaining ledger files by line-citation count, for the continuation rounds:manifest.json34,datasource.json28,permission.json25,email_template.json23,api.json21,dataset.json18,doc.json15.Evidence
All gates run at head
e243b3191, exit codes captured before any pipe.Gate family derived at that commit with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(no paths passed — the script took its own change set from the merge base): 25 families matched. All green except two that returned an explicit PREREQUISITE NOT MET, which is no reading rather than a failure:check:livenessEXIT=0— "everypath#symbolanchor names a symbol its file contains"check:empty-state,check:strictness-ledger,check:variant-docs,check:published-files,check:changeset-gate-self-tests,check:objectui-changeset,check:merge-driver,check:pm-half-states,check:page-declaration-shape,check:slot-lookup,check:test-source-alias,check:type-source-resolution,check:nul-bytes— allEXIT=0check-adr-0087-registration,check-changeset-no-major,check-empty-changeset,check-keyed-text-bounds,check-comment-mask-adoption,check-plugin-teardown-shape,check-undeclared-dep-imports,release-rehearsal-clone --self-test— allEXIT=0check-dev-prereqs.mjsEXIT=1— NOT MEASURED: "The workspace is not built — 1 unmet precondition, not a list of problems". Repo-scalepnpm build; this diff contains no TypeScript.scripts/pm/check-half-states.mjsEXIT=3— NOT MEASURED: "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."Vitest, through the shared verify lock, at head
e243b3191:That includes the
--ledger-rootself-test machinery PR #13004 committed.Ablation — the new anchors are genuinely checked
Gate green alone would not prove it: an anchor token that stops matching
PATH_REdegrades to prose silently, taking the citation's existence check with it. So one anchor was mutated to a symbol the cited file does not contain. Committed first, mutation confirmed on disk by grep counts in both directions, restore proven by an emptygit diff HEAD(not by an exit code), absolute paths under anEXIT INT TERMtrap. No build leg: the gate runs from source throughtsxand reads the JSON directly, so nodist/sits between the mutation and the reading.The direction was predicted before running: red, naming the entry. It also independently confirms the 42 new anchors parse as anchors rather than as prose — the mutated run still reported 47 pointers, so the count is real.
Contract gate
None applies. The writing surface is
packages/spec/liveness/*.jsononly — governance data, outside thepackages/spec/src/**path leg. No accept set moves, no schema key changes, no runtime behaviour changes. Clause-② is not reachable.Changeset
One is included,
patchon@objectstack/spec, and the dispatch's expectation ("no changeset expected") is corrected by measurement rather than assumed:livenessis named in that package'sfilesarray (packages/spec/package.json), so these ledgers ship inside the npm tarball and this is a published-data change.skip-changesetdoes not apply — the diff is not confined to the convention's closed list.Honest residual
isSymbolNamedchecks only that the cited file contains the identifier as a word; it cannot check that the symbol is the one enclosing the read. Gate-green therefore does not prove the re-closures are correct — the hand reads do, and the per-entry table above is the record of them. One anchor in this batch was caught wrong by exactly that limit during authoring (secret-fields.ts#redactSecretFields, a symbol that does not exist; the real ones arecollectMaskedReadFields/collectMaskedPasswordFields) and was corrected before commit.Generated by Claude Code