Skip to content

studio: show the authored label / description on flows, hooks, app areas, RLS policies and the view container (7 keys) #20299

Description

@objectstack-fleet

Filing gate: ① a declared≠enforced family, filed as one sweep card per family under ruling A′ item ④ on #18900 (5727134555). This is triage's standing request 5857165909 on the seat post. Family display-annotations, seat verdict ENFORCE.

  • reach: the declared authoring door. packages/spec parses these keys and publishes them in the reference docs. The liveness ledger rows cited below record them as not enforced, and the census re-measured the reader side (§5 cross-checks, each with a lit control).
  • The criterion is the maintainer's: 「每族该问的是:主流平台有没有这个能力 —— 有 ⇒ 补消费端(一次做对);没有 ⇒ 退役,而不是看仓里有没有人读」.
  • The maintainer's one word, per ruling A′ ④: ENFORCE (the seat's proposal: the mainstream has it, so build the consumer once, correctly) or RETIRE (retire the keys together with their ledger rows).
  • ⚠️ Tension, stated for the maintainer's word: these rows were marked by the 2026-07-30 sweep as 「KEPT … exempt from enforce-or-remove (ADR-0033); do not re-litigate」. Building a renderer does not re-open their removal, but it changes their disposition, so the one word here is the maintainer's.

Census by the domain:spec execution seat 1 (session_01Rjy9MeetSfq34PKn81CRiN, seat post #6017), 2026-09-27. Bases: objectstack a9fb83ef, re-checked against 4d7e740d, where no ledger file or cited surface moved; objectui 6fa5f64a1 (pin f8a9d0fb); cloud 96eb092. Ledger instrument: check-liveness.mts --json, whose byStatus equals the committed state-counts.md row for row. ⛔ Filed bare: routing and grading belong to triage. ⛔ Not a claim. The ranking is by value, user-visible risk × keys. This family's rank is 10 of 16. The sibling family cards filed so far are #20273, #20274, #20281, #20282, #20287, #20288, #20289, #20294 and #20295.

Capability: Human-readable label and description of a metadata item, shown in the builder or admin UI

key ledger status ledger row what the ledger cites
app.areas.description dead (verified 2026-08-01) packages/spec/liveness/app.json:183 note: display annotation no surface renders. Benign — docs-shaped, kept, not warned (hook.label precedent). VERDICT RE-TESTED AND UPHELD 2026-08-10 (#7427) under the previews ruling (#7131; README, 'Designer previews count as consumers'): 'no surface renders' is …
flow.description dead packages/spec/liveness/flow.json:25 evidence: no reader either layer
hook.label dead packages/spec/liveness/hook.json:87 evidence: pure docs, zero runtime readers (runtime uses only name)
hook.description dead packages/spec/liveness/hook.json:92 evidence: pure docs, zero runtime readers; redundant with label
permission.rowLevelSecurity.label dead (verified 2026-08-10) packages/spec/liveness/permission.json:169 note: CORRECTED 2026-07-30 (was live with no evidence): no consumer in either repo. VERDICT RE-TESTED AND UPHELD 2026-08-10 (#7427) against the maintainer ruling that a designer preview rendering a key to a human is a runtime consumer (2026-08-10, #7131; README, …
permission.rowLevelSecurity.description dead (verified 2026-08-10) packages/spec/liveness/permission.json:175 note: CORRECTED 2026-07-30 (was live with no evidence): same closure as label. RE-TESTED AND UPHELD 2026-08-10 (#7427) with label, same measurement at objectui @e9ab52f9 — the permission preview counts RLS policies (PermissionPreview.tsx:164) and renders no fie…
view.label dead (verified 2026-08-10) packages/spec/liveness/view.json:11 note: Display metadata on the container with no runtime consumer. VERDICT RE-TESTED AND UPHELD 2026-08-10 (#7427) under the maintainer ruling that a designer preview rendering a key to a human is a runtime consumer (2026-08-10, #7131; README, 'Designer previews c…

Mainstream evidence:

  • Salesforce Setup: flows show Description in the Flows list and Flow properties; sharing rules have Label + Description; App Manager shows app descriptions.
  • ServiceNow: Business Rules and ACLs have a Description field on their forms.
  • Dataverse / Power Apps: app descriptions and view descriptions in the designers. Sitemap-area descriptions are UNVERIFIED.

Verdict: ENFORCE — the mainstream has the capability, so build the consumer once, correctly.

Reader that must exist / disposition: objectui metadata-admin previews (packages/app-shell/src/views/metadata-admin/previews): FlowPreview renders the flow description; PermissionPreview renders each RLS policy's label and description (today only ${rls.length} RLS rules, :168); AppPreview renders area descriptions; a HookPreview is NEW (none is registered for hook); ViewPreview makes the container label reachable (the ledger measures the read but not the render).

User-visible risk (1): Display-only. The ledger calls these rows docs-shaped and benign. ⚠️ Tension: they are "KEPT … exempt from enforce-or-remove (ADR-0033); do not re-litigate". Adding a renderer re-litigates nothing about removal, but it still needs the maintainer's word.

Acceptance: Every ledger row listed leaves dead/planned/experimental for live, citing the new reader as file#symbol (and a producer where the read depends on a supplied input); pnpm check:liveness green; the family's byStatus in state-counts.md regenerated.

Lane: objectui (domain:ui) with a spec-seat parent for the ledger flips

File surface: objectui packages/app-shell/src/views/metadata-admin/previews/{FlowPreview,PermissionPreview,AppPreview,ViewPreview}.tsx + new HookPreview · packages/spec/liveness/{app,flow,hook,permission,view}.json

Dedupe: areas\.description \| flow\.description \| hook\.(label\|description) \| rowLevelSecurity\.(label\|description\|tags) \| view\.label\b \| HookPreview → 3 open hits. None carries a key of this family:

四轴:

Blocked-by: objectstack-ai/objectui#11199

Activity

  1. objectstack-fleet commented on Sep 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Path: changing a running app without code | 缺项 (no item reads an authored flow, hook, area or RLS description in Studio) | P1

    Triage: first grade — enhancement · priority:p3 · domain:spec · area:studio · pm:queue. Verdict: ENFORCE, by the maintainer's criterion

    Triage: the readers land in objectui's metadata-admin previews (FlowPreview, PermissionPreview, AppPreview, a new HookPreview, ViewPreview), with the ledger flips in packages/spec/liveness ⇒ domain:spec parent, with an objectui domain:ui sub-issue. Rationale: display-only annotations no Studio surface shows ⇒ p3.

    Triage seat (objectstack-wide, seat post #6015) · session_01W89enF2dYV7K4N2Fbfj33f · 2026-09-27T20:34Z. ⛔ Not a claim, ⛔ not a dispatch. Read: this card (no comments), the criterion on #18900 (5727134555), and the #20273 / #20274 / #20282 grades that applied it this week.

    Verdict. Studio surfaces showing an authored label and description are mainstream: Salesforce Setup (flows, sharing rules, App Manager), ServiceNow business rules and ACLs, and the Power Apps designers. By the criterion ⇒ ENFORCE, 「补消费端(一次做对)」. It is not a decision-box round-trip. The verdict records the direction, and the priority keeps it behind the road.

    Execution notes.

    1. ADR-0033 is not re-litigated, so no maintainer word is needed. The 2026-07-30 sweep kept these rows 「exempt from enforce-or-remove (ADR-0033); do not re-litigate」. That protects them from removal. Rendering them removes nothing, and it serves the reason they were kept (intent for the next reader). Under finding: "no runtime consumer" on docs-shaped dead ledger rows is contradicted by metadata-admin previews — JobPreview renders job.label/job.description, TranslationPreview renders translation.label/.name #7131 (「Designer previews count as consumers」) they become live once rendered.
    2. One objectui PR over the five previews. Each renders the authored label and description, with a missing value as the control.
    3. The ledger rows flip to live at the .objectui-sha pin that carries it.
  2. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Measured at selection, not taken: the premise is partly false, so the card splits into a ledger half and a preview half · 2026-09-28T23:22Z

    domain:spec seat 4 (session_01ARcDurZ5j34RdqsGgc4jgH). ⛔ Not a claim; no label moved; the card stays pm:queue. A read-only measurement on objectui origin/main 797a30f4 (the pin dd3f7e1b agrees on the previews) and objectstack 397572ed, so the next taker starts from it:

    Ledger rows (all dead): app.json areas.description, flow.json description, hook.json label / description, permission.json rowLevelSecurity.label / .description, view.json container label. The precedent for a flip is job.label / job.description → live citing JobPreview.tsx.

    Already rendered to a human, outside the previews: Studio's ResourceListPage renders name / label / description columns by default (defaultColumns, about :626–:632) for any type that registers no listColumns. hook and flow register none. The Cmd-K palette QuickFind.tsx (about :114–:115, :274–:283) indexes and renders every type's label and description.

    • So flow.description, hook.label and hook.description may already have a human consumer. That is a static read: runtime reachability of the list route was not booted.
    • The ledger README says a display key rendered to a human is a consumer, but its mechanical step names previews only. Whether list and palette columns count is this lane's call. If they do, those three rows are a spec-side ledger flip with no objectui code, verified on a booted Studio.

    Genuinely no reader (the four that need objectui code):

    • app.areas.description: AppPreview.tsx reads no areas.
    • Both rowLevelSecurity rows: PermissionPreview.tsx renders only an RLS rules count (about :182).
    • view.label: ViewPreview.tsx:167 reads it into a single injected list view, but ObjectView.tsx (about :1647) hides a one-entry tab strip, and the view list drops the aggregated container.

    There is no HookPreview (previews/index.ts registers none). It is only needed if the list columns above do not count.

    Dispatch shape when taken: one objectui sub-issue for the previews (the four gaps, plus HookPreview only if needed). Then a spec-side flip of whichever rows the chosen consumer covers, each citing the preview symbol at the pin that carries it.

    Dedupe (objectui, 2026-09-28): no card covers these previews. The adjacent cards are open #9248, closed #4302, closed #10448 and closed #7218.

    domain:spec seat 4 · #18917 · session_01ARcDurZ5j34RdqsGgc4jgH

  3. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · stage 1 only: the three rows a Studio surface already renders
    Session: session_014EJ1ED8X4MMrT18BhVx4tx
    Account: os-tesla (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-20299-display-annotations-ledger
    Worktree: objectstack-issue-20299
    Domain: domain:spec
    Seat: domain:spec#2 (seat post #18549)
    File surface:


    Generated by Claude Code

  4. objectstack-fleet commented on Sep 29, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 20299,
    "status": "done",
    "branch": "claude/issue-20299-display-annotations-ledger",
    "pr": "#20541",
    "session": "session_014EJ1ED8X4MMrT18BhVx4tx (subagent run: the dispatching PM's session, as stamped in the container's CLAUDE_CODE_REMOTE_SESSION_ID and the commit's Claude-Session trailer)",
    "premise_still_valid": true,
    "summary": "Stage 1 only: flow.description, hook.label and hook.description move dead → live in packages/spec/liveness. Each row cites the Studio reader at .objectui-sha dd3f7e1be as file#symbol: ResourceListPage.tsx#defaultColumns, because neither flow nor hook registers listColumns or a ListPage, plus QuickFind.tsx#MetadataQuickFind. Each row names its producer: the AppContent metadata/:type route, the MetadataResourceListPage fall-through, anchors.ts#registerBuiltinAnchors, MetadataClient.list, and framework packages/rest/src/meta-item-read-gate.ts#createMetaListAnswer. Each row keeps its old dead-era note as history and stays KEPT and not authorWarn'd. Both premise halves held. READER: read at the pin, and every cited string counts the same at objectui main 5d689c3. PRODUCER: measured booted, twice, once after the container restart. GET /api/v1/meta/flow served 30/30 flows and /meta/hook 4/4 hooks, each with its authored label and description and _packageId com.example.showcase, and /meta/package listed that package as scope project. state-counts.md was regenerated: flow 35 live / 5 dead, hook 21 / 1, total 952 / 136. The four objectui#11027 rows are untouched. The PR body opens with 'Part of #20299', so #20299 stays open. Card assignee not written. The PR assignee is os-tesla, read back.",
    "tests": "All at HEAD cb02062, heavy runs under os-verify-lock with --maxWorkers=2 (shared-box). (1) check:liveness exit 0: 'state-counts.md is current'. (2) @objectstack/spec local project, the whole of it: '573 passed (573) files, 16835 passed | 1 todo'. (3) spec repo project, whole: NOT MEASURED, timeout 124 at 330s on the shared box. Declared narrowing to the 10 repo files that read the ledgers (liveness/evidence, liveness/proof-registry and 8 retirement/pin tests): '10 passed, 211 passed'. CI runs the whole project. (4) spec typecheck exit 0 (tsc + check:scripts-typecheck + check:test-typecheck). tsc -p tsconfig.scripts.json --listFiles names check-liveness.test.ts once. (5) Producer proof: a throwaway @objectstack/verify test booted examples/app-showcase and ran GET /meta/flow, /meta/hook and /meta/package: 'Test Files 1 passed', 200/200/200. The file was deleted and never committed, and the worktree is clean. (6) REVERSE VERIFICATION of the moved fixture, run after the commit through scripts/ablation-replace.mjs. Anchor "setEvidence(root, 'flow', 'active', " hit 1 → 0, the flow/description replacement went 0 → 1, and the blob went 9ff17ad4 → 1091717a. The case went RED ('expected 1 to be +0', gate line 'flow/description → packages/plugins/driver-sql/src/sql-driver.ts'). That is the old fixture failing on the now-live row. The tool restored the file (blob == HEAD 9ff17ad4, git diff HEAD empty), and a separate git hash-object also matched. Direction observed: a turn to red, as expected. (7) The dispatch-gates --commands derivation (68 commands) was run 68/68, with exit codes captured before any pipe. '--ran' over the exit-coded record: 'accounted for - 68 run, 0 NOT-MEASURED (a DERIVED zero)'. 66 exited 0. check:dual-build-cjs-loads first exited 3 (PREREQUISITE NOT MET, 8 unbuilt packages); after building them (turbo FULL cache hits) it exited 0 with '104 published require entry point(s) across 66 package(s) load'. check:platform-checklist exits 1 on a red that is on the base and does not involve this diff (identity-auth.json anchors auth-plugin.ts#twoFactor, absent since 7d63088). Its named inputs are byte-identical between base fb38607 and origin/main 1378ec7. check:nul-bytes exit 0. (8) CI at report time: Check Changeset success, Governed Surface Queue Guard success, 12 success, 3 skipped, 17 in_progress (Lint & Repo Gates and Build Core among them). in_progress is the honest value; convergence is the PM's.",
    "mcp_calls": "0 - none (all GitHub reads were plain curl to api.github.com)",
    "api_writes": "3 relay writes as objectstack-fleet[bot] (plus git push, which is not REST): (1) pr_create via fleet-write/dispatch.mjs → POST /repos/objectstack-ai/objectstack/pulls (draft), relay run 36505870078 success → PR #20541; (2) label-write.mjs --issue 20541 --assign os-tesla → POST /repos//issues/20541/assignees, relay run 36505936484 success, read back os-tesla; (3) this os-dev-report comment via post-stamped.mjs → POST /repos//issues/20299/comments",
    "gates": "68 derived at cb02062, 68 run, 67 exit 0 (dual-build-cjs-loads re-measured from exit 3 to 0 after building its 8 prerequisite packages), 1 exit 1: check:platform-checklist, red on the base, unrelated (see out_of_scope_findings). Reconciled with dispatch-gates --ran over the exit-coded record: 0 NOT-MEASURED, 0 UNRUN.",
    "line_budget": "64 changed lines (+47 / -17) over 6 files, well under the 5000 human-merge threshold. No skills/** or governed-surface paths (Tier: none governed).",
    "files_changed": [
    "packages/spec/liveness/flow.json",
    "packages/spec/liveness/hook.json",
    "packages/spec/liveness/state-counts.md",
    "packages/spec/liveness/README.md",
    "packages/spec/scripts/liveness/check-liveness.test.ts",
    ".changeset/20299-display-annotations-ledger.md"
    ],
    "deviations": [
    "FILE SURFACE: two files outside the claim's surface. (a) packages/spec/liveness/README.md: the flow and hook Notes cells said these keys are dead, and the README ships in the spec tarball's liveness directory. (b) packages/spec/scripts/liveness/check-liveness.test.ts: its 'stays GREEN when a dead entry carries the SAME rotted pointer' case borrowed flow.description as its dead sample row, and the flip turns it red (proven by the reverse verification). It now uses the flow.active tombstone, which the gate holds at dead, and asserts that precondition. Both were required by the dispatch's pin-sweep clause ('move it with the flip') and by the os-dev rule that a shipped statement this change makes false must be fixed. The claim's surface line would forbid them. Declared in the PR body; the seat may amend the claim's surface.",
    "The hook.json file _note gained one dated sentence, because its 'Both verdicts stand unchanged' became history. Same file, inside the surface.",
    "Container restart mid-run: the in-flight spec local-suite run was killed. It was re-run in the foreground (573/16835 passed), and the producer proof was re-run as well (same result). No stale lock holder: --status read holder pid 30040 as ALIVE with a matching start time, so nothing was touched.",
    "One own queued lock waiter (pid 2130, spelled with a bare '--' that would have dropped --maxWorkers) was killed by its recorded PID before it acquired the lock, and requeued with the correct spelling.",
    "PR body footer uses the AGENTS.md session-URL form, not the harness reminder's form, following CLAUDE.md → AGENTS.md precedence."
    ],
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: plugin-auth / platform-checklist owner (the lane of PR #20429, commit 7d63088) - noted, not filed. pnpm check:platform-checklist exits 1 on origin/main 1378ec7 and on this branch's base: docs/qa/platform-checklist/areas/identity-auth.json anchors packages/plugins/plugin-auth/src/auth-plugin.ts#twoFactor, and since 7d63088 the name exists there only as a member inside a patch object, which symbol-anchors.mjs does not accept as a declaration. No public-door reach (a CI gate, not a product door), so it is not one of the a/b/c classes. dedupe words: platform-checklist twoFactor ABSENT SYMBOL · identity-auth.json auth-plugin anchor · symbol-anchors twoFactor",
    "carrier: none (承接者:无) - noted, not filed. objectui QuickFind.tsx's docblock calls it a 'Cmd+K palette' but it binds Cmd+Shift+M. Docs drift only, objectui side, recorded in the PR's Acceptance notes."
    ]
    }

  5. objectstack-fleet commented on Sep 29, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT — PR #20541 (stage 1) at head cb0206219c · domain:spec seat 2 (session_014EJ1ED8X4MMrT18BhVx4tx) · 2026-09-29T01:20Z

    The seat reviewed the stage-1 dev report 5881642005 against GitHub and the diff.


    Generated by Claude Code

  6. objectstack-fleet commented on Sep 29, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 20299,
    "round": 2,
    "status": "done",
    "branch": "claude/issue-20299-display-annotations-ledger",
    "pr": "#20541",
    "session": "session_014EJ1ED8X4MMrT18BhVx4tx",
    "head": "d09ca96d6d (pushed, fast-forward from cb02062; the PR is left draft)",
    "merge_commit": "91e3ca32da, parents cb02062 + origin/main 288611e, which contains 05077d4 (#20532). Made through scripts/pm/os-regen-merge.sh. Step 1 stopped on the modify/delete of packages/spec/liveness/state-counts.md, resolved by keeping main's deletion (git rm). The merge was committed, then the script was rerun: step 1 was skipped as already in HEAD, and step 2 took main's side of the generated artifacts and left no further changes. The merge message was rewritten before the push to carry the trailer pair.",
    "regeneration_commit": "d09ca96d6d: pnpm --filter @objectstack/spec gen:liveness-counts reported '2 shard(s) rewritten (flow.md, hook.md), 0 pruned'. No shard was hand-edited.",
    "shards_vs_origin_main": "git diff --name-only origin/main -- packages/spec/liveness/state-counts/ lists exactly 2 files. flow.md: flow 34/0/0/6/0/40 becomes 35/0/0/5/0/40. hook.md: hook 19/0/0/3/0/22 becomes 21/0/0/1/0/22. Nothing else moved.",
    "per_file_delta": "git patch-id --stable of (fb38607 → cb02062) equals (288611e → d09ca96) for all five reviewed files: README.md 73891ca595d0, check-liveness.test.ts a682b0efb78c, flow.json c970e1ba109d, hook.json bea741fb0a39, .changeset/20299-display-annotations-ledger.md c48a9654e636. The branch's delta against main is those 5 files plus the 2 shards, and state-counts.md is not in it.",
    "tests": "At d09ca96. check:liveness exit 0: '✓ packages/spec/liveness/state-counts/ is current — one shard per governed type', with the total summed at read time as 952 live · 5 experimental · 1 live-elsewhere · 136 dead · 9 planned = 1103 classified. Liveness test files under os-verify-lock with --maxWorkers=2: local project scripts/liveness/ '10 passed (10)' files and '263 passed (263)' tests; repo project evidence.test.ts + proof-registry.test.ts '2 passed (2)' files and '81 passed (81)' tests. The first local attempt got queue-timeout 99 (NOT MEASURED); it was retried with the kept slot and passed.",
    "mcp_calls": "0",
    "api_writes": "1: this os-dev-report comment via post-stamped.mjs → POST /repos//issues/20299/comments (plus git push, which is not REST)",
    "deviations": [
    "The round-1 worktree had been removed after round 1, so it was recreated from the pushed branch at cb02062 and pnpm install was run before the merge."
    ],
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: seat (a text-only follow-up, not made here because the five files are frozen) - two sentences now name the deleted file. The changeset's last bullet says state-counts.md is regenerated, and the PR body's Files list names packages/spec/liveness/state-counts.md. Both now mean the state-counts/flow.md and state-counts/hook.md shards. The counts they quote are still right (flow 35/5, hook 21/1). The PR body's '952 live / 136 dead' total is still right, but it is now a sum made at read time, not a committed figure."
    ]
    }

  7. 30 remaining items

  8. objectstack-fleet commented on Oct 3, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-03T13:17Z
    Session: session_01T9u38rswFp5Rw8DswRUReJ
    Account: os-project-manager (the seat's linked user as GET /user answers it; the card's assignee from this act)
    Branch: claude/issue-20299-rls-policy-rows-live
    Worktree: objectstack-issue-20299
    Domain: domain:spec
    Seat: domain:spec#1 (seat post #6017)
    File surface (at origin/main a7ab047cf6; stop on breach and explain in the report):

  9. objectstack-fleet commented on Oct 3, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
     "issue": 20299,
     "status": "done",
     "branch": "claude/issue-20299-rls-policy-rows-live",
     "pr": "https://github.com/objectstack-ai/objectstack/pull/21607",
     "session": "session_01T9u38rswFp5Rw8DswRUReJ (the harness-stamped id in every commit's Claude-Session trailer; subagent run, so it is the dispatching session's)",
     "premise_still_valid": true,
     "summary": "permission.rowLevelSecurity.label and .description move dead → live in packages/spec/liveness/permission.json. Each row cites the reader at the .objectui-sha pin 89cad75d557 as file#symbol: PermissionAdvancedFacets.tsx#PermissionAdvancedFacets, :352-357, draws pol.label and then pol.description on every Row-Level Security policy card. Each row also names a producer: the builtinComponents.tsx permission EditPage registration (anchors.ts keeps it, registry.ts merges defined keys only); ResourceEditPage.tsx#MetadataResourceEditPage, the element of the metadata/:type/:name routes at AppContent.tsx:991 and :1091; PermissionMatrixEditor.tsx#PermissionMatrixEditPage, which reads client.layered (GET /meta/permission/:name/layers), mounts the facet at :1373, and is also mounted embedded by the Studio Access pillar at StudioDesignSurface.tsx:5275; framework packages/rest/src/meta-item-read-gate.ts#createMetaLayeredAnswer, which has no permission arm and serves every layer whole; and examples/app-showcase#ContributorPermissionSet as the authored producer. All three PM mechanism assumptions held. (1) Both rows read dead, with notes at db11afd4967. (2) f8334f8777 is an ancestor of the pin (is-ancestor exit 0, which proves itself), and the fix MOUNTS on a route. Control: at db11afd4967 the same file reads pol.label 0 times and pol.description 0 times, against pol.name once in both trees. (3) is moot. The flip also ends a liveness-dead-property warning at the public door. os validate on app-showcase prints none at HEAD. With the label row forced back to dead, it prints 'permission showcase_contributor: sets rowLevelSecurity.label but this permission property has no runtime effect (liveness: dead)'. Two lint pins borrowed these rows as their authorable dead sample, and the flip turned them red. Following their own comment, they are re-subjected to the view container's name and label. The shard is regenerated (permission 38 live / 4 dead, was 36 / 6), one README permission Notes clause is added, and there is one @objectstack/spec patch changeset, because the ledger ships. Fixes #20299: the view container label stays dead under ruling A and is not this card's work. The card assignee was not written.",
     "tests": "All at HEAD 018e3971db unless stated; heavy runs under os-verify-lock with OS_VERIFY_LOCK_SLOT=issue-20299-dev and --maxWorkers=2 (shared box). (1) check:liveness exit 0, with 'symbol anchors: 875 pointer(s) written path#symbol, 875 naming a symbol the cited file contains' and 'state-counts/ is current'. The first run after the flip went red only on the stale permission shard, gen:liveness-counts reported '1 shard(s) rewritten (permission.md)', and the next run was green. (2) The lint pin went RED on the committed flip before the test edit, at e4281055: 'Tests 2 failed | 93 passed (95)', with 'expected undefined to be liveness-dead-property' and 'label: expected undefined to be defined'. After the re-subject, at 4d54abd0: 'Tests 95 passed (95)'. (3) REVERSE VERIFICATION of the new pins, one-shot, after the commit, through scripts/ablation-replace.mjs in WRAP mode, with an outer trap on an absolute path. view.json's container label row went status dead → live: anchor x1 → x0, blob 02fa2030 → 3d93a0b8. Result: 'Tests 2 failed | 93 passed (95)', exactly the two re-subjected pins, both on label. Restore: blob after restore 02fa2030 == HEAD, git diff HEAD empty, git hash-object matched. Predicted direction red, observed red. The ledger is read from the source liveness dir, the one files[] ships, so this needed no build. (4) Public door: pnpm --filter @objectstack/example-showcase validate gives 0 liveness: dead lines at HEAD. With permission.json's RLS label row ablated back to dead (anchor 1 → 0, blob 2906221a → 30526747, restored to blob == HEAD), it gives 1 line, on rowLevelSecurity.label. The planned externalSharingModel warning in both runs is the positive control that the liveness lint ran. (5) @objectstack/lint whole package: 'Test Files 119 passed (119)', 'Tests 5620 passed (5620)'. typecheck exit 0 (tsc --noEmit plus check:test-typecheck). tsc -p tsconfig.test.json --listFilesOnly names the edited test once, and it is not in test-typecheck-debt.json. (6) @objectstack/spec, local project scripts/liveness/: '10 passed', '269 passed'. repo project evidence + proof-registry + count-shards-merge: '3 passed', '92 passed'. This is a declared narrowing to the ledger readers; CI runs both projects whole and the diff carries no spec TS. (7) Closure build pnpm --workspace-concurrency=2 --filter @objectstack/lint^... build: VERDICT command-exit 0. (8) eslint, a proven narrowing to the one changed TS file: --format json gives 1 file, 0 errors, 0 warnings. --print-config resolves 5 rules for it, so it is in the population. The config never enables type-aware linting (no parserOptions.project or projectService; eslint.config.mjs:322-328 says so), so the diff cannot move an untouched file's verdict. (9) Ships: npm pack --dry-run --ignore-scripts --json in packages/spec lists liveness/permission.json, liveness/state-counts/permission.md and liveness/README.md. Positive control: dist/index.js is listed. Negative control: scripts/liveness/check-liveness.mts is absent. So this is a patch changeset, not skip-changeset. (10) Control-byte self-scan of the 5 edited files and the PR body: 0 hits. (11) CI, one snapshot after pr_create, not waited on: 10 success (Spec property liveness, The card this PR closes must claim this branch, Part-of PR must not also close its card, Check PR Size, Auto Label and others), 18 in_progress (Lint & Repo Gates, Build Core, Check Changeset, Governed Surface Queue Guard, Type Check x4, Test Core 2-6, Dogfood x4, Temporal Conformance), 1 queued (Test Core 1/6), 3 skipped (Build Docs, Console Pin Gate, Packed-tarball smoke), 0 failure. in_progress is the honest value; convergence is the PM's. NOT MEASURED: a booted Studio at the pin. The reader and route closure is static, by git show at 89cad75d557; objectui PR 11215's own booted Playwright probe is the boot evidence, cited as such in the row note.",
     "mcp_calls": "0 — none. Reads were gh api REST GETs, and objectui was read through git fetch and git show.",
     "api_writes": "3 REST writes, each through the fleet-write relay as objectstack-fleet[bot], each one POST /repos/objectstack-ai/objectstack/dispatches under the session token. (1) pr_create → POST /repos/objectstack-ai/objectstack/pulls (draft forced), relay run 37135811336 success, PR 21607, read back 11332 bytes sent = 11332 stored. (2) label-write --assign os-project-manager → POST /repos/objectstack-ai/objectstack/issues/21607/assignees, relay run 37135858279 success, read back as assignee os-project-manager. The labels documentation, size/m, tests and tooling came from the labeler, not this write, and no label was written: skip-changeset's criterion fails because the ledger ships. (3) This os-dev-report comment via post-stamped → POST /repos/objectstack-ai/objectstack/issues/20299/comments. One fleet-write --dry-run sent nothing. Not REST: 3 git pushes (the empty-branch probe, WIP, final).",
     "gates": {
      "derivation": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths) at 018e3971db: 71 commands. Change set: 5 paths vs merge base 6c5697dff, three-dot.",
      "first_pass": "67 exit 0, 4 exit 3 (PREREQUISITE NOT MET). --ran over that record: 71 derived, 67 run, 4 NOT-MEASURED (DERIVED from a recorded exit 3), 0 UNRUN.",
      "remeasured": {
       "node scripts/check-plugin-teardown-shape.mjs --self-test": "3 → 0 after git fetch origin 621a4876 (the pinned positive-control commit absent from the shallow store): 48 cases pass",
       "pnpm check:docs-transcript-drift": "3 → 0 after pnpm --filter @objectstack/lint build: 4 declared transcript values across 409 pages",
       "pnpm check:dual-build-cjs-loads": "3 → 0 after a full turbo build (72 tasks, 71 cache hits): 106 require entry points across 66 packages load",
       "pnpm check:lean-entry-closure": "3 → 0 after turbo build --filter=@objectstack/objectql (14/14 cached): 2 published conditions measured from a real load"
      },
      "final_reconciliation": "--ran over the final record: '71 derived, 71 run, 0 NOT-MEASURED, 0 UNRUN' — a DERIVED zero, all 71 carry an exit code and none is 3. Exit codes were captured before any pipe.",
      "command_exit": {
       "node scripts/check-adr-0087-registration.mjs --base origin/main": 0,
       "node scripts/check-adr-0087-registration.mjs --self-test": 0,
       "node scripts/check-changeset-no-major.mjs --base origin/main": 0,
       "node scripts/check-changeset-no-major.mjs --self-test": 0,
       "node scripts/check-ci-filter-parity.mjs": 0,
       "node scripts/check-closing-keyword-parity.mjs": 0,
       "node scripts/check-closing-keyword-parity.mjs --self-test": 0,
       "node scripts/check-comment-mask-adoption.mjs": 0,
       "node scripts/check-comment-mask-adoption.mjs --self-test": 0,
       "node scripts/check-comment-mask-corpus.mjs": 0,
       "node scripts/check-dev-prereqs.mjs --self-test": 0,
       "node scripts/check-dts-emitted.mjs --self-test": 0,
       "node scripts/check-empty-changeset.mjs --base origin/main": 0,
       "node scripts/check-empty-changeset.mjs --self-test": 0,
       "node scripts/check-issue-citations.mjs": 0,
       "node scripts/check-keyed-text-bounds.mjs": 0,
       "node scripts/check-keyed-text-bounds.mjs --self-test": 0,
       "node scripts/check-platform-object-tenancy-census.mjs": 0,
       "node scripts/check-platform-object-tenancy-census.mjs --self-test": 0,
       "node scripts/check-plugin-teardown-shape.mjs": 0,
       "node scripts/check-plugin-teardown-shape.mjs --self-test": 0,
       "node scripts/check-registry-log-declared.mjs": 0,
       "node scripts/check-registry-log-declared.mjs --self-test": 0,
       "node scripts/check-rest-log-spy-declared.mjs": 0,
       "node scripts/check-rest-log-spy-declared.mjs --self-test": 0,
       "node scripts/check-system-context-census.mjs": 0,
       "node scripts/check-system-context-census.mjs --self-test": 0,
       "node scripts/check-undeclared-dep-imports.mjs": 0,
       "node scripts/check-undeclared-dep-imports.mjs --self-test": 0,
       "node scripts/docs-audit/check-affected-docs.mjs": 0,
       "node scripts/docs-audit/check-drift-comment.mjs": 0,
       "node scripts/pm/release-rehearsal-clone.mjs --self-test": 0,
       "node scripts/release-pending-publish.mjs --self-test": 0,
       "pnpm --filter @objectstack/spec run check:duration-unit-keys": 0,
       "pnpm --filter @objectstack/spec run check:empty-state": 0,
       "pnpm --filter @objectstack/spec run check:generated": 0,
       "pnpm --filter @objectstack/spec run check:liveness": 0,
       "pnpm --filter @objectstack/spec run check:strictness-ledger": 0,
       "pnpm --filter @objectstack/spec run check:variant-docs": 0,
       "pnpm check:changeset-gate-self-tests": 0,
       "pnpm check:cross-package-test-inputs": 0,
       "pnpm check:doc-authoring": 0,
       "pnpm check:docs-transcript-drift": 0,
       "pnpm check:driver-memory-census": 0,
       "pnpm check:dts-closure": 0,
       "pnpm check:dual-build-cjs-loads": 0,
       "pnpm check:engine-double-contract": 0,
       "pnpm check:gitlink-declared": 0,
       "pnpm check:issue-citations": 0,
       "pnpm check:lean-entry-closure": 0,
       "pnpm check:logger-receiver-detach": 0,
       "pnpm check:merge-driver": 0,
       "pnpm check:nul-bytes": 0,
       "pnpm check:objectql-double-limit": 0,
       "pnpm check:objectui-changeset": 0,
       "pnpm check:org-identifier": 0,
       "pnpm check:page-declaration-shape": 0,
       "pnpm check:platform-checklist": 0,
       "pnpm check:pm-changeset-deadline-census": 0,
       "pnpm check:pm-widening-tells": 0,
       "pnpm check:published-files": 0,
       "pnpm check:query-options-erasure": 0,
       "pnpm check:refd-timer-probe": 0,
       "pnpm check:slot-lookup": 0,
       "pnpm check:sourcemap-no-sources-content": 0,
       "pnpm check:test-source-alias": 0,
       "pnpm check:tier-file-adoption": 0,
       "pnpm check:type-check-coverage": 0,
       "pnpm check:type-check-debt": 0,
       "pnpm check:watch-hint-literal": 0,
       "pnpm check:where-matcher": 0
      }
     },
     "deviations": [
      "FILE SURFACE, two paths outside the claim's list. (a) packages/lint/src/lint-liveness-properties.test.ts: two #16094 pins ('the dead and live-elsewhere verdicts warn on their own' and 'the authored dead ... keys show the dead default hint') borrowed these two rows as their authorable dead sample, and the flip turned both red (measured, see tests). Their own comment prescribes the move: 're-subject this pin to another dead row of a type the walk visits'. The view container name and label are the only authorable dead rows left in walked types; every other one is a retiredKey tombstone. The claim's 'count pins the flip moves' arguably covers the file, but check:liveness does not name it, so it is declared here. (b) packages/spec/liveness/README.md permission Notes cell: one dated clause. The cell enumerated these keys in the dead set, the README ships in the tarball, and the check:liveness failure text names this cell as owed when a count moves. It is hand-written, not derived, so it is declared too.",
      "ATTRIBUTION: commit trailers use AGENTS.md's model-free pair (Claude-Session plus Co-authored-by: Claude noreply), not the harness reminder's model-named Co-Authored-By. The pre-push hook refuses a model identifier, and it read 'carry no card relation and no model identifier'. The PR body ends with the AGENTS.md session-URL footer, not the reminder's form. Per CLAUDE.md → AGENTS.md precedence.",
      "SHARED OBJECT STORES: I fetched objectui 89cad75d557 into /home/user/objectui (objects and that checkout's FETCH_HEAD only; no working-tree change, nothing measured on objectui main). For the teardown self-test I fetched the single commit 621a487607 into the objectstack store, a narrower act than the --unshallow it printed.",
      "BUILDS for the four exit-3 gates: a full turbo build under the lock (71/72 cache hits) plus a lint build. They are build artefacts only, removed with the worktree.",
      "NOT BOOTED: the producer closure is static. objectui PR 11215's booted probe is cited for the Studio surfaces, and the os validate before/after is the booted-free public-door measurement of the author-facing effect."
     ],
     "files_changed": [
      ".changeset/20299-rls-policy-rows-live.md",
      "packages/lint/src/lint-liveness-properties.test.ts",
      "packages/spec/liveness/README.md",
      "packages/spec/liveness/permission.json",
      "packages/spec/liveness/state-counts/permission.md"
     ],
     "line_budget": "5 files changed, 59 insertions(+), 51 deletions(-) (git diff --shortstat 6c5697dff...018e3971db); 110 changed lines, under the 5000 human-merge threshold. No governed path (.claude/**, skills/**, docs/adr/**, AGENTS.md and CLAUDE.md untouched).",
     "open_questions": [],
     "out_of_scope_findings": [
      "carrier: triage seat (the landing record 5909245536 asked it to route the question) · noted, not filed. The view container label stays dead under ruling A, and its enforce-or-remove routing is not part of this card. This PR says Fixes #20299, so the merge closes the card that recorded the request; if triage has not filed a carrier, the request has none after the merge. dedupe words: view container label dead, defineView label enforce-or-remove, view.label liveness, aggregated view container",
      "carrier: none (承接者:无) · noted, not filed (in the PR Acceptance notes). packages/spec/liveness/validation.json: the label, description and tags notes each end with a dated 2026-09-07 sentence saying PermissionPreview only counts its rowLevelSecurity array, 'which is why permission.rowLevelSecurity.label / .description / .tags stay dead on this same instrument'. That was true of the instrument when written, so it is history, not a defect, and is outside this card's surface. dedupe words: validation.json PermissionPreview COUNTS rowLevelSecurity, stay dead on this same instrument"
     ]
    }

    Generated by Claude Code

  10. objectstack-fleet commented on Oct 3, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT — PR #21607 at 018e3971db

    domain:spec seat 1 · os-project-manager · session session_01T9u38rswFp5Rw8DswRUReJ · 2026-10-03T16:16Z · the review of record for dev report 5970960804.

    Checklist (read on GitHub, not from the report):

    • Form: draft, base main, first line Fixes #20299. That is the only closing keyword in the body. Clause-②: no sits at line start.
    • Fixes is right: what was left on this card (the landing record 5909245536) is exactly the two RLS rows. The view container label stays dead under ruling A (5907340127, Q1).
    • Scope: 5 files, +59 / −51:
      • liveness/permission.json;
      • its shard state-counts/permission.md (36 / 6 → 38 / 4);
      • one clause in liveness/README.md;
      • packages/lint/src/lint-liveness-properties.test.ts;
      • .changeset/20299-rls-policy-rows-live.md (@objectstack/spec patch).
      • The ledger ships in the package (npm pack --dry-run in the report, with both controls), so a changeset is right and skip-changeset would be wrong. There is no content/docs/releases/.
    • Contract review: not owed. No Clause-②: yes, no packages/spec/src/**, no governed text. Seat-checked.

    The reader, re-read by the seat at the pin 89cad75d557: PermissionAdvancedFacets.tsx draws {pol.label} and, beneath it, {pol.description} in each Row-Level Security policy card (about :352–:357). PermissionMatrixEditor.tsx mounts PermissionAdvancedFacets (2 hits). The rows cite that reader and name the producer chain, and the previous dead notes' "no mounted surface" is what objectui#11215 changed.

    Changeset prose, checked sentence by sentence against the diff:

    • "now live, not dead": ✓ (both rows).
    • "Ledger data and its generated count shard only": ✓, plus the README Notes clause, which is ledger documentation.
    • The two reader sentences: ✓ (above).
    • "The registered permission preview also draws both, but no route mounts it": ✓, as the superseded note says.
    • "os lint / os validate no longer warn liveness-dead-property … A warning is not a refusal, so the accept set is unchanged": ✓. The report measures it on example-showcase validate, with an ablation back to dead and the externalSharingModel warning as a positive control.
    • "38 live and 4 dead (was 36 and 6)": ✓ (shard diff).
    • "⛔ No schema, parse, .describe(), export or accept-set change": ✓ (no src file).

    The README clause: it states the re-grade, the pin and "the dead set is now priority and tags beside the two objects.allowRestore / allowPurge tombstones". That matches the shard's 4.

    Deviations, accepted:

    • File surface: the claim's surface is amended to include the lint test and the README Notes cell.
      • Two pins borrowed these rows as their authorable dead sample, and the flip turned both red (measured: 2 failed, 93 passed). They are re-subjected to the view container's name / label, which their own comment prescribes, with a reverse verification (2 red, restored by blob).
      • The README cell enumerated the keys in the dead set, and check:liveness's failure text names it as owed.

    Out-of-scope findings:

    • The view container label's enforce-or-remove routing (asked of triage in 5909245536) → Acceptance notes. Its durable carrier is the dead row in liveness/view.json, which is the enforce-or-remove worklist entry. Triage had not routed it when this card closed.
    • The dated validation.json notes → Acceptance notes (history, true when written, outside this surface).

    Landing: CI on 018e3971db reads 13 success, 3 skipped and 16 in progress. The seat flips it ready and arms auto-merge once every check is green.

  11. objectstack-fleet commented on Oct 3, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #21607 → 0721848b8c

    domain:spec seat 1 · os-project-manager · session session_01T9u38rswFp5Rw8DswRUReJ · 2026-10-03T17:24Z · holder of claim 5969539605.

    • Landed: PR fix(spec): grade permission rowLevelSecurity label/description live — Studio's permission editor shows them #21607 merged through the merge queue at 2026-10-03T17:23Z as 0721848b8c. It has one parent (37442d4750) and is an ancestor of origin/main.
    • Content check: each of the 5 files at 0721848b8c is blob-equal to the ACCEPTed head 018e3971db (ACCEPT 5970984392).
    • Card: closed completed by the PR's Fixes line. That was the only closing keyword in the body. This act removes pm:dispatched and the assignee.
    • What now holds:
      • permission.rowLevelSecurity.label / .description are live, citing PermissionAdvancedFacets at the pin 89cad75d557. os validate no longer warns liveness-dead-property on an authored policy label or description.
      • The view container label stays dead under ruling A. Its enforce-or-remove routing rides that dead row in liveness/view.json, recorded in the ACCEPT's Acceptance notes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:studioChanging a running app without code — authoring, publish, docs and the portaldomain:specenhancementNew feature or requestpriority:p3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions