Uh oh!
There was an error while loading. Please reload this page.
test(tooling): fail when an exported schema name has a second authority - #6348
Merged
os-warren merged 1 commit intoAug 25, 2026
Merged
Conversation
Adds the recurrence guard the 2026-08-25 family ruling (objectui#6172, decision A1) ordered: a root-suite gate that re-derives, from source, every exported type-level name in the published packages that carries more than one authority -- a second declaration, or a type-marked aliasing re-export publishing a name something else already declares. Deliberate re-exports are one declaration with many export sites and are not counted; near-spellings and derived names are anchored out. Today's 46 collisions land as a named, shrink-only baseline that fails in both directions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012CZgmFFzqA9cX8tBMhvpFe
os-warren
marked this pull request as ready for review
August 25, 2026 14:59
Uh oh!
There was an error while loading. Please reload this page.
os-warren
deleted the
claude/issue-6273-one-authority-per-exported-name
branch
August 25, 2026 15:11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#6273
The recurrence guard the 2026-08-25 family ruling ordered (decision 甲/A1 on #6172, verbatim acceptance 「同意」): every exported schema name has exactly one authority. The cleanup cards fix instances; this re-derives the collision set from source on every test run so the #6172 / #6155 / #6169 / #6170 / #6086 class cannot silently regrow after they land.
One file:
scripts/__tests__/one-authority-per-exported-name-6273.test.ts.Where it lives, and why
A root-suite test, not a
check:script. Both were open per the card. The test inherits the vitest run that already exists and needs no workflow wiring — acheck:script would owe a new job and its own path in that workflow'spaths:filter (#6321), which is new surface for no extra signal. #6337 (card #6186) just demonstrated the whole shape end to end in the same directory, so this is the freshest house precedent rather than a new convention.⛔
scripts/check-spec-symbol-derivation.mjs(#5899, another identity) is untouched. Its subject is a different claim — "a local declaration sharing a name with an@objectstack/specexport must be derived from the spec". This one is about two authorities inside objectui. Different population, different verdict; no reason to serialise behind it.What counts as an authority
export interface X/export type X/export enum X(anddeclare/const enum)export type { A as X } from './a'— an alias publishing a nameexport { X } from './x',export type { X } from './x',export * from './x',export * as ns from './x'export { X as X } from './x'export const/export function/export classexport interface Xin one fileTwo stated bounds, because a claim has to be bounded or derivable (2026-08-25 close-out, decision B1):
type-marked. This is lossless rather than a heuristic:tsconfig.base.jsonsets"isolatedModules": truerepo-wide, so a type re-export must carry the marker to compile. It also stops a value alias (export { helper as Grid }) reddening against an unrelatedinterface Grid.The two defects #6337 warned about, and how each is answered
(1) A leg that silently never fires. The positive control exercises the alias leg on its own cases, not just the declaration leg — and the alias leg has a live instance on the real tree, so it is demonstrably not vacuous:
packages/plugin-calendar/src/index.tsxpublishesCalendarViewEvent as CalendarEvent, a name@object-ui/typesalready declares.(2) The gate reddening on its own source. Solved with a real discriminator, ⛔ not a filename exemption. Unlike #6337's gate this one needs one mask, not two, and the reason is a property of the subject rather than a copied pattern: a declaration and an export clause are code in every spelling they have, so nothing here needs string literals to survive the mask. That single mask is also what lets the scan read
packages/create-plugin/src/templates.ts:417— which writesexport interface ${…}Schema extends BaseSchema {inside a template literal — without reddening on it. It is proved directly rather than argued: the matcher is run over this test file's own bytes and must find nothing, independently of the population bound.Negative controls — every one a spelling this repository really writes
Cited where it lives, because an assertion that reds on legitimate code gets deleted by the first person who hits it:
export type { StatusFieldSource } from './record-semantics.js';—packages/types/src/index.ts:71export * from './registry/Registry.js';—packages/core/src/index.ts:10export { formatTitleTemplate as formatRecordTitle }—packages/app-shell/src/utils/index.ts:9(a value alias)export { default as en }—packages/i18n/src/locales/index.ts:5KanbanConditionalFormattingRule/KanbanNativeConditionalFormattingRulenext to the contestedConditionalFormattingRule—packages/types/src/objectql.ts:2202/:2181(derived names are not collisions)expect(typesFile).toContain('export interface HeatmapSchema extends BaseSchema {');—packages/create-plugin/src/__tests__/templates.test.ts:449expect(source).toContain('export type { ChatMessage }');—packages/plugin-chatbot/src/__tests__/chat-message-contract.test.ts:448expect(typesSrc).toContain('export interface CalendarEvent {');—packages/plugin-calendar/src/__tests__/name-collision-5044.test.ts:173MenuItem as AppMenuItemcure pattern —packages/types/src/index.ts:59— stays green, or the remedy itself redsThe population refuses to collapse
Three floors, because three things can collapse independently — the package derivation, the file walk, and the matcher itself. Measured on
79ebf30d1: 38 published packages (derived fromprivate !== true, not listed), 1,364 files, 2,158 authority sites. Floors are 30 / 1000 / 1500.Baseline — re-measured today, not taken from the card
FormField,MarkdownSchema,KanbanSchema) and #6155 (KanbanCard×4). This baseline is today's measurement on79ebf30d1, and it differs:FormFieldis already clean — one declaration,packages/types/src/form.ts:911. It is not in the table.MarkdownSchema,KanbanSchemaandKanbanCard×4 are still live, andKanbanCard's four files match finding(types):KanbanCard/KanbanColumnare declared four times in this tree and the published copies disagree (cardsvsitems,badgesvslabels) #6155's count exactly — which is also the evidence that this population is co-extensive with the one the family cards counted (two of the four areKanbanEnhanced.tsx/KanbanImpl.tsx, neither a barrel).KanbanColumncollides across the same four files asKanbanCardand no family card mentions it;ActionSchemacollides insidepackages/typesitself (crud.tsvsui-action.ts);DataSource,ComponentMeta,ComponentConfig,SchemaNode,MenuItem,ValidationFunctionandThemeProviderPropsare all cross-package. Reported up as new information.KNOWN_COLLISIONSis ⛔ SHRINK-ONLY and reconciles in both directions: a new name or a new site is fresh debt, and a listed site that no longer collides is a stale entry that must come down in the same PR that cleaned it. Without that second direction the table degrades into a skip-list nobody dares touch — the shapecheck-skills-paths.mjsandcheck-doc-fence-languages.mjsalready refuse. The failure message prints a copy-paste-ready baseline line so nobody has to hand-transcribe one, and the remedy text points at theMenuItem as AppMenuItemworked example.Evidence — red before, green after, on the real tree
Fixture controls prove the matcher discriminates; this proves the whole pipeline (population walk → matcher → reconcile) fires on a real second declaration in real source. Injected a second
export interface MarkdownRendererPropsintopackages/plugin-markdown/src/types.ts, with anEXIT-trapped restore and absolute paths:No build/
distleg exists to invalidate: the gate reads tracked source text, so neither leg needs a rebuild — stated rather than assumed.Gates run — union taken at
78a9140c9, the final commitExit codes captured by redirect before any pipe. Each gate's own verdict line:
pnpm exec vitest run --project unit scripts/__tests__Test Files 78 passed (78) / Tests 2273 passed (2273)pnpm type-check:scripts(tsc -p tsconfig.scripts.json)--listFilesshows 1 hit for this file, so it is really compiled, not excludedpnpm lint:root✖ 28 problems (0 errors, 28 warnings)— all pre-existingno-explicit-anywarnings elsewhere;eslint --format jsonon this file alone:errors: 0, warnings: 0node scripts/check-control-bytes.mjs✅ check-control-bytes: OK (scanned 5225 tracked text file(s); skipped 85 binary).node scripts/check-lint-coverage.mjs✅ lint coverage: 46/46 packages linted, 0 with outstanding errors (0 total).node scripts/check-type-check-coverage.mjs✅ type-check coverage: 45/46 via type-check … ✅ test type-check coverage: 41/41node scripts/check-changeset-presence.mjs✅ No source of a released package changed in this range, so no changeset is owed.No changeset, on that gate's own verdict — one test file, no published source. ⛔ No
skip-changesetlabel (#4912); that mechanism does not exist in this repo.Heavy commands were serialised through the shared verify lock. Repo-wide
pnpm lint(turbo, all packages) is left to CI, which runs the farm exactly once regardless.Generated by Claude Code