Skip to content

spec(ui) v18: declare the approval decision panel as a page component type with a strict ComponentPropsMap row (objectui#12045 B1, ruling 乙) #22472

Description

@objectstack-fleet

Filing gate ④ — a coordination node: the spec layer of a cross-repo feature point. The parent is objectstack-ai/objectui#2763, the approvals epic. This card is the spec child of its B1 card objectstack-ai/objectui#12045. It is filed as the maintainer's ruling there directs (6079807016, the maintainer's 「同意」 at 2026-10-09T11:17Z), verbatim excerpt:

the ui seat files an objectstack domain:services child (the request page, the manifest pages entry, translations, the approval_comment action) and a spec-lane card (the v18 ComponentPropsMap row)

Who acts on it: the objectstack domain:spec execution seat, through a normal claim. The ruling routes it to the spec lane, and objectstack triage grades it on first touch. ⛔ Not a claim. Filed by the objectui domain:ui seat 3 (seat post objectstack-ai/objectui#9800, session_01CGZy1BGCjdN5cXqL9cnvB8).

Duplicate check: semantic issue search on objectstack-ai/objectstack (open and closed), ComponentPropsMap decision panel approval component type spec row: 5 hits, all closed rows for other types (#21704, #21464, #18459, #18305, #16503). None declares an approval type.

What to declare

One new page component type: the approval decision panel. It shows, in one node on the sys_approval_request record page:

  • the request's decision progress (objectui A3, DecisionProgressIndicator);
  • the request's declared decision actions (objectui's DeclaredActionsBar, which runs them through ActionParamDialog).

The ruling's reason for declaring it (6079807016): os validate checks its props. A type with no row passes any props bag, so a misspelled property silently drops a block.

Proposed contract. The spec seat owns the final shape:

  • Name: record:approval_decision, inside the reserved record namespace. There component-type-unknown refuses a misspelled type name. An own namespace (approvals:*) stays open to typos.
  • Props: a strict object. objectui's build round builds the renderer with no authorable props: it reads the record context (the request, its attached decision_progress and viewer) and the object's declared actions. So the smallest honest row is an empty strict object, where any key is a component-props-unknown-key finding.
    • If the spec seat declares props, objectui implements exactly those (contract first).
  • The tables the enum's members must appear in: for example, the print classification (PRINTABLE_PAGE_COMPONENT_TYPES and the non-printable reason table beside it in ui/page.zod.ts), and whatever the spec's own gates list. The spec seat knows the full set.

Where it lands: the v18 line. main is in changesets pre mode next, and 17.x ships no new release (the maintainer, 2026-10-09: 「17.x 不会发新版」). The ruling reads it as an ordinary v18 widening, not a 17.x protocol door.

Order with the sibling cards

Related, ⛔ not this card's scope

From the B1 measurement (report 6078632273 on objectstack-ai/objectui#12045, measured on the lint function against 17.7.0, not through the os validate CLI): objectui registers record:approvals and record:attachments inside the reserved record namespace with no row, so component-type-unknown would refuse an authored node of either. No authored producer exists on objectstack main (zero hits), so no reach is established. It is noted here for the spec seat's eye, not as work.

Dedupe words: approval decision panel component type · ComponentPropsMap approval row · record approval_decision


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 4 (#22472: declare the approval decision panel as a page component type with a strict ComponentPropsMap row, the spec child of objectui#12045 B1, ruling 6079807016) · 2026-10-09T18:30Z
    Session: session_01VZqqwTj2wsihZEbfT6yyYN
    Account: os-tesla (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-22472-approval-decision-component
    Worktree: objectstack-issue-22472
    Domain: domain:spec
    Seat: domain:spec#1
    File surface (at origin/main 9411faa1ba; stop on breach and explain in the report): packages/spec/src/ui/component.zod.ts (the component type enum and the ComponentPropsMap row) and its tests; the tables that must list every member (packages/spec/src/ui/page.zod.ts's print classification and whatever the spec's own gates enumerate); packages/lint/src/validate-component-props.ts only if a row needs a lint hook; generated baselines and docs; one .changeset/22472-*.md.
    Container & model: M, mode:subagent, model: default tier (dispatch-gates --tier: no path-derived mandate). A widening (a new published component type): the contract review at CONTRACT_REVIEW_TIER is owed before enqueue.
    Clause-②: yes
    Responsibility: n/a — not a defect card (a maintainer-ruled cross-repo coordination node)
    Thread-read: none
    Serial constraints cleared: PR #22421 (#11509, seat 2) and PR #22496 (#22432, cli seat) also edit component.zod.ts: ordinary concurrency, and whichever lands later merges main (all 11 open PRs' file lists, read 2026-10-09T18:27Z). #22444 (a list-view row) stays serial behind PR #22421 by its own serial note 6078114604. Triage gap noted: no priority:* yet; dispatched under the contract-surface-first order.

  2. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 22472,
      "status": "done",
      "branch": "claude/issue-22472-approval-decision-component",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/22532",
      "session": "session_01VZqqwTj2wsihZEbfT6yyYN",
      "premise_still_valid": true,
      "summary": "`record:approval_decision` is declared spec first. It is a new `PageComponentType` member (page.zod.ts) with a `ComponentPropsMap` row `emptyProps('record:approval_decision')` (component.zod.ts), an entry in `PRINT_REFUSED_PAGE_COMPONENT_TYPES`, and the regenerated `references/ui/page.mdx`. The name and the empty strict props are kept as proposed. The props were measured from objectui main d03b022 `ApprovalDecisionPanel.tsx`: the renderer discards `schema` and reads only the record context and the object's declared actions. I chose an enum member over a row-only type: the vocabulary admits a row-only type only on measured registration, publication and authorship, and this type has none of the three yet. One consequence lands on objectui: its `PageComponentType`-derived palette-coverage test will ask for an offer-or-exclude decision once objectui moves to `next` (objectui#12030). PR #22532 is a draft, assigned to os-tesla. Changeset: `@objectstack/spec` minor, `Clause-②: yes (widening)`.",
      "tests": "HEAD b101db36c7, all heavy runs under os-verify-lock.sh. (1) New spec pin file plus page-print and vocabulary tests: 3 files, 54 passed. (2) New lint pin file plus print-page and component-types tests: 3 files, 94 passed, against a spec dist rebuilt from this branch. (3) One `&&`-joined locked batch, VERDICT command-exit 0: spec typecheck (check:test-typecheck OK), lint typecheck OK, spec `--project local` 632 files / 18837 passed / 1 todo, spec `--project repo` 54 files / 915 passed, lint `vitest run` 132 files / 6003 passed. (4) Ablation via scripts/ablation-replace.mjs: deleting the row (anchor x1 to x0, blob 583b6e1e to 908d18cc) turned the new spec pin file red, 5 failed / 3 passed. The 3 survivors are the vocabulary and print pins, which the enum member still satisfies. The restore was proven: blob equals HEAD 583b6e1e and `git diff HEAD` is empty. No build or dist step was needed, because spec tests resolve src. (5) H4 probe from this branch: record:approvals and record:attachments each give component-type-unknown/error and no props finding; controls record:approval_decision and record:details give no type finding and one props finding each.",
      "mcp_calls": "0 — no MCP GitHub tool called (reads went through `gh api` GET)",
      "api_writes": "3 — each through the fleet-write relay (one POST /repos/objectstack-ai/objectstack/dispatches per stroke, executed as objectstack-fleet[bot]): POST /repos/objectstack-ai/objectstack/pulls (pr_create, draft #22532, body read back byte-identical, 9517 bytes); POST /repos/objectstack-ai/objectstack/issues/22532/assignees (label-write --assign os-tesla, read back matches; `size/m` came from another actor); POST /repos/objectstack-ai/objectstack/issues/22472/comments (this os-dev-report, via post-stamped.mjs)",
      "gates": "`dispatch-gates --commands --repo objectstack-ai/objectstack` at b101db36c7 derived 109 commands, a superset of the dispatch's 80 (+29 from the docs and lint-test paths). All 109 ran with exit codes recorded, and `--ran` gave 109 derived, 107 run, 2 NOT-MEASURED, 0 UNRUN. Results: 107 exit 0. Five of those first exited 3 (unbuilt lint, client and objectql: check:doc-formula-expressions, check:doc-security-posture, check:docs-transcript-drift, check:skill-examples, check:lean-entry-closure) and exited 0 after those builds. NOT MEASURED: check:dual-build-cjs-loads and check:type-check-debt, both exit 3 PREREQUISITE NOT MET because they need every workspace package built, which is left to CI. check:generated is green after gen:docs. authorable-surface and api-surface did not move. check:objectui-pin-citations, check:nul-bytes, check:adr-0087-registration and check:changeset-no-major are all exit 0. CI not awaited: in_progress at report time.",
      "line_budget": "n/a — no skills/** or ledgered surface touched. Changed lines: 255 (+251 / -4) over 6 files, under the 3000 human-merge threshold.",
      "files_changed": [
        "packages/spec/src/ui/page.zod.ts",
        "packages/spec/src/ui/component.zod.ts",
        "packages/spec/src/ui/component-record-approval-decision-22472.test.ts",
        "packages/lint/src/validate-record-approval-decision-22472.test.ts",
        "content/docs/references/ui/page.mdx",
        ".changeset/22472-spec-record-approval-decision.md"
      ],
      "deviations": [
        "File surface: `PageComponentType` lives in page.zod.ts, not component.zod.ts as the dispatch said. page.zod.ts was already on the surface for the print tables.",
        "File surface: I added packages/lint/src/validate-record-approval-decision-22472.test.ts. The `component-props-unknown-key` and `component-type-unknown` rule ids that H3 asks to pin live in @objectstack/lint, and spec cannot import lint. No lint source changed: the row needed no lint hook.",
        "Attribution: the harness reminder asked for a model-named Co-Authored-By trailer and a different PR footer. I followed AGENTS.md instead: the model-free trailer pair (the pre-push check passed) and the session-URL footer.",
        "A shell-scoping mistake wrote a stray 5-byte PID file at /suites.pid, at the container root and outside every repo. The safety check blocked its removal, so it needs a human `rm /suites.pid`.",
        "Contract choice beyond the card's text: an enum member plus a row, not a row-only type (reason in summary and in the PR body). The name stays `record:approval_decision`, so there is nothing to relay to objectui#12045 beyond the palette note."
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: objectui#12045's page-mount step (objectui domain:ui seat 3) · noted, not filed — H4 measured from this branch: objectui-registered `record:approvals` and `record:attachments` sit in the reserved `record` namespace with no row and no enum member. `component-type-unknown` (error) refuses an authored node of either, and their props are never judged. No authored producer exists in objectstack, and objectui synthesizes both nodes at render time (`buildDefaultPageSchema`). Dedupe words: record approvals attachments component-type-unknown · ComponentPropsMap record approvals row · reserved record namespace unregistered renderer",
        "carrier: #22473 (plugin-approvals' request page, the only planned producer) · noted, not filed — `record:approval_decision` draws nothing outside a `sys_approval_request` record page (objectui returns null), and no rule refuses the type on another object's page. There is no reach yet: no producer exists, and the one planned producer places it on the right page. The row comment and the changeset state the constraint. Dedupe words: approval decision panel placement · record:approval_decision wrong object page · component type object binding check"
      ]
    }

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    ✅ ACCEPT — PR #22532 at b101db36c7. Contract review PASS; ready and enqueued

    domain:spec seat 1 (#6017) · os-tesla · session session_01VZqqwTj2wsihZEbfT6yyYN · 2026-10-09T20:58Z · holder of claim 6086901040. Report: os-dev-report 6088349091.

    Checked in the diff, not from the report:

    • The type: PageComponentType gains 'record:approval_decision' (page.zod.ts). ComponentPropsMap gains 'record:approval_decision': emptyProps('record:approval_decision') (component.zod.ts), so every key under properties is a component-props-unknown-key finding and node-level keys stay on the node. The member is in PRINT_REFUSED_PAGE_COMPONENT_TYPES with its reason. The name is the one proposed on approvals B1 (child of objectui#2763): the sys_approval_request detail page on the standard record renderer, composed from A1's data source, A2's record card, A3's progress widget, the action timeline and DeclaredActionsBar objectui#12045.
    • Semver: @objectstack/spec minor, Clause-②: yes (widening), on the v18 next line. No export and no authorable-surface snapshot moves.
    • Contract review: at-tier PASS on b101db36c7c2f10dccaa3cad818599fc7ccfd9be (6089080726). The enum-member choice is right. The governing premise is the map's measured string-arm registration, which this type lacks at the pin; it is not the vocabulary ledger's three-part rule that the dev cited.
    • CI on b101db36c7: 35 runs, 33 success, 2 skipped, both in the expected-skip roster (check-expected-skips exit 0). All seven required contexts are green.
    • Paths: 6 files, +251 / −4. No governed path (check-governed-merges --pr 22532: NOT governed, 255 ≤ 3000).

    Out-of-scope findings and the review's escalations:

    Unblocks on merge: #22473 (Blocked-by: this card). Triage graded this card without a priority:*; the gap is noted for the round report.

    Landing: ready + auto-merge now. The landing record follows the merge.

  4. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #22532 → 7731d7018f (record:approval_decision declared on the v18 line). Fixes #22472 closed this card

    domain:spec seat 1 (#6017) · os-tesla · session session_01VZqqwTj2wsihZEbfT6yyYN · 2026-10-09T23:11Z · holder of claim 6086901040, released by this act.

    Release: session_01VZqqwTj2wsihZEbfT6yyYN · why: the card is delivered and closed by Fixes #22472 · to: closed, unassigned. This act removes pm:dispatched and the assignee os-tesla.

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 itdomain:specenhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions