Skip to content

docs(spec): name the mis-aimed group case in navigationContributions[].group - #16508

Merged
huangyiirene merged 2 commits into
mainfrom
claude/issue-14925-nav-contribution-group-describe
Sep 7, 2026
Merged

docs(spec): name the mis-aimed group case in navigationContributions[].group#16508
huangyiirene merged 2 commits into
mainfrom
claude/issue-14925-nav-contribution-group-describe

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes #14925

The describe() on navigationContributions[].group was true and incomplete: it documented the omitted case and said nothing about group being present and naming no group the target app declares — the case that actually bites, because the contributing package cannot see the target app's group ids at authoring time (the target app belongs to another package). A wrong id is undetectable from the contributor's own source, and the platform relocates the items to the app top level rather than refusing them, so the menu renders, a smoke test passes, and the information architecture has silently changed.

The line, located by symbol

Re-located by symbol as instructed rather than trusted from the card: NavigationContributionSchema's group property in packages/spec/src/ui/app.zod.ts. It is still at :764 — the anchor had not drifted.

Final wording

'Target group nav-item id to append into (e.g. "group_integrations"); omit to append at
 the app top level. Naming a group the target app does not declare is not refused: the
 items are appended at the app top level anyway and a `nav_contribution_group_missing`
 diagnostic is emitted — by the runtime at `warn`, and by `os build` and `os validate`
 at compile time.'

Four decisions behind it:

  • "is not refused" leads, because the surprise is the absence of a refusal, not the presence of a diagnostic.
  • The diagnostic code is spelled in full, so an author who sees nav_contribution_group_missing in build output can search back to the key that produced it.
  • Both commands are named. Naming only os build would have been wrong against what shipped — see below.
  • No pipe characters. This string renders into two markdown table cells; a | would break both rows.

Verification of the two corrections in comment 5525508353 — checked against the tree, not inherited

os validate reports the diagnostic too. CONFIRMED. findNavGroupDiagnostics has exactly two non-test call sites, and they are the two commands: packages/cli/src/commands/compile.ts:49 and packages/cli/src/commands/validate.ts:43. Each folds the result into its own warnings list — compile.ts:202, validate.ts:148 — rather than into a key of its own. validate.ts:130 carries the reason in-source: the residue pin "asserts that nothing rides in build's warnings that validate does not also report".

② A top-level navigationGroupDiagnostics key does not exist. CONFIRMED. git grep navigationGroupDiagnostics returns exactly one hit repo-wide, and it is prose, not code: packages/cli/src/utils/nav-contribution-groups.ts:46, in a doc block explaining that the first cut carried such a key and that two standing pins (build-json-advisory-parity.e2e.test.ts, build-json-undeclared-key-parity.e2e.test.ts, both present in packages/cli/test/) rejected it. No schema, no payload, no emitter. Nothing here describes it.

Regeneration — the command, and the count actually measured

pnpm --filter @objectstack/spec gen:schema     # exit 0
pnpm --filter @objectstack/spec gen:docs       # exit 0 — "Generated 228 files"

⛔ No generated artifact was hand-edited.

Measured, not repeated from the card. The card estimated "~14 artifacts"; the measurement says 26 carriers, and they split in a way worth stating because only one half is reviewable in this diff:

count command
Tracked files the regeneration moved 2 git diff --name-only
Generated carriers of the new sentence, all of them 26 grep -rl "Naming a group the target app does not declare" content/docs packages/spec/json-schema

The 24 that are not in the diff are the packages/spec/json-schema/ tree, which .gitignore:63 excludes — built on demand, not committed. They are 12 json-schema/api/*.json and 10 json-schema/kernel/*.json package envelopes, the bundled json-schema/objectstack.json, and json-schema/ui/NavigationContribution.json itself. So the card's "~11 api envelopes" undercounted, and its list omitted the kernel/ envelopes entirely.

The two tracked files are content/docs/references/ui/app.mdx and content/docs/references/kernel/manifest.mdx, one table row each.

Clause ② reads NO — confirmed mechanically, and the gate was proved able to say otherwise

Prose on an existing key. group is still SnakeCaseIdentifierSchema.optional(); nothing is refused that was not refused before.

  • pnpm --filter @objectstack/spec check:api-surfaceexit 0, verdict line: @objectstack/spec public API surface + factory signatures unchanged ✓
  • pnpm --filter @objectstack/spec check:authorable-surfaceexit 0, and authorable-surface.json plus json-schema.manifest.json are byte-identical to base (the regeneration left them untouched; only the two .mdx files appear in git status).

A silent green is not a reading, so the second gate was ablated at the committed state to show it can go red on exactly this axis. One new authorable key injected into the same schema (groupFallback), proved on disk (injected-text count 1, git hash-object differing from the HEAD blob), produced:

❌ authorable-surface/ is out of date (1 key(s) not recorded).      exit 1

Restored with git checkout HEAD -- packages/spec/src/ui/app.zod.ts, proved by an empty git diff HEAD, and the gitignored schema tree regenerated afterwards so no probe residue survives (grep -rl "ABLATION PROBE" packages/spec/json-schema/ returns nothing, while the real sentence still returns its 24 files — the positive control for that zero).

Gates and tests

Derived with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (change set: 4 paths vs merge base 21c5dcbb3) — 90 commands, 89 green. Every exit code captured before any pipe.

  • pnpm --filter '@objectstack/spec...' build — exit 0 (check-dts-emitted: 34/34)
  • pnpm --filter @objectstack/spec typecheck — exit 0
  • pnpm --filter @objectstack/spec test — exit 0, 482 files / 13102 tests passed
  • check:docs — exit 0, 228 generated files in sync with packages/spec. Ablated too: reverting only the two regenerated .mdx files to base makes it exit 1, naming both files "out of date" — so its green here is a measurement of this regeneration and not of an untested gate.
  • Five gates first returned PREREQUISITE NOT MET for unbuilt packages, which is NOT MEASURED rather than red. Four were cleared by building @objectstack/lint, @objectstack/formula, @objectstack/client, @objectstack/client-react and re-running: check:doc-formula-expressions, check:doc-security-posture, check:skill-examples, check:docs-transcript-drift — all exit 0.
  • One declared narrowing: pnpm check:dual-build-cjs-loads needs a full-repo dist/ (it named 86 unbuilt packages) and stays NOT MEASURED here — a whole-workspace build does not fit this container's foreground budget. It reads emitted CJS loadability; this diff is one string literal inside a .describe(), two generated markdown table rows and a changeset, and moves no package's exports map or build shape. Left to CI.

Verdicts, logs and the two ablation transcripts are in the report comment on #14925.

Changeset

.changeset/nav-contribution-group-mis-aim-describe.md, @objectstack/spec: patch. Patch is the level: the published JSON Schema description for an existing key changes and the generated reference rows change, so it is user-visible and needs an entry — but no key is added or removed, no type moves, and no runtime behaviour changes, which is what would have made it minor.

Out of scope


Generated by Claude Code

…].group

The describe() documented only the omitted case. Name the third case an
author cannot detect from their own source: the contributing package does
not see the target app's group ids, so a wrong id is not refused -- the
items are appended at the app top level and a
nav_contribution_group_missing diagnostic is emitted, by the runtime at
warn and by os build and os validate at compile time.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T6HeZvT9wdSJD1ZxJb5Eno
Regenerated with the repo's own tooling
(pnpm --filter @objectstack/spec gen:schema && ... gen:docs); the two
tracked reference tables are the only tracked artifacts that move.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T6HeZvT9wdSJD1ZxJb5Eno
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation protocol:ui tooling labels Sep 7, 2026
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 2 documentable anchor(s).

1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/ui/setup-app.mdx (via group_integrations (literal, a string literal in NavigationContributionSchema))
What this run could not see
  • the SDK route bridge reached 61 of 219 client-bound route-ledger rows — the other 158 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 158: 0 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 — 130 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 c383352cb752245899b6ca7e2dc7d233405113eepackageMentionDocs.

Which tree this was computed on

This run read content/docs from a0e6a3f1a14248d993d1211d281820fc2db0eabe — the merge of head 049daaeaa23e6fe56e87d281913c40a23402030d into base c383352cb752245899b6ca7e2dc7d233405113ee, 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 a0e6a3f1a14248d993d1211d281820fc2db0eabe && git checkout a0e6a3f1a14248d993d1211d281820fc2db0eabe
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin c383352cb752245899b6ca7e2dc7d233405113ee 049daaeaa23e6fe56e87d281913c40a23402030d && git checkout -B drift-repro c383352cb752245899b6ca7e2dc7d233405113ee && git merge --no-ff 049daaeaa23e6fe56e87d281913c40a23402030d

node scripts/docs-audit/affected-docs.mjs --json c383352cb752245899b6ca7e2dc7d233405113ee

⚠️ 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 c383352cb752245899b6ca7e2dc7d233405113ee → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@huangyiirene
huangyiirene marked this pull request as ready for review September 7, 2026 06:56
@huangyiirene
huangyiirene added this pull request to the merge queue Sep 7, 2026
Merged via the queue into main with commit 51df9fd Sep 7, 2026
36 checks passed
@huangyiirene
huangyiirene deleted the claude/issue-14925-nav-contribution-group-describe branch September 7, 2026 07:30
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 protocol:ui size/s tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs(spec): navigationContributions[].group describe() documents the omitted case but not the mis-aimed one

2 participants