Skip to content

feat(spec): retire the six branded identifier schemas and EventNameSchema (ADR-0049 enforce-or-remove) - #14158

Merged
os-support-ai merged 6 commits into
mainfrom
claude/issue-13612-identifier-retirements
Sep 1, 2026
Merged

feat(spec): retire the six branded identifier schemas and EventNameSchema (ADR-0049 enforce-or-remove)#14158
os-support-ai merged 6 commits into
mainfrom
claude/issue-13612-identifier-retirements

Conversation

@os-support-ai

Copy link
Copy Markdown
Collaborator

Fixes #13612
Fixes #13613

Clause-②: yes

Family-folded dispatch (both cards RULED retire on 2026-09-01, director decision batch C, verbatim approval — comments 5486945231 and 5486945957): two ADR-0049 enforce-or-remove retirements of declared-but-unenforced identifier schemas, executed per the spec-property-retirement playbook with the ADR-0087 conversion for published-export removals. Each card's increment is independently verifiable: its own export-set delta, its own retired-defs rows and D3 semantic entry, and its own section of the shared changeset.

Card 1 — #13612: the six branded identifier schemas (commit a406443)

shared/branded-types.zod.ts removed whole — the file held exactly the six brands and their type exports (18 export statements: ObjectNameSchema, FieldNameSchema, ViewNameSchema, AppNameSchema, FlowNameSchema, RoleNameSchema, plus ObjectName/ObjectNameParsed through RoleName/RoleNameParsed). No schema in either repo ever composed a brand, so the promised compile-time safety was unobtainable.

  • Registered: six retired-defs rows under major 18 (shared/ObjectName, shared/FieldName, shared/ViewName, shared/AppName, shared/FlowName, shared/RoleName) plus D3 semantic entry branded-identifier-schemas-retired; six keys deliberately deleted from json-schema.manifest/shared.json behind the json-schema.manifest.json 的「deliberate removal」删行仍是纪律而非门禁 —— #4650 的同类洞,上移一层(整 schema 级) #4725 gate.
  • Untouched, per the ruling: the five surfaces' real validators — inline regexes at data/object.zod.ts:1581, data/field.zod.ts:887, automation/flow.zod.ts:616; bare SnakeCaseIdentifierSchema at ui/app.zod.ts:1288, identity/position.zod.ts:87 (line numbers re-verified on this branch's base; the issue cited the older e2debee positions). SnakeCaseIdentifierSchema and SystemIdentifierSchema themselves are unchanged.
  • api-surface/shared.json −18 rows (6 const + 12 type); declaration-map and export-origins follow; reference page content/docs/references/shared/branded-types.mdx deleted by gen:docs.

Card 2 — #13613: EventNameSchema and its three bindings (commit 928a373)

EventNameSchema and its EventName type removed from shared/identifiers.zod.ts. Its only three binding fields — EventTypeDefinitionSchema.name (kernel/events/core.zod.ts), EventSchema.name (same file), EventMessageSchema.eventName (api/websocket.zod.ts) — had zero runtime consumers; the platform-checked vocabulary is the closed literal enums DataEventType / BulkDataEventType (api/events.zod.ts), which never referenced it.

Derived judgments (contract-review items, declared per the dispatch)

Accept/reject behavior changes, one by one:

  1. Seven published exports removed (six brands + EventNameSchema, with 13 type exports total). Consumer effect: TS2305 at the import line on upgrade. Measured consumer population: zero — census on the branch base and re-run on the merged tree; every remaining repo reference is the retirement apparatus itself (ledger entries, registry, retirement comments).
  2. EventTypeDefinitionSchema.name: EventNameSchema (min 3, lowercase dot grammar) replaced by plain z.string(), describe pointing at the closed enums. Accept set WIDENS — every previously valid document stays valid; previously refused spellings (PascalCase, kebab-case, leading digit or dot, length under 3) now parse. Widening rather than enum-binding is deliberate: EventTypeDefinitionSchema declares custom event types, and binding it to the closed enums would be a new constraint the ruling did not order.
  3. EventSchema.name: same replacement, same widening, same reasoning.
  4. EventMessageSchema.eventName: same replacement, same widening, same reasoning.
  5. Test dispositions: branded-types.test.ts deleted whole (it tested only the brands). identifiers.test.ts drops its EventNameSchema block. kernel/events.test.ts's reject-side fixture pinned exactly the deleted grammar branch (it stayed green only because EventNameSchema refused) — repinned as an acceptance pin that holds the widening, refused spellings included, so a silent regression to a schema-level grammar goes red with the retirement named.
  6. No tombstone, no D2 conversion, on the [finding] The ApiKey reference table documents better-auth's apiKey-plugin schema — a plugin this platform does not load and a shape sys_api_key does not have #8715 route-3 shape: no authored document ever embedded a branded value, and the event-field change is a widening, so there is no source rewrite for os migrate meta to carry. The retired-defs table plus the two semantic entries are the declaration.

Small in-scope cleanups, declared: the ZOD_SCHEMA_AUDIT_REPORT.md line naming EventNameSchema as part of the identifiers module was corrected (the file is hand-maintained — last touched by #13895); a generator comment in packages/spec/scripts/lib/schema-section.ts that used ObjectName as its worked example now uses SystemIdentifier (a surviving bare-scalar def); llms.txt's hand-kept module counts (shared 13 to 12, total 207 to 206) and quick-reference.mdx's page count (8 to 7) corrected — both gate-caught, both are counts the file removal genuinely moves.

Out of scope, untouched, per the ruling: BucketConfigSchema / ObjectStorageConfigSchema / LifecyclePolicyRuleSchema (issue comment 5473339621 — not covered by the ruling, still awaiting one) and #13621 (SystemIdentifierSchema prose correction — separate card; the "Event keys" line in SystemIdentifierSchema's docblock is that card's surface, not this one's).

Semver

@objectstack/spec minor with BREAKING banner — the launch-window grade both rulings name explicitly, matching the #14128 / scim-provider precedents; check-changeset-no-major green. ADR-0087 disposition marker: registered branded-identifier-schemas-retired, event-name-schema-retired (both ids new in this diff; check-adr-0087-registration green).

Verification (all readings at merged head a46ef31 unless noted)

  • Full spec suite: 448 files / 12033 tests, all passed (vitest run at a46ef31, post-merge; the pre-merge lap caught the events.test.ts fixture, fixed in commit 928a373).
  • pnpm --filter @objectstack/spec typecheck: green (both cards' laps).
  • Dispatch gate list plus the dispatch-gates.mjs derived union (~70 gates, per-gate redirect-first exit capture): all PASS at a46ef31, including check-adr-0087-registration, check:migration-registry, check:spec-changes, check:upgrade-guide, check:authorable-surface, check:generated, check:liveness, check:empty-state, check:llms-txt, check:skill-refs, check:skill-examples, check:docs, check:variant-docs, check:yaml-examples, check:quick-reference-counts, check:strictness-ledger, check:spec-parsed-alias, and the changeset gate family. Derivation-added gates beyond the dispatch list were run and are green (doc gates, skills gates, corpus-claim-drift, published-files family and the rest).
  • NOT MEASURED locally, CI-owed (each by its own printed verdict, exit 3 prerequisite class): check:dual-build-cjs-loads and check:type-check-debt need the full workspace built (33+ sibling packages without dist — a container state this spec-only diff cannot move; the dispatch pre-authorized leaving dual-build to CI); check-test-completeness grades a saved turbo test log CI produces; check-dev-prereqs reports the same unbuilt-workspace state (66 of 67 dists absent at worktree creation — spec and every closure this PR's gates read were built locally).
  • Reverse verification (direction stated before running: absence expected): rebuilt dist declarations carry none of the seven names; the only dist occurrences are the retirement prose itself (semantic-entry strings and the schema-site comments in the bundles). The manifest ratchet fired exactly once per card before registration (the gen:schema silently drops PageTabsProps since #2967 — references regen would delete real docs #2978 tripwire, the route's own evidence) and passed after the retired-defs rows landed.
  • Projection note, direction stated to prevent a false alarm: spec-changes.json and docs/protocol-upgrade-guide.md are byte-identical by design — they project D2 conversions, and this retirement ships none (route 3); the same zero-delta holds for the feat(spec): remove the dangling postgres and nats values from ClusterDriverSchema #14128 semantic entry already on main. authorable-surface is also untouched: the brands were never authorable properties. Liveness ledger: no rows existed for any of the seven defs (never composed), so no ledger edits — check:liveness and check:empty-state green.

skills/** readings (dispatch DoD)

All eight touched files are the auto-generated references/_index.md (regenerated by gen:skill-refs; header says do not edit): per file before to after — objectstack-ai 45 to 45, objectstack-api 49 to 49, objectstack-automation 44 to 44, objectstack-data 65 to 65, objectstack-i18n 35 to 35, objectstack-platform 61 to 61, objectstack-query 35 to 35, objectstack-ui 56 to 56 (one line shortened in place: the identifiers.zod.ts export list drops EventNameSchema). Whole bundle: SKILL.md sum 10537 to 10537 (zero SKILL.md touched); all skills files sum 17863 to 17863. Net zero growth.

Open questions

None blocking. One observation recorded on the cards' comment trail rather than acted on: the three object-storage schemas from comment 5473339621 remain declared-but-unread and still await a ruling.


Generated by Claude Code

…ed-types.zod.ts

ADR-0049 enforce-or-remove, maintainer ruling 2026-09-01 (director batch C,
verbatim approval: retire; binding weighed and not adopted). No schema in
either repo ever composed a brand, so the promised compile-time safety was
unobtainable, while the surfaces the brands were named for are validated by
inline regexes or bare SnakeCaseIdentifierSchema — those five real
validators are the contract of record and are untouched here. Removes the
module whole (6 schemas + 12 type exports), registers the six shared/* defs
under RETIRED_DEFS_BY_MAJOR 18 plus the D3 semantic entry
branded-identifier-schemas-retired, deletes the six manifest keys behind the
#4725 gate, and regenerates api-surface / declaration-map / export-origins /
reference docs. SnakeCaseIdentifierSchema and SystemIdentifierSchema stay
published and unchanged.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mciyv38maJ6HYVMiaM26T1
…nly event-name contract

ADR-0049 enforce-or-remove, maintainer ruling 2026-09-01 (director batch C,
verbatim approval: retire). EventNameSchema presented itself as the
platform's event-name grammar while nothing that runs consumed its three
binding schemas (EventTypeDefinitionSchema.name, EventSchema.name,
EventMessageSchema.eventName); the vocabulary the platform actually checks
is the closed literal enums DataEventType / BulkDataEventType, which never
referenced it. Removes the schema and its EventName type, widens the three
binding fields to plain z.string() with describes that point at the enums,
registers shared/EventName under RETIRED_DEFS_BY_MAJOR 18 plus the D3
semantic entry event-name-schema-retired, deletes the manifest key behind
the #4725 gate, drops the Iso499 isomorphism pin with the schema (836 ->
835, ledgered in the pin file), and regenerates baselines, reference docs
and skill refs. The kernel events fixture that pinned the retired grammar's
reject branch is repinned to the widening (the refused spellings now parse).
WebSocketEventSchema.channel stays a deliberate z.string(); the enums are
byte-for-byte untouched.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mciyv38maJ6HYVMiaM26T1
…l moves

llms.txt counts *.zod.ts modules per domain (shared 13 -> 12, total 207 ->
206) and quick-reference.mdx declares how many reference pages
content/docs/references/shared/ publishes (8 -> 7); both moved when
shared/branded-types.zod.ts left with its six schemas. Caught by
check:llms-txt and check:quick-reference-counts.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mciyv38maJ6HYVMiaM26T1
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 43 documentable anchor(s). ⚠️ 14 changed file(s) yielded no anchor (packages/spec/ZOD_SCHEMA_AUDIT_REPORT.md, packages/spec/api-surface/shared.json, packages/spec/declaration-map/shared.json, …), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

42 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: node scripts/docs-audit/affected-docs.mjs --json 2bff79ae381d72c38c30ac9695eed429f1b61761.

3 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails.

What this run could not see
  • 14 changed file(s) yielded no anchor (packages/spec/ZOD_SCHEMA_AUDIT_REPORT.md, packages/spec/api-surface/shared.json, packages/spec/declaration-map/shared.json, …) — pages documenting those are invisible to this run
  • 1 anchor(s) matched too much of the corpus to be a work list: created_at (literal, 33 pages)
  • 4 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • 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 — 128 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 2bff79ae381d72c38c30ac9695eed429f1b61761packageMentionDocs.

Which tree this was computed on

This run read content/docs from a93c6b6cfb591281c9facde378000de34a53a41a — the merge of head 881b685f5c753767701032bcc12a488b575b9c5e into base 2bff79ae381d72c38c30ac9695eed429f1b61761, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin a93c6b6cfb591281c9facde378000de34a53a41a && git checkout a93c6b6cfb591281c9facde378000de34a53a41a
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 2bff79ae381d72c38c30ac9695eed429f1b61761 881b685f5c753767701032bcc12a488b575b9c5e && git checkout -B drift-repro 2bff79ae381d72c38c30ac9695eed429f1b61761 && git merge --no-ff 881b685f5c753767701032bcc12a488b575b9c5e

node scripts/docs-audit/affected-docs.mjs --json 2bff79ae381d72c38c30ac9695eed429f1b61761

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 2bff79ae381d72c38c30ac9695eed429f1b61761 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling labels Sep 1, 2026
The ObjectName-to-SystemIdentifier rename in the :565 comment was decorative
(zero behavior, forced by no gate) and its only measured effect was to
co-edit the generator that the #11705 pure-regeneration exception trusts,
which kept the eight regenerated skills/*/references/_index.md files
GOVERNED. The retired name stays in the comment as a tolerable historical
example; check:skill-refs, check:docs and check:generated pass unchanged
against the unmodified generator.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mciyv38maJ6HYVMiaM26T1

Copy link
Copy Markdown
Collaborator Author

Micro-patch (commit 881b685): reverted the decorative comment-example rename in packages/spec/scripts/lib/schema-section.ts (line 565, ObjectName back as the historical worked example, byte-identical to origin/main).

Why: the rename was zero-behavior prose forced by no gate, but it co-edited the generator that the #11705 pure-regeneration exception trusts, so the exception refused to lift the eight regenerated skills/*/references/_index.md paths and check-governed-merges read the PR as GOVERNED — one line of decoration was buying a maintainer manual merge. The retired name staying in that comment is tolerable prose debt; this PR body's "Small in-scope cleanups" line about schema-section.ts is superseded by this revert.

Gate re-readings at 881b685, unmodified generator + new sources, zero regeneration deltas: check:skill-refs PASS, check:docs PASS, check:generated PASS (no gate named the comment line — confirming the rename was never gate-forced).

New governed reading, verbatim from node scripts/pm/check-governed-merges.mjs --test over the PR's 44-file list at 881b685:

governed-surface predicate: 0 of 44 path(s) hit the register (5 surfaces, repo-agnostic).
  ✅  NOT governed — ordinary queue landing applies to a PR with exactly this file list.

All eight skills hits now carry the #11705 note: "PURE REGENERATION — byte-equal to pnpm --filter @objectstack/spec gen:skill-refs recomputed on THIS tree". The other 44 files are untouched by this patch round.


Generated by Claude Code

@os-support-ai
os-support-ai marked this pull request as ready for review September 1, 2026 09:27
@os-support-ai
os-support-ai added this pull request to the merge queue Sep 1, 2026
Merged via the queue into main with commit 45b9051 Sep 1, 2026
38 checks passed
@os-support-ai
os-support-ai deleted the claude/issue-13612-identifier-retirements branch September 1, 2026 10:04
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 tests tooling

Projects

None yet

2 participants