Repository navigation
fix(app-shell): a position decision output lists the position registry and commits position names (objectui#7611) - #12152
Merged
objectstack-fleet[bot] merged 4 commits intoOct 11, 2026
Conversation
…y and commits position names (objectui#7611) The Approve/Reject dialog rendered a position decision output as a sys_position lookup. A fresh database holds no sys_position rows, so the picker offered nothing, and a row it did offer committed a row id where the spec (objectstack#22710) and the engine's resolveAs position read a machine name. decisionOutputParams moves position from the record-lookup table to a catalog table, and renders it as a select over the registry items the caller read through the console's metadata store (ensureType), the reader RecipientPickerField lists the same registry through. DeclaredActionsBar reads them at click time. No reader degrades to free text; an empty registry is still a picker. Claude-Session: https://claude.ai/code/session_01Rerax7QTjKMPCUZxQUtPFR Co-authored-by: Claude <noreply@anthropic.com>
…the name guard is pinned (objectui#7611) The first ablation of the empty-name clause in registryOptions stayed green: the fixture held no item whose name is an empty string. Claude-Session: https://claude.ai/code/session_01Rerax7QTjKMPCUZxQUtPFR Co-authored-by: Claude <noreply@anthropic.com>
…t, not during render (objectui#7611) Writing the ref during render raised react-hooks/refs on DeclaredActionsBar. A click always lands after a commit, so an effect with no dependency list keeps the ref current without keying on the store's context identity. Claude-Session: https://claude.ai/code/session_01Rerax7QTjKMPCUZxQUtPFR Co-authored-by: Claude <noreply@anthropic.com>
…stry read (objectui#7611) Awaiting the registry read on every approve/reject moved the dispatch out of the click's tick, and DeclaredActionsBar.overrideAffordance's poll, which reads the dispatch synchronously after its click, timed out three times. A decision with no catalog output now dispatches synchronously, as before; decisionOutputsReadRegistry is the one predicate the bar asks, and a store with no catalog output to serve is never read. Claude-Session: https://claude.ai/code/session_01Rerax7QTjKMPCUZxQUtPFR Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ 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
|
This was referenced Oct 11, 2026
objectstack-fleet
Bot
deleted the
claude/issue-7611-decision-output-position
branch
October 11, 2026 19:41
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #7611
Clause-②: no
Item 3a of the C9 remainder census on #7611 (comment 6111307114), dispatched by the seat's answer 6111342697 as PR-2a. Item 3b, the spec-derived approver readers, waits on objectstack-ai/objectstack#22865 and is not in this PR, so #7611 remains open.
What changes
decisionOutputParams,positionleavesOUTPUT_LOOKUP_OBJECTS, which keepsdepartmentandteam, and becomes the one entry of a newOUTPUT_REGISTRY_TYPEStable: a catalog kind. Nothing else in the diff namesposition.selectover the registry items the caller passes asregistry. Each option's value is the item's machine name and its label is the item'slabel, else its name. Items without a name are dropped, and the list is sorted by name. This is the same readingRecipientPickerField's registry kinds make of the same registry (ADR-0131 D3/D7, objectui#12089).readDecisionOutputRegistryreads those items through the console's metadata store,ensureType('position'), once per type. A failed read maps to an empty list.decisionOutputsReadRegistrysays whether any output is a catalog kind.DeclaredActionsBaris the one decision surface. The Approval Center and the record page both mount it. It reads the store raw fromMetadataCtx. Only a decision with a catalog output awaits the registry read; every other decision still dispatches in the click's own tick.selectis a declared param type, andresolveActionParams()copies itsoptionsthrough key by key.decision_output_defsdocblock in apps/console'sapprovalsApi.tssaid position values are record ids. It now says position commits machine names.Measured in a browser
Setup:
origin/main8532783f65withobjectstack dev --seed-admin --fresh. It ran in a detached worktree; the closure build was 60 of 60 tasks cached.DEV_PROXY_TARGETpointed at it: one from this branch, and one from the basea7d492011for the before leg.GET /api/v1/data/sys_positionanswers"records":[]with"total":0, andGET /api/v1/meta/positionserves 16 positions.The pending approval:
pr2a_position_output, was saved at runtime withPUT /api/v1/meta/flow/pr2a_position_output. It has two approval steps.lead_review, declaresdecisionOutputs: [{ key: 'parallel_positions', type: 'position', multiple: true, required: true }].co_sign, has the approver{ type: 'expression', value: 'vars.lead_review.parallel_positions', resolveAs: 'position' }.decision_output_defscarries the position output.Before (base
a7d492011). Checked on the Approval Center and on the record page:GET /api/v1/data/sys_position?top=50and shows "No options found".After (this branch). Checked on the Approval Center and on the record page:
GET /api/v1/meta/positionand sends nothing tosys_position.POST /api/v1/approvals/requests/ID/approvewith the body{"outputs":{"parallel_positions":["auditor","manager"]}}.The engine routes by those names:
node_config_jsonstores__decisionOutputs: {"parallel_positions":["auditor","manager"]}.co_signrequest opened withpending_approversset to the users who holdauditorandmanagerinsys_user_position: the demo auditor and the admin.The after leg ran at
87aa90858, then again at4223b14c0on a second fresh database. Both runs sent the same wire body and opened the same downstream slate.6eb495c67changes only when the bar awaits the read, and a position output still awaits it. The pins and the ablation table below cover that commit.Not on the wire: the replaced lookup committed
sys_positionrow ids (LookupField's default id field). That is read from code. A fresh database has no rows, so there was nothing to commit.Tests (head
6eb495c67)packages/app-shellandapps/consolethat namesDeclaredActionsBar, a decision output, orApprovalDecisionPanel. The list was enumerated bygit grep -land covers the Approval Center page, the record page's approval actions and the override-affordance suite.pnpm --filter @object-ui/app-shell type-check: exit 0. That istsc --noEmitplustsc -p tsconfig.test.json. Run with--listFilesOnly, the test program lists both edited test files.check-changeset-presence(5 source files, 2 released packages, 1 changeset) andcheck-changeset-no-major;check:changeset-claims,check:pending-changeset-literals;check:new-line-citations(0 new) andcheck:control-bytes;check:vi-mock-specifiers,check:vi-mock-inherit,check:vi-mock-override-shapeandcheck:test-path-roots;check:i18n-keys,check:shell-escape-residueandcheck:spec-symbols.no-explicit-any, on theas anyaction fixtures the test file's other cases also use.--format json. The rooteslint.config.jsenables no type-aware linting (noparserOptions.projectand noprojectService), so this diff cannot move the verdict on any file it does not touch.One-time ablations
Every leg ran through objectstack's
scripts/ablation-replace.mjsin wrap mode. The anchor had to hit, the blob had to change, and the restore was proven: blob equal to HEAD, and an emptygit diff HEAD. No dist was involved, because vitest aliases every@object-ui/*package to itssrc.positionfromOUTPUT_REGISTRY_TYPES87aa90858,6eb495c6787aa90858,6eb495c6787aa90858{}without a reader, and[]for a read that fails"87aa9085887aa90858[]87aa9085887aa9085887aa9085887aa90858,4686fb7dd87aa908586eb495c676eb495c67Two legs did not measure on the first try:
4686fb7ddadds one, and the rerun went red on 2 pins.Not measured here, declared for CI
4223b14c0was stopped after about 11 minutes: it held the shared verification lock while another agent waited behind it. Before it stopped, it had reported one red file,DeclaredActionsBar.overrideAffordance(3 failed). That suite reads the dispatch synchronously after its click, so awaiting on every decision broke it.6eb495c67keeps the dispatch synchronous unless a catalog output exists, and the file is green in the 29-file run.pnpm test,pnpm lint, and the console'stype-check. The console change is a comment.Acceptance notes
everyoneandguest. The engine'sexpandPositionUsersreadssys_user_positionrows plus the membership tier, so a position held only implicitly probably resolves to nobody, and a run that picked one would route intoonEmptyApprovers. The sharing-rule recipient picker offers the same list. Successor: none.RecipientPickerField. Polish, noted only.multipleoutput renders as a chip group (MultiSelectField), which was 16 chips on the showcase. Polish, noted only.Changeset:
.changeset/7611-decision-output-position-registry.md(@object-ui/app-shelland@object-ui/console, minor). Draft per AGENTS.md section 9: this PR comes from a dispatched claim.Developer session
session_01Rerax7QTjKMPCUZxQUtPFR, dispatched by the epic PM of objectstack-ai/objectstack#15194.Generated by Claude Code