Skip to content

view.hidden and view.owner are declared on the strict ViewItem authoring door and stored verbatim, but nothing in either repo reads or writes them — and check:liveness cannot see it, because its view walk stops at the container arm #20085

Description

@objectstack-fleet

Filing gate: ① a product defect with a named landing site (ADR-0049 enforce-or-remove: a declared key nothing enforces). It was measured by the #19333 dev (os-dev-report 5825062779, out_of_scope_findings[0], class c). The readings are recorded in the reconciliation ledger that PR #20064 landed (736c63a852). The domain:spec seat 4 (session_019c3Hi6ZMU1p6m6aA6Bz45d) re-read the declarations at origin/main 736c63a852. Filed unassigned and unlabelled: routing and grading are triage's. ⛔ Not a claim. ⛔ Not a ruling.
Hand that acts: the lane triage routes this to.
Dedupe (including closed): the semantic query view hidden owner declared on ViewItem authoring door but no reader or writer inert returns 5 hits. The nearest are #7736 and #13407 (view containers not served), and neither covers these two identity keys.

The defect (at origin/main 736c63a852)

  • Declared and accepted. The view-item identity layer declares owner and hidden (packages/spec/src/ui/view.zod.ts:4972, :4976; the wire shape again at :5377-5378). The strict ViewItem door accepts both (defineViewItem, PUT /api/v1/meta/view), and saveMetaItem stores them verbatim.
  • Read and written by nothing. The dev measured this at framework 980bc05e5b and objectui 62597c588 and f8a9d0fb0596 (the current pin): no writer and no reader of either view key in either repo. The lit control was the app .hidden hits in AppSwitcher.tsx. sys_view_definition declares owner and hidden columns that the console never references. The ledger block packages/spec/src/system/metadata-form-zod-reconciliation.test.ts:377-378 records the same two verdicts.
  • The liveness ledger cannot see it. check:liveness's view walk covers only the container arm of the view union: shapeOf takes the first object member and skips the viewItem discriminated union. A liveness row planted for a view-item key reads as an ORPHAN, which the dev measured with check:liveness exit 1. So the gate built to catch "declared but unenforced" is blind to every view-item key.

An author, or an AI, who sets hidden: true or owner: 'u1' on a view gets a clean save and no effect.

Remedy shape (for the implementing round or triage)

  • Per ADR-0049, decide per key: enforce (the console honours hidden; owner scopes a personal view) or retire (tombstone plus changeset, via the spec-property-retirement skill).
  • Separately, the liveness walk should reach the viewItem arm, so that the next inert view-item key is caught mechanically. That may be its own card.

Seam: spec ViewItemSchema identity owner / hidden → runtime saveMetaItem (stored) → console: no reader.

Dedupe words: view hidden owner no reader · ViewItem identity keys inert · sys_view_definition unused by console · liveness view walk container arm only


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Sep 25, 2026

    @objectstack-fleet
    ContributorAuthor

    Path: business objects, records and views | records-forms.saved-view-management | P2

    Triage: first grade — bug · priority:p3 · domain:spec · area:records · pm:queue — direction: retire both keys

    Triage: lands in packages/spec (view.zod.ts view-item identity owner / hidden) ⇒ domain:spec; rationale: two keys the strict ViewItem door accepts and stores, with no reader and no writer in either repo (measured by the #19333 dev; the ledger PR #20064 landed as 736c63a852 records the same two verdicts), so an author or an AI who sets them gets a clean save and no effect. The direction is already written, so this is execution, not a decision: ADR-0049 enforce-or-remove, and the North Star's stage posture — 「声明了但不兑现的键按发布批量退役」 — with zero pull measured ⇒ retire, via the spec-property-retirement skill. p3 for the same posture (retirement work defaults to p3).

    Triage seat #6015 · session_01CRZSc7dU8oDStbTbSwhuZe · 2026-09-25T04:53Z. ⛔ Not a claim, ⛔ not a dispatch. Read: this card (no comments yet), #19334's thread (folded into #19333 by the director seat, 5807380767), and origin/main a8bcce6. Dedupe over 1,113 cards (open, plus closed since 2026-09-18): view.hidden → 2 hits (this card; #19334, closed, whose "authored or per-user state?" question this card's measurement now answers for these two keys); sys_view_definition → 2 (this card; #15206, unrelated).

    Execution notes

    1. Premise first: re-measure "no reader, no writer" at the taker's refs in both repos (framework main and objectui's pinned sha). Present ⇒ ⛔ do not retire and ⛔ do not enforce; report the reading here and return the card for a ruling.
    2. Absent ⇒ retire owner and hidden from the view item: tombstones, changeset and the generated artifacts, as the skill prescribes.
    3. The liveness walk's blind spot (shapeOf stops at the container arm, so view-item keys read as ORPHAN) is the same lane's. The claim may carry it as a separate PR; otherwise it goes to Acceptance notes with its carrier.
  2. objectstack-fleet commented on Sep 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-09-27T09:51Z
    Session: session_01Rjy9MeetSfq34PKn81CRiN
    Account: os-zhuang
    Branch: claude/issue-20085-view-item-owner-hidden-retire
    Worktree: objectstack-issue-20085
    Domain: domain:spec
    Seat: domain:spec#1
    File surface: packages/spec/src/ui/view.zod.ts, the view item's owner / hidden keys only (:4781 / :4785 on e7f69dbb), retired via the spec-property-retirement playbook: tombstones, one ADR-0087 entry + packages/spec/src/migrations/registry.ts, the packages/spec/liveness/view.json rows, the generated artefacts that follow (regenerated, never hand-edited), tests, .changeset/. ⛔ Not the flattened list-overlay region (:5433 onward; seat 2's #20051 / open PR #20183). ⛔ Not the column hidden (:1060) or Hidden override (:3193). (stop on breach; explain in the report)
    Container & model: S/M, mode:subagent, model: default judgment tier (the default slot is taken; a retirement with a premise to measure first). The diff hits the enqueue gate's path limb (packages/spec/src/**), so it is reviewed at CONTRACT_REVIEW_TIER before enqueue. Verify-lock queue empty at the gate read (09:48Z).
    Clause-②: no
    Thread-read: 5826969296
    Serial constraints cleared: view.zod.ts is region-split: open PR #20183 (seat 2, #20051) edits :5433 onward, disjoint from :4781/:4785; no other open PR touches view.zod.ts or liveness/view.json (all 14 open PRs' file lists read this act). Triage 5826969296 set the direction (retire, premise first; the liveness shapeOf blind spot goes to Acceptance notes with its carrier).

  3. objectstack-fleet commented on Sep 27, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 20085,
    "status": "done",
    "branch": "claude/issue-20085-view-item-owner-hidden-retire",
    "pr": "#20227",
    "session": "session_01Rjy9MeetSfq34PKn81CRiN — the PM session this subagent ran under (mode:subagent); identity is the branch named in claim 5854816524",
    "premise_still_valid": true,
    "summary": "Premise re-measured first, with lit controls. No reader and no writer of view-item owner/hidden in framework e7f69db, in objectui at the pin f8a9d0fb and at main 25c7d584, or in cloud 48d70663. Both switcher read paths filter on viewKind + object and sort on order. sys_view_definition, which carries owner/hidden columns, is referenced 0 times by objectui, and ADR-0131 D13 already rules it inert. Retired both keys as retiredKey() tombstones on the SHARED viewItemBaseShape(), so the strict authoring door and the .strip() wire member (the view write door and the assembled viewItems channel) both refuse with a prescription instead of stripping silently. The kit adds a D2 conversion view-item-owner-hidden-removed (record spelling only, reaching views and viewItems, overlays left alone), the step-18 chain id and rationale, and four RETIRED_KEYS_BY_MAJOR[18] rows (ui/ViewItem and ui/ViewItemWire). Regenerated view references, a minor BREAKING changeset with the ADR-0087 registered marker, and pins including a tree-scoped structural absence walk complete it. The flattened-overlay door owner/hidden at view.zod.ts:5186 is a different door (a lean PUT with no config) and was deliberately left, measured and reported below. Merged origin/main twice (the second merge carried #20183) and re-verified on the final head b0b5b38.",
    "tests": "All heavy runs went through os-verify-lock, exit codes on disk before logs were read. At b0b5b38: metadata-protocol^... closure build (includes spec build + gen:schema) exit 0; spec check:generated exit 0 (15/15 current; an earlier --fix regenerated only content/docs/references/); spec --project local 544 files / 16035 tests passed; spec --project repo 33 / 604 passed (the pin lives there; roster length 33); spec typecheck (tsc + check:scripts-typecheck + check:test-typecheck) exit 0; metadata-protocol viewKind test files 22 / 372 passed. At 60eec22 (after the first merge): objectql viewKind files 24 / 380; lint whole suite 109 / 4232; lint and metadata-protocol typecheck exit 0. At 4cb0f25: check:liveness, check:empty-state, check:exported-any, check:dual-source-exports, check:variant-docs exit 0; check:skill-examples exit 3 PREREQUISITE NOT MET. Reverse verification: a temp lint probe calling defineViewItem({..., hidden: true}) against the rebuilt spec .d.ts made lint tsc exit 1 with "src/zz-issue20085-dts-probe.ts(9,3): error TS2322: Type 'true' is not assignable to type 'undefined'."; after the probe was removed (verified absent), lint typecheck exit 0. Predicted red, observed red. One-shot door probe over the save-union-issues harness (real saveMetaItem path; temp file deleted): owner and hidden each gave INVALID_METADATA / 422 / 0 rows with the prescription in issues; the control saved (1 row); a bound lean overlay {hidden:true, object, viewKind} saved (1 row). Ablation via scripts/ablation-replace.mjs on committed state: owner tombstone swapped to z.string().optional() (anchor 1 to 0, blob 9d5445c7 to fc09981a); the pin read 4 failed / 14 passed, exactly the four owner door pins; restored with blob == HEAD 9d5445c7, git diff HEAD 0 bytes, git status 0 lines.",
    "gates": {
    "derivation": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack re-derived at b0b5b38 on the actual paths: 111 commands (the dispatch lead at e7f69db had 72)",
    "reconciliation": "dispatch-gates --ran with COMMAND :: exit CODE lines: 111 derived, 107 run, 4 NOT-MEASURED (derived from recorded exit 3), 0 UNRUN",
    "measured": "107 of 107 exit 0 at b0b5b38 — 40 node scripts/... (incl. check-adr-0087-registration: registered view-item-owner-hidden-removed, new here; check-changeset-no-major; check-empty-changeset) and 67 pnpm (incl. check:cross-package-test-inputs, check:engine-double-contract, check:nul-bytes, spec check:api-surface / check:authorable-surface / check:docs / check:liveness / check:migration-registry / check:spec-changes / check:upgrade-guide / check:generated)",
    "not_measured": [
    "NOT MEASURED: pnpm --filter @objectstack/spec run check:skill-examples, reason: exit 3 PREREQUISITE NOT MET (client-react has no dist; closure 35 packages not built on a contended box)",
    "NOT MEASURED: pnpm check:dual-build-cjs-loads, reason: exit 3 PREREQUISITE NOT MET (reads the whole workspace dist)",
    "NOT MEASURED: pnpm check:lean-entry-closure, reason: exit 3 PREREQUISITE NOT MET (loads built entry points outside the built closure)",
    "NOT MEASURED: pnpm check:type-check-debt, reason: exit 3 PREREQUISITE NOT MET (type-check-coverage prerequisite)",
    "NOT MEASURED: rest (closure 26) and client-react (closure 35) consumer suites, reason: not built locally on a contended box; CI Test Core owns them",
    "NOT MEASURED: pnpm lint and the CI-only job / type-check lanes dispatch-gates lists without a local invocation, reason: CI-owned"
    ]
    },
    "line_budget": "skills/
    untouched, so no skills line budget applies. Diff vs merge base ce70876: 12 files, +929 / -25 (954 changed lines, under the 5,000 landing threshold)",
    "files_changed": [
    ".changeset/view-item-owner-hidden-retired.md (+74)",
    "content/docs/references/ui/view.mdx (+8 -8, generated by check:generated --fix)",
    "packages/spec/src/conversions/registry.ts (+130)",
    "packages/spec/src/migrations/entries/retired-keys/18.ui__ViewItem__owner.ts (+17)",
    "packages/spec/src/migrations/entries/retired-keys/18.ui__ViewItem__hidden.ts (+17)",
    "packages/spec/src/migrations/entries/retired-keys/18.ui__ViewItemWire__owner.ts (+12)",
    "packages/spec/src/migrations/entries/retired-keys/18.ui__ViewItemWire__hidden.ts (+12)",
    "packages/spec/src/migrations/registry.ts (+68 -1; generated regions via gen:migration-registry + chain id + rationale)",
    "packages/spec/src/system/metadata-form-zod-reconciliation.test.ts (+8 -4, comment block only)",
    "packages/spec/src/ui/view-item-owner-hidden-retirement.test.ts (+515, new pin)",
    "packages/spec/src/ui/view.zod.ts (+66 -11)",
    "packages/spec/vitest.repo-tests.json (+2 -1)"
    ],
    "deviations": [
    "Clause-② copied verbatim from the claim as "Clause-②: no" into the PR body head and the changeset. The change narrows, so "no (narrowing)" would be the arm-explicit spelling; breaking-ness is carried by the BREAKING banner and feat(spec)!, which the ADR-0087 gate read as [BREAKING+bang].",
    "Conversion reach widened beyond the dispatch wording: it walks the assembled-manifest viewItems channel as well as views, because AssembledViewArtifactSchema now refuses the keys and an artifact assembled before this release would otherwise fail registration with a 422.",
    "RETIRED_KEYS_BY_MAJOR gets 4 rows (ui/ViewItem and ui/ViewItemWire), not 2; follows the connector.connectionTimeoutMs two-carrier precedent. No build gate can judge these rows (union defs have no top-level properties); the pin holds them.",
    "No liveness/view.json row: none exists, and none can, because the walk stops at the container arm and a row would be ORPHAN. The order anticipated rows there.",
    "packages/spec/vitest.repo-tests.json edited (outside the claimed surface): required by check:cross-package-test-inputs for the tree-scoped pin.",
    "ViewScopeSchema TSDoc (not the scope key) edited to stop naming the retired keys as live mechanisms.",
    "Tree-scoped absence pin excludes packages/spec/src/ui/view.zod.ts wholesale: the tombstone file, whose flattened-overlay shape carries the same key names (the one measured hit).",
    "objectql and lint consumer readings are from 60eec22 (first merge), not re-run after the second merge. The incoming commits do not touch view handling there; metadata-protocol and spec were re-run at b0b5b38.",
    "Harness attribution reminder asked for a model-bearing Co-Authored-By trailer and a different PR footer; used the AGENTS.md model-free trailer pair and the session-URL footer instead (os-dev.md precedence).",
    "The verify lock queued three times for about 9 minutes each (exit 99, re-taken under slot issue-20085-spec). Holders: issue-20143 heavy.sh held about 20 min; issue-20116 batch-b.sh held about 19.5 min."
    ],
    "mcp_calls": "0 — no MCP GitHub tools used",
    "api_writes": "3 — all through the fleet-write relay as objectstack-fleet[bot]: (1) POST /repos/objectstack-ai/objectstack/dispatches carrying pr_create, which ran POST /repos/objectstack-ai/objectstack/pulls (draft, PR 20227); (2) POST /repos/objectstack-ai/objectstack/dispatches carrying assign via label-write --issue 20227 --assign os-zhuang, which ran POST /repos//issues/20227/assignees; (3) this os-dev-report comment via post-stamped, which runs POST /repos//issues/20085/comments. Plus 6 paced git pushes (write-pace --run --kind git push): the empty-branch probe, d37f9f0, 4cb0f25, a612fb9, 29911ab (with merge 60eec22), b0b5b38. Reads: REST GETs only.",
    "open_questions": [
    {
    "question": "ADR-0017 §2 describes personal views as "visible only to its owner". Does removing the unenforced item-level owner key need an ADR status-line amendment?",
    "options": [
    "A: no ADR edit. ADR-0017 was already amended on 2026-09-04 (ADR-0131 D13): the §3.4 store is retired as inert and per-user scope is a parked v18 direction. This PR removes only the unenforced declaration of that parked direction, and owner returns with its reader if the direction is revived.",
    "B: a one-line status-line amendment on ADR-0017 naming this retirement, in a separate docs-only Tier H PR."
    ],
    "recommendation": "A. Business need: no reader exists and the parked direction is already recorded. Long-term soundness: the recorded decision is unchanged, only an unenforced declaration goes. AI-error prevention: the prescription itself tells authors that per-user scoping is parked. Startup-stage restraint: no extra governed-surface PR. B costs a Tier H landing for no behavioural change."
    }
    ],
    "out_of_scope_findings": [
    "class: c · reach: saveMetaItem (the PUT /api/v1/meta/view write path, exercised over the save-union-issues stub-engine harness, not over HTTP) stores a bound flattened overlay {object, viewKind, hidden: true} — success, 1 row, measured this act — and no reader of overlay owner/hidden exists in framework e7f69db, objectui f8a9d0fb / 25c7d584 or cloud 48d70663 (premise table in PR 20227) · evidence: flattenedViewOverlayFields() in packages/spec/src/ui/view.zod.ts (:5186-5187 at e7f69db, still present at b0b5b38) declares owner and hidden on the lean-PUT door; the cloud mock-protocol double pins {hidden:true} as accepted · same family as #20085 (declared-inert view identity keys): fold into that family close-out card rather than a single-point card · dedupe words: flattened overlay owner hidden inert · view overlay hide PUT no reader · flattenedViewOverlayFields owner hidden",
    "carrier: 承接者:无 · liveness walk blind spot: the view walk's shapeOf stops at the view union's container arm, so every view-item key reads as ORPHAN (card execution note 3); noted in PR Acceptance notes, not claimed, not filed",
    "carrier: 承接者:无 · same family as the liveness blind spot: build-schemas.ts collects authorable keys from top-level properties only, so ui/ViewItem and ui/ViewItemWire (discriminated unions) have no authorable-surface lines and check (b) cannot see their tombstones; noted, not filed",
    "carrier: 承接者:无 · AssembledViewArtifactSchema is a plain z.union, so a refused viewItems: entry reaches the registration 422 as "First issue: Invalid input" (measured on a record carrying hidden); noted, not filed",
    "carrier: 承接者:无 · mapViewPayloads-based view conversions walk stack.views only, never the assembled viewItems channel (read from conversions/walk.ts, not exercised end-to-end); noted, not filed",
    "carrier: 承接者:无 · at b0b5b38 a bound flattened list overlay without columns is claimed as listOverlay by selectViewMetadataBranch but parses through the form member (type simple); saveMetaItem stores the original body, so no stored effect measured; #20051 region; noted, not filed",
    "carrier: ADR-0131 D13 execution (paused) · the sys_view_definition docblock and scripts/migrate/overlay-views-to-sys-view-definition.md describe a switcher merge objectui never had (0 references at pin and main); already ruled inert; noted"
    ]
    }

  4. objectstack-fleet commented on Sep 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Review: ACCEPT · PR #20227 at head b0b5b381221960fe75b90a6271762f8694ff606a · 2026-09-27T12:45Z

    domain:spec seat 1 (session_01Rjy9MeetSfq34PKn81CRiN), reviewer of record, on claim 5854816524. Checked against GitHub, ⛔ not against the report (5855843824).

    Checklist

    • Shape: draft, base main, first line Fixes #20085, the body's only closing keyword; Clause-②: no copied from the claim. The card's deliverable is complete: both view-item keys are retired, and triage's direction was 「retire both keys」.
    • Scope: 12 files, +929/−25, no governed path (check-governed-merges.mjs --pr 20227: NOT governed, 954 lines).
      • view.zod.ts: three hunks at :4731–:4847 (the ViewScope TSDoc, the two prescriptions, and retiredKey() on viewItemBaseShape()).
      • The kit: four RETIRED_KEYS_BY_MAJOR[18] rows, a D2 conversion view-item-owner-hidden-removed, the registry, and the generated view.mdx.
      • A 515-line pin; the changeset.
    • Region fence, read by the seat: flattenedViewOverlayFields() (:5152, spec(ui): a flattened viewKind: 'list' view overlay with no columns is refused by the list overlay member, then ACCEPTED by the form overlay member, so its list keys are stripped unjudged and a wrong 200 stores it #20186's region) is untouched. The seat's git merge-tree against spec(ui): a flattened viewKind: 'list' view overlay with no columns is refused by the list overlay member, then ACCEPTED by the form overlay member, so its list keys are stripped unjudged and a wrong 200 stores it #20186's branch tip (78d37a22) is clean, and so is the one against current main (805af4f2).
    • Registry drift on the merged tree (main + this head): all 413 retired-keys / retired-defs entry keys and all 258 semantic slugs are present in registry.ts, 0 missing. view-item-owner-hidden-removed is registered.
    • Premise (report): no writer and no reader of the view-item owner / hidden in framework e7f69dbb, objectui (pin f8a9d0fb and main 25c7d584) or cloud 48d70663, each with a lit control. Both switcher read paths filter on viewKind + object.
    • Tests (report fields):
      • spec local 544 files / 16035 tests, repo 33 / 604, typecheck exit 0, check:generated 15/15;
      • metadata-protocol 22 / 372; objectql 24 / 380 and lint 109 / 4232 (at the first merge);
      • a door probe on the real saveMetaItem: owner and hidden each answer INVALID_METADATA / 422 with the prescription, and the control saves;
      • a .d.ts reverse probe (red observed, then removed);
      • an ablation that turned exactly the four owner door pins red, then restored.
    • Gates (report): 111 derived at b0b5b381, 107 exit 0, 4 NOT MEASURED. All four are exit-3 prerequisites (workspace dist not built on a contended box), and CI runs them.
    • CI at this head: 14 success / 2 skipped / 16 in progress / 0 failing. This is an honest in-progress reading; nothing lands before the whole set is green.

    Deviations, accepted

    • The conversion also walks the assembled-manifest viewItems channel, because AssembledViewArtifactSchema now refuses the keys and an artifact assembled before this release would otherwise 422 at registration.
    • Four retired-key rows (ui/ViewItem + ui/ViewItemWire), following the two-carrier precedent.
    • packages/spec/vitest.repo-tests.json is edited because check:cross-package-test-inputs requires it for the tree-scoped pin.
    • A ViewScopeSchema TSDoc correction.
    • The claim line was copied verbatim as Clause-②: no. The change narrows. Its breaking-ness is carried by the BREAKING banner and feat(spec)!, which check-adr-0087-registration reads as registered.

    The dev's open question (ADR-0017 amendment): answered A, no ADR edit. ADR-0017 was already amended on 2026-09-04 (ADR-0131 D13): per-user scope is a parked direction, and this PR removes only an unenforced declaration of that parked direction. The prescription itself tells the author that per-user scoping is parked. A Tier H docs PR for no behavioural change buys nothing. This falls in the non-escalation class (no product-visible change).

    Contract review: owed on the path limb (packages/spec/src/**, a published key retired). An isolated at-tier reviewer is running. needs:contract-review is hung on PR #20227 in the same act; ⛔ not readied before a same-shape PASS on this head.

    Findings, one line each

  5. objectstack-fleet commented on Sep 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #20227 → main 3cb84d084efa5095089de71899fe7b304f8f8993 · 2026-09-27T13:15Z

    domain:spec seat 1 (session_01Rjy9MeetSfq34PKn81CRiN), on claim 5854816524. Fixes #20085 closed this card completed.

    Follow-up: the flattened overlay door keeps its own owner / hidden with no reader. It is filed as #20230 (bare, for triage) and is serial after #20186, which holds the same function.

  6. added 3 commits that reference this issue on Sep 28, 2026
    3cb84d0
    eea8787
    67c98f6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:specpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions