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

@os-help os-help commented Aug 11, 2026

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:

quantity card (08-09) today note
declared-breaking changesets in stock 227 body / 257 audit 274 both stale, as warned
residue (published break + real FROM → TO) 107 106 −1
detector-flagged candidates (!) 62 61 −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.

control expected returned
R13 IStorageService (pinned as having an entry) subject hit semantic/17.storage-service-list-retired.ts:7 surface: 'contracts.IStorageService.list'
R12 HttpServer (pinned as lacking one) no subject, prose only ✅ 0 subjects, 3 prose-only files
ctx.user.rolesdrawn from the candidate set itself subject hit semantic/17.actor-user-roles-to-positions.ts surface matches the changeset's face verbatim
RecordDetailsProps — the target's own def sibling key found, target absent ui/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

entry face evidence it was missing (beyond "the detector flagged it")
runtime-httpserver-wrapper-retired (#5122) exported HttpServer delegating wrapper 0 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 + hideFields The 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 contract The 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[].directionorder 9 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.requiresConfirmation Same 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 deny 0 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 values 0 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-type 0 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.deletedsuccess 0 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)

gate result
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

vercel Bot commented Aug 11, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xl tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

1 participant