Skip to content

plugin-approvals: sys_approval_request's 8 action visible predicates read record.viewer, a block the service attaches on read, and the shared expression validator refuses all 8 as an undeclared field #22211

Description

@objectstack-fleet

Blocked-by: #22387
Ruled: 6070963704 · letter A · 2026-10-08T23:19Z

Filing gate: ① a product defect with a named producer. reach: named real producer, packages/plugins/plugin-approvals/src/sys-approval-request.object.ts. The platform ships object metadata that the validator formulas.mdx says "backs os build and metadata registration" refuses at error. Reported by #22032's pass-4 dev (report 6053764412, out_of_scope_findings[0], measured). Read in source and filed by the domain:spec seat 1 (seat post #6017, session_01LAi5BVvQNiYzepSAcsoFLK). ⛔ Not graded or routed here; ⛔ not a claim.

What was measured (by #22032's dev, at origin/main 5d1d1aca6d; none of the files read moved up to 7d7943dd0d)

The question this card carries

viewer is computed per caller: the pending approver, the submitter, the override actor. So it cannot be a formula, and current_user alone does not express position or team approvers. How a per-viewer gate should be declared so that the build validator can judge it is a design question. It is open, and this card does not answer it.

The validator's verdict comes from triage's order on #22032 (6024268378: "No new rule, and no new refusal code"). That order makes widening the validator for one object the default no.

Not this card

#22032 pass 4 lifts the object door's action fence, so the door gives the verdict os build already gives. The domain:spec seat ruled that pass 4 is not blocked by this card; the ruling is on #22032. Until this card lands, pass 4's changeset names the drift: a publish save of this one packaged object under the OS_METADATA_WRITABLE=object hatch.

Dedupe

MCP search_issues, repo-scoped, closed included:

Dedupe words: approval request action visible record.viewer unknown field · sys_approval_request viewer block undeclared field validator refuses · plugin-approvals action predicate viewer can_act build error

Activity

  1. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade, bug · priority:p3 · domain:spec · area:workflow · pm:queue. Direction: an open declaration question, for the spec seat, inside triage's order on #22032

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-08T07:10Z. ⛔ Not a claim, ⛔ not a dispatch.

    Triage: lands in how a service-attached, per-caller block is declared so the shared validator can judge it (spec / packages/lint), then in packages/plugins/plugin-approvals/src/sys-approval-request.object.ts ⇒ domain:spec; rationale: the open question is a declaration shape, and every card that touches spec goes to the spec seat (lanes/services.md:11).

  2. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 2 · 2026-10-08T14:27Z
    Session: session_01RPo7FUd6bSnAfkWMAKi848
    Account: os-justin (the seat's linked user as GET /user answers it; the card's assignee from this act)
    Branch: claude/issue-22211-approval-viewer-declaration
    Worktree: objectstack-issue-22211
    Domain: domain:spec
    Seat: domain:spec#3 (seat post #18883)
    File surface (at origin/main 799eb000c; stop on breach and explain in the report):

    Triage's order 6054592515, binding:

    • "the fix declares what the service attaches, in a shape the validator already reads. It does not teach the validator an exception for viewer."
    • "If no existing shape can declare it, that is a spec addition. It is Clause-② yes, and the seat says so on this card before building."

    So this claim is measurement-bounded:

    • if an existing shape fits, the dev lands the declaration with Clause-②: no;
    • if none fits, the dev reports needs_decision with the measurement and builds nothing. This seat then posts the Clause-② yes statement here before any build.
  3. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 22211,
      "status": "needs_decision",
      "branch": "claude/issue-22211-approval-viewer-declaration",
      "pr": null,
      "session": "session_01RPo7FUd6bSnAfkWMAKi848 (mode:subagent; this is the PM's id, and my identity is the branch). The newest Claim on #22211 (6062089126) names this branch and worktree objectstack-issue-22211. I checked it before any write.",
      "premise_still_valid": true,
      "summary": "Stopped at the fork, and built nothing. No existing declaration shape fits. The validator resolves `record.X` only by checking X against every key of the object's `fields` (any type) plus the closed set of platform-injected system columns. Every field type except `formula` creates a JSON or scalar column. `formula` is the only virtual type, and it is a row-derived expression the engine evaluates on every generic read. It returns only number, text, boolean or date, so it cannot carry the per-caller block. Any field declaration also enters the generated translation bundles, forms, list-view pickers and exports. And no shape gives the misspelling pin the dispatch asks for: the validator never resolves a segment after the first, so `record.viewer.can_actt` passes under every declaration. A spec addition is needed, Clause-② yes (widening). The proposed shape is in open_questions.",
      "measurement": {
        "where_the_validator_resolves_record_paths": [
          "The field index is every key of `obj.fields`, in either the list or the map shape, with NO filter on field kind, unioned with `injectedColumnsFor(obj)`: packages/lint/src/validate-expressions.ts:152-177 (`buildFieldIndex`). Field kind is read only into the advisory type-soundness map (:259-281, `buildFieldTypeIndex`), where `json`, `composite` and every unmapped type become `dyn` (packages/formula/src/validate.ts:243-249).",
          "Action predicates are judged with that index, record scope: `checkAction`, validate-expressions.ts:2157-2169, over each object's `actions[]` at :2209-2213, through `check` at :1370-1375.",
          "The refusal: `checkFieldExistence`, packages/formula/src/validate.ts:625-648, emits `unknown-field` as an ERROR for each first segment not in the index. Its regex `RECORD_REF_RE` (:312) captures exactly ONE segment after `record.` or `previous.`.",
          "Nested paths: no pass resolves a segment after the first. `record.viewer.can_act` and `record.viewer.can_actt` are the same verdict under any declaration of `viewer`. packages/lint/src/validate-predicate-path-refs.ts:55-63 states that the `record.*` layer is not a closed key set, and leaves it to an open question on #7010.",
          "Injected names: `resolveInjectedSystemColumns` (packages/spec/src/data/injected-system-columns.ts:139) is a platform-owned closed plan, governed only by `systemFields` (packages/spec/src/data/object.zod.ts:2008-2049, closed to `tenant` and `audit`) and `ownership`. No authorable entry can add a name to it."
        ],
        "how_the_service_attaches_viewer": [
          "`attachViewers`, packages/plugins/plugin-approvals/src/approval-service.ts:7018-7032 (doc :7001-7017). Shape: `{ can_act: boolean, is_submitter: boolean, can_override: boolean }`. It is computed per caller from `heldSlot`, the owner check and `isOverrideActor`. The status is ANDed into `can_act` and `can_override`.",
          "Read paths: `listRequests` (:6817) and `getRequest` (:6934) only, after `rowFromRequest` (:1032), which maps explicit keys. No other non-test source assigns `.viewer`.",
          "The generic data door serves this object (`apiMethods: ['get', 'list']`, sys-approval-request.object.ts:635) WITHOUT `viewer`, and there the 8 predicates fail closed by design (the comment at :399-401)."
        ],
        "candidate_shapes": [
          "Shape `json` field (with `readonly`, `hidden` or `internal`) · the validator reads it: yes (any key) · fits: NO · side effects: a JSON column `viewer` on sys_approval_request, which is a schema migration on every deployment (packages/drivers/driver-sql/src/sql-driver.ts:19847, the JSON_COLUMN_TYPES branch of `createColumn`); a permanently stored null served on the generic door; `readonly` strips only non-system writes, so isSystem writes, seed replay and migration still write it (packages/spec/src/data/field.zod.ts:1894); `internal` omits it from generic reads but 'storage, filtering and indexing are untouched' (:1892); `hidden` is UI-only (:1859). This is the stored column for a per-caller block that the dispatch rules out.",
          "Shape `composite` field with declared sub-fields · the validator reads it: yes, first segment only; the sub-fields are never consulted, so it is no better than `json` for the misspelling pin · fits: NO · side effects: the same JSON column (FieldType comment 'stored as JSON on the parent row', field.zod.ts:87-88; sql-driver.ts:19847).",
          "Shape `formula` field · the validator reads it: yes, and it also judges its expression · fits: NO · it is the only virtual type: no column (sql-driver.ts:19806-19807 and :19101-19103; driver-turso remote-transport.ts:2044; plugin-audit audit-writers.ts:372 `VIRTUAL_FIELD_TYPES = {'formula'}`). But: (1) the engine evaluates it on every generic read with no projection (packages/objectql/src/engine.ts:1553), so the generic door would start serving a computed `viewer` key; (2) `returnType` is closed to number, text, boolean and date (field.zod.ts:1696), so no object block; (3) a formula is row-derived, and `viewer` is per caller (heldSlot over positions and teams, the admin override), which the card states cannot be a formula; any expression written there, `null` included, declares something false; (4) it enters the generated field labels (plugin-approvals/src/translations/en.objects.generated.ts, one entry per field, times 4 locales), forms, list-view column pickers and exports.",
          "Shape `summary` or `autonumber` · fits: NO · both are stored or rolled up from children (`RUNTIME_OWNED_FIELD_TYPES`, field.zod.ts:243-271), and neither describes a service-attached block.",
          "Shape injected system column (`systemFields`, `ownership`) · the validator reads it: yes (`injectedColumnsFor`) · fits: NO · it is a closed platform plan (injected-system-columns.ts:139; object.zod.ts:2008-2049); `viewer` cannot be added without a spec change.",
          "Shape surface roots (`ExprSchemaHint.roots`, packages/formula/src/validate.ts:94-160) · fits: NO · the validator sets roots per authoring surface, and object metadata never sets them; the predicates read `record.viewer`, not a root; using roots means editing validate-expressions.ts, which this claim excludes, and is the validator exception the order forbids."
        ],
        "the_eight_predicates_at_799eb000c": "sys-approval-request.object.ts :451-452 approve, :481-482 reject, :504-505 reassign, :525 send_back, :540 request_info, :567 remind, :608-609 recall, :624 resubmit. The object declares no `viewer` key in `fields` (grep: `viewer` occurs only in the comments at :389-418 and in these predicates)."
      },
      "tests": "Read-only measurement: nothing installed, built, run or committed. Every claim above is a source read at origin/main 799eb000c, which equals the claim's stamp, with file:line. NOT MEASURED: an executed rerun of the 8 refusals at 799eb000c. Reason: the container has no node_modules and no built dist in any checkout, and this card is measurement-bounded. The verdict is the one #22032's pass-4 dev measured at 5d1d1aca6d (report 6053764412). The code path is re-read here at 799eb000c and unchanged in mechanism: formula validate.ts:312 and :625-648, lint validate-expressions.ts:152-177 and :2157-2213.",
      "mcp_calls": "0",
      "api_writes": "1 REST write: this os-dev-report comment, through scripts/pm/post-stamped.mjs (POST /repos/objectstack-ai/objectstack/issues/22211/comments, by whichever transport the tool's auto route picked). Not REST: one `git push -u` of the empty branch claude/issue-22211-approval-viewer-declaration (the write probe; it equals origin/main 799eb000c). No pr_create and no label-write, because nothing was built. Reads: single-card REST reads of #22211, its comments, and comment 6053764412.",
      "open_questions": [
        {
          "question": "Clause-② yes (widening): which spec addition declares a block that a service attaches to the rows it serves, per caller and never stored, so that the build validator can judge `record.viewer.*`? No existing shape can declare it without a column, a generic-door change or a false formula (measurement above). The seat posts the Clause-② statement on this card before any build. NOTE: the dispatch did not carry the four-axis escalation framework, so the options below are compared on measured blast radius and cost only. They are NOT axis-graded; the seat grades them from its own copy.",
          "options": [
            "A: an object-level declaration outside `fields`. A new optional `ObjectSchema` key, for example `attachedOnRead: { viewer: { description, attachedBy: 'getRequest/listRequests', keys: { can_act: 'boolean', can_override: 'boolean', is_submitter: 'boolean' } } }`, as a strict record of closed leaf maps. It is not a field, so no driver, column, form, list view, export, write path or translation bundle ever reads it: the drivers iterate `fields` only. Consumers from landing day (ADR-0049): (1) the validator adds the declared top-level names to the field-existence set, and judges the SECOND segment against `keys`, so `record.viewer.can_actt` is refused. That is the misspelling pin the dispatch wants, and no existing shape can give it. (2) A plugin-approvals conformance pin: the keys `attachViewers` emits equal the declared `keys`. Cost: spec `minor` (ObjectSchemaBase is a strictObject, object.zod.ts:1706, so this widens the accept set); `patch` for lint and formula (buildFieldIndex in validate-expressions.ts, serial behind open PR #22268; checkFieldExistence in formula validate.ts:625 for the nested segment) and for plugin-approvals; plus the generated spec artifacts (schema, authorable-surface baseline, docs) and a liveness-ledger row. It also gives the service's other undeclared read attachments a home: `decision_progress`, `pending_approver_groups` and the flow steps (approval-service.ts :6994, :6997, :7065). None of them is read by a predicate today.",
            "B: a field-level 'not stored' marker, either a new FieldType member or a new `storage` key such as `persisted: false` (`storage` is the ADR-0113 strict block, field.zod.ts:1160). Every column-creating seam must honor it from landing day: driver-sql `createColumn` and schema-drift (its default branch would otherwise create a column, sql-driver.ts:19808-19847), turso, mongodb, memory and sqlite-wasm, the objectql write path (refuse writes) and read projection. The field still enters forms, list-view pickers, exports and the translation bundles unless each of those learns the marker too. And sub-keys are still unjudged, unless `composite`-style sub-fields are reused AND the validator learns nested segments. Cost: spec `minor`, plus `patch` across 5 drivers, objectql and lint. This is the largest blast radius of the three.",
            "C: move the gate off `record`. The action surface mounts a `viewer` root, and the predicates become `viewer.can_act`. That is a renderer binding in objectui, an authoring-surface root in the validator (validate-expressions.ts, excluded by this claim), and a change to where the service attaches its result. It is cross-repo, it changes the authored predicates rather than declaring them, and it arguably reopens how the #3310 surface is shaped, which the card says is settled."
          ],
          "recommendation": "A. It is the only shape with no storage, no write-path, no generic-door and no UI or translation side effect, because nothing but the validator and one conformance pin reads it. It is also the only one that can make `record.viewer.can_actt` a refusal, so the declaration is not a wildcard. Its build is serial behind #22268 (validate-expressions.ts). Declared arm: `Clause-②: yes (widening)`, with a `minor` changeset on @objectstack/spec."
        }
      ],
      "out_of_scope_findings": [
        "carrier: the build that follows whichever option the seat picks · noted, not filed. The validator never resolves a `record.X.Y` segment after the first (formula validate.ts:312; lint validate-predicate-path-refs.ts:55-63, which leaves it open on #7010), so a misspelled nested key on ANY declared json or composite field passes the build. This is read-only inference, not a reproduced defect, so it is not filed. Option A closes it for declared attachments only."
      ],
      "files_changed": [],
      "gates": "None run: nothing was built or committed, so `dispatch-gates.mjs --commands` has no change set to derive from. NOT MEASURED: every gate family, reason: no diff.",
      "deviations": [
        "Stopped at the first fork, as the measurement-bounded claim requires: no existing shape fits without side effects, so nothing was built, no PR was opened and no label was written.",
        "os-dev expects the dispatch to carry the four-axis escalation framework for a needs_decision report. This dispatch did not carry it, and per os-dev I did not invent one. The options are compared on measured blast radius only, and the seat grades them.",
        "The dispatch's Step-2 pin ('a misspelled `record.viewer.can_actt` is still refused') cannot be met by ANY existing shape, because the validator checks only the first segment. That alone would have forced this fork, even if a side-effect-free shape had existed.",
        "The empty branch claude/issue-22211-approval-viewer-declaration is pushed (equal to origin/main 799eb000c) and left for the seat to reuse or delete. The worktree had no install and no edits; it is removed after this report is posted, without --force."
      ]
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Seat verdict: ACCEPT the measurement, needs-user-decision: how to declare a block a service attaches per caller

    domain:spec seat 3 (#18883) · os-justin · session session_01RPo7FUd6bSnAfkWMAKi848 · 2026-10-08T14:38Z · holder of claim 6062089126, which this act releases.

    Checked on origin/main 799eb000c, not from the report (6062234309):

    • buildFieldIndex (packages/lint/src/validate-expressions.ts:152–:177) takes every key of fields plus injectedColumnsFor(obj), the closed set of platform-injected columns. checkFieldExistence (packages/formula/src/validate.ts:625–:648) refuses the first segment that is not in that index, and RECORD_REF_RE (:312) captures only one segment.
    • attachViewers (packages/plugins/plugin-approvals/src/approval-service.ts:7018–:7032) attaches { can_act, is_submitter, can_override } to each row on listRequests / getRequest only.
    • Every field type except formula creates a column, and formula is row-derived, returning only number / text / boolean / date.

    Triage 6054592515 set two conditions: "in a shape the validator already reads", and "if no existing shape can declare it, that is a spec addition. It is Clause-② yes, and the seat says so on this card before building". The measurement found no existing shape that works without a side effect. This is a spec addition, Clause-②: yes (widening). The options differ in the shape of the public contract, so the choice goes to the maintainer.

    Release: session_01RPo7FUd6bSnAfkWMAKi848 · why: the measurement round is delivered, and choosing the contract shape is the maintainer's · to: needs-user-decision, unassigned. Whoever implements the ruled shape claims afresh. Branch claude/issue-22211-approval-viewer-declaration is empty, equal to 799eb000c, and can be deleted.


    待裁(needs-user-decision):审批服务在读取时按调用者附加的 viewer 块,该怎么声明,才能让构建校验器判得了它?

    维护者速读

    • 改了什么: 什么都没改。本轮只做了测量,没有 PR。
    • 测出的关键事实:
      • 审批单 sys_approval_request 自带 8 个操作按钮(同意、拒绝、转办等)。它们的显示条件读 record.viewer.can_act 这类值。
      • viewer 不是存储的字段。它是审批服务读取时按「谁在看」现算、再附上去的。
      • 构建校验器只认对象里声明了的字段,所以平台自带的这 8 个条件在 os build 里全部报错。以 OS_METADATA_WRITABLE=object 发布保存这个对象,也会被拒。
      • 现有的字段类型里,没有一种能既声明它、又不建数据库列、不进表单和翻译。
      • 校验器只检查第一段:record.viewer.can_actt 这样的拼错,现在无论怎么声明都拦不住。
    • 席位意见: 推荐 A:在对象上新增一个与 fields 并列的声明,专门登记「服务读取时附加的块」。
    • 你要做的: 回一个字母,A / B / C。

    一句话问题

    平台里有「读取时按调用者计算、从不存储」的数据,这类数据在元数据里用什么形状声明?

    Governing text

    前提(各带复核命令)

    1. 校验器只认 fields 加注入列。 git show origin/main:packages/lint/src/validate-expressions.ts | sed -n 152,177p
    2. 只判第一段。 git show origin/main:packages/formula/src/validate.ts | sed -n 312p
    3. viewer 的形状与附加点。 git show origin/main:packages/plugins/plugin-approvals/src/approval-service.ts | sed -n 7018,7032p

    选项 × 真实代价

    选项 做什么 代价
    A 在 ObjectSchema 上新增可选键(暂名 attachedOnRead),登记块名和它的叶子键与类型。它不是字段,驱动、表单、导出、翻译都不读它。校验器把块名加入可识别集合,并且判第二段,所以 can_actt 会被拒。plugin-approvals 加一个一致性测试:attachViewers 实际附加的键要等于声明的键。 spec minor,lint / formula / plugin-approvals 各一个 patch。lint 那一侧要排在 #22268 之后串行。审批服务另外几个读时附加的块(decision_progress 等)以后也有地方登记。
    B 给字段加一个「不存储」标记(新类型,或 storage.persisted: false)。 5 个驱动、objectql 的写入和读取路径都要认这个标记,表单、导出、翻译也要各自认。第二段仍然判不了。影响面最大。
    C 不再从 record 读,改在操作按钮这一层挂一个 viewer 根变量。 要动 objectui 的渲染绑定和校验器的作者面(正是 triage 禁止的例外),等于重开已经裁定的 #3310 形态。

    业务含义直译

    • A: 给「服务现算、不落库」的数据单独开一本登记簿,校验器照着登记簿查,连拼错都能查出来。
    • B: 硬把它塞进字段登记簿,再在每个读字段的地方加一句「这个别存」。
    • C: 换一扇门,不从 record 进。

    os-decision-facets

    • ① 项目长远合理性:
      • A 把「读时附加的块」做成一等声明:一处登记、一个读者,以后再有这类块(审批进度、待审组)也有地方放。
      • B 让每个处理字段的地方都多一个分支,长期维护成本最高。
      • C 改的是已经裁定的作者面。
    • ② 实际业务拉动:
      • 实测拉动:平台自带的审批单今天就有 8 个按钮条件被构建报错,发布保存会被拒。
      • A 只给这一个真实生产者开口子,此外还有 3 个已知的读时附加块。
      • B 的影响面远大于需求。
    • ③ 防 AI 犯错:
      • A 是三者里唯一能拒收 record.viewer.can_actt 这种拼错的。
      • 声明加一致性测试,保证声明的键等于服务实际附加的键,不会声明了却不兑现。
      • B、C 都只能放行第一段。
    • ④ 创业阶段不扩散:
      • A 新增一个可选键,读者只有校验器和一条一致性测试,面最小。
      • B 牵动 5 个驱动。
      • C 跨仓。
      • 新增门禁:无(沿用现有的 unknown-field 规则)。

    Prior rulings read: triage 6054592515 (this card); #3310 (the per-caller viewer semantics, settled); #7010 (record.* nested keys as an open question, validate-predicate-path-refs.ts:55–:63); #22032's pass-4 report 6053764412 (the measured refusal). None rules the declaration shape.

    推荐

    A。 读者只有校验器和一条一致性测试,不建列、不碰写入路径和界面。它也是唯一能把嵌套键的拼错变成拒收的形状。

    裁后执行

  5. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #295 item 1 · letter A · maintainer 「同意」 2026-10-08T23:18Z

    Director seat, summon #35, session_01VYToj6PQehTEKNrjGM9akg (GitHub os-zhuang; written as objectstack-fleet[bot] via the relay). Presented in batch #295 from the domain:spec seat 3's decision request (6062299739) on the measurement report 6062234309: A a new optional ObjectSchema key, working name attachedOnRead, registering the blocks a service attaches per caller on read with their leaf keys and types; B a field-level "not stored" marker; C a viewer root variable on the action surface. The seat recommended A; the maintainer answered 「同意」. Thread-read: 6062299739. Freshness: no comment since the presentation; body unchanged; labels bug, needs-user-decision, domain:spec, priority:p3, area:workflow. Premises re-read on origin/main b460153912: buildFieldIndex (packages/lint/src/validate-expressions.ts:152, :174) indexes every fields key plus injectedColumnsFor(obj); RECORD_REF_RE (packages/formula/src/validate.ts:312) captures one segment after record.; attachViewers is called from listRequests and getRequest only (packages/plugins/plugin-approvals/src/approval-service.ts:6817, :6934); the string attachedOnRead occurs nowhere in the repository.

    The ruling

    A — an object-level declaration beside fields. ObjectSchema gains one optional key, working name attachedOnRead: a strict record of the blocks a service attaches to the rows it serves, computed per caller and never stored, each block naming its leaf keys and their types. It is not a field. Drivers, forms, list views, exports, write paths and translation bundles never read it. Its readers from landing day (ADR-0049, enforce-or-remove): (1) the shared validator adds each declared block name to the field-existence set and judges the second segment against the block's declared keys, under the existing unknown-field rule, so record.viewer.can_actt is refused; (2) a plugin-approvals conformance test pins that the keys attachViewers emits equal the keys sys_approval_request declares. sys_approval_request declares viewer with can_act, can_override and is_submitter, all boolean. ⛔ Not taken: B (a stored-column marker that every driver, the write path, forms, exports and translations must each learn, and the nested segment still unjudged), C (moves the gate off record, is cross-repo, and reopens the #3310 surface the card calls settled). ⛔ Not ruled: a validator exception for viewer; triage's order stands (no new rule, no new refusal code; the declaration is what the existing rule reads). The service's other read attachments (decision_progress, pending_approver_groups, the flow steps) may be declared under the same key when a predicate first reads them; this ruling requires none of them.

    Prior rulings read: triage 6054592515 (this card: declare in a shape the validator reads, else a spec addition with Clause-② yes); #3310 (the per-caller viewer semantics, settled); #7010 (record.* nested keys, open at validate-predicate-path-refs.ts:55–:63); #22032 pass-4 report 6053764412 (the measured refusal) and its order 6024268378; ADR-0049. check-prior-rulings over 7 terms → 3 ADR hits (ADR-0005 §5, ADR-0105 D5, ADR-0119 D3), all on the term enforce-or-remove alone, none on the declaration shape; thread: 0 rulings of 4 comments. 自检: 只看①选 A;②③④ 是否翻转:否(③ 反而加强:三者中唯一能拒收第二段拼错的形状)。置信缺口:8 处拒收未在 b460153912 上重新执行,沿用 #22032 第 4 部分在 5d1d1aca6d 的实测,代码路径逐行复读未变;attachedOnRead 是暂名,终名由 spec 卡定。

    State

    • needs-user-decision → pm:queue (domain:spec, priority:p3) in this act; the Ruled: line added to the body. The spec seat files the two build cards the verdict names: spec (the new key, the second-segment judgement, the liveness-ledger row; Clause-②: yes (widening), a minor changeset on @objectstack/spec) and plugin-approvals (the declaration and the conformance test); the lint side is serial behind fix(lint)!: os build and the object save door refuse a select option's visibleWhen that reads parent (#22157) #22268; contract review attached. Branch claude/issue-22211-approval-viewer-declaration is empty and may be deleted by whoever claims.

    Generated by Claude Code

  6. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    pm:queue → pm:blocked: the ruling's two build cards are filed, #22386 (spec) and #22387 (plugin-approvals) · Blocked-by: #22387

    domain:spec seat 2 (#18549) · os-sales · session session_01DhTqaEHqPVSVnAkjG3jywn · 2026-10-09T01:03Z · acting on the ruling of record 6070963704. Thread-read: 6070963704.

    The ruling's state section reads: "The spec seat files the two build cards the verdict names: spec (the new key, the second-segment judgement, the liveness-ledger row; Clause-②: yes (widening), a minor changeset on @objectstack/spec) and plugin-approvals (the declaration and the conformance test); the lint side is serial behind #22268; contract review attached."

    Filed (finding, for triage's first grade and route):

    The ruling's premises, re-read on origin/main at this stamp:

    This card: pm:queue → pm:blocked in this act, and the body gains Blocked-by: #22387. It stays unassigned and holds the defect's record. It closes when #22387's PR lands. No seat dispatches it on its own.


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    Closing as completed: its plan said it closes when #22387's PR lands, and PR #22479 landed

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-09T14:06Z. Blocked audit. ⛔ Not a claim, ⛔ not a dispatch.

    Thread-read: 6072125030

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:workflowApprovals and automation — the work that runs without a person driving itbugSomething isn't workingdomain:specpm:blockedpriority:p3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions