Repository navigation
feat(app-shell): register record:approval_decision, armed in @object-ui/types (objectui#12342) - #12362
Conversation
…ui/types (objectui#12342) Spec 18 declares the block; the decision panel was written but no registration mounted it, so a page naming it passed the spec and drew nothing. Register it from a side-effect leaf in the app-shell entry, arm it in @object-ui/types/zod from the spec's empty strict row (the namespaced registered-types ratchet never rises), regenerate the CLI's known types, and pin a real render for a pending request, a decided one and a viewer who may not decide. Claude-Session: https://claude.ai/code/session_01XVp19E1MYUTFM3dnkwz8gB Co-authored-by: Claude <noreply@anthropic.com>
…er tier's warning (objectui#12342) The family-D refusal sentence carries the corrected objectui#10928 clause, as content-channel-parser-tier-clause-10928 requires of every member. Claude-Session: https://claude.ai/code/session_01XVp19E1MYUTFM3dnkwz8gB Co-authored-by: Claude <noreply@anthropic.com>
|
changeset-claim-re-read
|
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
|
Standing down on one red:
Generated by Claude Code |
Contract reviewServed-tier: Inputs read: card #12342 body, the first grade ( ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
Fixes #12342
Clause-②: yes
What
@objectstack/spec18 declares the page blockrecord:approval_decision.ApprovalDecisionRendererexisted, but no registration mounted it, so a page naming the block passed the spec and drew nothing. This PR registers it and lands everything a registered, page-authorable type needs in this repo.@object-ui/app-shell). New side-effect leafviews/record-approval-decision-renderer.tsxregistersApprovalDecisionRendererasrecord:approval_decision(namespacerecord,skipFallback: true, so no bareapproval_decision). It joins the entry's side-effect imports and both halves of the packagesideEffectsarray, the same pathrecord:approvalsandrecord:attachmentstake. The renderer itself is unchanged and still not exported from the entry.@object-ui/types). NewRecordApprovalDecisionBlockSchema(zod,zod/record-approval-decision.zod.ts) plus a TS twin of the same name (record-approval-decision.ts), and a new member ofAnyComponentSchema(zod and TS). Thepropertiesbag restates the spec row: the spec builds it inline as an empty strict object and exports it under no name, the same situation aselement:divider. So the only bag it accepts is{}.body/childrenare refused by name.known-schema-types.tsregenerated (node scripts/regenerate-known-schema-types.mjs): plusrecord:approval_decision.PALETTE_EXCLUSIONSreason changed, from "not yet registered" to "renders (registered by@object-ui/app-shell), not yet offered"..changeset/12342-register-approval-decision.md(app-shell and types minor, cli patch).Why it lands outside app-shell too
The card read this as registration plus pins. Measurement showed that registration alone would raise a ratchet pin that must never rise.
registered-types-validate-ratchet-10859(@object-ui/cli) counts registered namespaced types thatobjectui validaterefuses attype. Onmain,validateAuthoredDocumentanswersinvalid_unionattypeforrecord:approval_decision, and also forrecord:approvalsandrecord:attachments(probe run on base065a1cf). Registering the block without an arm would takeNAMESPACED_REFUSED_AT_TYPEfrom 308 to 309. The panel's own docblock already planned for the registration, its side-effect import, itsknown-schema-types.tsline and its zod arm to land together. The arm follows thecloud:widgets' precedent (its own module, wired intoAnyComponentSchema, TS twin plus mirror-parity pair). It is not inpublic-blocks.zod.ts, because that union is pinned to the ADR-0080 curated list and this block is not curated.Premise checks (dispatch section 2)
views/approval-decision/ApprovalDecisionPanel.tsx, and its test pinnedComponentRegistry.has('record:approval_decision') === false. The pin is flipped totrueplusget(...) === ApprovalDecisionRenderer, and a new row renders{ type: 'record:approval_decision' }through the realSchemaRenderer.sideEffectshandling as the two siblings (check:side-effects-arraygreen). The siblings are registered without arms, so copying them exactly is what the ratchet refuses (see above).RecordDetailViewonly skipsuseRecordApprovalson asys_approval_requestpage, and its comment names this block as the place where decisions are drawn. It mounts no panel by any route of its own; the panel appears only where page metadata places the block.RecordDetailView.tsxis not edited, so this PR has no interaction with feat(print): render a page that declaresprint— print CSS, printable blocks whole, record print action (objectui#11958) #12356.@objectstack/spec18.0.0-next.0 carriesComponentPropsMap['record:approval_decision']asemptyProps(...), a strict object with no member. The new arm test re-reads that row on every run: its key set is empty, and the arm's bag accepts and refuses exactly what the row does.Pins on a real render
apps/console/src/services/approvalRequestsDataSource.decisionPage.test.tsx(realRecordDetailView, realDeclaredActionsBar, routed approvals source):approved, no tally,can_act: false) gets the panel with no progress bar and no decision. A viewer who may not decide (the submitter, pending) gets the tally and the recall control, and no approve or reject. CONTROL: the deciding viewer gets both decisions and no recall. The pending-request rows already present still pass.Verification (final head
e7e004c)e7e004cunder the verify lock:packages/types/+packages/cli/in full,packages/app-shell/src/views/approval-decision/,packages/app-shell/src/views/metadata-admin/previews/__tests__/, the product-neutral ratchet, the two console files,scripts/__tests__/known-schema-types-derivation-5115.test.ts--Test Files 427 passed (427),Tests 11161 passed (11161).@object-ui/types,@object-ui/app-shell,@object-ui/cliall exit 0 on3a9b5d5, after building their dependency closure (--filter '@object-ui/app-shell^...' --filter '@object-ui/cli^...').@object-ui/typeswas re-run one7e004cand exits 0. The only change from3a9b5d5toe7e004cis one string literal in the arm's refusal text. The app-shelltsconfig.test.jsoncoverssrc/**/*.test.tsx, so the uncastSchemaRendererrow is type-checked against the built@object-ui/types.packages/app-shell/src/index.tsthroughablation-replace.mjs(anchor 1 to 0, blob changed) turns the console file red:Tests 7 failed | 4 passed (11), starting with the registration row. Restore was proven by blob == HEAD.can_acttotrueturnsa decided requestred (expected button to be null). Restore was proven by blob == HEAD.e7e004c:check: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-citationsall 0.check-changeset-fixed.mjs,check-changeset-presence.mjsandcheck-changeset-no-major.mjsare 0.check:sdui-registration-pinsis 0 after a full console build (approval_decision 1 chunk(s), 16 of 16 present; measured on3a9b5d5, ande7e004cchanges no registration or array).check:spec-floorsis 1, with "The scan collapsed: 0 package(s) declare @objectstack/spec in a consumer-facing field". That is the known failure onmain(objectui#12334), and this diff touches no dependency field.eslint --format jsonover the 17 changed.ts/.tsxfiles gives 17 results, 0 errors and 0 warnings. The packagelintscripts areeslint .(types, app-shell, console) andeslint src(cli).eslint.config.jssets noproject/projectService, so linting is not type-aware and this diff cannot change the verdict on any untouched file. The fullpnpm lintrun belongs to CI.Acceptance notes
Clause-②: no):@object-ui/types/zodexportsRecordApprovalDecisionBlockSchema,@object-ui/typesexports the TS type of the same name, andAnyComponentSchema/StrictAnyComponentSchema/objectui validatenow accept arecord:approval_decisionnode. All three follow from the spec row. They are reported here and in the dev report; noClause-②line is written.NODE_ENVELOPE(responsiveStyles). Like thecloud:arms, it declares no node-level key without a measured producer, and Studio does not offer the block.record:approvalsandrecord:attachmentsremain registered without arms.objectui validatestill refuses both attypewhile the spec accepts them, and they stay inside the namespaced ratchet count. Not addressed here; noted in the dev report.Generated by Claude Code