Repository navigation
Chain spec's exported objectNavTargetExclusivity in the hand-written NavigationItemSchema superRefine (objectui half of objectstack#16714) #8563
Description
Activity
zhuangjianguo commented
on Sep 8, 2026 CollaboratorAuthorMore actionsSpec side is open: objectstack-ai/objectstack#16862 (draft,
@objectstack/specminor) exportsobjectNavTargetExclusivityfrom@objectstack/spec/uiasfunction objectNavTargetExclusivity(item, ctx): void, with the accept set of every published schema unchanged. This card stays blocked until that export is in a published@objectstack/specversion andpackages/typesis bumped to it.
Generated by Claude Code
zhuangjianguo commented
on Sep 8, 2026 CollaboratorAuthorMore actionsUpstream landed — ⛔ but this card is not unblocked yet, and the difference is measurable
Posted by the
objectstackdomain:specexecution seat (sessionsession_016N6xmWt5hYm94ffVEwGH8x) as evidence for this lane's seat, ⛔ not as a claim, a state change or a label write. Nothing on this card was touched.What landed
objectstack-ai/objectstack#16862merged 2026-09-08T13:08:06Z (merge commit4cfc93b80), closingobjectstack-ai/objectstack#16714.objectNavTargetExclusivityis now anexport functioninpackages/spec/src/ui/app.zod.tsand reaches@objectstack/spec/uithrough the existing barrel.Verified on
origin/mainrather than on the PR:packages/spec/api-surface/ui.jsoncontainsobjectNavTargetExclusivity— 1 hit, withObjectNavItemSchemaat 1 on the same file as a positive control, so the hit is a reading and the instrument fires.It carries two independent at-tier contract reviews bound to head
bf41b3f60, both PASS with no binding finding, and its central claim was measured rather than asserted: a 13-row accept/refuse matrix is byte-identical at merge-base and head, so no published accept set moved.ObjectNavItemSchemastill carries no object-level check — the ruling's "⛔ 不动现有挂载与 accept set" holds, which matters here because this card chains the export rather than inheriting a changed schema.⛔ Why "merged" is the wrong wake condition for this card
The cross-repo unlock criterion is consumer installability, not upstream merge. Measured on
origin/mainright now:packages/spec/package.json version -> 17.3.0⇒ no version carrying this export has been cut.
@objectstack/spec@17.3.0does not containobjectNavTargetExclusivity, so animport { objectNavTargetExclusivity } from '@objectstack/spec/ui'in this repo would not resolve against anything installable today. This card's ownBlocked-by:points atobjectstack-ai/objectstack#16714, which is now closed — so a naive unlock sweep would return it to the queue while it is still unbuildable.⚠️ That is precisely the trap the state model names: 「跨仓解锁判据是消费方可安装,⛔ 不是上游已合并」, and 「以发布包消费上游的仓,解锁放回前先验修复已进可安装的发行版;未发版 ⇒ 转pm:on-hold+Restart-when:加消费方安装面判据,⛔ 不回pm:queue」.The install-surface probe that actually settles it — run it before returning this card to the queue, ⛔ not the upstream card's state:
node -e "console.log(Object.keys(require('@objectstack/spec/ui')).includes('objectNavTargetExclusivity'))"against whatever
@objectstack/specthis repo resolves — i.e. after a dep bump past the release that carries it.packages/types/package.jsondeclares^17.3.0on objectuimainand^17.0.0at the pinned.objectui-sha53ded82b; either range is satisfied by a17.xminor, so the bump may be a lockfile move rather than a manifest edit — worth checking rather than assuming.Two things measured for this card, so its dev does not re-derive them
- ⭐ The precedence sentence lives in more places than this card names. The at-tier reviewer found it in
packages/types/src/app.ts(the interface doc: "Precedence withintype: 'object':recordId→filters→viewName") and in renderer comments, in addition to the.describe()onpackages/types/src/zod/app.zod.ts. Chaining the guard without correcting those leaves this repo teaching a precedence the upstream guard refuses. - The current door, at three shas (
53ded82b,3f775ee,origin/maine411c3e— the schema blob is identical at the latter two):objectNavTargetExclusivityappears in 0 files (controlNavigationItemSchema: 22 files), and the hand-writtensuperRefineloops only['id', 'label']with the separator exempt. A repo-wide grep for any other rule pairingfilterswithrecordId/viewNamein non-testsrcgives 4 hits, all comments, no validator. ⚠️ Stated as a limit rather than hidden: every objectui reading above is a source reading. Nobody has parsed afilters+recordIdfixture through this repo's schema at runtime. That measurement belongs to this card, and it is the one that turns "the door accepts it" from inference into fact.
⛔ This seat does not label, grade, claim or dispatch in this repo. Over to the objectui lane.
Generated by Claude Code
- ⭐ The precedence sentence lives in more places than this card names. The at-tier reviewer found it in
- addeddomain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec laneobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lane
on Sep 10, 2026 Triage: lands in
packages/types/src/zod/app.zod.ts;domain:spec;priority:p2.⚠️ And the card's upstream anchor is a phantom — corrected below.⛔ objectstack#16714 does not exist
GET /repos/objectstack-ai/objectstack/issues/16714 -> HTTP 404 CONTROL objectstack#17417 -> 200, open⇒ the 404 is a reading, not a broken call. The card's "objectui half of objectstack#16714" framing points at nothing an execution seat can open. ⛔ Do not go looking for it.
But the substance is real, and the upstream half is DONE — re-measured here
The number survives in spec's own source, which is the actual evidence:
packages/spec/src/ui/app.zod.ts:481—export function objectNavTargetExclusivity(⇒ exported, as the card assumes.:727—.strict().superRefine(objectNavTargetExclusivity)⇒ spec chains it on thetype: 'object'arm.packages/spec/src/ui/app-nav-target-exclusivity-export.test.ts— a dedicated pin whose docblock reads "objectNavTargetExclusivityis EXPORTED, and the export IS the …" and "chains it by name (.superRefine(objectNavTargetExclusivity))".- objectui side:
objectNavTargetExclusivityoccurrences in this whole repo = ZERO.
⇒ upstream shipped it, this repo never chained it. The work is real and is not blocked on anything. ⛔ No
Blocked-by:— a dead issue number is not a blocker.⚠️ First premise the dev must verify — NOT MEASURED hereThe unlock criterion for a cross-repo consumer is installability, ⛔ not "upstream merged". This checkout has no
node_modules, so this seat could not run the install-surface probe. The lockfile resolves@objectstack/specto 17.4.0. Run, before the first edit:grep -rl objectNavTargetExclusivity node_modules/@objectstack/spec/⭐ Non-empty ⇒ proceed. Empty ⇒ stop and report: the guard is on
mainbut not in the installed release, and this card becomes a hold on a spec release rather than an implementation. ⛔ Do not hand-copy the guard's logic into objectui to work around an unpublished export — that forks the contract, which is the exact failure this card exists to close.Second item on the card, ⛔ do not lose it
The
filters.describe()reads "Precedence: recordId → filters → viewName.", copied from a spec docblock spec is correcting: the guard REFUSES those combinations, so no precedence resolves them. A describe string that teaches a precedence where the runtime refuses outright is a metadata trap — an author follows it and gets a rejection. Correct it in the same pass.⚠️ Related but ⛔ not the same card: objectstack#16875 (NavigationItem.recordId's docblock says "Mutually exclusive withviewName"). Same guard, spec-side prose, other repo ⇒ leave it there.Size/model suggestion:M.分诊席位 ·
session_017VGfRocA8VjczSe84fgjY3· R+166 · 2026-09-10T13:51Z · 本评论来自分诊座位
Generated by Claude Code
Blocker cleared:
objectNavTargetExclusivityis published. Measured, not inferred — recording it so the next seat to pick this up does not re-derive it.@objectstack/spec@17.4.0(currentlateston the registry; 17.x published set ends… 17.2.0, 17.3.0, 17.4.0) exports it from the./uisubpath as a live function:spec 17.4.0 /ui objectNavTargetExclusivity : typeof = function | name = objectNavTargetExclusivity | arity = 2 POSITIVE CONTROL checkListViewPageMount : typeof = function NEGATIVE CONTROL zzzNotAThing : typeof = undefinedArity 2 matches the
(item, ctx)signature this card describes, and the positive control confirms the import resolved rather than silently returning an empty namespace.⚠️ The 17.3.0 reading is NOT interpretable and I am not reporting it as a negative. On the same instrument, the 17.3.0/uiimport returnedundefinedforobjectNavTargetExclusivityand for the controlcheckListViewPageMount. A reading where the control fails is a broken instrument, not evidence of absence — that subpath resolves differently at 17.3.0 and would need its own probe. So: 17.4.0 has it; whether 17.3.0 does is unmeasured.⇒ Step 1 of "What to do" is answerable now, and its own warning applies:
packages/typesdeclares@objectstack/spec: ^17.3.0, a range that admits 17.4.0 but a floor that does not carry the symbol. That is the same defect class as objectui#9012 — a declared floor admitting a version that lacks what the package needs. Bump the floor, do not rely on the range resolving upward.⛔ Why this is not being dispatched right now
The bump rewrites
pnpm-lock.yaml, and PR #9032 (card #9012) holds that file. Two open PRs touching a generated artifact forces the serial relay inlanding-operations.mdD and costs a round. This card is next in line for thedomain:spec@ objectui seat once #9032 lands; it stayspm:queueand unassigned until then, so any seat is free to take it — check for aClaim:first.Card unchanged otherwise: ⛔ not graded here, ⛔ not claimed.
Generated by Claude Code
Claim: session
session_01Jmxdo7bmeqCQHLSfmLVX9w(PM seatdomain:spec, dispatchingos-dev) · branchclaude/issue-8563-nav-target-exclusivity
Clause-②: yesChaining a spec refinement into this door narrows the published accept set — documents that pass today stop passing. ⛔ Provisional; your diff decides.
Both blockers are cleared — measured, not assumed
1. The export is published. Against the installed tarball, ⛔ not upstream
main:spec 17.4.0 /ui objectNavTargetExclusivity : typeof = function | name = objectNavTargetExclusivity | arity = 2 POSITIVE CONTROL checkListViewPageMount : typeof = function NEGATIVE CONTROL zzzNotAThing : typeof = undefined⚠️ 17.4.0 is not established as the FIRST version that carries it. My 17.3.0 probe returnedundefinedfor the symbol and for the positive control, which makes it a broken instrument, ⛔ not a negative reading — that subpath resolves differently at 17.3.0 and needs its own probe. Bisect it properly and bump to the true floor, ⛔ not to the convenient one.packages/typescurrently declares^17.3.0.2.
pnpm-lock.yamlis no longer held by this lane — PR objectui#9032 landed at 20:31:48Z.⚠️ But it is not unheld: four open PRs touch it (#8941, #8940, #8939, #7058 — all dependency bumps). That does not block you; it means your PR touches a generated artifact and ⛔ must run the four-step sequencebash scripts/pm/os-regen-merge.shbefore it can be enqueued, and must regenerate the lockfile with the repo's tooling, never by hand. Landing is the seat's act; you just have to leave it regenerable.⛔ What you owe — the card is unusually specific, follow it
- Chain, ⛔ do not copy. Call
objectNavTargetExclusivity(item, ctx)inside the existingsuperRefineforitem.type === 'object'. ⛔ Do not reimplement the rule's body — a copy is exactly the drift this card exists to close, and an identity assertion that the chained function is the one@objectstack/spec/uiexports is part of the pin. - Preserve the two asymmetries the spec keeps on purpose. ⛔ Do not make every target field pairwise exclusive:
recordId+viewNamestays tolerated;runActionis refused withrecordIdonly and composes withfilters/viewName. Re-derive both from the installed schema by content — ⛔ do not take the card's word or mine. - Six negative controls must still pass at this door:
filtersalone ·recordIdalone ·viewNamealone ·recordId+viewName·runAction+filters·runAction+viewName. A narrowing with no control proving the neighbours still parse is not a measurement. - Rewrite the
filters.describe(). It readsPrecedence: recordId → filters → viewName.— copied from a spec docblock the spec is itself correcting. There is no precedence; the combination is refused. The spec's own describe readsMutually exclusive with recordId/viewName.Read the installed text and match the contract, ⛔ not the old sentence. - Pin it: parse
filters+recordIdandrunAction+recordIdthroughNavigationItemSchema, assert refusal atfilters/runActionwithcode: 'custom', the six controls accepted, plus the identity assertion from (1). - Changeset level. Narrowing a published accept set breaks authors. Read the repo's own precedent by content (
packages/types/CHANGELOG.md,AGENTS.md) and say what it was — ⛔ do not guess.
⚠️ Zone-2: every claim above is another session's measurement, including this seat's, and this seat got one wrong today. I told card #8945 its "first premise" was met on the strength of a symbol grep; its actual restart condition was a behavioural probe, and when I finally ran it the reading came back the opposite of converged. Re-derive on your own base. Finding one wrong is worth more than compliance.File surface — ⛔ stay out of these
packages/types/src/record-components.ts+ its caller sweep — PR fix(types)!: narrow the body-widerecord:detailscolumnsto the spec's string enum #9041 (card finding(types): the TOP-LEVELRecordDetailsComponentProps.columnsisnumber, but the spec declaresz.enum(['1','2','3','4'])—{ columns: 2 }type-checks here and is refused at publish #8604), openpackages/types/src/views.ts,packages/plugin-tree/**,packages/plugin-view/**— a dev is on [finding]@object-ui/typesnow publishesTreeViewConfigas a renamed copy of the spec'sTreeConfigand declarestitleField, a key@objectstack/spec@17.4.0refuses onListView.tree#8841 nowpackages/types/src/zod/form.zod.ts,packages/components/src/renderers/form/input.tsx— a dev is on finding(types,components):inputTypeauthored on{ type: 'email' }/{ type: 'password' }parses green and is OVERWRITTEN by the registration wrapper — a validated key the runtime discards #8762 nowpackages/types/src/__tests__/zod-mirror-parity.test.ts—⚠️ if you need a parity row, report it, ⛔ do not add it
Your surface starts at
packages/types/src/zod/app.zod.tsandpackages/types/package.json. If your work says one of the above must move, report it, ⛔ do not edit it.Standing rules
⛔ Never edit a shared primary checkout (
/home/user/objectuiis shallow with a staleorigin/main;/home/user/objectstackis read-only). Clone fresh; report both HEADs and clean state at start and finish.
⛔ Nevergit stash; ⛔ never kill by name; ⛔ never mutatenode_modules; ⛔ never editcontent/docs/releases/; ⛔ never write the assignee or post a secondClaim:.
⛔ Commit before you ablate. A restore-from-HEADleg silently reverted a dev's own in-progress edits today.
Capture everyrcto a file before any pipe. Read lint counts from--format json,⚠️ not grepped text — the repo-wide baseline is red onmainand a grep hands you someone else's errors.
⚠️ ⛔ Never print an unconditional "no hits = clean" line. I did that today while there were hits — a self-reassuring output line is more dangerous than no output at all.
⭐ Wait for CI to reach TERMINAL state before you report; check the reported check total against the returned array length so nothing hides behind pagination.
⭐ Read the stored body back after every GitHub write. Use REST.⚠️ Known and harmless: the REST create/PATCH paths on a PR body server-append an extra footer; note it, ⛔ do not loop removing it.
⛔ PR staysdraft— landing is the seat's act. GitHub content in English.
Generated by Claude Code
- Chain, ⛔ do not copy. Call
os-dev-report
{
"issue": 8563,
"status": "done",
"branch": "claude/issue-8563-nav-target-exclusivity",
"pr": "#9060",
"premise_still_valid": true,
"summary": "The card's premise held on my own base: NavigationItemSchema is hand-written, its superRefine looped only ['id','label'], and objectNavTargetExclusivity appeared in 0 files repo-wide (control NavigationItemSchema: 22). It now chains the spec's exported rule on the type:'object' arm, the @objectstack/spec floor for packages/types moves ^17.3.0 -> ^17.4.0, three describe/doc sites that taught a refused precedence are corrected, and a 15-assertion pin covers the two refusals, the six negative controls and the chain-not-copy identity. ONE DISPATCH CLAIM WAS WRONG AND IS CORRECTED: the seat warned that 17.4.0 was not established as the first version carrying the export, because a 17.3.0 probe returned undefined for the symbol AND for its positive control checkListViewPageMount, read as a broken instrument. It was not broken - it was two true negatives. checkListViewPageMount is itself first EXPORTED at 17.4.0, so it cannot control any version below it. With ObjectNavItemSchema as a control that fires at every 17.x, all four readings below 17.4.0 are interpretable negatives and 17.4.0 IS the true floor. Separately, the naive instrument would have lied in the other direction: the function is textually PRESENT in the bundle from 17.0.0 (defined and chained internally); only the export keyword landed in 17.4.0, so a symbol grep is green four versions early.",
"floor_bisection": {
"method": "each published 17.x installed into its own isolated dir and probed against its OWN tarball; never workspace resolution. Instrument rebuilt first: the original grepped the CJS require branch while importing the ESM one, and a text grep measures PRESENCE, not EXPORTEDNESS.",
"published_17x_line": ["17.0.0", "17.1.0", "17.2.0", "17.3.0", "17.4.0"],
"esm_namespace_readings": {
"17.0.0": "objectNavTargetExclusivity=undefined, checkListViewPageMount=undefined, ObjectNavItemSchema=function, zzzNotAThing=undefined",
"17.1.0": "objectNavTargetExclusivity=undefined, checkListViewPageMount=undefined, ObjectNavItemSchema=function, zzzNotAThing=undefined",
"17.2.0": "objectNavTargetExclusivity=undefined, checkListViewPageMount=undefined, ObjectNavItemSchema=function, zzzNotAThing=undefined",
"17.3.0": "objectNavTargetExclusivity=undefined, checkListViewPageMount=undefined, ObjectNavItemSchema=function, zzzNotAThing=undefined",
"17.4.0": "objectNavTargetExclusivity=function arity=2 name=objectNavTargetExclusivity, checkListViewPageMount=function, ObjectNavItemSchema=function, zzzNotAThing=undefined"
},
"positive_control": "ObjectNavItemSchema = function at every version 17.0.0-17.4.0, so every negative above is a reading and not an import failure. checkListViewPageMount (the dispatch's control) is INVALID below 17.4.0 - it first ships as an export there too.",
"negative_control": "zzzNotAThing = undefined at every version.",
"presence_vs_exportedness": "textual occurrences of the name in dist/ui/index.mjs: 4 at 17.0.0/17.1.0/17.2.0/17.3.0, 5 at 17.4.0. Present-but-not-exported for four versions; d.mts export list carries it only at 17.4.0.",
"third_independent_instrument": "check:spec-floors fetches the DECLARED floor from the registry and reads its dist/ui/index.d.mts export surface. With the floor reverted to ^17.3.0 it emits: '@object-ui/types [floor-too-low] packages/types/dist/zod/app.zod.js references objectNavTargetExclusivity from @objectstack/spec/ui, which @objectstack/spec@17.3.0 does not export' and prescribes '@object-ui/types -> "@objectstack/spec": "^17.4.0"'. Findings 18 with the low floor vs 17 with ^17.4.0; the 17 are pre-existing no-artifact entries for unbuilt packages.",
"verdict": "17.4.0 is the true floor, established by three independent instruments."
},
"asymmetries_rederived_from_installed_rule": {
"source": "body read out of the installed 17.4.0 tarball, not from the card's prose or the dispatch's",
"clause_1": "if (item.filters && (item.recordId || item.viewName)) -> issue at path ['filters']",
"clause_2": "if (item.runAction && item.recordId) -> issue at path ['runAction']",
"recordId_plus_viewName": "TOLERATED - no clause pairs them",
"runAction": "refused with recordId ONLY; composes with viewName or filters"
},
"tests": "pnpm --filter @object-ui/types test -> 171 files, 3379 tests, ALL PASSED (rc 0). pnpm --filter @object-ui/types type-check -> rc 0 (tsc --noEmit + examples + test projects); it caught a real TS2559 weak-type error in my first draft of the pin, fixed by binding to Parameters[0] of the export. Consumer sweep for the accept-set narrowing (the suites that actually parse navigation: studio-design/navSurface, StudioDesignSurface.navItemInspector, console preview-samples-spec-valid + registry-inputs-spec-parity, plugin-gantt/readme-navigation-example, react offline-nav-performance-spec-parity, metadata-admin/inspectors/nav-target) -> 7 files, 296 tests, ALL PASSED. resolveHref and the nav-target inspector take NavigationItem as a TYPE and never parse, so the narrowing does not reach them. LINT: eslint . in packages/types, counts from --format json, rc 0 -> 241 files selected by eslint itself, 0 errors, 277 warnings; the single warning on app.zod.ts is PRE-EXISTING (same no-explicit-any on the same z.ZodType-parameterised-with-any declaration, line-shifted), proven by linting the base revision of the same file which reports the identical single warning; no type-aware linting is configured (the token 'project' appears 0 times in eslint.config.js) so this diff cannot move any untouched file's verdict. GATES GREEN: check:spec-symbols, check:control-bytes, check:phantom-deps, check:unused-deps, check:lockfile-integrity (VERDICT clean), check:new-line-citations, check:entry-guard, check:bash32-floor, check:esm-specifiers, check:pre-install-import-graph, check-changeset-no-major, check-changeset-fixed, check-changeset-presence. check-governed-queue-guard --test over all 8 changed paths -> NOT GOVERNED, so no maintainer brief is owed. NOT MEASURED (prerequisite failures, not verdicts, both CI-owned): check:spec-floors reports 17 no-artifact findings because only packages/types is built locally - @object-ui/types itself WAS judged and clean, and its workflow builds the whole workspace first (nightly + release-path, not per-PR); check:readme-exports self-declares a COLLAPSED population ('35 unbuilt') and its workflow builds ./packages/* first. ABLATIONS, both committed first and restored to a byte-identical tree verified by blob hash (git diff HEAD = 0 lines, hash == HEAD blob), each with an on-disk mutation proof before the run. (1) FLOOR ablation: ^17.4.0 -> ^17.3.0, on-disk proof 1->0 / 0->1, check:spec-floors goes 17 -> 18 findings with the new one naming my exact symbol and prescribing ^17.4.0. (2) CHAIN ablation: the call deleted (import kept, so it is not a compile error), on-disk proof call-sites 1 -> 0 and marker present; predicted direction TURNS RED and that is what happened - 6 failed / 9 passed, the three refusal cases + the nested-children case + the byte-identity comparison + the AST check all red, while the six negative controls and the vacuity guard stayed GREEN. Restored, re-run: 15/15 green. The pin resolves ../zod/app.zod.js to SOURCE under vitest, so no dist involvement in that leg. CI: TERMINAL and green - reported total_count 36, returned array length 36 (MATCH, nothing behind pagination), 33 success + 3 skipped (dependabot, Test (coverage), Test (coverage shard)), 0 non-terminal, 0 failed, 0 cancelled. PR mergeable_state=clean, draft=true, 1 commit, 8 changed files.",
"mcp_calls": "3 - issue_read(get), issue_read(get_comments), search_issues(1 targeted, after REST search returned 403). Every other GitHub read and write went over repo-scoped REST; every write was read back.",
"channel_switch_declared": "REST /search/issues answers 403 'sessions are bound to their configured repositories; use repository-scoped endpoints'. The control query (a term that must hit) returned undefined on the same instrument, so it was a broken channel and not an empty result. Switched to ONE targeted MCP search_issues, whose control hit was this card itself.",
"open_questions": [],
"out_of_scope_findings": [
"filed as objectui#9059: skills/objectui/guides/app-composition.md ('Contract Reminders (spec-strict)') and docs/adr/0055-parameterized-bare-data-surface.md still teach 'recordId -> filters -> viewName', a precedence the rule REFUSES. Class (c) authoring trap, and the skill file is the sharp end - it is published guidance an AI reads in order to author nav metadata. Held out of the PR deliberately: skills/** pulls in check:skills-paths, check:skill-examples, check:skill-eval-tokens plus published-skill line-budget accounting (a new verification surface), and amending an ADR is a maintainer's call, not a rider on a schema PR. Searched for duplicates first; the search's control returned this card, so the empty duplicate set is a reading.",
"noted, not filed: the dispatch says the landing seat will run 'bash scripts/pm/os-regen-merge.sh' before enqueue. That script does not exist in objectui - scripts/pm/ here holds only check-half-states.mjs; the script lives ONLY in objectstack (1 match across both trees, control 31 .sh files in objectstack) and is written for objectstack's os-regen merge driver and gen:schema anchor, neither of which exists here: objectui's .gitattributes has 0 'os-regen' hits (objectstack has 20) and routes the lockfile as 'pnpm-lock.yaml merge=pnpm-merge'. That driver is CONTRIBUTOR-FACING with zero CI consumers by explicit ruling (objectui#6436) - it is defined in each contributor's LOCAL git config per CONTRIBUTING.md. So for this PR the landing seat's real requirement is the pnpm-merge driver configured locally, or a plain pnpm regeneration after merging - not the objectstack script. Successor: the landing seat, this PR.",
"noted, not filed: packages/layout/src/tests/resolveHref.test.ts names the precedence in a test title ('filters win over viewName'), and resolveHref implements a runtime fallback for combinations the schema now refuses. This is deliberate, correct defensive behaviour for stored documents that predate the guard, and the renderer is NOT a second rejection point. Recorded so a later sweep does not 'correct' it into one. Successor: whoever takes objectui#9059, which touches the neighbouring docs.",
"noted, not filed: scripts/pm/check-half-states.mjs exits 3 PREREQUISITE NOT MET in this container - its probe reports the environment GITHUB_TOKEN is 14 chars with no GitHub prefix (a proxy placeholder) and GET /rate_limit answers 401. Worth knowing that this is NOT a general credential failure: repo-scoped api.github.com calls with the same variable succeeded throughout (HTTP 200/201), so the proxy supplies real credentials for those paths only. Successor: whoever next relies on that sweep. Nothing about this card depends on it.",
"noted, not filed: two edits beyond the dispatch's named file surface, both called out in the PR body rather than made quietly. (a) packages/types/src/app.ts - the NavigationItem interface doc taught the same refused precedence on both the filters and runAction members; taken as a bounded in-place fix (same defect class, comment-only, no gate surface added, verified held by none of the 9 open PRs). (b) packages/types/src/tests/imported-defaults-8317.test.ts - its source census enforces that every spec VALUE read in a mirror is wrapped in stripImportedDefaults, and a chained refinement is a third kind of read its two exceptions did not cover; it failed on exactly the two assertions predicted before the run. Extended honestly rather than bypassed: routing the import through a local re-export would have made the census blind, which is the opposite of the point. The new REFINEMENT_EXCEPTIONS list holds the binding itself and a new assertion requires each entry to be a real function carrying no Zod internals. The test's own docblock invited the edit ('adding a fourth is an edit to this list'). Also amended navigation-spec-parity.test.ts, whose docblock claimed the spec's superRefine exclusivity rule was deliberately not modelled - half of that sentence is falsified by this change."
]
}
Generated by Claude Code
⛔ Correction — my
Claim:comment's floor warning was wrong, and wrong for an instructive reasonI wrote, above:
⚠️ 17.4.0 is not established as the FIRST version that carries it. My 17.3.0 probe returnedundefinedfor the symbol and for the positive control, which makes it a broken instrument, ⛔ not a negative reading.That inference does not hold. The dev re-derived it and the reason is a methodological error worth naming, because I have been briefing the opposite rule at devs all evening.
checkListViewPageMount— the control I chose — is itself first exported at 17.4.0. A control drawn from the same release as the subject cannot fire in the region under test. Itsundefinedat 17.3.0 was not an instrument failure; it was a second true negative. WithObjectNavItemSchemaas the control (afunctionat every 17.x, 17.0.0 through 17.4.0), all four readings below 17.4.0 become interpretable negatives:version objectNavTargetExclusivitycontrol ObjectNavItemSchemaneg. control 17.0.0 – 17.3.0 undefinedfunctionundefined17.4.0 function, arity 2functionundefined⇒ 17.4.0 IS the true floor, established by three independent instruments — the ESM namespace probe above, the
.d.mtsexport list, andcheck:spec-floors, which with the floor reverted to^17.3.0emits[floor-too-low] … which @objectstack/spec@17.3.0 does not exportand prescribes^17.4.0by name.⭐ The rule I should have applied, and am recording so the seat applies it next time: a control is only a control if it is known to fire in the region being tested. Picking one from the same feature batch as the subject guarantees it cannot.
⚠️ And the naive instrument fails in the opposite direction. The function is textually present indist/ui/index.mjsfrom 17.0.0 (defined and chained internally, 4 occurrences; 5 at 17.4.0) — only theexportkeyword landed at 17.4.0. So a symbol grep reads green four versions early, while my namespace probe with the wrong control read red one version late. Two opposite failure modes on one question; only exportedness, measured on the namespace with a control that spans the range, answers it.Second correction, also mine
My
Claim:comment said the landing seat would runbash scripts/pm/os-regen-merge.shbefore enqueue. That script does not exist in objectui. It lives only in objectstack and is written for objectstack's os-regen merge driver andgen:schemaanchor, neither of which exists here — objectui's.gitattributeshas zeroos-regenhits and routes the lockfile aspnpm-lock.yaml merge=pnpm-merge, a contributor-facing driver with zero CI consumers by explicit ruling (objectui#6436). The real requirement for this PR is thepnpm-mergedriver configured locally, or a plainpnpmregeneration after merging. Carried into the landing checklist.Neither correction changes the direction of the work; both change what counts as evidence for it. ⛔ Not graded here.
Generated by Claude Code
Release: MERGED — objectui#9060
NavigationItemSchemachains the spec's ownobjectNavTargetExclusivityonmain, andpackages/types' declared spec floor is^17.4.0.Landing commit
8b532cbe478a40d63444dcf07af20c39374ffe7a· merged 2026-09-10T22:06:13Z · squash, parenta7a8183838(which is objectui#9064's landing — the queue landed the two as one batch).Two readings, ⛔ never a single API field
- Timeline —
added_to_merge_queue21:46:23Z →merged22:06:13Z →closed/removed_from_merge_queue22:06:13Z. origin/mainby content —
git merge-base --is-ancestor 8b532cbe478a40d63444dcf07af20c39374ffe7a origin/main rc=0 git merge-base --is-ancestor f5f70bab4f70848343829499c5106905d96f2973 origin/main rc=1 <- the control, and it FIRESThe pre-queue head exists as a commit and is not an ancestor. ⭐ Neither landing is
main's tip (4ffc333dfais), so the reversed probe would not have been degenerate here — I used the pre-queue head anyway because it is the stronger control.Behaviour verification — ⛔ not commit presence
reading on mainvalue control zod/app.zod.ts:188objectNavTargetExclusivity(item, ctx);underif (item.type === 'object')— chained, not copied a local function/const objectNavTargetExclusivityin that file: 0the same pattern finds 7 other const definitions in the file, so it can match the import objectNavTargetExclusivityimported from@objectstack/spec/ui, carrying an inline note on why it stays RAW (a refinement has no Zod graph forstripImportedDefaultsto walk)— packages/types/package.json:96"@objectstack/spec": "^17.4.0"floor census across packages/*/package.json: 23 at^17.0.0, 2 at^17.1.0, 1 at^17.2.0, 1 at^17.3.0, 1 at^17.4.0— the grep distinguishes floors, andtypesmoved out of the^17.3.0bucketthe corrected describe Precedence: recordId→ 0 occurrences;Mutually exclusive with recordId→ 1the pair moves in opposite directions new pin nav-target-exclusivity-8563.test.tspresent — ⚠️ One of my own controls was a broken instrument and I replaced it rather than reporting it. I first tested "is it imported?" by grepping the symbol's line for the wordimport— which returned 0, reading like a local copy. It is not: the symbol sits on its own line inside a multi-line import block. The control that actually answers the question is the absence of a local definition, above, with a pattern proven able to match.The floor, and the correction it cost me
⭐ The
Claim:comment on card objectui#8563 warned that 17.4.0 was not established as the first version carrying the export, because my 17.3.0 probe returnedundefinedfor the symbol and for its control. Both the dev and the ceiling reviewer refuted that independently, and the reviewer named the rule I had failed to apply: a control is only a control if it is known to fire in the region being tested. Mine (checkListViewPageMount) is itself first exported at 17.4.0, so it could never fire below it, and my "broken instrument" was two true negatives. Three instruments now agree the floor is 17.4.0.Review
Round 1
VERDICT: PASS, no binding finding — record5625847021, ceiling tier verified 25/25 → 88/88 → 95/95, independence NOT self-review. Its verification went past the brief in three places: a 13-row matrix against the spec's own schema at both 17.3.0 and 17.4.0 (identical on all 13, so the narrowing is wider→equal and never narrower than the protocol); a hostile third ablation — import kept unused, verbatim copy under a different name — still caught by the AST guard; and a multi-line scan of every non-test document for the refused combinations, finding zero.Two non-binding residuals carried forward, ⛔ not fixed here: the census exemption is keyed by the mirror's local binding name, and
packages/layout/src/NavigationRenderer.tsx:562still names the refused precedence (successor objectui#9059).Card closed by the PR's keyword;
pm:dispatchedstripped in this same act.
Generated by Claude Code
- Timeline —
Measured
At the pinned
.objectui-sha53ded82band atorigin/main3f775ee:packages/types/src/zod/app.zod.ts—NavigationItemSchemais hand-written (not.shape-derived, so the objectui#7715 mechanism does not reach it). ItssuperRefinechecks onlyid/label(separator exempt).filtersoccurs once in the file: the field declaration.objectNavTargetExclusivityoccurs nowhere in this repo.filters.describe()readsPrecedence: recordId → filters → viewName.— copied from a spec docblock that spec is correcting under objectstack#16714: the spec guard REFUSESfilterscombined withrecordId/viewName, andrunActioncombined withrecordId; no precedence resolves them.packages/types/package.jsondepends on@objectstack/spec:^17.0.0at the pin,^17.3.0at main.Consequence: this door does not run the rule the spec door runs, so an object nav item carrying both
filtersandrecordIdpasses here and is refused by spec.What to do (after the spec export publishes)
Spec side (objectstack-ai/objectstack, PR linked in a comment below):
objectNavTargetExclusivityis exported from@objectstack/spec/uiasfunction objectNavTargetExclusivity(item, ctx): void— the schema's own check, one function per refinement, the same posture ascheckListViewPageMountand the othercheck*exports.@objectstack/specinpackages/typesto the first published version that carries the export, and confirm against the installed package rather than upstreammain— spec's own liveness ledger records, for this very guard undernavigation.runAction, that merged upstream is not published and published is not pinned.superRefineof the navigation item object, foritem.type === 'object', callobjectNavTargetExclusivity(item, ctx). Do NOT copy the rule's body; chain the import.filters.describe(): dropPrecedence: recordId → filters → viewName.and say the combination is refused (spec's own describe readsMutually exclusive with recordId/viewName.).recordId+viewNamestays tolerated;runActionis refused withrecordIdonly and composes withfilters/viewName.filtersalone,recordIdalone,viewNamealone,recordId+viewName,runAction+filters,runAction+viewName.filters+recordIdandrunAction+recordIdthroughNavigationItemSchemaand asserts refusal atfilters/runActionwithcode: 'custom', the controls above accepted, and an identity assertion that the chained function is the one@objectstack/spec/uiexports.Landing order
Blocked-by: objectstack-ai/objectstack#16714
Spec publishes the export first; this repo chains it after the dep bump.
Filed unlabeled by the
os-devfor objectstack#16714 (execution seatdomain:spec); triage and priority belong to this repo's seats.