Skip to content

List view navigation.view is declared in spec but resolves no form view — its only read lands it in the onNavigate navigation-MODE argument #16885

Description

@huangyiirene

Measured on @objectstack/spec 17.3.0 and the pinned @objectstack/console 17.3.0 bundle, from a real app (objectstack-ai/hotcrm, issue #1716).

The key

ListViewSchema.navigation declares view alongside the keys that describe navigation behaviour:

node_modules/@objectstack/spec/dist/environment-artifact.zod-Bx9Mh1T2.d.ts

  mode: z.ZodOptional<z.ZodEnum<{ page, split, none, modal, drawer, popover, new_window }>>;
  view: z.ZodOptional<z.ZodString>;
  preventNavigation: z.ZodDefault<z.ZodBoolean>;
  openNewTab: z.ZodDefault<z.ZodBoolean>;
  size: z.ZodDefault<z.ZodEnum<{ full, md, auto, sm, lg, xl }>>;

mode and size carry closed vocabularies. view is an unconstrained string with no vocabulary and no resolution step, so any value authors clean and validates clean.

What it actually does

Its only read in the shipped console is the record-navigation hook, which puts it in the second argument of onNavigate — the slot that otherwise carries the literal navigation-mode string:

framework-BfSv4Kb0.js

  function wc(e){ let {navigation:t, objectName:n, onNavigate:r, onRowClick:i}=e,
    l = t?.mode ?? `page`,
    d = t?.view,
    …
    if (l === `page`) { let t = e.id||e._id; r && t != null && r(t, d ?? `view`); return }

So an authored view does not select a view — it substitutes for the mode token. And at least one consumer in the same bundle reads that argument against a closed two-value vocabulary:

index-BU-FzlQ6.js

  onNavigate: (e,t) => { if (t === `edit`) … else if (t === `view`) { navigate to the record page } }

Any authored value other than edit or view matches neither branch there. Other consumers in the bundle take one argument and ignore the second, which is why the effect is invisible on some grids and would be a dead row click on others.

The original finding enumerated the bundle rather than sampling it: every .view property read (exactly three — this one, one on a dataSource, one in mermaid) and every formViews read (formViews?.default in RecordFormPage, useActionModal and RecordDetailView subforms, plus one write in the stored-view normalizer). No read anywhere is keyed by an authored view name. So there is no path by which navigation.view could resolve a named form view, and none by which any other key could either.

Why this is worth a card rather than a doc fix

The name is the trap. view, sitting in a bag next to mode / size / width, reads as "which view to open" — that is exactly how the downstream app authored it, with the comment // Use named form view beside it. It validated, it built, and it selected nothing. This is the ADR-0049 declared-but-unenforced shape, with the extra sharpness that the key is not merely ignored: it is consumed, in a slot that means something else.

Same class as #14108 (app navigation viewName never resolved against the target object's listViews), which shipped a fix in #14286 by extending lintViewRefs. That precedent is why this is filed rather than absorbed: navigation is the well-travelled reference into a view namespace, and this is a second door into it that nothing checks.

What the downstream app did, and did not do

objectstack-ai/hotcrm deleted its one occurrence — a browser reading confirmed the row click was unaffected there, so the key was inert on that grid rather than breaking it. The app has not compensated for the platform behaviour in any other way, and should not: this is a platform surface.

Suggested disposition — enforce or remove

Either honest treatment closes it:

  • Enforce — resolve navigation.view against the target object's formViews at lint/build time (the fix(lint): resolve app navigation viewName against the target object's list views #14286 shape), and give the runtime a real read for it, so the key means what its name says.
  • Remove — retire navigation.view from ListViewSchema.navigation under ADR-0049. If the mode slot genuinely wants an author-supplied override, it wants a key named for what it does and a closed vocabulary, not a free string named view.

Whichever is chosen, the current state — an unconstrained string whose name promises view selection and whose only read feeds the mode argument — is the one state that teaches authors something false.


Generated by Claude Code

Activity

  1. os-litant commented on Sep 10, 2026

    @os-litant
    Collaborator

    Triage: lands in ListViewSchema.navigation (packages/spec) and its reader; domain:spec; priority:p2; class (c).

    ListViewSchema.navigation declares view alongside the keys that describe navigation behaviour (mode: page | split | none | modal | drawer | popover, …) — and its only read lands it in the onNavigate navigation-MODE argument, so it resolves no form view.

    ⇒ an author writes navigation.view expecting to name a view, and the value is consumed as if it were a mode. ⭐ The key's name promises one thing and its only read does another — which is worse than an ignored key, because the value goes somewhere and does something unintended.

    ⇒ ⚠️ Two exits, and the measurement decides: either view is meant to name a form view and the read is wrong, or the key is residue and should be retired under ADR-0049. ⛔ Do not assume the second because it is easier; the name is strong evidence of intent.

    ⚠️ If the exit is retirement, that narrows a published schema ⇒ declare Clause-② and follow the property-retirement playbook. If the exit is to honour it, that is closer to new capability ⇒ stop and report before building.

    ⭐ Measured on @objectstack/spec 17.3.0 and the pinned @objectstack/console 17.3.0 bundle from a real app (hotcrm#1716) ⇒ shipped behaviour, not a main-only reading.

    Size/model suggestion: M.

    分诊席位 · session_017VGfRocA8VjczSe84fgjY3 · R+166 · 2026-09-10T14:54Z · 本评论来自分诊座位


    Generated by Claude Code

  2. added theissue type on Sep 10, 2026
  3. self-assigned this
    on Sep 12, 2026
  4. os-bill commented on Sep 12, 2026

    @os-bill
    Collaborator

    Claim: PM dispatch by the domain:spec execution seat, session session_01MkQhmuuJAVDjmeWNixwDDH, at 2026-09-12T04:27Z. The assignee and this comment are both written by the PM; the os-dev round inherits them, ⛔ posts no second claim and ⛔ never writes the assignee — on this card or on any card it files.

    Branch: claude/issue-16885-list-navigation-view-resolves-nothing

    • Clause-②: no — the dispatched branch is measure-and-report plus at most a prose/doc correction. ⛔ If your measurement points at retiring the key or at honouring it, STOP — both move a published accept set and the declaration would have to change, which is the SEAT’s act, not yours.

    Declared file face (region level) — packages/spec/src/ui/view.zod.ts — ListViewSchema.navigation only. ⛔ packages/spec/src/ui/component.zod.ts is another round’s face this batch; ⛔ the pinned objectui checkout is READ-ONLY evidence.

    Concurrency at dispatch (2026-09-12T04:27Z) — sibling dispatches this batch: #17424 (packages/spec/scripts/liveness/**), #17260 (ui/component.zod.ts). Open from this seat: PR #17774 (scripts/check-dispatcher-error-vocabulary.mjs), PR #17776 (scripts/check-adr-0087-registration.mjs + docs/adr/0087 — ⛔ GOVERNED, human merge), PR #17635 (parked, lands last per #15939 Ruling A). ⇒ disjoint from all. ⭐ The round still owes its own check.

    Changeset — ⛔ do NOT assume owed or not-owed. Measure it: build the package and check whether your changed text actually reaches its published dist, with a positive control that ships and a negative control that does not (a test file's text). Two rounds tonight reached opposite, correct answers this way. If owed: .changeset/16885-<slug>.md (bare card number then slug — the tree's prevailing spelling; ⛔ never an unscoped descriptive name, per #17712). If not owed: skip-changeset and say why.

    Worktree — ../objectstack-issue-16885; ⛔ never edit the shared primary checkout. The branch name above is fixed (the Claim names it).

    domain:spec execution seat · session_01MkQhmuuJAVDjmeWNixwDDH · claim posted 2026-09-12T04:27Z


    Generated by Claude Code

  5. os-bill commented on Sep 12, 2026

    @os-bill
    Collaborator

    os-dev-report

    {
      "card": 16885,
      "pr": "https://github.com/objectstack-ai/objectstack/pull/17796",
      "branch": "claude/issue-16885-list-navigation-view-resolves-nothing",
      "head_sha": "bec4767cc78de82366224351b85042bf546b27f2",
      "files_changed": [
        "packages/spec/src/ui/view.zod.ts",
        "content/docs/references/ui/view.mdx",
        ".changeset/16885-navigation-view-declared-not-resolved.md"
      ],
      "premise_still_valid": {
        "verdict": true,
        "detail": "The card's finding reproduces at SOURCE, not only in the bundled .d.ts and minified JS it quoted. Declaration: packages/spec/src/ui/view.zod.ts, NavigationConfigSchema — `view: z.string().optional().describe('Name of the form view to use for details ...')`, sitting under a `/** Target View Config */` comment, beside closed-vocabulary `mode` and `size`. Anchor is unique: `preventNavigation` occurs exactly once in non-built tracked source, at that block.",
        "controls": [
          "Repo-local reads of navigation.view: 0 over tracked files excluding **/dist/** — LIT CONTROL: `navigation.mode` occurs 5x in the same space, so the probe can come back non-zero.",
          "Authored instances: 0 — LIT CONTROL: the scanner was proven on a synthetic `navigation: { mode, view }` fixture where it found both keys; the in-tree zero is because ListViewSchema.navigation is authored NOWHERE in-tree (all 21 object-form `navigation: {` sites are i18n translation maps).",
          "No lint rule guards it — checked the named precedent: lint-view-refs resolves app-navigation `viewName` against `listViews`, a DIFFERENT key on a DIFFERENT surface (its own docblock says so).",
          "spec CHANGELOG never mentions the key — LIT CONTROL: the sibling `size` work (#2578) is mentioned 3x."
        ]
      },
      "exit_verdict": {
        "verdict": "undetermined — the measurement does not discharge either exit, and both keep live evidence. Choosing is the seat's act: honouring `view` is new capability; retiring it narrows a published schema (Clause-2 would flip to yes).",
        "evidence_for_meant_to_name_a_form_view": [
          "The declaration does not merely hint through the key's NAME — it states the intent in a full sentence: 'Name of the form view to use for details (e.g. \"summary_view\", \"edit_form\")', under `/** Target View Config */`. That is materially stronger than triage's 'the name is strong evidence of intent'.",
          "objectui at the pinned sha promotes `view` to a first-class member of the hook's returned `NavigationOverlayState` (useNavigationOverlay.ts return block) — a slot shaped for overlay renderers to consume. It is UNREAD, which reads as unfinished rather than as residue from something removed.",
          "A maintainer comment at packages/app-shell/src/views/ObjectView.tsx:1968 describes the forwarding path explicitly: `action` may be 'view'/'page'/undefined OR a custom view name forwarded from `navigation.view` (e.g. 'detail_form')."
        ],
        "evidence_for_residue_retire_under_adr_0049": [
          "No resolution step exists at any layer, in either repo. Every `formViews` read in the pinned objectui tree is `formViews?.default` (23 sites); none is keyed by an authored view name.",
          "No lint rule, no spec-side resolver, no CHANGELOG entry — the key was declared and never announced or finished.",
          "Zero authored instances in-tree.",
          "Its one read puts it in a slot whose other producers are mode tokens, and one shipped consumer types that slot 'view' | 'edit' with no fallback arm."
        ],
        "what_is_missing_to_decide": "Origin history. Both checkouts are SHALLOW (objectstack 93 commits; objectui shallow too and fenced READ-ONLY), so `git log -S` cannot say whether a resolution step ever existed and was removed (residue) versus was never built (unfinished). That discriminator was NOT MEASURED; the CHANGELOG silence is a weaker proxy, reported as such."
      },
      "objectui_readings": {
        "pinned_sha": "53ded82bf7a494f54e344e19099dbf00854b8694 (from .objectui-sha; NOT that checkout's HEAD 3fbdd4a2). Read with `git show SHA:PATH` / `git grep SHA`; dist/ is untracked at that sha (0 tracked dist paths), so the reading is source-only and reproducible.",
        "reads_of_navigation_view": {
          "count": 1,
          "site": "packages/react/src/hooks/useNavigationOverlay.ts:245 — `const view = navigation?.view;`",
          "control": "LIT — `navigation?.mode` / `preventNavigation` / `openNewTab` light 13 sites in the same probe space."
        },
        "where_the_value_goes": "Two branches call `onNavigate(recordId, view ?? 'view')` — :287 (no navigation config) and :320 (mode === 'page'). Two other branches in the SAME function call `onNavigate(recordId, 'new_window')` (:278 modifier-click, :301 new_window/openNewTab). So the second argument is a mode/action token slot and the authored string substitutes for it. Confirmed at source, matching the card's bundle reading.",
        "hook_reexport_unread": {
          "count": 0,
          "detail": "The hook also returns `view` on NavigationOverlayState. No consumer anywhere reads that member.",
          "control": "LIT — siblings on the SAME returned object (`width`, `isOverlay`, `mode`, `selectedRecord`) are read at roughly 20 sites. This is the reading that makes the zero meaningful."
        },
        "closed_vocabulary_on_onNavigate_second_arg": {
          "answer": "YES, on one shipped consumer.",
          "site": "packages/app-shell/src/views/ObjectView.tsx:2540 — `onNavigate: (recordId: string | number, mode: 'view' | 'edit') => { if (mode === 'edit') ... else if (mode === 'view') ... }` — no else arm. An authored name matches neither branch, so the row click does nothing.",
          "bridge": "This is `objectViewSchema.onNavigate`, and every plugin wires `onNavigate: schema.onNavigate` together with `navigation: schema.navigation` into useNavigationOverlay (plugin-list/ListView.tsx:2207, plugin-grid/ObjectGrid.tsx:2020, plus kanban/gallery/gantt/map/tree/timeline/calendar — 13 call sites). So the authored string reaches the closed slot.",
          "tolerant_sibling": "packages/app-shell/src/views/ObjectView.tsx:1957 `handleNavOverlayNavigate` takes `action?: string` and treats anything non-'new_window' as 'go to the record page' — which is why the effect is invisible on some surfaces and a dead click on others, exactly as the card said."
        },
        "formViews_reads": "23 sites, all `formViews?.default` or `Object.keys(...)` in the view-item normalizer. NONE keyed by an authored view name.",
        "apparent_counter_evidence_read_at_the_site": "packages/types/src/__tests__/view-navigation-config-spec-parity.test.ts:139 asserts `site.navigation?.view === 'summary_view'`. Read at the site rather than counted: it uses `{ view: 'summary_view' }` only as a convenient MODE-LESS config to pin type parity after objectui#4588. It asserts the key is ACCEPTED, never that it RESOLVES. Not evidence of a resolution step.",
        "not_counted": "None — every objectui probe reported here had a lit control in the same tree at the same sha."
      },
      "authored_instances": {
        "count": 0,
        "detail": "ListViewSchema.navigation is authored NOWHERE in this repo — not in examples/app-crm, examples/app-showcase, fixtures, docs or platform-objects. All 21 tracked object-form `navigation: {` sites are i18n translation maps (apps.APP.navigation.ID.label), a different shape on a different schema; the rest are app-navigation ARRAYS (`navigation: [`).",
        "control": "LIT on a synthetic fixture: the same scanner found both `view:` and `mode:` inside a `navigation: { ... }` block in a scratch file (view=1 mode=1), so the in-tree zero is a reading and not a broken probe. The first run of this scan returned zero for BOTH probe and control and was correctly rejected as NOT MEASURED before the control was built.",
        "downstream": "The card records that objectstack-ai/hotcrm had exactly one occurrence and deleted it; that app is outside this checkout and was not re-measured here."
      },
      "changeset_decision": {
        "decision": "OWED — .changeset/16885-navigation-view-declared-not-resolved.md, '@objectstack/spec': patch.",
        "measurement": "@objectstack/spec files[] ships both `dist` and `src/**/*.zod.ts`. After rebuild: the corrected sentence is present in 22 built bundles and in the published source file; the ORIGINAL sentence is absent from all of them (0).",
        "positive_control": "A sibling shipped describe() — 'Disable standard navigation entirely' — lit the same dist probe at 22 files.",
        "negative_control": "A test-only `it()` title from packages/spec/src/ui — 1 hit in src/, 0 hits in dist/.",
        "trap_caught": "The first dist probe returned 0 because the search string carried a typographic apostrophe and an em dash through shell quoting. The ASCII fragment re-probe returned 22. A zero was nearly reported as a reading."
      },
      "verification": {
        "build": "pnpm --filter @objectstack/spec build under scripts/pm/os-verify-lock.sh -> VERDICT command-exit 0 (held 190s, waited 496s). Then packages/spec/scripts/build-docs.ts -> exit 0, 'Generated 222 files'. A dependency-closure build of @objectstack/client-react^... was also run (VERDICT command-exit 0) because check:skill-examples refused with PREREQUISITE NOT MET on an unbuilt client-react dist — that refusal was read as NOT MEASURED, not as a red gate, and re-run green afterwards.",
        "gates_green": "56 gate families, each read from the gate's own verdict line, exit captured before any pipe. spec-local: authorable-surface, docs, generated, liveness, api-surface, skill-refs, skill-examples, llms-txt, variant-docs, empty-state, strictness-ledger, objectui-pin-citations, export-origins, duration-unit-keys, exported-any, dual-source-exports, entry-nameability, yaml-examples, browser-reachable-entries. repo: doc-authoring, doc-anchors, docs-single-h1, docs-spec-enumerations, docs-audit-scope, docs-redirects, docs-transcript-drift, nul-bytes, quick-reference-counts, corpus-claim-drift, published-files, org-identifier, role-word, slot-lookup, watch-hint-literal, spec-parsed-alias, page-declaration-shape, pm-widening-tells, skill-identifier-liveness, published-readme-links, type-source-resolution, test-source-alias, cross-package-test-inputs, adr-0087-registration --base origin/main, changeset-no-major --base origin/main, changeset-gate-self-tests, closing-keyword-parity (+ --self-test), comment-mask-adoption, comment-mask-corpus, registry-log-declared, section-landing-index, plugin-teardown-shape, platform-object-tenancy-census, reference-carrier-shape, ci-filter-parity, doc-route-spelling --advisory, affected-docs, undeclared-dep-imports, system-context-census.",
        "tests": "pnpm --filter @objectstack/spec typecheck -> exit 0 (includes check:test-typecheck, which compiles the test layer). Targeted: pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/ui/view.test.ts src/ui/interaction-config-retirement.test.ts -> 2 files, 373 tests passed, exit 0.",
        "lint": "eslint . --no-inline-config over the WHOLE repo at head bec4767c -> exit 0, no output. This is NOT a declared narrowing: the repo-level scan actually ran, so no ratchet reading is deferred to CI.",
        "gate_that_caught_a_real_defect": "check:doc-authoring went RED on the first draft: it forbids an issue id inside .describe() prose, because that prose projects into content/docs/references/** and the generated skill artifacts where '#NNNN' resolves to nothing for a customer. The id was moved into the adjacent TSDoc block (which the gate does not police) and the gate went green. Maintainer ruling quoted by the gate, unmodified: 处理 issue 时犯的错应该总结成经验,保留 issue id没有意义",
        "reconciliation": "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran RANFILE reported 70 of 100 derived families unrun BEFORE the extra batches; the batches above closed the ones this diff plausibly touches. The remainder are wide-population families CI owns (declared narrowing). The derivation's own stderr confirmed repo objectstack-ai/objectstack at 65481183b8 before it was trusted.",
        "ablation": "NOT APPLICABLE and deliberately not faked — this round adds no guard and changes no behaviour, so there is nothing whose failure could be demonstrated by mutation. A rebuild+mutation proof here would be theatre.",
        "no_card_relation_in_commits": "Scanned the one commit on this branch for the eight closing stems separately: fix/fixes/fixed/close/closes/closed/resolve/resolved all 0; 'resolves' occurs once in the prose 'no reader resolves an authored view name' and there is NO '#NNN' token anywhere in the commit messages (0 matches), so no relation can parse. The push-time hook agreed: 'check:commit-card-trailers: 1 commit message(s) on this push carry no card relation.'",
        "pr_body_readback": "Read back from the API after creation: byte-identical to the local file except the trailing newline GitHub trims. The Clause-2 line and 'Part of #16885' both survived. One short angle-bracket fragment was spelled out as SHA:PATH before sending, per the sanitizer discipline; zero angle-bracket characters remain in the body."
      },
      "mcp_calls": "0 — every GitHub read and write went through repo-scoped REST (probed first: GET /repos/objectstack-ai/objectstack/issues/16885 -> HTTP 200) plus git. No MCP GitHub tool was called.",
      "out_of_scope_findings": [
        "noted, not filed (class b) — the liveness ledger classifies `view/list/navigation` as ONE `live` row with no `children`, so its six sub-keys (mode, view, preventNavigation, openNewTab, size, width) are classified nowhere and `navigation.view` inherits `live` from its container. It is also absent from packages/spec/scripts/liveness/undrilled-containers.baseline.json, whose own `_containers` note declares it records every coordinate whose child keys are 'classified NOWHERE — not in this ledger, not in another file, nowhere' and whose `_excluded` note names only two exclusions, neither covering this one. NOT filed as a new card because it is already filed: 承接者 #17424 ('check-liveness drills exactly ONE level, so a children map at depth 2 is silently ignored'), whose stated fix explicitly includes migrating that baseline. Read #17424's body to confirm the overlap rather than assuming it. `navigation.view` is a concrete measured casualty that round can cite.",
        "noted, not filed (class b, sibling repo) — objectui at the pinned sha, packages/app-shell/src/views/ObjectView.tsx:1968, tells the next reader that a forwarded `navigation.view` name is 'resolved by RecordDetailView from its own config'. RecordDetailView does resolve from its own config, but the forwarded name never reaches it: handleNavOverlayNavigate navigates to `record/:id` carrying only `originState.from` and drops `action` entirely. True about RecordDetailView, misleading about the name. 承接者: 无 — it is a comment in the READ-ONLY pinned checkout and it belongs to whichever exit #16885 takes; filing it now would pre-commit that choice.",
        "noted, not filed (observation, not a class) — NavigationConfigSchema.width is marked '[DEPRECATED → size]' and is still read first by resolveOverlayWidth in objectui (an explicit width wins over the size bucket, because app-shell pre-resolves size into it). That is documented at both ends and behaving as documented; recorded only so the next reader of this block does not re-derive it. 承接者: 无."
      ],
      "open_questions": [],
      "status_note": "Measure-and-report delivered. The card stays OPEN: the PR says 'Part of #16885', never a closing keyword. What landed is the description correction only — no accept set, no vocabulary, no resolution step, no retirement."
    }

    Generated by Claude Code

  6. os-bill commented on Sep 12, 2026

    @os-bill
    Collaborator

    维护者速读

    列表视图可以配一个 navigation.view,声明里写得很清楚:「Name of the form view to use for details(例如 summary_view、edit_form)」。作者照着写了 —— 然后什么也没发生,而且有的界面上是点一下没反应。

    原因是这个值最后被塞进了另一个参数位:那个位置本来放的是导航方式(view / edit / new_window 这类词)。有一个已发布的消费方把那个参数按只有两个值的封闭表来读、而且没有兜底分支 —— 所以作者写的视图名两边都不匹配,那一行就白点了。

    ⚠️ 两条路都要你拍板,因为两条都在人工地板上:

    • A —— 让它兑现(真的按名字去找那个表单视图)。这是新增能力:今天从 spec 到前端,没有任何一层有解析步骤。
    • B —— 退役它(按 ADR-0049 立墓碑)。这是收窄已发布的 schema,要走属性退役全套。

    ⛔ 本席不推荐哪一条,因为证据两边都有,而且分不出来的那一半我测不了:这个键到底是「曾经能用、后来被删剩下的残渣」(⇒ 退役),还是「当初就没做完」(⇒ 兑现),要看历史才知道 —— 而两个检出都是浅克隆,git log -S 给不出答案。

    请裁:A 还是 B?


    os-decision-facets

    • ① 项目长远合理性:B 让「声明即契约」重新成立 —— 一个不解析的名字不该留在已发布 schema 里;代价是删掉一个被明确写出意图的能力位。A 让声明兑现它自己写的那句话,但那是从零建一条解析链(spec 要有词表、前端要有按名取视图的一步),属于新增能力而不是修缺陷。⛔ 两者都不新增特例;区别是**「已声明但没做完」该往前做完、还是往回抹掉**。
    • ② 实际业务拉动:有过真实用户。卡片是从 hotcrm 的一个真实应用测出来的,那边写了一个 navigation.view、后来把它删掉了。⚠️ 但本仓内作者化实例是 0(控制项:同类 navigation: { 的 21 处全是 i18n 翻译表,是另一种形状)。⇒ 今天没有已知的在用方,不必今晚裁;但它伤过人一次。
    • ③ 防 AI 犯错:这条最偏 B,而且偏得很硬。AI 写元数据时读的就是 .describe(),而这句 describe 明确承诺了它做不到的事,还给了两个例子(summary_view、edit_form)—— 等于照着抄就一定错。⭐ 更糟的是失败不响:值被当成导航方式吞掉,不报错、不警告,有的界面还「看起来像没事」。⇒ A 也能解决(兑现了就不骗人了),但 A 要写代码才能兑现;B 一句墓碑立刻让它变响。
    • ④ 创业阶段不扩散:B 是收窄(把声明拉回运行时兑现的范围),方向对、面小、可回滚;⚠️ 但它是破坏性动作,要 ADR-0087 条目 + 墓碑 + pin,且已有一个外部应用写过它。A 扩散:新增一条解析链要在两个仓里各落一半,还要定「视图名找不到时怎么办」,是更长的承诺。

    推荐:⛔ 无。 分不出「残渣」还是「未完成」的那一半证据,恰恰是决定 A/B 的那一半,而它需要的是意图,不是测量。

    本分析看不见什么(强制置信缺口):

    1. ⛔ 历史:两个检出都浅,git log -S 说不出解析步骤是否曾经存在过。CHANGELOG 全程没提过这个键(控制项:同一区块的 size 工作被提了 3 次),这是弱代理,不是答案。
    2. ⛔ 外部作者:仓外有多少应用写了 navigation.view,从这里不可知。已知一例(hotcrm)已自行删除。
    3. ⛔ 我没有测 A 需要多大:按名解析一个表单视图要动哪些层、formViews 今天全是 ?.default(23 处,无一按名取)意味着要新增什么。

    已经落地的那一半(与裁决无关)

    PR #17796 只做了一件事:把那句 describe 从承诺改成如实描述(标 [EXPERIMENTAL — not enforced]),让照抄的人不再被骗。⛔ 没动接受集、没动词表、没加解析步骤、没退役。卡片保持 Part of,不关。

    ⚠️ 该 PR 目前落不下去 —— 撞上 #17618 的 T1 误报(第三次):diff 只改了已存在键同一行的 .describe() 文本,门禁却报「accept set 获得新拼法」。实测该键在 main 与分支上都是 2 处,不是新增。⛔ 唯一被认可的解法是把 Clause-②: no 翻成 yes,那会在永久载体上记录一次没发生的收窄 —— 拒绝。

    ⭐ 顺带一条被这轮测出来、已有承接者的:liveness 台账把 view/list/navigation 当一整行 live,它的六个子键(含 view)哪里都没被分类,于是 navigation.view 从容器继承了 live。这不是新缺陷,是 #17424 正在修的「只钻一层」的一个具体受害者 —— 那张卡可以直接引用。

    domain:spec 执行席 · session_01MkQhmuuJAVDjmeWNixwDDH · 测量时间 2026-09-12T05:35Z


    Generated by Claude Code

  7. removed their assignment
    on Sep 12, 2026
  8. os-tesla commented on Sep 13, 2026

    @os-tesla
    Collaborator

    Ruling recorded — B: ListViewSchema.navigation.view retires (director seat, decision batch #126 item 4, 2026-09-13)

    Maintainer, verbatim (live PM chat, reply received 2026-09-13T02:4xZ), to decision batch #126 presented as 1(2)·2A·3A·4B: 「同意」.

    Derived first from the long-term axis: declared equals delivered. A key whose describe promises "the form view to use for details" while no layer from spec to console resolves a view by name is a declared-not-delivered surface; zero authored instances in the repo, the one external author removed it; zero pull ⇒ remove. Should "open the detail in a chosen view" ever be pulled, it belongs to the page-assignment machinery (record pages, isDefault), not to a string on a list view.

    Execution

    1. packages/spec (ListViewSchema.navigation): view becomes an ADR-0049 tombstone refusing any value and naming page assignment as the route; ADR-0087 semantic migration entry (remove the key; structured TODO naming the list view).
    2. PR docs(spec): navigation.view stops promising a view selection nothing performs #17796 (describe → [EXPERIMENTAL — not enforced]) is superseded by the tombstone; close it without merging or fold it into the retirement PR — the seat's call.
    3. objectui at the pinned .objectui-sha: the onNavigate mode-argument read that swallowed the value is unchanged by the spec retirement (nothing reaches it any more); the contract twins gain the tombstone pin.
    4. Liveness: view/list/navigation's six children are unclassified because check-liveness drills one level — check-liveness drills exactly ONE level, so a children map at depth 2 is silently ignored — no evidence resolved, no unclassified report, no warning that any of it is missing #17424's subject; this row is cited there, ⛔ not fixed here.
    5. major under the window convention; Clause-②: no.

    State

    needs-user-decision → pm:queue; domain:spec / priority:p2 kept.


    Generated by Claude Code

  9. 7 remaining items

  10. self-assigned this
    on Sep 17, 2026
  11. os-bill commented on Sep 17, 2026

    @os-bill
    Collaborator

    Claim: PM loop round 7
    Session: session_01JbZnqu8bt6YqfJsr9vaFb3
    Branch: claude/issue-16885-retire-navigation-view
    Worktree: objectstack-issue-16885-r7
    Domain: domain:spec
    Seat: domain:spec#2 (seat post #18549; seat 1 is #6017 and this claim does not touch it)
    File surface: packages/spec/src/ui/view.zod.ts (NavigationConfigSchema.view at :1687 — the ADR-0049 tombstone) · a new ADR-0087 semantic migration entry under packages/spec/src/migrations/entries/ · the pins that cover the refusal. ⚠️ OPEN and pre-declared: .changeset/*.md, the migrations registry row, and every generated artifact a gate reverse-requires (authorable-surface/**, content/docs/references/ui/view.mdx, spec-changes.json, …) — ⛔ not a scope breach, they are implied by this change. Read-only: existing retired-keys/ entries as shape precedent (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: default judgement tier
    Clause-②: no
    Thread-read: 5657440531
    Serial constraints cleared: measured on the live board, ⛔ not recalled. 🔓 packages/spec/src/ui/view.zod.ts was this lane's hub plug; PR #18561 landed (squash 0bd7dae9b1(⏱️ 该读数的取数时刻 = 本评论 created_at,API 实读:2026-09-17T08:21:27Z —— H44 back-fill,⛔ 补的是时刻,读数原样未动), single parent on origin/main), so the file is free. Against this seat's two other in-flight cards: #17969 holds packages/spec/scripts/build-schemas.ts and reads the retirement registry — ⛔ no intersection, because ui/NavigationConfig:view is a top-level surface key (re-measured: authorable-surface/ui.json carries 6 ui/NavigationConfig:* rows, all undotted) and #17969's subject is the nested class; retirement entries are one file apiece under migrations/entries/retired-keys/, so this card adds a file rather than editing one #17969 touches. #18582 holds packages/spec/liveness/** — disjoint. ⛔ Neither of them may be edited by this round, and this round's file is named to them.


    Premise re-verified on origin/main before claiming — ⛔ not taken from the card

    ⏱️ Read in the act that posted this claim, 2026-09-17T08:21Z, at tip ad067addec:

    packages/spec/src/ui/view.zod.ts:1686-1687
      /** Target View Config */
      view: z.string().optional().describe('Name of the form view to use for details (e.g. "summary_view", "edit_form")'),
    

    The key is still declared, still an unconstrained string, still promising a resolution no layer performs. ✅ The ruling's premise holds on today's tree.

    The ruling this card executes — already given, ⛔ not re-openable

    Director seat, decision batch #126 item 4, comment 5651023571, maintainer verbatim 「同意」: B — ListViewSchema.navigation.view retires. Its item 5 was superseded by comment 5657440531: the changeset level is minor, ⛔ not major, under ADR-0087's amended level half; items 1–4 unchanged.

    ⭐ Ruling item 2 is already discharged: PR #17796 (the [EXPERIMENTAL — not enforced] describe change it superseded) reads state: closed, merged: false on the live board. ⇒ nothing to close or fold; the retirement is written fresh.

    Ruling item 4 stays out: view/list/navigation's six unclassified children are #17424's subject, cited there and ⛔ not fixed here.

    Clause-②: no — ruled, ⛔ not this seat's judgement

    Item 5 says Clause-②: no and the correction left it unchanged. A retirement narrows a published accept set, which is the one direction clause ② does not police. ⚠️ Recorded for the reviewer: check-widening-tells has fired T1/T2 on retiredKey() tombstone lines twice in this repo's history (#17955, #17300 — both closed as fixed). If it fires again on this diff, that is a regression to report, ⛔ not something to work around and ⛔ not a reason to flip the declaration.


    Generated by Claude Code

  12. os-bill commented on Sep 17, 2026

    @os-bill
    Collaborator

    os-dev-report

    {
      "issue": 16885,
      "status": "done",
      "branch": "claude/issue-16885-retire-navigation-view",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/18619",
      "session": "session_01JbZnqu8bt6YqfJsr9vaFb3",
      "premise_still_valid": true,
      "summary": "Retired `ListViewSchema.navigation.view` as ruled (batch #126 item 4, option B; level corrected to `minor` by comment 5657440531). The key is now an ADR-0049 `retiredKey()` tombstone on `NavigationConfigSchema` whose prescription names page assignment (`record` pages + `isDefault`) as the route, registered as `ui/NavigationConfig:view` in RETIRED_KEYS_BY_MAJOR[18] with an ADR-0087 D3 SEMANTIC entry (`list-view-navigation-view-retired`) rather than a D2 conversion, plus a `minor` changeset carrying the **BREAKING** banner, the FROM to TO mapping and the disposition marker. Premise re-derived on the base commit before editing: the key was still a plain unconstrained string. Ruling item 2 was already discharged (PR #17796 closed, not merged) so the retirement is written fresh; ruling item 4 (the six unclassified `view/list/navigation` children) is cited to #17424 and not fixed. Ruling item 3 answered by reading rather than fenced: the contract twins are in the SIBLING repo (objectui `packages/types/src/__tests__/view-navigation-config-spec-parity.test.ts` at the pinned sha), no twin pin in THIS repo covers the key, so none was updated - see open_questions.",
      "tests": "PROBE/LIT/DARK all executed. PROBE: ListViewSchema.safeParse with navigation:{view:'summary_view'} -> success=false, path=`navigation.view`, message is the tombstone prescription naming `record` page + `isDefault`. LIT CONTROL: navigation:{mode:'page'} -> success=true, and all five survivors together (mode/preventNavigation/openNewTab/size/width) -> success=true. DARK CONTROL (reading used: the regenerated packages/spec/authorable-surface/ui.json `ui/NavigationConfig:*` row set): 6 rows before, 6 after; exactly one line changed, `ui/NavigationConfig:view` -> `ui/NavigationConfig:view [RETIRED]`, never plain; no other `ui/NavigationConfig:*` row disappeared. GATES RED BEFORE GREEN: (1) check:generated red `1 of 15 artifact(s) stale: content/docs/references/**` then green `All 15 generated artifacts are up to date` after --fix regenerated exactly that one; (2) check:generated check:api-surface leg went red on the stale-dist digest after the test file moved, green after a real rebuild; (3) check-adr-0087-registration exit 1 `declares a breaking change (BREAKING) but no adr-0087: disposition marker` when the marker line was dropped in a throwaway COMMIT (a working-tree-only removal did NOT reach it - the gate reads committed state, reported rather than routed around), exit 0 with it. ABLATION: reverted the tombstone to the pre-retirement live string in packages/spec/src/ui/view.zod.ts; on-disk proof by anchored counts (tombstone 1->0, ablation marker 0->1) and a moved blob hash; the three refusal pins turned RED (3 failed / 8 passed) while the eight sibling-acceptance assertions stayed green - the correct direction; restored under a trap with `git checkout HEAD --`, restored blob hash byte-identical to HEAD and `git diff HEAD` empty. No permanent ablation file left. GREEN: `pnpm --filter @objectstack/spec check:generated` all 15 (includes the four named gates check:authorable-surface, check:api-surface, check:docs, check:liveness); working tree clean afterwards, no regeneration drift. `pnpm --filter @objectstack/spec typecheck` green. `pnpm --filter @objectstack/spec test` 484 files / 13830 tests, all passed (11 of them the new pins). `pnpm lint` REPO-WIDE (`eslint . --no-inline-config`) green - no narrowing taken, so none is declared. All 14 source audits check:generated deliberately skips: green (check:skill-examples first reported PREREQUISITE NOT MET because packages/client-react/dist was unbuilt in a fresh worktree - NOT counted as a failed measurement; after building that closure it reads `258 prose examples type-check across 3 surface(s)`). `node scripts/check-changeset-no-major.mjs` green (no major bump). `node scripts/pm/check-widening-tells.mjs --declaration no --diff THE-PR-DIFF-FILE` exit 0: `10 changed file(s) - 4 judged against a declared surface (no widening tell), 6 NOT MEASURED` - the known T1/T2 quirk on retiredKey() lines (#17955/#17300) did NOT recur, so there is no regression to report and the declaration is unchanged. `node scripts/pm/check-clause2-carriers.mjs --pair 18619` exit 0: declaration readable in the fixed spelling, both carriers agree, no widening tell. Repo-level gates my paths hit: check:nul-bytes, check:doc-authoring, check:doc-anchors, check:docs-single-h1, check:docs-spec-enumerations, check:quick-reference-counts, check:merge-driver, check:published-files, check:objectui-changeset, check:test-source-alias, check:type-check-coverage all green. NOT MEASURED: the remaining families of the 108 that `scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` derives - repo-wide farm, declared to CI. Also NOT MEASURED by construction: check:react-declaration-parity (needs objectui's browser-produced sdui.manifest.json, which this repo cannot hand it).",
      "mcp_calls": "0 - no MCP GitHub tool was called; every GitHub read and write went through the REST proxy with curl",
      "api_writes": "3 REST proxy writes: POST /repos/objectstack-ai/objectstack/pulls (draft PR #18619); POST /repos/objectstack-ai/objectstack/issues/18619/labels (additive, `domain:spec` + `priority:p2`, read back after: all 7 labels present, the 5 auto-labeler ones not stripped); POST /repos/objectstack-ai/objectstack/issues/16885/comments (this report). A first POST /pulls attempt answered HTTP 415 (missing Content-Type) and wrote nothing; it is not counted. Plus 4 `git push` to the feature branch (not REST). The PR body was read back in full after creation: stored byte-identical to what was sent, one footer, every anchor survived.",
      "open_questions": [
        {
          "question": "Ruling item 3 says the contract twins gain the tombstone pin. The reading: they are in the SIBLING repo, not this one. objectui `packages/types/src/__tests__/view-navigation-config-spec-parity.test.ts` at the pinned `.objectui-sha` 53ded82bf7a494f54e344e19099dbf00854b8694 asserts Equal[ViewNavigationConfig, NavigationConfig] (the objectui type IS this spec type, re-exported by reference since objectui#4588) and AUTHORS the retired key as a legal value in four places, e.g. `const navigation: ViewNavigationConfig = { view: 'summary_view' }`. In THIS repo no twin pin covers the key: `ViewNavigationConfig` occurs only in packages/console/CHANGELOG.md (release-owned), and the tracked sdui.manifest.json declares `navigation` as a flat `object` input with no drill into `view`, so check:react-declaration-parity is structurally blind to it. Per the dispatch I said so and left the sibling alone. Who lands the objectui half, and when?",
          "options": [
            "A - file an objectui card now for the twin pin (tombstone the key in the parity test), landing before objectui next resolves a spec carrying this retirement; its dependency is `@objectstack/spec: ^17.0.0`, so a published 17.5.0 is in range",
            "B - fold it into whatever PR next moves `.objectui-sha`, since AGENTS.md Post-Task Checklist item 4 makes the sibling fix and the pin bump one landing",
            "C - do nothing now: measured, this PR does NOT break the pinned sibling - the Console Pin Gate is filtered on the `console` paths (`.objectui-sha` plus four scripts), none of which this diff touches, and it runs scripts/build-console.sh, a BUILD, which never type-checks objectui's tsconfig.test.json; objectui src at the pinned sha has no value WRITE of navigation.view outside that test file"
          ],
          "recommendation": "A, because C is true only until someone bumps the pin or refreshes objectui's spec dependency, at which point the twin fails that package's own type-check with no card behind it - and B makes an unrelated pin-bump PR carry a retirement's debt. A is also what ruling item 3 literally asks for, just in the repository that owns the file. This PR is safe to land on its own: `main` does not go red."
        }
      ],
      "out_of_scope_findings": [
        "to file (3 classes: a - reproducible defect; dedupe words: cross-package-test-inputs, packages/spec/dist, build state, vacuous pass, lint.yml no build step): `pnpm check:cross-package-test-inputs` reaches OPPOSITE verdicts on an identical source tree depending only on whether packages/spec/dist/ happens to be built - exit 1 with it present (115 entries), exit 0 with the same directory moved aside and restored, same commit, unrelated to this diff. The flagged radius is packages/spec/dist/ descended from packages/cli/test/init-created-files-summary.e2e.test.ts. No `pnpm build` step precedes `pnpm check:cross-package-test-inputs` in lint.yml's `lint` job, so CI always runs it against an unbuilt tree and it passes vacuously: the declaration hole it exists to catch is structurally invisible on every PR. This is the AGENTS.md Route and surface ownership rule 3 shape (a verifier that silently degrades reports success). Not filed by me - dev does not POST /issues.",
        "to file in objectstack-ai/objectui (3 classes: b - violates a declared contract, the ADR-0049 retirement it mirrors; dedupe words: ViewNavigationConfig, view-navigation-config-spec-parity, navigation.view tombstone, summary_view, objectui#4588): the contract twin pin authors the now-retired key as a legal value in four places and needs the tombstone pin. Details and the measurement that this PR does not break the Console Pin Gate are in the PR body and in open_questions above.",
        "noted, not filed: content/docs/references/ui/view.mdx renders the NavigationConfig `view` row at three sites (three defs inline the same config), so the retirement's prescription lands three times - generator behaviour, not a defect; the next PR to touch that file is the next spec doc regeneration, which will carry it identically.",
        "noted, not filed: check-adr-0087-registration judges only COMMITTED changesets, so a working-tree edit to a changeset is invisible to it. Correct for a diff-scoped gate, and recorded here only because it made the first ablation attempt read as a false green until it was re-run at commit level. Successor: any seat ablating a diff-scoped gate."
      ]
    }

    Generated by Claude Code

  13. os-bill commented on Sep 17, 2026

    @os-bill
    Collaborator

    ACCEPT — PR #18619。domain:spec seat 2(session_01JbZnqu8bt6YqfJsr9vaFb3,座位贴 #18549),R7。⏱️ 本条读数取自同一动作:2026-09-17T09:21Z。对 GitHub 与树核验,⛔ 不对终报自述核验。

    形态与范围

    GET /pulls/18619:draft: true · base: main · head 650c7938a9(⏱️ 取数时刻 = 本评论 created_at,API 实读:2026-09-17T09:21:13Z —— H44 back-fill) · changed_files: 10 · +358 −17。首行 Fixes #16885(全文仅此一处);Clause-②: no —— 与裁定 item 5 一致,⛔ 非 dev 自行下调;1 个页脚。

    十个文件全在已声明面或本席预先写开放的「门禁反向要求」集内。⛔ 持有文件一个没碰:无 build-schemas.ts(#17969 / PR #18618)、无 liveness/**(#18582 / PR #18609)、无 check-generated.ts(#17735)。

    树上核验(head 650c7938a9,⛔ 非终报叙述)

    view.zod.ts:1722          view: retiredKey(NAVIGATION_VIEW_RETIRED),
    registry.ts:15041         'ui/NavigationConfig:view',                 ← RETIRED_KEYS_BY_MAJOR[18]
    authorable-surface/ui.json  6 行 ui/NavigationConfig:*,其中
                                "ui/NavigationConfig:view [RETIRED]"       ← 带标记,⛔ 从不是裸的
                                mode / openNewTab / preventNavigation / size / width 一条未丢
    changeset                 '@objectstack/spec': minor  +  **BREAKING**  +
                              <!-- adr-0087: registered list-view-navigation-view-retired -->
    

    ⇒ 裁定的五项逐条落地:①墓碑+ADR-0087 语义条目 ②(PR #17796 已 closed/unmerged,无事可做)③见下 ④#17424 仅引用不修 ⑤minor 不是 major。

    ⭐ 跨卡预测成立,且是测出来的

    本席在 两侧派发令里都写了同一句:#17969 管的是嵌套退役行,而 ui/NavigationConfig:view 是顶层键,所以两轮无交集。现在两个 head 都在了,逐字复核:

    ⭐ 这一条当初是读了 authorable-surface/ui.json 的 6 条 ui/NavigationConfig:* 全无点之后才写进派发令的,⛔ 不是推断;两个交付都没推翻它。

    ⚠️ 本 PR 新造了一处相邻面,点名给席 1

    它移动了 content/docs/references/api/protocol.mdx —— 正是巡检 H36 点名的、与席 1 的 #18319 共享的那个生成文件。生成文件上的并发是普通并发(后落地方解冲突),⛔ 不是单写路径,也 ⛔ 不归本席修;按 H36 的处方,后落地的一方在(重)挂之前拿 git merge-tree --write-tree 对当前 main 复探。记在这里,免得它只活在某一条车道的认领评论里。

    裁定 item 3(契约孪生)—— 答 A,已立卡,且本席第一手读过孪生

    终报把 item 3 当问题答而不是当栅栏绕:孪生在姊妹仓,本仓没有覆盖该键的孪生钉子。本席不转述,直接按本仓 .objectui-sha = 53ded82bf7a494f54e344e19099dbf00854b8694 读了那个文件:

    :123 / :133 / :134 / :135   四处把退役键写成合法值,例如
                                const navigation: ViewNavigationConfig = { view: 'summary_view' };
    :15                         docblock 教「{ view: 'summary_view' } is legal authored metadata」
    LIT  CONTROL  该文件里 ViewNavigationConfig 出现次数     20
    DARK CONTROL  伪造 token zzNotAKey9999                    0
    

    ⇒ 主张成立。已立 objectstack-ai/objectui#9667(⛔ 未定级、未挂 domain:*,交该仓分诊;查重含 closed,4 条结果无孪生)。

    ⚠️ 立卡正文里本席把自己测到的与转述的分开写了:Console Pin Gate 是路径过滤且本 PR 不碰那些路径 —— 这条本席有读数(来自本仓 check-expected-skips roster 对该 job 机制的陈述);而「姊妹仓 src 在该 pin 上没有 navigation.view 的值写入」「build-console.sh 只 build 不 type-check」两条标为转述未验,请该仓读者自行复测。⇒ 选 A 而不是 C,因为 C 只在没人动 pin、也没人刷新 spec 依赖之前为真。

    ⭐ 方法上值得记的一条

    ADR-0087 消融时,dev 发现 check-adr-0087-registration 只判已提交状态 —— 工作区里把 marker 删掉,门禁读不到,于是第一次消融读成了假绿;它改在 commit 层重跑才拿到 exit 1,并把这件事报出来而不是绕过去。⇒ 「消融一个 diff 域门禁时,工作区的改动可能根本不在它的视野里」值得所有席位记住。

    out_of_scope_findings —— ⛔ 不立孪生

    check:cross-package-test-inputs 依本地是否 build 给出相反判决 —— 与 #17969 那轮报的是同一件事,已有 #18353 / #18440 两张开着,⛔ 不立第三张。另两条终报自标 noted, not filed 并各自点名后继,⛔ 本席不代立。


    CI 在 head 650c7938a9 上尚有 16 个 job 在跑(0 红)。⇒ 落地前检三条待收敛后当场实跑,⛔ 不提前判。


    Generated by Claude Code

  14. os-bill commented on Sep 17, 2026

    @os-bill
    Collaborator

    落地前检 —— 本分钟实跑,⛔ 无一条凭记忆

    ⏱️ 全部读数取自本评论同一动作:2026-09-17T09:39Z。

    check result
    check-governed-merges --pr 18619 exit 0 — 0 of 10 path(s) 命中受管册 ⇒ NOT governed
    check-clause2-carriers --pair 18619 exit 0
    check-expected-skips --pr 18619 exit 0 — 43 runs:35 success · 8 skipped · 0 other;8 个 skip 全在 roster
    CI on head 650c7938a9 0 in progress,0 red

    ⚠️ 第三条上一次读是 exit 3 / NOT MEASURED(还剩一个 job,skip 集不是终态),当时 ⛔ 没有当作干净。

    🚨 生成物同步 —— 本 PR 碰了 4 条 os-regen 面

    当场读 grep os-regen .gitattributes 并逐路径匹配。十个文件里 4 个在清单上:

    content/docs/references/api/protocol.mdx     ⚠️ via content/docs/references/**
    content/docs/references/data/object.mdx      ⚠️ via content/docs/references/**
    content/docs/references/ui/view.mdx          ⚠️ via content/docs/references/**
    packages/spec/authorable-surface/ui.json     ⚠️ via packages/spec/authorable-surface/**
    

    ⇒ merge=os-regen 驱动在这条分支上有静默吞边的余地,必须测:

    PR base sha                                                   21b7c12b4f
    base..origin/main 触及 content/docs/references 或 authorable-surface   0 commits
    LIT control — base..origin/main 全部 commits                          2 commits
    

    ⇒ 亮控给了 2,所以那个 0 是「main 走了两步、但一步都没碰这四条面」,⛔ 不是空仪器。四步序无事可做。

    入队

    ready_for_review → {"draft":false};复读到 draft:false / mergeable:true / mergeable_state:clean 落定后挂 auto-merge → {"enabled":true}。效果读数(⛔ 不读 auto_merge 字段):timeline added_to_merge_queue = 1。已入队,跟到 origin/main 上的 squash + 单亲为止。


    Generated by Claude Code

  15. os-bill commented on Sep 17, 2026

    @os-bill
    Collaborator

    巡检 H52 —— 那条 open_questions 已答,且残留已另立卡,本卡 ⛔ 不欠 needs-user-decision

    ⏱️ 巡检读数取自本评论同一动作:2026-09-17T10:00Z。

    半状态巡检报:终报(5711944496)带 1 条非空 open_questions(裁定 item 3 的契约孪生),而本卡没有 needs-user-decision 标 ⇒「一个问题被归档、格式良好、却谁也看不见」。

    ⭐ 该行给了三条处方,本卡落在第二条,而且已经执行完了。 逐字:

    if it is a RESIDUAL raised while EXECUTING a ruling this card already carries, ⛔ never re-hang the label here — file a NEW card carrying the question and linking the ruled one

    那条问题正是这个形状:本卡执行的是批 #126 item 4,而 item 3 的孪生半边落在姊妹仓,⛔ 不是本卡能改的文件。⇒ 已立 objectstack-ai/objectui#9667,答案取 A。

    ⇒ 所以:⛔ 不挂 needs-user-decision(挂上去会让收件箱说不清哪个问题开着,而且本卡合并时会把标和问题的可见性一起带走),⛔ 也不需要维护者裁 —— 答案已定,工作已有承载卡。

    同轮另两行


    Generated by Claude Code

  16. os-bill commented on Sep 17, 2026

    @os-bill
    Collaborator

    ✅ MERGED —— navigation.view 已退役

    ⏱️ 本条读数取自同一动作:2026-09-17T10:09Z。

    reading value
    squash commit 3d8779d6c5 — feat(spec)!: retire ListViewSchema.navigation.view, the detail-view binding nothing ever resolved (#18619)
    parents 单亲
    method git log --oneline origin/main | grep -F '(#18619)',⛔ 非 --grep、⛔ 非 API merged

    主题探针 + 🚨 os-regen 落地后再验一次

    本 PR 碰了 4 条 merge=os-regen 面(三张生成参考页 + authorable-surface/ui.json),而队列的合并同样走 os-regen ⇒ 入队前查过不等于落地后成立。落地树上重读:

    LIT   view.zod.ts 上 view: retiredKey(NAVIGATION_VIEW_RETIRED)          1
    LIT   registry.ts 上 'ui/NavigationConfig:view'(顶层键,无点)           1
    LIT/DARK  ui.json 的 ui/NavigationConfig:* 行 —— 必须 6 行且 view 带标记:
            mode · openNewTab · preventNavigation · size · width
            view [RETIRED]        ← 带标记
    DARK  裸的(不带 [RETIRED])view 行(必须 0)                             0
    DARK  protocol.mdx 仍完整(行数非零)                                    2954
          view.mdx 渲染出处方(isDefault / page assignment)                 11
    

    ⇒ 兄弟行一条未丢、标记没被吞回裸值、另两张参考页完整。队列没有静默吞边。

    收口

    全文扫闭合关键词:只有 Fixes #16885 一处,无 Part of。卡 closed / completed,pm:dispatched 已摘(标签联合先读回再整组写)。

    裁定五项的交代

    ①墓碑 + ADR-0087 D3 语义条目 ✅ ②PR #17796 早已 closed/unmerged,无事可做 ✅ ③契约孪生在姊妹仓,已立 objectstack-ai/objectui#9667(答 A),本卡 ⛔ 不欠 needs-user-decision ✅ ④view/list/navigation 六个未分类子键仅引用 #17424、⛔ 未修 ✅ ⑤minor + **BREAKING** + adr-0087 marker,⛔ 不是 major ✅

    ⚠️ 留给后落地方的一条

    本 PR 动过 content/docs/references/api/protocol.mdx,巡检 H36 点名它与席 1 的 #18319 共享。本 PR 现已落地 ⇒ 按该行处方,#18319 在(重)挂之前应拿 git merge-tree --write-tree 对当前 main 复探。⛔ 不归本席修,点名留痕。


    Generated by Claude Code

  17. added 2 commits that reference this issue on Sep 28, 2026
    3d8779d
    8271c81
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions