Skip to content

docs(spec): state the view name grammar per body spelling in the view module header - #13262

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-13134-view-name-grammar-doc
Aug 30, 2026
Merged

docs(spec): state the view name grammar per body spelling in the view module header#13262
os-zhuang merged 1 commit into
mainfrom
claude/issue-13134-view-name-grammar-doc

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

Fixes#13134

Documentation only. Per the placement ruling on the card (comment 5461535963): the rule lands in packages/spec/src/ui/view.zod.ts as family-level JSDoc, not in docs/adr/** and not in content/docs/** alone. Zero schema-shape edits, zero accept/reject changes — all three body spellings were already internally consistent and the flat-named rows already parse.

What the note says

ViewMetadataSchema is a union over three persisted view body spellings, and they do not share one name grammar. Re-measured against the built schema (packages/spec/dist), not read off source:

body spellingrecognised byname is declared asflat (undotted) name
standalone ViewItem recorda nested configViewItemNameSchemaQUALIFIED_ITEM_NAME_PATTERN, dot REQUIREDrejected, invalid_format at ["name"]
flattened runtime overlayinline view config; no config, no container slotz.string().optional() — no grammaraccepted
defineViewcontainera container slot (list / form / listViews / formViews)z.string().optional() on ViewSchema — no grammaraccepted, and normally IS flat

Both failure directions the card names are readable from the note, and it states explicitly that the in-tree flat-named rows (case_grid, cases, the container row crm_lead) are correct as written, not defects awaiting a dotted rewrite.

One correction to the card's measured table

The card's third row says the container's name is "not in the declared shape". That is false against origin/main: ViewSchema does declare name, as z.string().optional() with the describe "Item name — supplied by the metadata door; for an object-scoped container it is the object name." So the container's row is the same mechanism as the overlay's — an ungrammared optional string — not an absent key. The card's conclusion is unaffected (flat container names are accepted, and the ADR-0017 §3.2 dual-read is why they are flat), but the note states the measured mechanism rather than the card's.

Probe output, against dist/ui/index.mjs after a fresh pnpm --filter @objectstack/spec build:

RECORD flat -> REJECT
invalid_format @ ["name"]: View item name must be a dotted snake_case qualified name, e.g. "crm_lead.pipeline".
RECORD dotted -> ACCEPT
OVERLAY flat -> ACCEPT
CONTAINER flat -> ACCEPT
ViewSchema top-level keys: name, label, object, list, form, listViews, formViews, protection, _lock, ...
has name? true
overlay `name` def: optional -> string, checks: []

Where it landed

  • packages/spec/src/ui/view.zod.ts — the block is the module's doc block, so it reaches the generated reference page through the module-description machinery (packages/spec/scripts/lib/file-description.ts: top-level, header zone, documenting no symbol).
  • Three pointer comments, one at each declaration site the rule is about — viewItemBaseShape()'s name, flattenedViewOverlayFields()'s name, and ViewSchema's name — so a source reader standing at any one of the three is told the other two exist. Each points at the header block rather than restating the rule, so there is one copy to drift.
  • packages/spec/src/conversions/view-spelling-walk.test.ts — the fixture-hygiene half. The copy-on-write identity probe's record-shaped body now carries a dotted name (crm_lead.clean). Measured before changing it: the conversion chain never reads name — flat and dotted both return the same object reference, zero notices, output deep-equal to input — so the test proves exactly what it proved before.

Side effect worth naming: the reference page's opening paragraph changes

ui/view.zod.ts had no module description, so findModuleDocBlock selected the next qualifying block — the doc comment sitting above the HttpRequest re-export import. That is why content/docs/references/ui/view.mdx and both skill reference indexes opened with "HTTP Method Enum & HTTP Request Schema", which is the #5059 defect class (an internal note published as a page's subject). Adding a real module description displaces it. The HttpRequest note is unchanged in the source, where it documents that re-export.

skills/** is touched — governed surface, and the two readings

gen:skill-refs regenerates the pointer row's one-line description from the module doc block's first line, so two published indexes changed:

filebeforeafterdelta
skills/objectstack-data/references/_index.md65650
skills/objectstack-ui/references/_index.md56560
all skills/**/SKILL.md (package total)10515105150
all skills/**/*.md (package total)17242172420

One replaced line per file, generated, no net growth — and the replacement is a correction: the indexes previously described ui/view.zod.ts as "HTTP Method Enum & HTTP Request Schema".

⚠️skills/** is a governed surface (Prime Directive #14). This PR is DRAFT with needs:contract-review, and beyond the contract-review chain its landing needs the governed path — a pinned maintainer approval, or the maintainer's own merge. ⛔ No seat marks it ready, queues it, or arms auto-merge.

Verification

All runs on the final commit 08115261 unless noted; heavy runs serialized through scripts/pm/os-verify-lock.sh.

  • pnpm --filter @objectstack/spec build && pnpm --filter @objectstack/spec check:generated✓ All 14 generated artifacts are up to date. (exit 0, on 08115261). The two artifacts it proved stale mid-work — check:skill-refs and check:docs — were regenerated with check:generated --fix, never hand-edited.
  • pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 over the 7 view/conversion/file-description suites → Test Files 7 passed (7) · Tests 583 passed (583).
  • pnpm --filter @objectstack/spec typecheck (= tsc --noEmit + check:scripts-typecheck + check:test-typecheck) → exit 0. The edited test file is covered: check:test-typecheck: OK — @objectstack/spec's test layer compiles under packages/spec/tsconfig.test.json.
  • pnpm lint (eslint . --no-inline-config, repo-wide, not narrowed) → exit 0.
  • Gate families re-derived from the real change set with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (59 matched). Run locally and green, each read from the gate's own verdict line: check:nul-bytes, check:doc-authoring, check:doc-anchors, check:docs-single-h1, check:role-word, check:quick-reference-counts, check:skill-compatibility, check:skill-frame-sync, check:agent-test-spelling, check:docs-audit-scope, check:docs-redirects, check:keyed-text-bounds, check:merge-driver, check:spec-parsed-alias, check:where-matcher, check:engine-double-contract, check:pm-governed-merges, check-doc-frontmatter, check-doc-route-spelling, check-docs-section-name, check-section-landing-index, check-comment-mask-adoption, and the changeset family (check:changeset-gate-self-tests, check:objectui-changeset, check:pm-half-states, check-adr-0087-registration, check-changeset-no-major, check-empty-changeset, release-rehearsal-clone --self-test).
  • NOT MEASURED:scripts/pm/check-half-states.mjs exits 3 — PREREQUISITE NOT MET — the token in the environment is not a valid GitHub credential. Its own text says nothing was swept, so this is no reading rather than a failure.

Changeset: patch for @objectstack/spec (text face in published src/**/*.zod.ts). Non-breaking, so no ADR-0087 marker — check-adr-0087-registration agrees: this PR adds no declared-breaking changeset.

Session: https://claude.ai/code/session_01KX8wnyjStaZcuMyAMNsy3N


Generated by Claude Code

`ViewMetadataSchema` is a union over three persisted `view` body spellings and
they do not share one `name` grammar: a standalone ViewItem record requires the
dot (`ViewItemNameSchema` / `QUALIFIED_ITEM_NAME_PATTERN`), while a flattened
runtime overlay and a `defineView` container each declare an ungrammared
`z.string().optional()` and accept flat names. Nothing said so — the rule was
reconstructible only by reading three schema factories, and the grammar is
selected by a body shape the author never names explicitly.
Adds a family-level JSDoc block as `ui/view.zod.ts`'s module description, plus
a pointer comment at each of the three declaration sites, and regenerates the
reference page and the two skill reference indexes. No schema change: every
accept/reject decision is unchanged.
Also retires the one in-tree record-shaped fixture a future author would copy
into a rejection (`conversions/view-spelling-walk.test.ts`) by giving it a
dotted name; the conversion chain does not read `name`, measured.
@os-zhuang
os-zhuang marked this pull request as ready for review August 29, 2026 16:05
@os-zhuang
os-zhuang enabled auto-merge August 29, 2026 16:05
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

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

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

  • content/docs/api/metadata-api.mdx(via ViewSchema (symbol))
  • content/docs/getting-started/quick-reference.mdx(via ViewSchema (symbol))
  • content/docs/ui/actions.mdx(via ViewSchema (symbol))
What this run could not see
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 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 — 126 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 74049254d47bd0edd2a2fcd732dcc01c91504f10packageMentionDocs.

Which tree this was computed on

This run read content/docs from 1ce0148cbf5fa60ce7f5a129d316e455f8e37b97 — the merge of head 081152617303cbb350603dfa344e4abde8082327 into base 74049254d47bd0edd2a2fcd732dcc01c91504f10, 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 1ce0148cbf5fa60ce7f5a129d316e455f8e37b97 && git checkout 1ce0148cbf5fa60ce7f5a129d316e455f8e37b97
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 74049254d47bd0edd2a2fcd732dcc01c91504f10 081152617303cbb350603dfa344e4abde8082327 && git checkout -B drift-repro 74049254d47bd0edd2a2fcd732dcc01c91504f10 && git merge --no-ff 081152617303cbb350603dfa344e4abde8082327
node scripts/docs-audit/affected-docs.mjs --json 74049254d47bd0edd2a2fcd732dcc01c91504f10

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

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationprotocol:uisize/mteststooling

Projects

None yet

3 participants

@os-project-manager@os-zhuang@claude