Skip to content

chore(spec): re-anchor the closing twelve liveness ledgers to consuming symbols (#13003 batch 4) - #13044

Merged
os-trump merged 1 commit into
mainfrom
claude/issue-13003-anchor-adoption-b4
Aug 29, 2026
Merged

chore(spec): re-anchor the closing twelve liveness ledgers to consuming symbols (#13003 batch 4)#13044
os-trump merged 1 commit into
mainfrom
claude/issue-13003-anchor-adoption-b4

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Part of #13003

Adoption batch 4 — the intended closing batch — of the path#symbol liveness citation grammar landed by #12516. Batches 1–3 are PRs #13035, #13038 and #13039, all merged; this branch takes the entire measured tail.

It does not close the card. The gate's own line-citation counter reads 2, not 0, so per ruling comment 5458356183 and the guard comments themselves the two non-vacuity floors stay in place, the two test files are untouched, and this body opens Part of rather than a closing keyword. The two survivors are not skips: both are entries whose live VERDICT is falsified, not their citation, and re-anchoring either one would have dressed a dead entry as freshly verified in order to hit a number. They are reported instead — see "The two held entries" below.

What landed

Eighty of the eighty-two remaining path:NNN citations, across twelve ledgers, become path#symbol, together with every path-only pointer in the same entries. Each was re-closed by READING the code on the tree at 8cb96ec41 — never by shifting a line, never by trusting byte-identity, never carried forward unread. verifiedAt: "2026-08-28" is stamped on every re-closed entry (the date the dispatch pinned and the date the re-closure was performed; the run crossed into 08-29 UTC during verification).

Census, from the gate's own counters

counterbase 8cb96ec41head 88a1b24e2
line citations written path:NNN82 (82 in range)2 (2 in range)
symbol anchors written path#symbol383 (383 resolved)499 (499 resolved)
repo-local evidence paths declared by live entries464 (464 resolved)467 (467 resolved)
key-mention (entry, cited file) pairs464 asked / 463 anchored / 1 exempt467 asked / 466 anchored / 1 exempt

Verdict lines at head, quoted from the gate itself:

line citations: 2 pointer(s) written `path:NNN`, 2 inside the cited file.
symbol anchors: 499 pointer(s) written `path#symbol`, 499 naming a symbol the cited file contains.
key-mention anchoring: 467 (entry, cited file) pair(s) asked, 466 anchored, 1 exempt.

What the re-closure found

67 of the 80 were already wrong, every one IN RANGE — so the existence check, the line bound and the key-mention check were all green on all 67. Six files were 100% rotted: validation.json 10/10, seed.json 6/6, view.json 5/5, dashboard.json 4/4, flow.json 4/4, qa.json 4/4.

The dominant shape is block drift — a whole ledger's pointers moving together when the file above them grows, so each one stays plausible beside its neighbours:

  • validation.json: nine of ten pointers had settled inside ONE 70-line ADR-0124 docblock, roughly 1,200 lines above evaluateValidationRules.
  • app.json: name / label / description had come to rest on three CONSECUTIVE lines of one unrelated function, resolveActionResultDialog.
  • capability.json: label / description / scope on three consecutive lines of one docblock about an outcome counter.
  • qa.json: all four moved by the same amount when a diagnostic helper was added at the head of runner.ts.

The sharpest single case is flow.status, which had come to rest on private flowLedgerDisabled = new Set() — the map ADJACENT to the one this key writes. #10243 had split the single flowEnabled map into flowStatusDisabled (this key) and flowLedgerDisabled (the durable toggle), composed by isFlowEnabled; the pointer landed on a plausible line, in the right class, naming the wrong fact.

Two silent classes close with the drift. Seventeen positions across four files were written as bare :NNN suffixes with no path in front of them — PATH_RE never matches those, so they degraded to prose that nothing has ever resolved, bounded or key-checked (translation.objects alone carried five of its six positions that way). Three more entries — hook.retryPolicy / timeout / onError — cited a path with NO line, which a line bound cannot falsify by construction. All twenty are repo-rooted anchors now.

Three citations were falsified in PROSE as well as position, and the prose is corrected with the line, because a name written beside a line is what a reader trusts when the line still looks plausible:

entrythe prose saidthe tree says
view.objectgetViewsByObject() in packages/objectql/src/engine.tsit is in packages/metadata/src/metadata-manager.ts
field.requiredWhenfieldRequiresParentRootno such symbol (0 occurrences); it is hasParentScopedRequiredWhen
translation.metadataFormstranslateMetaTypesno such symbol; it is translateMetaTypesResponse

mapping.json is the batch's counter-example and is kept as one: five of its seven pointers landed on the read or inside the statement performing it, because #11210 re-measured that file on 2026-08-23. The other two had already drifted five lines in five days. Correctness of a line is a property of the day it was measured; the anchor is what makes it a property of the code.

The two held entries

action.json / execute — the singleton batch 1 left standing

The dispatch asked why it survived batch 1 and for an honest disposition. It survived by decision, not by oversight, and batch 1 said so in its own commit message: its cited .transform lowering was removed in protocol 17 (#3855) and the key is now a retiredKey tombstone, so the live verdict — not the citation — is what is falsified. That is an ADR-0049 re-classification, which the dispatch method reports rather than executes. It was reported as #13036, which is open and awaiting triage.

Re-checked here on the current tree rather than taken on trust: packages/spec/src/ui/action.zod.ts declares execute: retiredKey('executewas removed in @objectstack/spec 17 — usetarget…'), the target docblock states the alias "was removed in protocol 17", and there is no .transform touching the key anywhere in the file. The suggested disposition remains dead, matching the already-tombstoned siblings action.shortcut / action.bulkEnabled with the row STAYING (the rls.priority precedent — retiredKey keeps the key in the walked shape). Not executed here.

Its citation is neither foreign-adjacent nor a producer pointer: packages/spec/src/ui/action.zod.ts:581 is a local evidence line, in range, in a file that names the key — which is exactly why nothing has ever flagged it.

field.json / conditionalRequired — the same class, found by this batch

Measuring the tail turned up a second instance of the identical shape, previously unrecorded. field.conditionalRequired is ledgered live on packages/spec/src/data/field.zod.ts:639 with the claim that "the FieldSchema .transform lowers conditionalRequired to requiredWhen and DROPS the alias". On the current tree:

  1. The key is a retiredKey tombstone (protocol 17, [P3] Retire the three deprecated aliases — via the ADR-0087 D2 conversion layer, not by deleting the keys #3855). requiredWhen's own describe() says it: "The only slot; the conditionalRequired alias was removed in protocol 17."
  2. The fallback the entry's note relies on — "objectql rule-validator.ts keeps its requiredWhen ?? conditionalRequired fallback on purpose" — is also gone. rule-validator.ts states "The ONLY predicate slot. The retired conditionalRequired alias…", and rule-validator.test.ts pins the absence: "does NOT read the retired conditionalRequired alias (PD Add comprehensive test suite for Zod schema validation #12 — no dialect fallback)".
  3. What remains is close-out machinery, not consumers: the ADR-0087 conversion field-conditionalRequired-to-requiredWhen, its migration-registry row, and an explicit "no entry for conditionalRequired" note in authoring-key-lint.ts.

Filed as #13043, a sub-issue of #13003, unassigned and bare for triage, on the #13036 shape. The entry here is byte-for-byte untouched and deliberately NOT re-stamped.

Consequence for the endgame, stated plainly: the line-citation counter cannot reach zero by citation work alone. Both survivors need an ADR-0049 verdict (#13036, #13043); once either entry stops being live, its evidence leaves the counted population, and when both do the counter is 0 and the floor deletion becomes due exactly as the guard comments instruct.

Per-entry tables

FROM shows the citation as it stood at the base commit and what that line is today, read straight off the file (angle brackets in quoted code are rendered as single guillemets, deliberately — see the byte discipline in AGENTS.md). ROT = the cited line (or range) did not cover a read of the key. OK = it did, so the row is a grammar migration rather than a repair. HELD = left untouched and reported.

action.json

entryFROM (citation at 8cb96ec — and what that line is TODAY)TOverdict
executeaction.zod.ts:581 — // the location table below. (House style set by the 'crypto.hash' /— (entry left untouched, verdict falsified — reported)HELD

app.json

entryFROM (citation at 8cb96ec — and what that line is TODAY)TOverdict
namei18n-resolver.ts:478 — opts?: ResolveOptions,i18n-resolver.ts#translateAppROT
labeli18n-resolver.ts:481 — if (!spec) return spec;i18n-resolver.ts#lookupAppAttr · i18n-resolver.ts#translateAppROT
descriptioni18n-resolver.ts:482 — const title = lookupActionResultDialogText(bundle, action, (n) =› n.title, opt…i18n-resolver.ts#lookupAppAttr · i18n-resolver.ts#translateAppROT
hiddenaccount.app.ts:40 — hidden: true,account.app.ts#ACCOUNT_APPOK
navigation.labeli18n-resolver.ts:456 — opts?: ResolveOptions,i18n-resolver.ts#lookupNavLabel · i18n-resolver.ts#translateAppROT
navigation.requiredPermissionsrest-server.ts:1844 — try {rest-server.ts#filterNavROT
navigation.requiresServicerest-server.ts:1832 — environmentId = await this.resolveRequestEnvironmentId(environmentId, req);rest-server.ts#filterNavROT
requiredPermissionsrest-server.ts:1814 — };rest-server.ts#filterAppForUserWithReasonROT
_unpublishedrest-server.ts:2669 — * Not translated and not cached, both deliberately: this is a diagnosticrest-server.ts#filterAppForUserWithReason · packages.ts#handlePackagesRequestROT
_unpublishedpackages.ts:245 — const ec: any = _context?.executionContext;rest-server.ts#filterAppForUserWithReason · packages.ts#handlePackagesRequestROT

capability.json

entryFROM (citation at 8cb96ec — and what that line is TODAY)TOverdict
namebootstrap-declared-capabilities.ts:210 — /**bootstrap-declared-capabilities.ts#upsertPackageCapability · validate-capability-references.ts#validateCapabilityReferencesROT
namevalidate-capability-references.ts:99 — if (typeof cap.name === 'string' && cap.name.length › 0) known.add(cap.name);bootstrap-declared-capabilities.ts#upsertPackageCapability · validate-capability-references.ts#validateCapabilityReferencesOK
labelbootstrap-declared-capabilities.ts:122 — * identical; they are not.bootstrap-declared-capabilities.ts#capabilityRowFieldsROT
descriptionbootstrap-declared-capabilities.ts:123 — */bootstrap-declared-capabilities.ts#capabilityRowFieldsROT
scopebootstrap-declared-capabilities.ts:124 — unchanged: number;bootstrap-declared-capabilities.ts#capabilityRowFieldsROT
packageIdbootstrap-declared-capabilities.ts:294 — //bootstrap-declared-capabilities.ts#bootstrapDeclaredCapabilities · bootstrap-declared-capabilities.ts#upsertPackageCapabilityROT

dashboard.json

entryFROM (citation at 8cb96ec — and what that line is TODAY)TOverdict
widgets.requiresServicerest-server.ts:1931 — //rest-server.ts#filterDashboardForUser · rest.test.ts#filterDashboardForUserROT
widgets.requiresServicerest.test.ts:3305 — it('ITEM level: nav entries the caller cannot satisfy are stripped from the se…rest-server.ts#filterDashboardForUser · rest.test.ts#filterDashboardForUserROT
widgets.filterBindingsvalidate-widget-bindings.ts:280 — }validate-widget-bindings.ts#effectiveFilterFieldROT
widgets.suppressWarningsvalidate-widget-bindings.ts:367 — }validate-widget-bindings.ts#validateWidgetBindingsROT

field.json

entryFROM (citation at 8cb96ec — and what that line is TODAY)TOverdict
requiredWhenrule-validator.ts:1810 — : 'requiredWhen for '${name}' failed to evaluate — skipped',rule-validator.ts#evaluateValidationRules · rule-validator.ts#hasParentScopedRequiredWhenOK
requiredWhenrule-validator.ts:763 — if (readsParentRoot(def.requiredWhen)) return true;rule-validator.ts#evaluateValidationRules · rule-validator.ts#hasParentScopedRequiredWhenOK
conditionalRequiredfield.zod.ts:639 — ]));— (entry left untouched, verdict falsified — reported)HELD
uniquesql-driver.ts:1853 — return unsupportedFilterError(sql-driver.ts#registerManagedObjectMetadata · sql-driver.ts#uniqueIndexesFromFieldsROT
referenceengine.ts:1672 — );engine.ts#cascadeDeleteRelations · engine.ts#planCascadeAtomicity · engine.ts#expandRelatedRecordsROT
autonumberFormatengine.ts:765 — // [#8690] Same door as the object branch, on the LOWERED condition — theengine.ts#applyAutonumbersROT
maxLengthrecord-validator.ts:127 — options?: string[];record-validator.ts#validateOneROT
minLengthrecord-validator.ts:130 — export class ValidationError extends Error {record-validator.ts#validateOneROT

flow.json

entryFROM (citation at 8cb96ec — and what that line is TODAY)TOverdict
successMessageengine.ts:1292 — * ''runtime'' — a 'sys_metadata'/runtime-authored row with no real packageengine.ts#executeWithoutRetry · engine.ts#resumeInternalROT
errorMessageengine.ts:1348 — * ## ⛔ This is NOT the retired 'flowEnabled' map under a new nameengine.ts#retryExecution · engine.ts#resumeInternalROT
statusengine.ts:1382 — private flowLedgerDisabled = new Set‹string›();engine.ts#registerFlow · engine.ts#isFlowEnabledROT
typeengine.ts:637 — * Structured rather than a log line because the finding has two consumers withengine.ts#resolveTriggerBindingROT

hook.json

entryFROM (citation at 8cb96ec — and what that line is TODAY)TOverdict
namehook-binder.ts:182 — : 'no handler';hook-binder.ts#bindHooksToEngineROT
objecthook-binder.ts:171 — }hook-binder.ts#bindHooksToEngine · hook-binder.ts#normalizeObjectsROT
eventshook-binder.ts:171 — }hook-binder.ts#bindHooksToEngineROT
handlerhook-binder.ts:237 — }hook-binder.ts#resolveHandler · hook-binder.ts#bindHooksToEngineROT
priorityhook-binder.ts:177 — result.skipped += 1;hook-binder.ts#bindHooksToEngineROT
retryPolicy [producer]hook-binder.ts:221 — const wrapped = wrapDeclarativeHook(hook, resolved, { logger, metrics: opts.me…hook-binder.ts#bindHooksToEngineOK
timeout [producer]hook-binder.ts:221 — const wrapped = wrapDeclarativeHook(hook, resolved, { logger, metrics: opts.me…hook-binder.ts#bindHooksToEngineOK
onError [producer]hook-binder.ts:221 — const wrapped = wrapDeclarativeHook(hook, resolved, { logger, metrics: opts.me…hook-binder.ts#bindHooksToEngineOK

mapping.json

entryFROM (citation at 8cb96ec — and what that line is TODAY)TOverdict
nameimport-mapping.ts:70 — return { ok: false, status: 404, code: 'MAPPING_NOT_FOUND', error: 'No mapping…import-mapping.ts#resolveNamedMappingOK
sourceFormatimport-mapping.ts:97 — return {import-mapping.ts#resolveNamedMappingOK
targetObjectimport-mapping.ts:75 — error: 'Mapping "${mappingName}" targets object "${artifact.targetObject}", no…import-mapping.ts#resolveNamedMappingOK
fieldMappingimport-mapping.ts:102 — }import-mapping.ts#resolveNamedMapping · import-mapping.ts#applyMappingToRowsOK
fieldMappingimport-mapping.ts:164 — }import-mapping.ts#resolveNamedMapping · import-mapping.ts#applyMappingToRowsOK
modeimport-prepare.ts:322 — if (!resolved.ok) return resolved;import-prepare.ts#prepareImportRequestROT
upsertKeyimport-prepare.ts:325 — // request writeMode/matchFields wins; absent ones fall back to theimport-prepare.ts#prepareImportRequestROT

qa.json

entryFROM (citation at 8cb96ec — and what that line is TODAY)TOverdict
scenarios.idrunner.ts:101 — stepName: step.name,runner.ts#runScenarioROT
scenarios.setuprunner.ts:54 — }runner.ts#runScenarioROT
scenarios.stepsrunner.ts:83 — steps: [],runner.ts#runScenarioROT
scenarios.teardownrunner.ts:98 — try {runner.ts#runScenarioROT

seed.json

entryFROM (citation at 8cb96ec — and what that line is TODAY)TOverdict
objectseed-loader.ts:98 — function quotableSeedFailureDetail(err: unknown): string | undefined {seed-loader.ts#loadDatasetROT
externalIdseed-loader.ts:119 — * suggests. Both passes share this one vocabulary so the two halves of the fil…seed-loader.ts#loadDataset · seed-loader.ts#decideWriteActionROT
modeseed-loader.ts:245 — export class SeedLoaderService implements ISeedLoaderService {seed-loader.ts#loadDataset · seed-loader.ts#decideWriteActionROT
env [producer]seed-loader.ts:174 — /**seed-loader.ts#resolveEnvConfigROT
envseed-loader.ts:191 — * A dataset carrying no 'env' at all is unrestricted — which is precisely whatseed-loader.ts#datasetAllowsEnv · seed-loader.ts#filterByEnvROT
recordsseed-loader.ts:434 — pairs.push({ field: fieldName, objectField: fieldDef.referenceVia });seed-loader.ts#loadDatasetROT

translation.json

entryFROM (citation at 8cb96ec — and what that line is TODAY)TOverdict
localeauthored-translation-sync.ts:148 — );authored-translation-sync.ts#readAuthoredTranslationLayerOK
objectsi18n-resolver.ts:735 — widgets?: WidgetLike[];i18n-resolver.ts#lookupObjectField · i18n-resolver.ts#lookupObjectFieldAttr · i18n-resolver.ts#resolveViewLabel · i18n-resolver.ts#lookupActionField · i18n-resolver.ts#lookupTabLabelROT
appsi18n-resolver.ts:442 — action: ActionLike,i18n-resolver.ts#lookupAppAttr · i18n-resolver.ts#lookupNavLabel · rest-server.ts#translateMetaItemROT
appsrest-server.ts:2001 — (blank line)i18n-resolver.ts#lookupAppAttr · i18n-resolver.ts#lookupNavLabel · rest-server.ts#translateMetaItemROT
messagesaudit-writers.ts:579 — if (!milestones || !after || !before) return null;audit-writers.ts#writeAudit · audit-writers.ts#writeCommentMentions · audit-writers.ts#translateWithROT
globalActionsi18n-resolver.ts:200 — ): TranslationData | undefined {i18n-resolver.ts#lookupActionField · i18n-resolver.ts#lookupActionResultDialogNodeROT
dashboardsi18n-resolver.ts:538 — * Apply the active locale to an action metadata document by overwritingi18n-resolver.ts#lookupDashboardAttr · i18n-resolver.ts#lookupWidgetAttr · i18n-resolver.ts#translateDashboardROT
pagesi18n-resolver.ts:636 — function lookupAppAttr(i18n-resolver.ts#lookupPageAttr · i18n-resolver.ts#lookupPageComponentCopyROT
metadataFormsrest-server.ts:2058 — * enforce" both survive unchanged.rest-server.ts#translateMetaTypesResponse · i18n-resolver.ts#lookupMetadataForm · i18n-resolver.ts#lookupMetadataFormFieldROT

validation.json

entryFROM (citation at 8cb96ec — and what that line is TODAY)TOverdict
namerule-validator.ts:665 — * the server; a lock that fails open leaves enforcement in the courtesyrule-validator.ts#evaluateValidationRules · rule-validator.ts#checkPredicateROT
namerule-validator.ts:676 — * reaches a runtime this branch has to judge.rule-validator.ts#evaluateValidationRules · rule-validator.ts#checkPredicateROT
activerule-validator.ts:647 — * ## Two faults, two answers (#4889)rule-validator.ts#evaluateValidationRulesROT
eventsrule-validator.ts:654 — * demonstrably locked; the historical (and deliberate, documented) policy i…rule-validator.ts#evaluateValidationRulesROT
priorityrule-validator.ts:657 — *rule-validator.ts#evaluateValidationRulesROT
severityrule-validator.ts:678 — function isReadonlyWhenLocked(rule-validator.ts#evaluateValidationRulesROT
messagerule-validator.ts:676 — * reaches a runtime this branch has to judge.rule-validator.ts#checkPredicate · rule-validator.ts#checkStateMachine · engine.ts#updateROT
messageengine.ts:3703 — * the probe's own failure, the same disposition #8895 gave therule-validator.ts#checkPredicate · rule-validator.ts#checkStateMachine · engine.ts#updateROT
typerule-validator.ts:706 — }rule-validator.ts#evaluateRule · rule-validator.ts#evaluateValidationRulesROT
conditionrule-validator.ts:697 — logger?.warn?.(rule-validator.ts#checkPredicateROT

view.json

entryFROM (citation at 8cb96ec — and what that line is TODAY)TOverdict
objectengine.ts:1653 — if (excludeObjects === undefined) return;engine.ts#resolveMetadataItemName · metadata-manager.ts#getViewsByObjectROT
list.nameview.zod.ts:1432 — }, {view.zod.ts#expandViewContainerWithDiagnosticsROT
form.sharingrest-server.ts:4384 — // are the same fact, resolved by the one reader thatrest-server.ts#findPublicFormView · rest-server.ts#resolveFormBySlugROT
listViewsview.zod.ts:1432 — }, {view.zod.ts#expandViewContainerWithDiagnosticsROT
formViewsrest-server.ts:4384 — // are the same fact, resolved by the one reader thatrest-server.ts#findPublicFormView · view.zod.ts#expandViewContainerWithDiagnosticsROT

Ablation — one new anchor, both legs proven on disk

Mutated ONE anchor added by this batch, on the COMMITTED tree, with an EXIT INT TERM trap holding an absolute-path restore. No build sits between the edit and the reading: check:liveness runs from source over the JSON ledgers via tsx, so there is no dist/ for a stale artifact to hide in — stated rather than assumed.

Predicted direction before running: RED, naming validation/condition and the invented symbol.

=== HEAD blob hash for packages/spec/liveness/validation.json ===
HEAD_BLOB=8d5b57e229a0561b96e4ede5a18684db071d915b
BEFORE=8d5b57e229a0561b96e4ede5a18684db071d915b
=== pre-mutation grep counts (both directions) ===
occurrences of 'rule-validator.ts#checkPredicate ' : 3 (expect 3)
occurrences of 'checkPredicateXQZ' : 0 (expect 0)
=== MUTATE ===
=== post-mutation grep counts (both directions) ===
occurrences of 'rule-validator.ts#checkPredicate ' : 2 (was 3, expect 2)
occurrences of 'checkPredicateXQZ' : 1 (was 0, expect 1)
AFTER=6c9306b9aa095983df680c0c4b5d7cdb492481c8
MUTATION CONFIRMED ON DISK
=== RUN GATE (mutated tree) ===
MUTATED_EXIT=1
symbol anchors: 499 pointer(s) written `path#symbol`, 498 naming a symbol the cited file contains, 1 UNRESOLVED.
✗ 1 anchored citation(s) name a symbol the cited file does not contain:
validation/condition → packages/objectql/src/validation/rule-validator.ts#checkPredicateXQZ
=== RESTORE ===
RESTORED=8d5b57e229a0561b96e4ede5a18684db071d915b
git diff HEAD --name-only: []
after restore — 'rule-validator.ts#checkPredicate ' : 3 (expect 3)
after restore — 'checkPredicateXQZ' : 0 (expect 0)
RESTORE CONFIRMED (blob equals HEAD, git diff HEAD empty)
=== RUN GATE (restored tree) ===
RESTORED_EXIT=0
line citations: 2 pointer(s) written `path:NNN`, 2 inside the cited file.
symbol anchors: 499 pointer(s) written `path#symbol`, 499 naming a symbol the cited file contains.

Observed direction matched the prediction. The mutation is proven on disk by BOTH grep directions plus a changed blob hash (hash-object compared against the HEAD blob, an empty hash treated as failure); the restore is proven by blob equality with HEAD plus an empty git diff HEAD, not by the exit code of git checkout. Restore is git checkout HEAD -- ABSOLUTE_PATH, never the bare form, so a polluted index cannot hand back the mutation.

Gates

Family derived at the committed head with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, no paths passed — 13 paths vs merge base 8cb96ec41, 25 families matched, no convention trigger fired (this diff adds and edits no test file, no gate script, no root-program TypeScript, no error code). Exit codes captured by redirect-then-read, before any pipe.

25 green, plus pnpm check:nul-bytes run on top of the derivation:

check:changeset-gate-self-tests · @objectstack/spec check:empty-state · @objectstack/spec check:liveness · check:merge-driver · check:objectui-changeset · check:page-declaration-shape · check:pm-half-states (the self-test, 1551 cases) · check:published-files · check:slot-lookup · @objectstack/spec check:strictness-ledger · check:test-source-alias · check:type-source-resolution · @objectstack/spec check:variant-docs · check-adr-0087-registration.mjs · check-changeset-no-major.mjs · check-comment-mask-adoption.mjs · check-dev-prereqs.mjs · check-empty-changeset.mjs · check-keyed-text-bounds.mjs · check-plugin-teardown-shape.mjs · check-undeclared-dep-imports.mjs · docs-audit/check-affected-docs.mjs · docs-audit/check-drift-comment.mjs · pm/release-rehearsal-clone.mjs --self-test · check:nul-bytes.

check-dev-prereqs.mjs was EXIT=1 on the unbuilt worktree ("67 of 67 workspace packages declare an entry point under dist/ that is not on disk"), which is a container prerequisite and NOT a reading. It was converted into a real one by building the closure the way lint.yml does — pnpm exec turbo run build --filter='./packages/*' --filter='./packages/*/*' --concurrency=2, 70/70 tasks successful in 6m34s under the shared verify lock — after which it prints ✓ 67 package build artifacts present and ✓ @objectstack/spec built from the sources on disk, EXIT=0.

One NOT MEASURED remains:node scripts/pm/check-half-states.mjs, EXIT=3 — PREREQUISITE NOT MET; the container has no valid GitHub credential and the gate says so itself: "Nothing was swept … It is not a clean board and it is not a dirty one — it is no reading at all." Standing across all four batches.

check:nul-bytes verdict line: check-nul-bytes: OK (scanned 7246 text file(s) -- 7246 tracked, 0 untracked-not-ignored; skipped 7 binary; no raw ASCII control bytes). Plus a hand scan of the twelve edited ledgers for the C0 class plus DEL: clean.

Every gate above ran at 88a1b24e2 with git diff HEAD empty, so the tree measured is the tree committed. No typecheck leg is owed: this diff contains no TypeScript.

Honest residual

Not in this PR

No status flip, no re-classification, no ledger row added or removed, no changes to check-liveness.mts, evidence.mts or any scan behaviour, no test file touched, and the two non-vacuity floors left exactly as ruling 5458356183 set them. .changeset/liveness-symbol-anchors-batch-4.md is a patch on @objectstack/specliveness/ is named in that package's files array, so these ledgers ship in the npm tarball and this is published data.

Clause ②: not reachable — ledgers plus one changeset, outside packages/spec/src/**, no accept-set or public-surface movement.

Session: https://claude.ai/code/session_01LpRNHxWZgSUgVnFT9mQQo4


Generated by Claude Code

…ng symbols (#13003 batch 4)
Adoption batch 4 -- the closing batch -- of the #12516 symbol-anchor citation
grammar, file-disjoint from batches 1-3 except for the one action.json entry
batch 1 deliberately left standing.
Eighty of the eighty-two remaining `path:NNN` citations across
liveness/app.json, validation.json, translation.json, field.json, hook.json,
mapping.json, capability.json, seed.json, view.json, dashboard.json, flow.json
and qa.json become `path#symbol`, together with every path-only pointer in the
same entries -- each re-closed by reading the code on the current tree rather
than by shifting a line. The gate's own counters move 82 -> 2 line citations
and 383 -> 499 symbol anchors.
Sixty-seven of the eighty were already wrong, every one IN RANGE and so
invisible to the existence check, the line bound and the key-mention check.
Six files were 100% rotted (validation 10/10, seed 6/6, view 5/5, dashboard
4/4, flow 4/4, qa 4/4). The dominant shape is BLOCK drift: nine of
validation.json's ten pointers had settled inside ONE 70-line ADR-0124
docblock ~1,200 lines above evaluateValidationRules, and app.json's
name/label/description onto three consecutive lines of one unrelated action
resolver. flow.status is the sharpest case -- it had come to rest on
`flowLedgerDisabled`, the map ADJACENT to the one this key writes, after
#10243 split the single flowEnabled map in two.
Two silent classes close with them: seventeen positions across four files were
bare `:NNN` suffixes with no path, which PATH_RE never matches, so nothing had
ever resolved, bounded or key-checked them (translation.objects alone carried
five); three entries (hook retryPolicy/timeout/onError) cited a path with no
line, unfalsifiable by a line bound by construction.
Three citations were falsified in PROSE as well as position: view.object
credited getViewsByObject() to packages/objectql/src/engine.ts (it is in
packages/metadata), field.requiredWhen named fieldRequiresParentRoot (no such
symbol; it is hasParentScopedRequiredWhen), and translation.metadataForms
named translateMetaTypes (it is translateMetaTypesResponse).
Nothing is re-classified. Two entries stay byte-for-byte untouched and NOT
re-stamped because their `live` VERDICT, not their citation, is what is
falsified -- action.execute (reported as #13036) and field.conditionalRequired
(reported as #13043), both retiredKey tombstones since protocol 17 whose cited
`.transform` lowering no longer exists. Those are ADR-0049 re-classifications
with their own card shape, so the line-citation counter reads 2 rather than 0
and the two non-vacuity floors stay in place.
Part of #13003
Claude-Session: https://claude.ai/code/session_01LpRNHxWZgSUgVnFT9mQQo4
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added size/m documentation Improvements or additions to documentation tooling labels Aug 29, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️12 changed file(s) yielded no anchor (packages/spec/liveness/app.json, packages/spec/liveness/capability.json, packages/spec/liveness/dashboard.json, …), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 12 changed file(s) yielded no anchor (packages/spec/liveness/app.json, packages/spec/liveness/capability.json, packages/spec/liveness/dashboard.json, …) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 126 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 8cb96ec41b34d987ca713cd94174af2fa45c955bpackageMentionDocs.

@os-trump
os-trump marked this pull request as ready for review August 29, 2026 00:39
@os-trump
os-trump enabled auto-merge August 29, 2026 00:39
@os-trump
os-trump added this pull request to the merge queueAug 29, 2026
Merged via the queue into main with commit 8f10a79Aug 29, 2026
35 checks passed
@os-trump
os-trump deleted the claude/issue-13003-anchor-adoption-b4 branch August 29, 2026 01:02
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mtooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@os-trump@claude