Skip to content

app-shell: spec 18's record:approval_decision page block renders nothing — ApprovalDecisionRenderer is written but never registered (the objectui half of spec 18's three record blocks, after #12030) #12342

Closed

Description

@objectstack-fleet

Filing gate ④ a coordination node: the objectui half of the three record blocks @objectstack/spec 18 added to PageComponentType: record:approvals, record:attachments and record:approval_decision. It was filed by objectui domain:ui seat 1 (seat post #5560, session_01CsyMRsFJBKNEMa4oPY1b5z) under the seat's judgment Q5 in record 6148150305 on #12030.

  • Reader (who acts): the objectui domain:ui lane, once objectui#12030 lands.
  • Dedupe: MCP search_issues in objectui, closed included, for record:approvals record:attachments record:approval_decision component renderer not rendered: 0 hits.
  • ⛔ Not a claim. For triage to grade.

What the spec declares

18.0.0-next.0, read by the seat in the published tarball, src/ui/page.zod.ts:

  • record:approval_decision "is the decision panel of an approval request: action controls that differ by viewer, beside a progress tally each decision changes".
  • record:approvals "is the record's live approval timeline, with a remind control only the submitter sees".
  • record:attachments "is a list of attached files with upload, download and delete controls".
  • ComponentPropsMap types the props: record:approvals takes RecordApprovalsProps, and record:approval_decision takes empty props.

What objectui does (at objectui#12030's head 2c15e40)

packages/app-shell/src/views/metadata-admin/previews/block-types.ts records one palette reason per block:

  • record:approvals and record:attachments render, registered by @object-ui/app-shell, and the default record page builds them. They are not offered in the Studio palette.
  • record:approval_decision: ApprovalDecisionRenderer (packages/app-shell/src/views/approval-decision/ApprovalDecisionPanel.tsx) is written, but no registration mounts it. Its test pins ComponentRegistry.has('record:approval_decision') === false.
  • So a page an author or an AI writes with record:approval_decision passes the spec and renders nothing.

Ask

  • Register record:approval_decision, so the declared block renders what the spec says it is. That closes the implementation gap: declared by the spec, not honoured by the runtime. Pins on a real render cover a pending request, a decided one, and a viewer who may not decide.
  • Palette: whether Studio offers any of the three is feature work. Triage grades it separately, and it is not required to close the gap above.

Restart when

objectui#12030 has merged, so objectui resolves @objectstack/spec 18.


Generated by Claude Code

Activity

  1. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    area:workflowApprovals and automation — the work that runs without a person driving it
    and removed on Oct 13, 2026
  2. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade on the queue · priority:p2 · domain:ui · target:v18 · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-14T06:02Z

    Read fresh. objectui#12030 has landed.

    • priority:p2. Spec 18 declares record:approval_decision, but objectui registers no renderer for it, so a page an author or AI writes with it passes the spec and renders nothing. That is declared ≠ delivered (AGENTS.md PD10) on a published block type. ApprovalDecisionRenderer already exists, so the work is the registration plus pins.
    • target:v18. The block is new in spec 18.
  3. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01XVp19E1MYUTFM3dnkwz8gB
    Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-12342-register-approval-decision
    Worktree: objectui-issue-12342
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: packages/app-shell/src/views/approval-decision/, the app-shell block registration it joins, packages/app-shell/src/views/metadata-admin/previews/block-types.ts (the palette reason line), and their tests (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: opus (default tier; dispatch-gates --tier --repo objectstack-ai/objectui reads no path-derived mandate)
    Clause-②: yes
    Responsibility: n/a — not a defect card
    Thread-read: 6162019039
    Serial constraints cleared: objectui PR #12356 (this seat, objectui#11958, in the merge queue at 2026-10-14T07:55Z) edits packages/app-shell/src/views/RecordDetailView.tsx for its Print button. This card may read that file's approval-decision branch and should not need to edit it; if it does, the PR merges main after #12356 lands. objectui#12343 (area:workflow, pm:queue) edits Studio's flow hold, a disjoint file.

    Clause-②: yes (corrected in place from no: the dev's measurement in PR #12362 shows the registration needs a new arm, RecordApprovalDecisionBlockSchema, exported from @object-ui/types and @object-ui/types/zod, and AnyComponentSchema / objectui validate now accept a record:approval_decision node. That widens a published export and accept set, derived from the spec's row. The first declaration, no, was the seat's misreading, and the change owes a contract-review-tier review before the queue.)


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
     "issue": 12342,
     "status": "done",
     "branch": "claude/issue-12342-register-approval-decision",
     "pr": "https://github.com/objectstack-ai/objectui/pull/12362",
     "session": "session_01XVp19E1MYUTFM3dnkwz8gB",
     "premise_still_valid": true,
     "summary": "record:approval_decision is registered from a new app-shell side-effect leaf (views/record-approval-decision-renderer.tsx, barrel import, both sideEffects entries), the same path as record:approvals and record:attachments. Registration alone would raise NAMESPACED_REFUSED_AT_TYPE in the cli ratchet registered-types-validate-ratchet-10859 from 308 to 309, and that pin never rises. So the arm lands with it: RecordApprovalDecisionBlockSchema in @object-ui/types/zod (empty strict bag restating the spec's unnamed emptyProps row, body/children refused by name), its TS twin, the AnyComponentSchema member, the mirror-parity pair (EXPECTED_MIRROR_PAIRS 195 to 196), the emit-headroom row, and the regenerated cli known-schema-types line. The landing point therefore spans types and cli as well as app-shell; the panel's own docblock had already planned this. The panel test pin is flipped to registered, plus a real-SchemaRenderer row. The console decisionPage test drops its self-registration and adds decided-request, non-decider (submitter) and decider-control cases on the real RecordDetailView. The palette reason line now says the block renders, and the palette offer is untouched. A1/A3/A4 measured true. A2 is true for the path but false for the arm: the siblings are unarmed. A3: RecordDetailView mounts no panel by any route of its own and is not edited, so there is no interaction with #12356.",
     "tests": "Final head e7e004c, one vitest run under the lock: packages/types/ + packages/cli/ full, app-shell approval-decision/ + metadata-admin/previews/__tests__/ + product-neutral ratchet, console decisionPage + registry-inputs-spec-parity, scripts known-schema-types-derivation-5115 -> 'Test Files 427 passed (427) / Tests 11161 passed (11161)', VERDICT command-exit 0. An earlier run on 3a9b5d5 found 1 red, content-channel-parser-tier-clause-10928: the new arm's refusal lacked the corrected clause. Fixed in e7e004c. type-check: types/app-shell/cli exit 0 on 3a9b5d5 after building the dependency closure (filter app-shell^... and cli^...); types re-run exit 0 on e7e004c, whose diff is one string literal. Ablation 1, via objectstack scripts/ablation-replace.mjs: deleting the barrel import (anchor 1->0, blob 498f6b87->cb22404a) -> console decisionPage 'Tests 7 failed | 4 passed (11)'; restored blob == HEAD. Ablation 2: decided row can_act false->true (anchor 1->0, blob 59373e50->3a01fd10) -> 'a decided request' red ('expected button to be null'); restored blob == HEAD, git diff HEAD empty. No dist leg: vitest resolves @object-ui/app-shell to source, shown by ablation 1 going red without a rebuild. Lint narrowed: eslint --format json on the 17 changed ts/tsx files -> 17 results, 0 errors, 0 warnings, exit 0. The package lint scripts are 'eslint .' / 'eslint src'; eslint.config.js has no project/projectService, so linting is not type-aware and untouched files keep their verdicts. Full pnpm lint is declared to CI. Gates on e7e004c, exit codes read directly: phantom-deps, self-import, unreferenced-sources, doc-example-readers, handler-key-reads, side-effects-array, element-data-source-declaration, spec-symbols, action-forward-parity, designer-field-key-parity, icon-record-names, i18n-keys, i18n-drift, i18n-designer-parity, registry-bare-names, control-bytes, new-line-citations = 0; check-changeset-fixed/presence/no-major = 0. sdui-registration-pins = 0 after a full console build on 3a9b5d5 ('approval_decision 1 chunk(s)', all 16 present); e7e004c moves no registration. spec-floors = 1 ('The scan collapsed: 0 package(s) declare @objectstack/spec...'), the known main failure objectui#12334, recorded and not fixed. Full app-shell and console suites: NOT MEASURED locally (size), declared to CI.",
     "mcp_calls": "0",
     "api_writes": "2 relayed REST writes as objectstack-fleet[bot] via scripts/pm/fleet-write/dispatch.mjs: (1) pr_create = POST /repos/objectstack-ai/objectui/pulls (draft) + POST /repos/objectstack-ai/objectui/issues/12362/assignees; (2) comment = POST /repos/objectstack-ai/objectui/issues/12342/comments (this report). Plus 2 git pushes of the branch. Zero label writes: objectui path labels come from labeler.yml, and the dispatch named none.",
     "open_questions": [],
     "out_of_scope_findings": [
      "class: b · reach: public door. On base 065a1cf, validateAuthoredDocument (the authoring face objectui validate judges through) answers invalid_union at ['type'] for {type:'record:approvals'} and {type:'record:attachments'}. @objectstack/spec 18 declares both PageComponentType members with rows, and plugin-detail's buildDefaultPageSchema emits both. They stay counted in NAMESPACED_REFUSED_AT_TYPE (308) · Seam: spec:ComponentPropsMap['record:approvals'|'record:attachments'] -> runtime: @object-ui/types/zod AnyComponentSchema (no arm) | renderer: RecordApprovalsRenderer / RecordAttachmentsRenderer · family: the namespaced registered-types ratchet (objectui#10872 family); fold into that family's closure card, no single-point card · dedupe words: record:approvals arm, record:attachments arm, NAMESPACED_REFUSED_AT_TYPE, objectui validate invalid_union",
      "Clause-② reading (dispatch asked for evidence if it differs): the change widens objectui exports and an accept set. New exports are RecordApprovalDecisionBlockSchema from @object-ui/types/zod (zod/index.zod.ts) and from @object-ui/types (TS twin). AnyComponentSchema, StrictAnyComponentSchema and objectui validate now accept a record:approval_decision node, pinned by packages/types/src/__tests__/record-approval-decision-arm-12342.test.ts. All of it is derived from the spec row. No Clause-② line was written to the PR body; the declaration is the PM's to revise · carrier: PM seat · noted, not filed"
     ]
    }
  5. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Regrade: p2 → p1 · consumer follow-up, class A · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-14T08:56Z

    The maintainer's rule of 2026-10-14 (「同意 A + C」): a consumer follow-up of a protocol change is p1 when its absence breaks users. Here, the spec declares record:approval_decision, and a page that uses it renders nothing. It is listed on objectui#12334's pre-release list. Scope and claim are unchanged.

  6. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
     "issue": 12342,
     "status": "done",
     "branch": "claude/issue-12342-register-approval-decision",
     "pr": "https://github.com/objectstack-ai/objectui/pull/12362",
     "session": "session_01XVp19E1MYUTFM3dnkwz8gB",
     "premise_still_valid": true,
     "summary": "Patch round (CI run 38538610357, shards 8 and 10 cancelled at the 20m cap). I measured the slowdown and could not attribute it to this change, so no fix is pushed: the branch stays at e7e004c. I reproduced the CI tree exactly: e7e004c merged with the PR base 2312bd9. The sequencer printed 'shard 8/12 runs 421 of 5052 files' and the same for shard 10. CI's own invocation (pnpm test --shard=N/12 plus the timings reporter) ran both shards green locally, in about 12 to 12.5 min. The same 421 files per shard, run on base 2312bd9, took the same total time. Shard 3, which CI completed in 11m26s, took 13.3 min locally, slower than 8 or 10, so 8 and 10 are not structurally heavier. The CI logs, read through MCP get_job_logs, show no hang: both shards were still completing files at the cancel. By file order in the local run, shard 8 had reached about 296 of 421 files and shard 10 about 302 of 421, so CI ran these two legs at roughly half the usual rate throughout. No file stalled. CI runs at the same hour (merge_group 38539642792 and 38539926609, push 38541511753, schedule 38543526037) had all 12 shards between 6 and 12 min. The first suspicion is refuted: no AnyComponentSchema-heavy file slowed. The types files in the two shards, the zod-mirror and emit-headroom files, exclusion-reason-truthfulness and registry-inputs-spec-parity all match base within noise. Status-check answer: done measuring. Nothing is blocking now; the time went to the verify-lock queue (three queue-timeouts of 9 min each) and to six shard-length runs of about 12 min each.",
     "tests": "Local shard runs, CI invocation, 4-core container shared with sibling agents: (a) CI tree (e7e004c merged with 2312bd9), --shard=8/12: 'Test Files 421 passed (421)', Duration 710.71s. (b) CI tree, --shard=10/12: 'Test Files 418 passed | 3 skipped (421)', Duration 749.46s. (c) Control, CI tree, --shard=3/12 (11m26s on CI): 'Test Files 421 passed (421)', Duration 798.06s. (d) Base 2312bd9, the same 421 files as CI shard 8 passed by path: 'Test Files 421 passed (421)', Duration 730.91s. (e) Base 2312bd9, the shard-10 files: 418 passed | 3 skipped, Duration 732.86s. (f) Earlier, on the unmerged branch plan: head e7e004c --shard=8/12 670.90s against base 065a1cf --shard=8/12 676.74s. The partition reshuffles because the new test file is weighed at the median: shard 8 keeps 226 of its 421 files. Per-file before/after comes from scripts/test-file-timings.mjs output over identical file sets. Shard 8: summed per-file cost 2092s base against 2036s head (ratio 0.973). Shard 10: 2102s against 2151s (ratio 1.023). The largest moves in either direction are first-file import costs in the console project, which change with scheduling and change both ways: faviconAfterNavigation 9.4s to 33.9s and docs-portal 10.2s to 34.4s, against registerRefusalCodes-10998 35.6s to 10.6s and verificationCallback-10893 36.3s to 10.9s. Files touched by this PR, base to head: exclusion-reason-truthfulness 10.0s to 12.2s, registry-inputs-spec-parity 31.1s to 28.6s. Within those sets, no file got slower in a way that holds up between runs. CI progress at the cancel, from the job logs read through MCP: shard 8's last completed files (block-config-schema-parity-8216, buildDefaultPageSchema) sit at about position 296 of 421 in the local order; shard 10's (MetadataService.specKeyReference, content-channel-e3-residual-9256) at about 302. Both were still progressing, so there was no hang. Same-hour CI runs had every shard between 6 and 12 min. No code change, so nothing was rebuilt or re-gated; the head e7e004c verification from the first round stands.",
     "mcp_calls": "2 — mcp__github__get_job_logs (read-only) for jobs 115767547192 and 115767547100: their log blobs are on productionresultssa1.blob.core.windows.net, which the egress proxy refuses (CONNECT 403), so REST could not read them. No MCP write tools.",
     "api_writes": "1 relayed REST write as objectstack-fleet[bot] via scripts/pm/fleet-write/dispatch.mjs: comment = POST /repos/objectstack-ai/objectui/issues/12342/comments (this report). No git push this round: there is no code change.",
     "open_questions": [
      {
       "question": "With the slowdown not attributable to the diff, how should PR #12362 get a green Test?",
       "options": [
        "A: re-run the CI workflow on e7e004c (a seat action) and treat a second slow 8/10 pair as new evidence",
        "B: push an empty merge of main to re-plan the shards (the partition reshuffles with the file list) and see whether the slow legs follow particular files",
        "C: hold for the weekly test-shard-timings refresh, since 74 files are weighed at the median"
       ],
       "recommendation": "A. It is the cheapest discriminating measurement. The per-file evidence says the code costs the same, and a recurrence on the same partition would point at specific files, which B would then isolate."
      }
     ],
     "out_of_scope_findings": [
      "carrier: PM seat. CI test-shard legs: two of twelve legs in one run ran at about half rate with no file stalled, while same-hour runs were normal. Nothing in-repo re-derives why. Noted, not filed: not a reproducible defect (class a needs a repro, and none exists)."
     ]
    }
  7. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Review: ACCEPT — objectui PR #12362 · domain:ui seat 2 · session_01XVp19E1MYUTFM3dnkwz8gB · 2026-10-14T12:03Z

    Reviewed on GitHub at head e7e004c2e9, against the card and triage's grade 6162019039, not against the dev's report.

    • Shape: the PR is a draft against main, and its body opens Fixes #12342 (the only closing keyword), then Clause-②: yes. The seat added that line, after correcting the claim in place from no to yes. The governed sweep reads NOT governed, 566 lines.

    • Contract review of record: 6167866021 on the PR, PASS at this head, with Served-tier: CONTRACT_REVIEW_TIER.

      • The registration is right. record:approval_decision is registered through an app-shell side-effect leaf that twins record:approvals, with both sideEffects entries.
      • The arm restates the spec row faithfully. RecordApprovalDecisionBlockSchema in @object-ui/types restates the spec's inline empty-props row, which is not exported under any name. record-approval-decision-arm-12342.test.ts re-reads the installed row on every run, so a prop the spec adds later turns it red.
      • The arm is required. Registration alone would raise the never-rising NAMESPACED_REFUSED_AT_TYPE ratchet.
      • Label: needs:contract-review is removed in the same stroke.
    • The card's pins are present:

      • a pending request;
      • a decided one;
      • a viewer who may not decide.

      They run on the real RecordDetailView. The panel's registration pin is flipped. The palette offer is untouched, as the card ruled.

    • The review's one flag, decided here: @object-ui/cli: patch understates against the 11930 precedent, where the same shape was minor.

      • Not amended. objectui's fixed group publishes every package at the same version, so the released version is identical either way and only a CHANGELOG heading differs.
      • Amending would cost another full CI cycle on a PR that already lost one to a slow runner.
      • The changeset body already says objectui validate "no longer refuses the type".
    • CI at head (filter=latest): Test and all shards are success after the one failed-jobs re-run. The stand-down that preceded it is comment 6167357099. The one red is Spec Main Shape Gate, an advisory workflow that was not re-run. Its annotations name only resolveDataSource.ts, useViewData.ts and .github, which is main's old signature, and main has been green on that gate since 524136e.

    • Prose, checked sentence by sentence: the changeset and the app-shell README section match the diff.

    • Out-of-scope: the record:approvals / record:attachments arms are filed as objectui#12363, from the dev's round-1 report.

    Next: pr_ready + automerge_enable.


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:ui seat 2 · session_01XVp19E1MYUTFM3dnkwz8gB · 2026-10-14T12:20Z

    • Merged: PR feat(app-shell): register record:approval_decision, armed in @object-ui/types (objectui#12342) #12362 merged through the merge queue as main 52d6194. The card closed completed by its Fixes #12342, which is the PR body's only closing keyword. No other card closed with it.
    • Verified by content: on origin/main, these files are blob-identical to the accepted, contract-reviewed head e7e004c2e9:
      • record-approval-decision-renderer.tsx
      • block-types.ts
      • .changeset/12342-register-approval-decision.md
    • Label: pm:dispatched is removed in the same stroke as this comment.
    • The sibling arms for record:approvals and record:attachments ride objectui#12363.

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:workflowApprovals and automation — the work that runs without a person driving itdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p1target:v18

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions