Repository navigation
Commit 1c52a5e
fix(spec): the strict blueprint nav item's label describe states that null inherits the target's current label (#21309)
Fixes #21248
Clause-②: no
## What changed
`StrictNavItem.label` in
`packages/spec/src/ai/solution-blueprint.zod.ts` is the describe the AI
design step reads. `propose_blueprint`'s structured output is generated
against `SolutionBlueprintStrictSchema`, and strict mode makes `label` a
required decision on every nav entry. Until now it read `'Nav entry
label, or null'`. It now reads:
> Nav entry label, or null. null ⇒ the entry inherits the CURRENT label
of what it opens at render time (a renamed target shows its new name); a
string ⇒ rendered verbatim, so never copy the target's label in as a
default. Write a label ONLY when the entry must read differently from
what it opens; otherwise null.
- The meaning of each arm is the lenient twin's, byte for byte. The
empty arm (`absent` there, `null` here) and the written arm (`present`
there, `a string` here) say the same thing on both sides.
`BlueprintNavItemSchema.label` is unchanged. The strict side adds the
closing steer the triage direction names.
- Shape unchanged: still `z.string().nullable()`, so the schema accepts
and refuses the same blueprints.
- A lockstep comment sits above the line, mirroring the one on
`viewName`.
- One pin in `packages/spec/src/ai/solution-blueprint.test.ts`, placed
in the `strict mirror ↔ lenient schema — key parity` block right after
the `viewName` pin (`states ONE label rule on both sides …`). It reads
both nav `label` describes the same way the `viewName` pin reads both
nav shapes. It extracts what each side's empty spelling and written
spelling mean, and asserts the two sides say the same thing. It pins
sameness, not wording, so both sides can be reworded together.
- `.changeset/21248-strict-nav-label-describe.md`: `@objectstack/spec`
`patch`, `Clause-②: no`.
⛔ No applier-side text matching. ⛔ No new gate.
## Premise checks (on `origin/main` `4e6dc2338a`)
1. **Describe locations hold.** Strict `:372` read `'Nav entry label, or
null'`; the lenient twin is at `:189`.
2. **Render-time inheritance holds at objectui's `.objectui-sha` pin
`31971ff1e28f`.** In `packages/layout/src/NavigationRenderer.tsx`,
`resolveNavItemLabel` returns `inheritedNavItemLabel(item, targetLabel)`
when `item.label === undefined`. The fallback order is: the view's label
(when the entry names a labelled view), then the object's or dashboard's
label, then the machine name. The label is asked of the host's metadata
on every render, so "a renamed target shows its new name on the next
render". A present string renders verbatim. The new describe states only
that. The strict `null` reaches the renderer as an absent label through
the null strip that this file's own strict-mirror header documents ("the
blueprint tools strip those nulls").
3. **The `viewName` lockstep pin is a KEY-parity pin, not a describe
pin.** It consists of `carries viewName …` and `the NAV ITEM schemas
carry exactly the same keys`. No describe-text pin existed before. The
new pin follows its style and sits beside it.
## Generated artefacts
After `pnpm --filter @objectstack/spec build`, `pnpm --filter
@objectstack/spec check:generated` reported all 15 artefacts up to date.
No tracked artefact carries this describe. The reference page renders
`SolutionBlueprintStrict.app` only one level deep (`nav` shows as
`object[]`), so the strict nav item's describe was never on
`content/docs/references/ai/solution-blueprint.mdx`, before or after
this change. The only copy is the gitignored
`packages/spec/json-schema/ai/SolutionBlueprintStrict.json`, which
carries the new text after the build.
## Verification (final head `f7fee5be0e`)
- `pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2
src/ai/solution-blueprint.test.ts`: 44 passed (43 before, plus the new
pin).
- `pnpm --filter @objectstack/spec test`: exit 0. Test Files 597 passed
(597); Tests 17475 passed, 1 todo.
- `pnpm --filter @objectstack/spec typecheck`: exit 0.
`check:test-typecheck: OK`, 52 test files compiled.
- **Ablation (two legs, run after the fix was committed).** Both used
`scripts/ablation-replace.mjs` in wrap mode, which verifies the write on
disk and restores against HEAD. The test imports
`./solution-blueprint.zod` by relative path, so no `dist/` sits on the
resolution path and no rebuild was needed.
- A1 reverted the strict describe to `'Nav entry label, or null'`. The
pin went red with `expected undefined to be defined` (1 failed, 43
passed). The file was restored: blob `9fad23cd1314` equals HEAD and `git
diff HEAD` is empty.
- A2 drifted the lenient clause from `absent ⇒ the entry inherits the
CURRENT label` to `absent ⇒ the entry copies the target label`. The pin
went red with `expected { …(2) } to deeply equal { …(2) }`. The file was
restored the same way.
- Expected direction: red. Observed direction: red on both legs.
- **Gates.** `node scripts/pm/dispatch-gates.mjs --repo
objectstack-ai/objectstack --commands` (no paths) derived 83 commands at
`f7fee5be0e`. All 83 ran and exited 0. `--ran` reconciliation: 83
derived, 83 run, 0 NOT-MEASURED, 0 UNRUN.
- On the first pass, three gates exited 3 with PREREQUISITE NOT MET:
`check:doc-formula-expressions`, `check:lean-entry-closure` and
`check:dual-build-cjs-loads`. Each went green once its prerequisites
were built (formula and lint; the objectql closure; the workspace
build). The final pass ran with those builds in place.
- The derivation printed STALE TREE: `origin/main` moved 15 commits
after the branch point. Of the files it changed that the derivation
reads, `ci.yml` only adds `env:` to the Build Core build step.
`scripts/pm/issue-transfer.mjs` and
`scripts/docs-audit/handwritten-docs.json` touch none of this diff's
paths.
- **Lint, narrowed (a measurement, not a full run).** `pnpm exec eslint
--no-inline-config --format json` over the two touched `.ts` files: 2
files, 0 errors, 0 warnings. ESLint's own `isPathIgnored` returns false
for both. `calculateConfigForFile` shows neither `parserOptions.project`
nor `projectService`, so type-aware linting is off and this diff cannot
change any verdict on an untouched file. The full `pnpm lint` is CI's.
- **`test:repo` (the spec `repo` vitest project), narrowed.** I ran the
4 of its 48 files that read the blueprint source or describes.
`scripts/solution-blueprint-header-row.test.ts`: 4 passed.
`scripts/escape-mdx.test.ts`, `scripts/query-pointer-row.test.ts` and
`src/api/rest-api-config-dead-keys-retirement.test.ts`: 39 passed.
- NOT MEASURED: `scripts/build-schemas-check-mode.test.ts` and the full
`test:repo` project. Reason: that file spawns `build-schemas.ts`
repeatedly, and neither run finished inside a 480 s bound on the shared
box. Left to CI.
- Not run locally, left to CI: Build Core, Test Core, Dogfood, Temporal
Conformance and the workspace type-check lanes.
## Acceptance notes
- Observation, not filed: `StrictNavItem.viewName`'s describe, which
this PR leaves unchanged, illustrates its rule with entries named by
their labels ("a 「工单列表」 entry with viewName null plus a 「工单看板」 entry
…"). This is a labelled example on the same nav item the model fills,
and the source report counts labelled examples among the inputs that
steer the model toward writing labels. No wrong answer has been measured
from it. carrier: the cloud seat's golden-journey measurement, after
cloud's pin carries this change.
- Downstream, and not part of this PR: cloud's half measures how many
nav entries a golden-journey build leaves null.
Generated artefacts touched: none tracked (see above). Diff: 3 files,
describe text, one test and one changeset.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01UtnxvdiN376GF3sgXwAw4d)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 7526058 commit 1c52a5e
3 files changed
Lines changed: 51 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
593 | 593 | | |
594 | 594 | | |
595 | 595 | | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
596 | 616 | | |
597 | 617 | | |
598 | 618 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
369 | 369 | | |
370 | 370 | | |
371 | 371 | | |
372 | | - | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
373 | 384 | | |
374 | 385 | | |
375 | 386 | | |
| |||
0 commit comments