Repository navigation
spec(ui): a navigation entry with no dataSource whose visible reads data.* is refused at parse (BREAKING, ADR-0087), question 2 of #24332's ruling #24450
Description
Filing gate ③: a task the maintainer ruled. This card carries question 2 of #24332's ruling (6259393328, batch #369 item 3, letters Q1 E · Q2 A); #24332 keeps the navigation dataSource + visible half and closes delivered when PR #24427 merges. ⛔ Not a claim.
The ruling, as the director recorded it (the maintainer's words, verbatim: 「24332 是核心需求吗?如果开发复杂的话,3002 也可以删除左侧的导航项。其他同意」, then 「同意」):
Question 2 — A. A navigation item without a
dataSourcewhosevisiblereadsdata.*is refused at parse, BREAKING with its ADR-0087 conversion, as its owndomain:speccard, p1target:v18,Clause-②: no (narrowing); in-repo impact measured at 0 declarations.
Reader who acts: the domain:spec seat that picks this card from the queue, through one os-dev dispatch. The ruling decides the route, and the dispatch decides the mechanics.
Why
- PR feat(spec): a navigation entry may declare one API data source, which its visible reads as data #24427 (spec / objectui navigation: an app's navigation item cannot read data, so a label or a visible gate cannot follow a live count (the control plane's 「环境」 for a single-environment organization) #24332) lets a navigation entry declare one API data source, by reference to the page element's
ElementApiDataSourceSchema. Itsvisiblereads the selected value asdata. - An entry that reads
data.*without declaring a source has nothing to read. The contract review of PR feat(spec): a navigation entry may declare one API data source, which its visible reads as data #24427 (6259056316③) read the pinned console (.objectui-sha0707b4ae37): CEL faults on an undeclared top-level identifier, and the navigation gate withholds the entry. So the entry vanishes silently, and the author is told nothing at authoring time. - Declared is enforced: the parse door should say so, with a prescription ("declare
dataSourceon this entry, or drop thedata.*read").
Hypotheses for the dispatch (measure, never assume)
- The narrowing needs a reader of a CEL expression's top-level roots in
packages/spec. Whether one exists is not measured. Candidates are the predicate-root tables the pagevisibleWhenpins read (packages/spec/src/ui/expression-scope-data-root.pin.test.ts) andpackages/formula's CEL root analysis. If a reader means importing a runtime package into spec, that breaks Prime Directive ✨ Set up Copilot instructions #2. The dev then reports the fork rather than building it. - Reach: 0
data.reads among navigationvisiblepredicates over the 38 navigation-declaring files of this repository. That is the spec / objectui navigation: an app's navigation item cannot read data, so a label or a visible gate cannot follow a live count (the control plane's 「环境」 for a single-environment organization) #24332 dev's reading at71fa166e96(report6258349182,open_questions[2]), not re-measured at filing, so the dispatch re-measures it. The control wascurrent_userpredicates in the same files, which hit. objectui's corpus measured nothing (control 0 too). cloud is not reachable from the spec seat's container. - The page-element
visibleWhenhas the same shape (adata.*read with noapibinding). It is outside this ruling: only navigation entries are ruled. Name it in the report; do not build it.
Acceptance
- A navigation entry with
visiblereadingdata.*and nodataSourceis refused at parse. The refusal sits at the entry'svisiblepath and names the fix. - An entry that declares
dataSourceand readsdata.*parses. Entries reading only other roots (current_user,features, …) parse. - The changeset is BREAKING, with its FROM → TO mapping, and
Clause-②: no (narrowing). One ADR-0087 disposition marker is in the changeset body.
Dedupe
search_issueson objectstack, "navigation item visible reads data without dataSource refused at parse narrowing": 2 hits, spec page.zod.ts: ElementApiDataSourceSchema still describes itself as "[PLANNED — not yet rendered]" and visibleWhen says no renderer reads the binding, but the console renders both (objectui#12197) #24300 (open: the page binding's stale describe) and [finding] page.zod.ts visibleWhen .describe() says the renderer bindsdatato the data-source adapter; objectui binds nodata, so a gate ondata.totalfaults and shows in both polarities (twin of #17203, which removedapp) #23036 (closed: the pagevisibleWhendescribe). Neither is this narrowing.- Control: "navigation item cannot read data label visible gate live count" → spec / objectui navigation: an app's navigation item cannot read data, so a label or a visible gate cannot follow a live count (the control plane's 「环境」 for a single-environment organization) #24332, 1 hit.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 19, 2026
Claim: PM loop round 8
Session:
session_01D6F9axfoPzR7t8G1J7YtzzAccount:
baozhoutao(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-24450-nav-visible-data-needs-datasourceWorktree:
objectstack-issue-24450Domain:
domain:specSeat:
domain:spec#3(seat post #18883)File surface (at
origin/main26501ae24or later; stop on a breach and explain it in the report):packages/spec/src/ui/app.zod.ts(the navigation entry schema's refinement), its tests underpackages/spec/src/ui/app-nav-*, the ADR-0087 migration entry it needs underpackages/spec/src/migrations/, generated baselines the gates name,.changeset/24450-*.md.Container & model:
M,mode:subagent,model: default (no path-derived mandate)Clause-②: no (narrowing)
Responsibility:
n/a — question 2 of #24332's ruling (6259393328)Thread-read: none
Serial constraints cleared: PR #24427 (#24332, the navigation
dataSource) has merged as26501ae24.Read on
origin/main26501ae24at 2026-10-19T05:21Z:packages/spec/src/ui/app-nav-item-api-data-source.test.tspresent.Generated by Claude Code
objectstack-fleet commentedon Oct 19, 2026
os-dev-report
{
"issue": 24450,
"status": "done",
"branch": "claude/issue-24450-nav-visible-data-needs-datasource",
"pr": "#24490",
"session": "session_01D6F9axfoPzR7t8G1J7Ytzz",
"premise_still_valid": true,
"summary": "NavigationItemSchema now refuses an entry with no dataSource whose CEL visible reads the root data. The refusal is one custom issue at the entry's own visible and names the fix (declare dataSource on this entry, or drop the data.* read). It is mounted once as a superRefine on the discriminated union, so it reaches navigation, areas[].navigation, children at any depth, and contribution items. The PM assumption that an in-spec CEL root reader already exists did not hold: expression-scope-data-root.pin.test.ts pins prose only. So a small, module-private, refuse-only-when-sure CEL lexer (celReadsRootData) was written in app.zod.ts. It skips strings and comments, member selections, calls, field/key names and macro-bound data, and imports no runtime package. The kit has a D3 semantic entry nav-item-visible-data-needs-data-source (no D2: the shape cannot be converted), a minor BREAKING changeset with Clause-②: no (narrowing), one ADR-0087 marker and the FROM to TO mapping, +31 dropped-refinements ledger sites printed by the build, and a regenerated app.mdx. Reach was re-measured at 26501ae with an AST census: 11 nav entries with visible; 0 read data without a dataSource; 2 read data with one (spec tests); control: 3 read current_user.",
"tests": "At head b911ad1 (merged origin/main 31ce45c). New app-nav-visible-data-needs-data-source.test.ts: 23 tests, green. Ablation via scripts/ablation-replace.mjs on anchor 'if (!celReadsRootData(visible.source)) return;', anchor x1->x0, blob 90cf1bbc->56f1eb19: 12 failed / 11 passed (every refusal red, every acceptance green). Restored blob==HEAD 90cf1bbc, git diff HEAD empty. No dist leg: the test imports ./app.zod from source. @objectstack/spec test: 699 files passed, 21290 tests passed (1 todo). spec test:repo: 70 files, 1162 passed. spec typecheck: exit 0. spec check:generated: all 14 up to date after rebuild. Downstream consumers: @objectstack/lint full suite 145 files / 6866 passed. @objectstack/metadata-protocol full suite 246 passed, 3 skipped / 20655 passed. @objectstack/cli unit tier NARROWED to nav.test.ts + i18n-.test.ts: 27 files / 308 passed; the rest of the unit tier and the integration tier are declared to CI. Pin sweep: the refusal text and the old describe sentence have no test hits repo-wide; the only hit is the regenerated reference page.",
"gates": "dispatch-gates --commands --repo objectstack-ai/objectstack derived 112 families at b911ad1. All 112 ran, all exit 0. --ran reconciles 112/112 run, 0 NOT MEASURED. Six first exited 3 (PREREQUISITE NOT MET: doc-formula-expressions, doc-security-posture, skill-examples, docs-transcript-drift, dual-build-cjs-loads, lean-entry-closure). They re-ran at exit 0 after a turbo build of the lint/objectql/client/formula closures (36 tasks, all cached). Stale-tree note: origin/main moved 8 commits past the merge, touching ci.yml, spec-shape-gate.yml and spec-shape-gate.mjs; CI reads those from the merge ref. CI at report time: 2 success, 1 skipped, 21 in_progress.",
"line_budget": "n/a — no skills/** or ratcheted ledger file touched; diff 6 files, +451/-49 vs merge base",
"files_changed": [
".changeset/24450-nav-visible-data-needs-data-source.md",
"content/docs/references/ui/app.mdx",
"packages/spec/dropped-refinements.baseline.json",
"packages/spec/src/migrations/entries/semantic/18.nav-item-visible-data-needs-data-source.ts",
"packages/spec/src/ui/app-nav-visible-data-needs-data-source.test.ts",
"packages/spec/src/ui/app.zod.ts"
],
"deviations": [
"File surface: two paths outside the claim's list. content/docs/references/ui/app.mdx is a generated reference page (gen:docs, demanded by check:docs because the visible describe changed). packages/spec/dropped-refinements.baseline.json is the hand-edited refinement ledger; the spec build refuses until the +31 sites it prints are recorded.",
"The ADR-0087 conversion named in the ruling is delivered as a D3 semantic entry only, with no D2 conversion. A missing dataSource cannot be invented, and dropping the data read changes the gate's meaning. Same shape as the view-chart-binding-dataset-required narrowing.",
"Labels: zero writes. The dispatch write budget names none."
],
"mcp_calls": "0",
"api_writes": "2 — fleet-write relay: pr_create (POST /repos/objectstack-ai/objectstack/pulls + POST /repos//issues/24490/assignees), and this os-dev-report comment (POST /repos//issues/24450/comments); plus git push of the branch (not a REST write)",
"open_questions": [],
"out_of_scope_findings": [
"carrier: the page-element visibleWhen twin (a page component whose visibleWhen reads data. with no API dataSource binding) is the same shape, outside this ruling, which covers navigation entries only; named per the dispatch, not built · noted, not filed · dedupe words: page component visibleWhen data root without api dataSource refused",
"carrier: celReadsRootData under-refuses data as a CEL map-literal key ({data: 1}), which it cannot tell apart from a message field name without a type table; noted in PR Acceptance notes · 承接者:无"
]
}
Generated by Claude Code
objectstack-fleet commentedon Oct 19, 2026
Maintainer decision: in 18.0 ·
target:v18added · triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-19T07:24ZTriage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch.
Provenance. The seat put its 18.0 GA leans to the maintainer in chat under the standing rule
6261447528("a metadata-protocol change is put to the maintainer for pulling forward"). The maintainer answered 「同意你的建议」.target:v18is added. spec / objectui navigation: an app's navigation item cannot read data, so a label or a visible gate cannot follow a live count (the control plane's 「环境」 for a single-environment organization) #24332's ruling already named it "p1target:v18", and the label had been missing.6261853191on [epic] ADR-0131 — total organization ownership: no NULL organization_id (v18 line) #15194, the gate is 8b (feat(spec,drivers,objectql,plugin-security):organization_idNOT NULL per cleared table; one predicate for Layer 0 and every driver; bothorWhereNullarms, the__global__sentinel and the #13491 ledger retire (ADR-0131 D1/D8/D9) — protocol 18 #15212) and then the F1 re-test. This card ships in 18.0 if it lands first, and does not hold the release.Generated by Claude Code