Skip to content

chore(spec): backfill nine ADR-0087 ledger entries missing from the v17 stock (#6350) - #7624

Merged
os-help merged 1 commit into
mainfrom
claude/issue-6350-adr-0087-stock-reconciliation
Aug 11, 2026
Merged

chore(spec): backfill nine ADR-0087 ledger entries missing from the v17 stock (#6350)#7624
os-help merged 1 commit into
mainfrom
claude/issue-6350-adr-0087-stock-reconciliation

Conversation

@os-help

Copy link
Copy Markdown
Collaborator

Fixes#6350

One-time manual ADR-0087 ledger reconciliation over the v17 stock, per the maintainer ruling (comment 5250635216). ⛔ The gate is untouched and still judges diffs only — nothing in CI starts auditing inventory, for the ruling's stated reason (#6129).

Fresh measurement — today vs the stale card

Every number on the card was from 2026-08-09 and flagged as a floor. Re-measured on origin/main @ e124711:

quantitycard (08-09)todaynote
declared-breaking changesets in stock227 body / 257 audit274both stale, as warned
residue (published break + real FROM → TO)107106−1
detector-flagged candidates (!)6261−1 — not materially grown
ledger-touched (~)45

The set did not grow, so the full 61 were judged rather than sampled. The stock grew by 17 breaking changesets while the residue shrank — every one of those 17 landed carrying a disposition, which is the forward gate working.

⚠️The clone must be unshallowed first. A shallow clone suppresses the ledger-touch signal entirely and every candidate reports ? instead of !/~ (the script says so itself and prints the fix). Counting was grep -c / wc -l throughout, never grep | head. Arithmetic reconciles: 39 answered + 0 unpublished-exempt + 129 no-prescription-exempt + 106 residue = 274. No in-repo pin of these quantities exists — the classifier's arms are pinned (self-test S1–S7) but no count is; the only in-repo number is check-adr-0087-registration.mjs:1622's prose "227", which is explicitly a statement about filing time, not a ratchet.

Positive controls — the scanner proved it can see before any zero was believed

Coverage was judged with a harness that separates ledger subjects (id: / surface: / export const entry) from prose mentions (text inside another entry's reason / acceptanceCriteria). That distinction is the whole point: it is exactly the confusion that gave the issue-number proxy precision 0/3.

controlexpectedreturned
R13IStorageService (pinned as having an entry)subject hitsemantic/17.storage-service-list-retired.ts:7 surface: 'contracts.IStorageService.list'
R12HttpServer (pinned as lacking one)no subject, prose only✅ 0 subjects, 3 prose-only files
ctx.user.rolesdrawn from the candidate set itselfsubject hitsemantic/17.actor-user-roles-to-positions.ts surface matches the changeset's face verbatim
RecordDetailsProps — the target's own defsibling key found, target absentui/RecordDetailsProps:layout found; sections / hideFields absent

The last two are controls drawn from the targets' own unique content, not generic ones: the same search, on the same def and the same corpus, finds real coverage where it exists.

Registered — 9 entries, with the evidence each was missing

entryfaceevidence it was missing (beyond "the detector flagged it")
runtime-httpserver-wrapper-retired (#5122)exported HttpServer delegating wrapper0 subject hits; the 3 HttpServer* hits are prose in other entries, one of which (http-server-runtime-vocabulary-retired) registers #5295's system/http-server.zod.ts vocabulary — a different face. Sibling fixture R13 has the same shape and an entry.
record-details-sections-object-form (#5611)RecordDetailsProps.sections + hideFieldsThe same def carries a registered sibling key (ui/RecordDetailsProps:layout), proving the search reaches it; sections / hideFields have 0 subject hits. Authorable metadata on the publish/parse path.
data-driver-query-omit-object (#5181)IDataDriver query-parameter contractThe only subject hit on this interface is data-driver-find-stream-retireda different member. Two later, smaller driver-parameter changes (#6321, #6083) both registered and both cite #5181 as background; the larger sibling they derive from never got an entry.
sort-node-direction-rejected (#4721)orderBy[].directionorder9 prose files, 0 subjectsdirection is a common word, the textbook proxy trap. Half a retirement had shipped: SortNodeSchema carries aliases: { direction: 'order' } in code with no ledger half.
tool-requires-confirmation-retired (#3715)tool.requiresConfirmationSame half-retirement: a live retiredKey() tombstone stands in ai/tool.zod.ts:59 with the full prescription, and 0 ledger subjects. Per registry.ts: the tombstone is the proof the removal was declared, the ledger entry is the documentation channel — "a retirement needs both".
export-axis-opt-in (#3544)allowExport unset flips to deny0 subject hits. A secure-default flip whose metadata is unchanged and still parses, so no gate anywhere tells an upgrader its meaning inverted — the same class as the registered rest-requireauth-default-flip (12) and action-descriptor-resume-authority-default-flip (17).
apimethod-enum-shrink (#3543)enable.apiMethods 8 legacy values0 subject hits. Authorable enum; the mapping widens permissions (historyget, searchlist), which is why it is semantic not mechanical.
sharing-rule-recipient-reconcile (#1878)sharing-rule group / guest / owner-type0 subject hits. The two neighbouring conversions cover different faces (sharing-recipient-role-to-position = the role→position rename; sharing-rule-access-level-full-to-edit = access levels). Security surface: silent under-sharing.
client-delete-result-success (#5638)DeleteDataResult.deletedsuccess0 subject hits and 0 prose. Published TS surface; every if (r.deleted) has read undefined since it was written.

Each of the nine stock changesets now carries its <!-- adr-0087: registered … --> marker, so the judgement is recorded where the next auditor reads rather than only in a PR body.

Reconciliation is measurable in the repo's own standing audit surface (--audit-stock, before → after): answered 39 → 48, residue 106 → 97, flagged candidates 61 → 52.

Judged NOT missing — 34 candidates, with what covers each

Full accounting of the 61: 9 registered + 34 not-missing + 11 owed-but-not-written + 7 borderline-not-owed = 61. All 61 were judged; 11 of the judgements were not acted on, and that is declared below rather than rounded to done.

Wrong channel — a pure def/export rename (7). Not my judgement call; the repo rules on it twice. scripts/lib/renamed-defs.ts lists retiredKey() + an ADR-0087 conversion as remedy #2 and rejects it: "semantically false… Registering it would pollute the ADR-0087 registries with a migration consumers must not run."migrations/registry.ts:4000: "A rename is not a retirement… an entry here would be a false claim that the contract shrank." Positive control: 4 of the 7 are literally in the RENAMED_DEFS tableaction-location-dual-source-c17 (:109), package-dependency-dual-source-c7 (:120), http-method-defkey-collision (:139), field-mapping-tri-source-c12 (:83–84). Of the rest, rate-limit-config-dual-source-c9 is documented by name in that table's header as ABSORBED (renamed then retired in the same unreleased major; carried by the connector-rate-limit-config-removed conversion, which is present); http-method-dual-source-c14 re-exports an existing type with zero shape change; dual-source-cross-form-convergence's TransformTypeSchema half is covered by the retired-def shared/FieldMappingTransform.

Covered by a named existing entry (2).

Declared-only family removed — no author path, no consumer (14).dev-plugin-protocol-family-removed, kernel-metadata-loader-envelope-removed, lifecycle-event-registry-enforced, plugin-lifecycle-hooks-retired, prune-dead-audit-config-cluster, prune-dead-capabilities-descriptor, prune-orphan-featureflag-schema, objectql-dead-use-retired, session-dual-source-c4, event-schema-dual-source-c6, environment-artifact-dual-source-c10, tenant-plan-dual-source-c16, etl-author-shape-aliases, retire-the-dev-stub-table. Each states its own exemption and gives the reason the exemption is real (no load path parses it, so no authored source can carry the keys); the two most explicit cite the plugin-runtime.zod.ts DynamicLoadingConfig precedent (#3950). The ETL family additionally is registered, as retired-defs automation/ETL*.

Runtime behaviour or wire shape, with no authored metadata and no removed authorable key (11).empty-capability-answers-501, retire-the-dispatcher-auth-mock, dispatcher-error-code-is-semantic, settings-error-details-declared-slot, findone-requires-a-predicate, deprecate-kernel-assignment-notifications, better-auth-1-7-0-rc-2-and-prod-dep-batch (a third-party upgrade shipping its own idempotent boot-time backfill), compose-stacks-i18n-single-valued, hook-context-api-scoped-context and subscribe-metadata-event-subject (both type narrowings — additive for already-correct code), action-param-option-visible-when (a capability opened, not removed).

⚠️ Declared partial — 11 judged OWED, deliberately not written

The #4001 unknown-key strictness wave and its authoring-gate neighbours: unknown-key-strictness-tier-a, -step2, -automation-batch11, -ui-batch13, -ui-batch15, -ui-batch16, view-subblock-strictness-batch18, strict-automation-control-flow-state-machine, rare-jars-shave, user-filters-allow-add-tab-promote-and-close, view-union-identity-precondition.

These are authorable metadata with real rename tables and 0 subject coverage, and the class is demonstrably registrable — ui-schemas-strict-unknown-keys (major 15) and dashboard-widget-strict-unknown-keys (major 16) are exactly this shape. I judge them owed. I did not write them because the precedent registers a wave as one entry per major, not one per batch, and choosing the grouping myself would harden an invented shape into a set-consumed ledger where a wrong grouping produces no error anywhere. This is a maintainer call and is the single largest piece of remaining work on this card.

⚠️ Borderline — judged not-owed with lower confidence (7)

Flagged rather than rounded: http-server-config-retired (nine keys with a full FROM → TO table, but the changeset shows there was no authoring entry at all — they could not be written down), retire-dev-service-marker, durable-suspended-screen-refetch (a sync→async contract break), sys-comment-retire-visibility-reply-count, membership-grade-not-capability-channel, converge-activation-event-schema (defineStudioPlugin's activationEvents string→object is authored), views-translation-key-runtime-identity (translation-bundle keys). Any of these could reasonably be ruled owed.

Gates run (with invocation scope)

gateresult
pnpm --filter @objectstack/spec run check:migration-registry✅ self-test ok; registry current (70 semantic / 18 retired-key / 45 retired-def)
pnpm --filter @objectstack/spec run check:spec-changes✅ up to date
pnpm --filter @objectstack/spec run check:upgrade-guide✅ up to date
pnpm --filter @objectstack/spec run typecheck✅ (tsc --noEmit + scripts + test-typecheck)
pnpm --filter @objectstack/spec exec vitest run src/migrations/migrations.test.ts✅ 92 passed — the full chain replays
node scripts/check-adr-0087-registration.mjs --self-test✅ 142 assertions over real temp git repos
node scripts/check-adr-0087-registration.mjs --base origin/main✅ green on this PR
node scripts/check-empty-changeset.mjs --base origin/main✅ green

Changeset included (@objectstack/spec: minor) — the entries change spec-changes.json, the published upgrade guide, and what os migrate meta emits.

⛔ Untouched, per scope: the gate's diff-only behaviour, packages/spec/src/**/*.zod.ts, and content/docs/releases/**.

Could not verify


Generated by Claude Code

…17 stock (#6350)
The #6148 completeness gate is diff-only by design (#6129), so every breaking
changeset already in the v17 train was never compared against the ADR-0087
ledger. This is the one-time manual reconciliation the maintainer ruled for.
The gate is untouched and still judges diffs only.
Measured today: 274 declared-breaking changesets in stock, 106 in the residue,
61 flagged as never having touched a ledger file. Judging all 61 by hand found
nine genuinely missing entries, registered here as D3 semantic migrations, and
each of the nine stock changesets now carries its adr-0087 disposition marker.
Two had shipped half a retirement: tool.requiresConfirmation carries a live
retiredKey() tombstone and SortNodeSchema carries aliases:{direction:'order'},
but neither had the ledger half. A retirement needs both.
spec-changes.json and docs/protocol-upgrade-guide.md are regenerated.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0198a2mSFFM18npoJfNtNv8z
@vercel

vercelBot commented Aug 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 11, 2026 9:15am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec.

106 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx(via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx(via @objectstack/spec)
  • content/docs/ai/skills.mdx(via @objectstack/spec)
  • content/docs/api/client-sdk.mdx(via @objectstack/spec)
  • content/docs/api/environment-routing.mdx(via @objectstack/spec)
  • content/docs/api/error-catalog.mdx(via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx(via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx(via @objectstack/spec)
  • content/docs/api/index.mdx(via @objectstack/spec)
  • content/docs/automation/approvals.mdx(via @objectstack/spec)
  • content/docs/automation/connectors.mdx(via @objectstack/spec)
  • content/docs/automation/flows.mdx(via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx(via packages/spec)
  • content/docs/automation/hooks.mdx(via @objectstack/spec)
  • content/docs/automation/index.mdx(via @objectstack/spec)
  • content/docs/automation/webhooks.mdx(via @objectstack/spec)
  • content/docs/automation/workflows.mdx(via @objectstack/spec)
  • content/docs/concepts/architecture.mdx(via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx(via packages/spec)
  • content/docs/concepts/index.mdx(via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx(via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx(via packages/spec)
  • content/docs/concepts/north-star.mdx(via @objectstack/spec)
  • content/docs/data-modeling/analytics.mdx(via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx(via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx(via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx(via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx(via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx(via @objectstack/spec)
  • content/docs/data-modeling/index.mdx(via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx(via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx(via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx(via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx(via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx(via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx(via @objectstack/spec)
  • content/docs/deployment/cli.mdx(via @objectstack/spec)
  • content/docs/deployment/tenancy-modes.mdx(via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx(via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx(via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx(via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx(via @objectstack/spec)
  • content/docs/getting-started/examples.mdx(via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx(via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx(via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx(via @objectstack/spec)
  • content/docs/kernel/cluster.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx(via @objectstack/spec)
  • content/docs/kernel/index.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/data-service.mdx(via @objectstack/spec)
  • content/docs/kernel/runtime-services/email-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/examples.mdx(via @objectstack/spec)
  • content/docs/kernel/runtime-services/index.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx(via @objectstack/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx(via @objectstack/spec)
  • content/docs/kernel/services-checklist.mdx(via @objectstack/spec)
  • content/docs/kernel/services.mdx(via @objectstack/spec)
  • content/docs/permissions/authorization.mdx(via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx(via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx(via @objectstack/spec)
  • content/docs/permissions/positions.mdx(via @objectstack/spec)
  • content/docs/permissions/rls.mdx(via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx(via @objectstack/spec)
  • content/docs/permissions/system-context.mdx(via packages/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx(via @objectstack/spec)
  • content/docs/plugins/development.mdx(via @objectstack/spec)
  • content/docs/plugins/index.mdx(via @objectstack/spec)
  • content/docs/plugins/packages.mdx(via @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx(via @objectstack/spec)
  • content/docs/protocol/diagram.mdx(via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx(via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx(via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx(via @objectstack/spec)
  • content/docs/ui/actions.mdx(via @objectstack/spec)
  • content/docs/ui/apps.mdx(via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx(via @objectstack/spec)
  • content/docs/ui/dashboards.mdx(via @objectstack/spec)
  • content/docs/ui/field-grouping-and-order.mdx(via @objectstack/spec)
  • content/docs/ui/forms.mdx(via @objectstack/spec)
  • content/docs/ui/index.mdx(via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx(via @objectstack/spec)
  • content/docs/ui/setup-app.mdx(via @objectstack/spec)
  • content/docs/ui/translations.mdx(via @objectstack/spec)
  • content/docs/ui/views.mdx(via @objectstack/spec)

7 release-owned page(s) also reference the affected code. These are read-only:

  • content/docs/releases/implementation-status.mdx(via @objectstack/spec)
  • content/docs/releases/index.mdx(via @objectstack/spec)
  • content/docs/releases/v12.mdx(via @objectstack/spec)
  • content/docs/releases/v13.mdx(via @objectstack/spec)
  • content/docs/releases/v16.mdx(via @objectstack/spec)
  • content/docs/releases/v17.mdx(via @objectstack/spec)
  • content/docs/releases/v9.mdx(via @objectstack/spec)

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tooling labels Aug 11, 2026
@os-help
os-help marked this pull request as ready for review August 11, 2026 09:42
@os-help
os-help added this pull request to the merge queueAug 11, 2026
Merged via the queue into main with commit 5823d59Aug 11, 2026
27 checks passed
@os-help
os-help deleted the claude/issue-6350-adr-0087-stock-reconciliation branch August 11, 2026 09:59
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/xltooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] #6148 的门禁只判 diff,v17 列车已有的 227 条 breaking changeset 从未被比对过 —— 抽样已见 2 条疑似同形漏登记

1 participant

@os-help