From fdd0746c555b8cf629a245c019d4d17600f2031b Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 30 Aug 2026 10:18:54 +0000 Subject: [PATCH 1/2] test(types): close the #4115 ledger's last batch with measured verdicts, not re-exports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Batch 8/8 of the objectstack#4115 any-erasure ledger covered `JoinNode`, `NavigationItem`, `NavigationItemSchema` and `JoinedReportBlock`, all filed as "blocked on objectstack#4171 — re-export when the upstream erasure lifts". #4171 closed completed on 2026-07-30. Re-measuring in the BUILT dist at spec 17.2.0 (not in source, and not from the issue's state) finds none of the four is burnable, for three different reasons — none of them the one the ledger recorded: - `JoinNode`: the spec no longer exports the symbol at all (TS2305 from both `/ui` and `/data`); spec 17.0.0 retired the cluster. Nothing to bind to. - `NavigationItem`: upstream is precise now, but the three semantic blockers #3177 measured are untouched by #4171. - `NavigationItemSchema`: upstream is precise now too — and that is exactly what makes the burn-down dangerous, because the live blocker is runtime shape. Referencing the spec's schema would make `objectui validate` reject metadata this renderer accepts today. - `JoinedReportBlock`: still erased, to `unknown`, by a cause `#4171` never covered (a bare `z.ZodTypeAny`, not recursion). So the batch lands zero re-exports and converts the remaining debt into pins that name their own release condition: - `app.zod.ts` carried a reason that measurement has made FALSE — "the spec's is `z.ZodType` and would validate nothing". Left alone, the next triage checks that claim, finds it false, and lands the regression this ledger exists to prevent. Replaced with the measured reason. - `JoinNode` absence is now pinned in the file that already owns "the spec does not own X", so a re-minted upstream name is caught. - The `JoinedReportBlock` pin no longer reads as pending on a closed issue. - `navigation-spec-parity.test.ts` gains the only mechanical guard for the CURRENT blocker: five pieces of metadata objectui accepts and the spec rejects, behind two positive controls. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB --- .../__tests__/navigation-spec-parity.test.ts | 52 +++++++++++++++++++ .../report-chart-query-spec-parity.test.ts | 20 ++++++- .../src/__tests__/spec-derived-unions.test.ts | 46 ++++++++++++++++ packages/types/src/zod/app.zod.ts | 22 ++++++-- 4 files changed, 136 insertions(+), 4 deletions(-) diff --git a/packages/types/src/__tests__/navigation-spec-parity.test.ts b/packages/types/src/__tests__/navigation-spec-parity.test.ts index e8f344d7e2..421d290208 100644 --- a/packages/types/src/__tests__/navigation-spec-parity.test.ts +++ b/packages/types/src/__tests__/navigation-spec-parity.test.ts @@ -38,6 +38,7 @@ import { describe, it, expect } from 'vitest'; import { NavigationItemSchema, NavigationAreaSchema } from '../zod/app.zod.js'; +import { NavigationItemSchema as SpecNavigationItemSchema } from '@objectstack/spec/ui'; /** Parse and return the surviving object, so "accepted" cannot hide a strip. */ function keep(input: unknown): Record | null { @@ -114,3 +115,54 @@ describe('NavigationAreaSchema keeps the spec fields it used to drop', () => { expect(r.success && r.data.description).toBe('Pipeline and accounts'); }); }); + + +// ───────────────────────────────────────────────────────────────────────────── +// Why this schema is NOT the spec's, stated as a measurement (objectui#3162) +// ───────────────────────────────────────────────────────────────────────────── + +/** + * The objectstack#4115 ledger filed `NavigationItemSchema` as "erased to `any` + * upstream — flow the spec's shape in by reference once objectstack#4171 lands". + * #4171 landed, and the spec's schema is precise now (pinned in + * `spec-derived-unions.test.ts`). That makes the ledger's stated reason spent — + * and it is exactly the moment the burn-down becomes DANGEROUS, because the + * remaining reason lives at runtime where no type-level probe can see it. + * + * The header above says it in prose: objectui keeps one flat, all-optional shape + * and the spec is a discriminated union of `.strict()` variants. Prose does not + * fail. This does: every case below is metadata `objectui validate` accepts today + * and the spec's schema rejects, so referencing the spec's schema would silently + * narrow the published CLI's accepted surface. + * + * The day the two are reconciled these flip and this block is the instruction to + * re-run the triage — not to delete the assertions until the divergence is + * actually gone. + */ +describe('referencing the spec NavigationItemSchema would reject metadata objectui accepts (objectui#3162)', () => { + /** Guards every rejection below from passing because the spec schema rejects everything. */ + it('accepts a fully spec-shaped item and a bare separator (positive controls)', () => { + expect(SpecNavigationItemSchema.safeParse({ + id: 'apps', type: 'object', label: 'Apps', objectName: 'sys_app', + }).success).toBe(true); + expect(SpecNavigationItemSchema.safeParse({ type: 'separator' }).success).toBe(true); + }); + + it.each([ + ['pinned', { id: 'apps', type: 'object', label: 'Apps', objectName: 'sys_app', pinned: true }, + 'backs useNavPins + FavoritesProvider'], + ['defaultOpen', { id: 'grp', type: 'group', label: 'G', children: [], defaultOpen: true }, + 'the legacy spelling this file keeps accepting for published metadata'], + ['visible: boolean', { id: 'ai', type: 'url', label: 'AI', url: '/ai', visible: true }, + 'menuItemToNavigationItem MANUFACTURES one when it inverts MenuItem.hidden'], + ['separator label', { type: 'separator', label: 'Section' }, + 'menuItemToNavigationItem emits one; the spec separator declares only id/order'], + ['single-character id', { id: 'a', type: 'url', label: 'A', url: '/a' }, + 'objectui requires only a non-empty id; the spec requires two characters'], + ])('the spec rejects %s (%s)', (_name, input, _why) => { + // objectui accepts it... + expect(NavigationItemSchema.safeParse(input).success).toBe(true); + // ...and the spec does not, which is the whole reason for the local schema. + expect(SpecNavigationItemSchema.safeParse(input).success).toBe(false); + }); +}); diff --git a/packages/types/src/__tests__/report-chart-query-spec-parity.test.ts b/packages/types/src/__tests__/report-chart-query-spec-parity.test.ts index d232d07355..3710dce9db 100644 --- a/packages/types/src/__tests__/report-chart-query-spec-parity.test.ts +++ b/packages/types/src/__tests__/report-chart-query-spec-parity.test.ts @@ -641,6 +641,15 @@ describe('renamed local dialects do not collide with a spec export (objectui#307 ['DriverQueryConfig', 'high-level query config the SQL AST builder consumes'], ['SqlDriverInterface', "objectui's SQL-oriented client driver abstraction"], ['DatasourceRegistration', 'in-memory datasource registration record'], + // objectui#3162 batch 8. `JoinNode` was ledgered as "erased to `any` upstream, + // re-export once objectstack#4171 lands". #4171 landed — and the symbol it was + // waiting on no longer exists: spec 17.0.0 retired `query.joins` and the whole + // JoinNode cluster (framework#4286), so there is nothing upstream to bind to + // and `data-protocol.ts` owns the name outright. Measured against spec 17.2.0: + // importing it from `@objectstack/spec/ui` OR `/data` is TS2305. This row is + // what tells us if the spec ever mints the name again, which is the only way + // the collision could come back. + ['JoinNode', "objectui's local query-AST join node; the spec retired its own (framework#4286)"], ])('the spec does not own `%s` (%s)', (name) => { expect(names).not.toContain(name); }); @@ -668,6 +677,15 @@ describe('renamed local dialects do not collide with a spec export (objectui#307 * types the schema properly, `IsUnknown<…>` flips to `false`, `true satisfies * false` stops compiling, and the failure is the instruction: re-run the triage * and burn it down. + * + * ⚠️ objectstack#4171 is CLOSED (completed 2026-07-30) and this symbol is STILL + * erased — do NOT read that closure as this pin's release. #4171 typed the + * RECURSIVE schemas (`NavigationItem`, `FormField`); it never touched + * `JoinedReportBlockSchema`, whose erasure has a different cause — a bare + * `z.ZodTypeAny` annotation, not recursion. Re-measured in the built dist at + * spec 17.2.0 (objectui#3162 batch 8): `IsUnknown` is still `true`. The pin + * below, not the state of any upstream issue, is what says when this is + * burnable. */ type IsUnknown = [unknown] extends [T] ? ([T] extends [unknown] ? true : false) : false; type IsAny = 0 extends 1 & T ? true : false; @@ -676,7 +694,7 @@ const _specJoinedReportBlockIsNotEvenAny = false satisfies IsAny { +describe('JoinedReportBlock stays in the ledger — still untyped upstream (objectui#3162)', () => { it('documents why: the spec ships the schema untyped', () => { // The compile-time pins above are the real guard; this keeps the reason // visible in the test report rather than only in a comment. diff --git a/packages/types/src/__tests__/spec-derived-unions.test.ts b/packages/types/src/__tests__/spec-derived-unions.test.ts index 262b7ff6a4..f728fa98ea 100644 --- a/packages/types/src/__tests__/spec-derived-unions.test.ts +++ b/packages/types/src/__tests__/spec-derived-unions.test.ts @@ -57,7 +57,9 @@ import { ACTION_LOCATIONS as SpecACTION_LOCATIONS, ActionLocationSchema as SpecActionLocationSchema, ActionSchema as SpecActionSchema, + NavigationItemSchema as SpecNavigationItemSchema, } from '@objectstack/spec/ui'; +import type { z } from 'zod'; import { FieldType as SpecFieldType, } from '@objectstack/spec/data'; @@ -147,6 +149,38 @@ const _validationErrorShape: ValidationError = { field: 'name', message: 'requir // gone with the imports. `packages/types/src/data-protocol.ts` now restates the // members locally, verbatim from the last spec that published them, as the // objectui query-AST vocabulary they have become. +// +// ── objectstack#4115 batch 8/8 (objectui#3162): CLOSED WITH ZERO RE-EXPORTS ─── +// +// The ledger's last batch — `JoinNode`, `NavigationItem`, `NavigationItemSchema`, +// `JoinedReportBlock` — was filed as "blocked on objectstack#4171; burn down when +// the upstream `any` erasure lifts". #4171 closed completed on 2026-07-30, and the +// re-measurement it licensed found that NONE of the four is burnable, for three +// DIFFERENT reasons — none of which is the one the ledger recorded. Measured in the +// BUILT dist at spec 17.2.0 (source and issue state were both insufficient: the +// whole point of this ledger is that dist erasure is invisible from either): +// +// - `JoinNode` — the spec no longer exports the symbol AT ALL +// (TS2305 from `/ui` and `/data`); spec 17.0.0 retired +// the cluster. Nothing upstream to bind to. Absence +// pinned in `report-chart-query-spec-parity.test.ts`. +// - `NavigationItem` — upstream IS precise now (`IsAny` and `IsUnknown` both +// `false`), so #4171 really did land. Binding is still +// wrong: the three semantic blockers pinned below are +// unaffected by it. `any` was never the only blocker — +// #3177 established that, and it still holds. +// - `NavigationItemSchema`— upstream IS precise now; pinned below. The live +// blocker is SHAPE, and it is a RUNTIME one: see +// `navigation-spec-parity.test.ts`. +// - `JoinedReportBlock` — STILL erased, to `unknown`, by a cause #4171 never +// covered. Pinned in +// `report-chart-query-spec-parity.test.ts`. +// +// So the batch burns down to zero re-exports and the ledger's remaining debt is +// now carried as state pins that name their own release condition, rather than as +// a card pointing at an upstream issue that has since closed without settling it. +// ⛔ A closed upstream issue is not a licence to re-export: prove the dist type is +// precise, then prove binding it does not narrow what this package already accepts. /** * Admission probes for `NavigationItem` and `FormField` (#3177). @@ -238,6 +272,17 @@ const _specSeparatorStillHasNoLabel = false satisfies 'label' extends keyof Extr // that drops a member (the objectstack#4115 failure class) fails here. const _navTypeCoversSpec = null as unknown as SpecNavigationItem['type'] satisfies NavigationItemType; +// `NavigationItemSchema` (objectui#3162 batch 8): upstream precision is SETTLED, +// so no future triage may re-derive the ledger's stale reason from prose. The spec +// now ships `z.ZodType`; this holds that +// measurement, and fires if the annotation ever regresses to `z.ZodType`. +// +// This pin deliberately does NOT say the schema is bindable — it says the OLD +// reason for not binding is spent. The live reason is runtime shape, and only +// `navigation-spec-parity.test.ts` can pin that, because it is about which +// metadata parses, not which types assign. +const _specNavSchemaIsNoLongerAny = false satisfies IsAny>; + // ── FormField: not one concept in two dialects, but two concepts on two layers ─ // // `select-option-spec-parity.test.ts` states the distinction in its own header — @@ -296,6 +341,7 @@ void _validationErrorShape; void _localNavIsNotYetTheSpecUnion; void _specNavVisibleStillRejectsBoolean; void _specNavStillHasNoPinned; void _specNavStillHasNoDefaultOpen; void _specSeparatorStillHasNoLabel; void _navTypeCoversSpec; +void _specNavSchemaIsNoLongerAny; void _specFormFieldIsNoLongerAny; void _specFormFieldStillHasNoName; void _specFormFieldInputStillHasNoName; void _specFieldSlotIsStillAName; void _localFieldSlotIsStillAnObject; void _specDependsOnStillTakesNoArray; diff --git a/packages/types/src/zod/app.zod.ts b/packages/types/src/zod/app.zod.ts index d458e70df2..51bfedfc54 100644 --- a/packages/types/src/zod/app.zod.ts +++ b/packages/types/src/zod/app.zod.ts @@ -126,9 +126,25 @@ export const NavigationItemSchema: z.ZodType = z.lazy(() => z.object({ * is what let that happen. * * One key is pinned locally, matching the TS twin in `app.ts`: - * - `navigation` — objectui's `NavigationItemSchema`, because the spec's is - * `z.ZodType` (objectstack#4171 / objectui#3162) and would validate - * nothing. + * - `navigation` — objectui's `NavigationItemSchema`. ⚠️ The reason is NO LONGER + * "the spec's is `z.ZodType` and would validate nothing". That was true + * when this was written and is false now: objectstack#4171 landed, and spec + * 17.2.0 declares `NavigationItemSchema: z.ZodType` — measured precise in the BUILT dist, not just in + * source (objectui#3162 batch 8). + * + * What blocks the burn-down now is SHAPE, not precision. The spec models + * navigation as a discriminated union of `.strict()` variants; objectui keeps + * one flat, all-optional object that deliberately accepts more. Measured + * against spec 17.2.0, referencing the spec's schema would make `objectui + * validate` REJECT metadata this renderer accepts today: `pinned`, + * `defaultOpen` and a separator carrying `label` all fail `unrecognized_keys`, + * `visible: boolean` fails `invalid_union`, and a one-character `id` fails + * `too_small`. Pinned by `__tests__/navigation-spec-parity.test.ts`. + * + * Converging on the union is a breaking change for every consumer that reads + * fields off `NavigationItem` without narrowing — tracked separately, and + * deliberately not smuggled into a ledger burn-down. * * `order`, `visible` and `requiredPermissions` were AREA-level keys until * `@objectstack/spec` 17.0.0 retired them (`AREA_VISIBLE_RETIRED` / From 2c3e93e863a9f28904313f2e5a2dd45902f45d0f Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 30 Aug 2026 10:26:39 +0000 Subject: [PATCH 2/2] chore(types): clear the #4115 machine-readable ledger, recording batch 8 as declared dialects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `check-spec-symbol-derivation.mjs` carries the ledger's enforceable half: a `DEBT` map keyed to objectstack#4115 whose `@object-ui/types` entry was exactly the three batch-8 symbols that still collide with a spec export, reported by the gate as "3 untriaged collisions". They are not untriaged — they are measured, and the measurement says they must NOT be burned down. That is what the guard's `ALLOW` registry is for: "a same-name symbol that is narrower or wider ON PURPOSE belongs here with that purpose written down". So the three move DEBT to ALLOW with their measured reasons and their release conditions named as pins, and the DEBT map empties. before: 13 declared dialects, 3 untriaged collisions in 1 packages after: 16 declared dialects, 0 untriaged collisions in 0 packages Also corrects the `FormField` ALLOW reason, which asserted "the spec's FormField type erases to `any` in its dist (objectstack#4171), so a re-export would delete typing outright". That is false now and `spec-derived-unions.test.ts` already pins it false (`_specFormFieldIsNoLongerAny`). It is the same defect class as the batch this PR closes — a spent `any`-erasure justification standing in for the real one — and the real reason (the two-layer split, guard header case 2c) is unaffected by precision. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB --- .../3162-types-ledger-batch8-verdicts.md | 33 +++++++++ scripts/check-spec-symbol-derivation.mjs | 70 ++++++++++++++++--- 2 files changed, 94 insertions(+), 9 deletions(-) create mode 100644 .changeset/3162-types-ledger-batch8-verdicts.md diff --git a/.changeset/3162-types-ledger-batch8-verdicts.md b/.changeset/3162-types-ledger-batch8-verdicts.md new file mode 100644 index 0000000000..d578606c34 --- /dev/null +++ b/.changeset/3162-types-ledger-batch8-verdicts.md @@ -0,0 +1,33 @@ +--- +--- + +Closes the last batch of the `@objectstack/spec` any-erasure ledger (objectstack#4115 batch +8/8) with zero re-exports, because measurement says none of the four symbols is burnable. + +The batch — `JoinNode`, `NavigationItem`, `NavigationItemSchema`, `JoinedReportBlock` — was +filed as "blocked on objectstack#4171; burn down when the upstream `any` erasure lifts". +That issue closed completed on 2026-07-30, which is the card's own start signal. Re-measuring +each symbol in the BUILT dist at `@objectstack/spec` 17.2.0 (source and issue state are both +insufficient — dist erasure is invisible from either) found three different reasons why +binding is still wrong, none of them the reason the ledger recorded: + +- `JoinNode` — the spec no longer exports the symbol at all; spec 17.0.0 retired the + `query.joins` cluster. Nothing upstream to bind to. +- `NavigationItem` — upstream is precise now, so "no longer `any`" is settled; the three + semantic blockers that actually prevent binding are untouched by it. +- `NavigationItemSchema` — upstream is precise now too, and that is exactly what makes the + burn-down dangerous: the live blocker is runtime shape, invisible to every type-level + probe. Referencing the spec's schema would make the published `objectui validate` reject + navigation metadata this renderer accepts today. +- `JoinedReportBlock` — still erased, to `unknown`, by a cause objectstack#4171 never + covered (a bare `z.ZodTypeAny`, not recursion). + +So the remaining debt is converted from a card pointing at an upstream issue into pins that +each name their own release condition, and the guard's machine-readable ledger +(`check:spec-symbols`) goes from "3 untriaged collisions" to zero, with the three symbols +recorded as declared dialects carrying their measured reasons. + +Two stale justifications were corrected in passing, both the same defect class this ledger +exists to catch — a comment asserting an upstream type "erases to `any`" when it no longer +does. Left alone, the next triage checks the claim, finds it false, and lands the regression. +No published behaviour changes; no runtime code was touched. diff --git a/scripts/check-spec-symbol-derivation.mjs b/scripts/check-spec-symbol-derivation.mjs index 0ed34f2864..30d0b3495c 100644 --- a/scripts/check-spec-symbol-derivation.mjs +++ b/scripts/check-spec-symbol-derivation.mjs @@ -255,8 +255,10 @@ const ALLOW = { "Two-LAYER vocabulary, not two dialects of one concept (objectui#3090): the spec's " + "FormField is the authored form-VIEW shape (`field` = object-field reference, presentation " + "deltas only) while this is the runtime widget config (`name` = form data path, " + - "self-contained). Not derivable — and the spec's FormField type erases to `any` in its dist " + - "(objectstack#4171), so a re-export would delete typing outright. The layers meet only in " + + "self-contained). Not derivable. ⚠️ It is NOT the `any` erasure that blocks this any more: " + + "objectstack#4171 landed and the spec's FormField is typed — `spec-derived-unions.test.ts` " + + "pins `_specFormFieldIsNoLongerAny`. The blocker is the two-LAYER split above, which " + + "precision does not touch (guard header case 2c). The layers meet only in " + "`normalizeSectionField` (@object-ui/plugin-form), gated by " + "sectionFields.spec-parity.test.ts (per-key behavioral coverage of the spec key set, both " + "directions). Misimport of the spec names is banned by the no-restricted-imports entry in " + @@ -339,6 +341,57 @@ const ALLOW = { "if the spec's `AuthProvider` ever stops being an enum of provider ids.", issue: 4115, }, + // ── objectstack#4115 batch 8/8 (objectui#3162) ─────────────────────────────── + // These three were the last DEBT entries. The ledger filed them as "blocked on + // objectstack#4171, burn down when the upstream `any` erasure lifts"; #4171 + // closed completed 2026-07-30, and the re-measurement it licensed found none of + // them burnable — for reasons that are NOT the one the ledger recorded. They are + // deliberate dialects, so they belong here with the reason written down, rather + // than in a debt bucket implying work that measurement says must not happen. + // Every verdict below was measured in the BUILT dist at spec 17.2.0. + "@object-ui/types:NavigationItem": { + reason: + "Precise upstream, still not bindable — guard header case 2c. objectstack#4171 landed and " + + "the spec's NavigationItem is neither `any` nor `unknown` any more, so `no longer any` is " + + "settled and is NOT a licence to bind. The spec models navigation as a nine-variant " + + "discriminated union; objectui keeps one flat shape carrying `visible: boolean` (the spec " + + "takes a CEL string / Expression envelope, and `menuItemToNavigationItem` MANUFACTURES a " + + "boolean when it inverts legacy `MenuItem.hidden`), plus `pinned` (`useNavPins` + " + + "`FavoritesProvider`) and `defaultOpen`, neither of which the spec declares at either tier, " + + "plus a separator carrying `label`. Each blocker is pinned one-per-line in " + + "packages/types/src/__tests__/spec-derived-unions.test.ts, written to stop compiling the day " + + "that specific blocker lifts. What IS derivable is already derived (`NavigationItemType` and " + + "the per-branch keys come off the spec).", + issue: 4115, + }, + "@object-ui/types:NavigationItemSchema": { + reason: + "Zod twin of the NavigationItem dialect, and the case where a precise upstream is most " + + "dangerous. The spec now ships `NavigationItemSchema: z.ZodType` — pinned by `_specNavSchemaIsNoLongerAny` — so the ledger's stated " + + "reason (`the spec's is z.ZodType and would validate nothing`) is spent. The live " + + "blocker is RUNTIME shape, invisible to every type-level probe: this schema has a published " + + "consumer in `objectui validate`, and referencing the spec's would make it REJECT metadata " + + "objectui accepts today — `pinned`, `defaultOpen` and a separator `label` all fail " + + "`unrecognized_keys` against the spec's `.strict()` branches, `visible: boolean` fails " + + "`invalid_union`, and a one-character `id` fails `too_small`. All five are pinned, behind two " + + "positive controls, in packages/types/src/__tests__/navigation-spec-parity.test.ts. " + + "Converging on the union is a breaking change tracked separately.", + issue: 4115, + }, + "@object-ui/types:JoinedReportBlock": { + reason: + "Guard header case 2b, and still live: the spec declares `JoinedReportBlockSchema` as a bare " + + "`z.ZodTypeAny`, so its exported type resolves to `unknown`. Re-exporting would replace this " + + "package's precise block interface (`name`/`columns`/`groupingsDown`/`groupingsAcross`/" + + "`filter`/`chart`) with nothing at all. ⚠️ objectstack#4171 is CLOSED and this is STILL " + + "erased — that issue typed the RECURSIVE schemas and never touched this one, whose erasure " + + "has a different cause. Re-measured at spec 17.2.0: `IsUnknown` is still `true`. Pinned in " + + "packages/types/src/__tests__/report-chart-query-spec-parity.test.ts, which fails the day the " + + "spec types the schema — that pin, not the state of any upstream issue, is the release " + + "condition.", + issue: 4115, + }, "@object-ui/types:SelectOption": { reason: "TS twin of the SelectOptionSchema dialect (objectui#3090): carries every spec key " + @@ -495,13 +548,12 @@ const ALLOW = { // divergent `_input` — so re-exporting it would silently change what parses. // Compare `_input` too before touching a schema const. const DEBT_ISSUE = 4115; -const DEBT = { - "@object-ui/types": [ - "JoinedReportBlock", - "NavigationItem", - "NavigationItemSchema", - ], -}; +// EMPTY since objectui#3162 (objectstack#4115 batch 8/8). The last three entries +// were not burned down — they were MEASURED not-burnable and moved to ALLOW as +// declared dialects, each carrying its own release condition as a pin. Re-adding +// a name here means "collides, not yet triaged"; a name whose triage concluded +// "deliberate divergence" belongs in ALLOW instead. +const DEBT = {}; // Files under these paths are not objectui's own authored surface. // - `ui/` is the Shadcn no-touch zone (AGENTS.md #7): upstream 3rd-party files