Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .changeset/spec-app-nav-guard-docblock-anchor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
'@objectstack/spec': patch
---

`app.zod.ts` docblocks: the navigation target-exclusivity guard now cites the commit that decided it, and says what that commit decided

Two docblock sentences in `src/ui/app.zod.ts` (which ships as source through the
package's `src/**/*.zod.ts` entry) cited a tracker number that no longer resolves
on GitHub. They now carry the lesson in words and anchor to commit `4cfc93b802`
in this repository's history: the `filters` docblock deliberately states no
precedence order, because objectui's hand-written mirror copied one from this
docblock and ended up accepting a combination the schema refuses; and
`objectNavTargetExclusivity` is exported so a mirror chains the schema's own rule.

Docblock text only. No schema, guard, accept set, export or `.describe()` string
changes.
13 changes: 9 additions & 4 deletions packages/spec/src/ui/app-nav-target-exclusivity-export.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

/**
* [#16714] `objectNavTargetExclusivity` is EXPORTED, and the export IS the
* check the navigation door runs — the spec half of the objectui mirror gap.
* `objectNavTargetExclusivity` is EXPORTED, and the export IS the check the
* navigation door runs — the spec half of the objectui mirror gap. Decided
* and landed in commit 4cfc93b802 (PR #16862 is a convenience link beside
* that sha, not the citation): export the guard so a mirror chains the
* schema's own rule, state no precedence order in the `filters` docblock,
* and move no schema's accept set.
*
* Why: objectui's `NavigationItemSchema` is hand-written (not `.shape`-derived,
* so the #16489 mechanism does not reach it) and its own `superRefine` checks
Expand Down Expand Up @@ -240,8 +244,9 @@ describe('the mount — the union branch carries the check, the exported ObjectN
expect(vectorOf(runExport, matrix)).not.toBe(vectorOf(() => [], matrix));
});

it('ObjectNavItemSchema carries no object-level check — the export moved no accept set (#16714 ruling)', () => {
// Deliberate non-change: which schema mounts the check is a separate
it('ObjectNavItemSchema carries no object-level check — the export deliberately moved no accept set', () => {
// Deliberate non-change, decided with the export itself (commit
// 4cfc93b802): which schema mounts the check is a separate
// question from whether a mirror can chain it, and it is NOT decided by
// this export. A later ruling that mounts the guard on the exported
// schema flips this pin on purpose; until then every fixture on the
Expand Down
10 changes: 6 additions & 4 deletions packages/spec/src/ui/app.zod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -454,8 +454,10 @@ export const ObjectNavItemSchema = lazySchema(() => strictObject(navItemSurface(
* without the guard a consumer would have to resolve the combination by
* picking one field and silently ignoring the rest, and a mirror that
* copies an ordering from this docblock instead of chaining the guard ends
* up accepting what this schema refuses (#16714). The guard's own docblock
* names the one legacy combination it tolerates (`recordId` + `viewName`).
* up accepting what this schema refuses — objectui's hand-written mirror
* did exactly that, which is why commit 4cfc93b802 took the ordering out of
* this docblock. The guard's own docblock names the one legacy combination
* it tolerates (`recordId` + `viewName`).
*/
filters: z.record(z.string(), z.string()).optional().describe(
'URL filter conditions — targets the /:objectName/data bare surface via filter[<field>]=<value> params instead of a saved view. Values support template vars {current_user_id}, {current_org_id}. Mutually exclusive with recordId/viewName.',
Expand Down Expand Up @@ -501,8 +503,8 @@ export const ObjectNavItemSchema = lazySchema(() => strictObject(navItemSurface(
* tolerated: it predates this guard and is documented as "viewName is
* ignored when recordId is set".
*
* EXPORTED (#16714), one function per refinement, the same posture as the
* `check*` exports of #16489: a hand-written mirror of the object nav item
* EXPORTED (commit 4cfc93b802), one function per refinement, the same posture
* as the `check*` exports of #16489: a hand-written mirror of the object nav item
* chains this very function in its own `superRefine` instead of restating
* the rule from prose — a restatement is what drifts. Its one mount in this
* module is the `type: 'object'` branch of {@link NavigationItemSchema}; the
Expand Down
6 changes: 3 additions & 3 deletions packages/spec/src/ui/object-refinement-check-exports.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -464,9 +464,9 @@ describe('each schema attaches its export BY IDENTIFIER — no inline copy', ()
// a second, shadowing binding of the same name — a local `function checkX` inside
// another function, say — satisfies every one of them while the door chains a
// different function object, and if it happened to agree on the fixture matrix it
// would satisfy leg 2 as well. Measured on the diff that added this: four names,
// one declaration each — so this closes a residual hole in the pin, it does not fix
// a live shadowing (#16715). It must stay green.
// would satisfy leg 2 as well. Measured on the diff that added this (commit
// b37f0b1767): four names, one declaration each — so this closes a residual hole
// in the pin; no live shadowing existed to fix. It must stay green.
const declarations = (src: string, name: string): number =>
src.match(new RegExp(`^\\s*(export )?function ${name}\\b`, 'gm'))?.length ?? 0;

Expand Down
Loading