Repository navigation
fix(app-shell): the flow inspector's inline visibleWhen cell for a screen field reads the screen's declared fields, as the Problems panel and the Debug run do (objectui#10772) - #10792
Conversation
… declared fields The flow inspector's inline expression cell for a screen node's fields[].visibleWhen column read the FLOW scope: it flagged a sibling-field predicate, said nothing on a run variable, and its picker offered the flow scope. It now names the column by the Problems panel's own isScreenVisibleWhenColumn (from the node in context and the list's fieldId), offers screenPredicateRoots(node) in its picker, and judges its inline note by screenVisibleWhenScopeError - the one rule the Problems panel and the Debug run's screen step share. Every other expression column keeps the flow scope. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN
…en visibleWhen cell A new patch changeset for the cell; a dated note after the pending 10743 entry's "Still on the flow scope" paragraph (frontmatter untouched); the README sentence that said the cell still reads the flow scope now says it follows the screen rule. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN
|
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
|
Contract reviewServed-tier: ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: FAIL One wording fix before landing. In |
…#10772 review) Claude-Session: https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN Co-authored-by: Claude <noreply@anthropic.com>
✅ 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
|
Contract reviewServed-tier: A narrow round-2 review, run in-seat by the dispatching seat, of the delta ① Derived judgments
② Semver levelUnchanged: ③ Boundary flags
Implemented-by: VERDICT: PASS |
Fixes #10772
Clause-②: no — a Studio authoring hint moves onto the already-ruled screen scope (ruling C on objectui#10743); no declared surface moves
Executes the triage direction on objectui#10772 (comment 5856191354, from ruling C
5853038135on objectui#10743) under claim 5856807565. Branchclaude/issue-10772-inline-cell-screen-scope, headb6e912aab4, base29b45f6a0c. Dispatched by thedomain:uiseat 2, sessionhttps://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN.What changed
inspectors/FlowObjectListField.tsx: theexpressioncolumn branch asksscreenVisibleWhenNode(context.node, fieldId, col.key). When that names a screen node, the picker getsscreenScopeGroups(node): one "Screen fields" section holding exactly[...screenPredicateRoots(node)], which is the screen's declared fields plusrecord.FlowExprIssuegetsscreenNode. Every other expression column is unchanged and keepsscopeGroups, the flow scope. New optional propfieldId: the list's descriptor id. It is never forwarded to a nested list, so a nested list can never qualify.inspectors/FlowExprIssue.tsx: new optional propscreenNode. When it is set, the unknown-reference step isscreenVisibleWhenScopeError(value, screenNode), andscopeGroupsis not read. The brace/shape error still comes first (validateExpressionClient), in the Problems panel's order (checkScreenVisibleWhen). The docblock now says which scope each cell reads (direction item 2).inspectors/FlowNodeConfigField.tsx(the plumbing): passesfieldId={field.id}toFlowObjectListField. One prop, plus a comment.previews/flow-expr-problems.ts:isScreenVisibleWhenColumnis nowexported, with its docblock saying why. The cell names the column with the same predicate the Problems panel uses, so the column's identity is not copied. ⚠ This file was not in the claimed file surface. It is declared here: one keyword, and no verdict moves.inspectors/flow-scope.ts:ScopeGroupIdgains'screen_fields'. This follows the approval precedent: its own id, so the section can never leak into the flow picker. The change is type-only.previews/screen-spec.ts: read-only. No export was needed;screenPredicateRootsandscreenVisibleWhenScopeErrorwere already exported..changeset/10743-studio-screen-visiblewhen-live.md: a dated note (objectui#10533 form) follows its "Still on the flow scope" paragraph. That paragraph is kept as the record of that change. Frontmatter md5 of lines 1–3 is4e8ce55021fe3b14329c8b4cb3f9f354before and after.packages/app-shell/README.md: the flows paragraph said "the inline inspector'svisibleWhencell still reads the flow scope (a follow-up)". This change makes that sentence false, and the README is published (fileslistsREADME.md), so it now says the cell follows the same rule. Declared as a file-surface addition..changeset/10772-inline-screen-visiblewhen-cell.md:'@object-ui/app-shell': patch.H1: reproduced on base
29b45f6a0cProbe (not committed): the real
FlowObjectListFieldwith thescreendescriptor'sfieldscolumns,contextset to the draft and node, and theresolveFlowScopegroups. The draft has arecord-after-updatestart oncrm_lead, a flow variableneedsApproval, and a screenreview. Readings, verbatim:["needsApproval","record","previous"]note,discount > 0(sibling): NOTES["discountis not a reference in scope at this step."]other,other_field == 'x': NOTES["other_fieldis not a reference in scope at this step."]reason,needsApproval == true(run variable): NOTES[]["needsApprovalvariable · boolean","recordtrigger record · crm_lead","previousrecord values before the change"]The card's measurement holds on base.
H2: the seam
col.kind === 'expression'branch ofFlowObjectListField. Before this change it renderedVariableTextInput groups={scopeGroups ?? []}andFlowExprIssue scopeGroups={scopeGroups}, andFlowExprIssueranfindUnknownRefs(value, role, scopeRoots(groups)).FlowNodeInspectorpassescontext={{ draft, node }}throughFlowNodeConfigFieldintoFlowObjectListField. The field id was missing. The Problems panel names the column byisScreenVisibleWhenColumn(type, fieldId, colKey), so the one missing input isfieldId, set byFlowNodeConfigFieldfromfield.id.screenVisibleWhenNode(context.node, fieldId, col.key), which returns aScreenPreviewNodeorundefined. It feedsscreenScopeGroups(node), which isscreenPredicateRoots(node), for the picker, andFlowExprIssue.screenNode(screenVisibleWhenScopeError(value, node)) for the note. No third copy of the rule.screenVisibleWhenScopeErrorreturns forneedsApproval == trueon this screen is the sentence "needsApprovalis not a field on this screen". No nearest-field suffix is added, because no declared field is close. The Problems panel shows the same sentence prefixed by the row label ("Reason: …"). The inline cell sits in the row, so it shows the sentence without a prefix. The pin asserts equality with the panel's message instead of pinning the literal.Pins and ablation
New file
inspectors/FlowObjectListField.screenVisibleWhen-10772.test.tsx. It mounts through the real plumbing:FlowNodeConfigFieldwith the realscreenanddecisiondescriptors,contextset to the draft and node, andresolveFlowScopegroups.discount > 0andother_field == 'x'(both declared on the screen) show no note and no alert.needsApproval == truecell shows exactly onerole="note"namingneedsApproval. The panel's messages on nodereviewequal["Reason: " + that note], atwarning.[...screenPredicateRoots(review)](discount,other_field,note,extra,reason,record), with noneedsApprovaland noprevious.conditions[].expressionupstream of the screen:discount > 0is flagged namingdiscount,needsApproval == trueis clean, and the picker equals theresolveFlowScopetokens (needsApproval,record,previous).29b45f6a0cunder the head pin file, with blobs confirmed equal to base. The restore was trap-driven withgit checkout HEAD --, every blob was re-checked equal to HEAD, andgit diff HEADwas empty afterwards. Result:Tests 3 failed | 1 passed (4). Pins 1–3 are red; control 4 is green.b6e912aab4:Tests 4 passed (4).ablation-replace.mjsin wrap mode. It replacedconst screenNode = screenVisibleWhenNode(context?.node, fieldId, col.key);withconst screenNode: ScreenPreviewNode | undefined = undefined;. The anchor hit exactly once and went from 1 to 0 hits; the blob went from599051a346e0toda61329c536d. Run over the pin file plus the three existingFlowObjectListField.*suites:Test Files 1 failed | 3 passed (4),Tests 3 failed | 11 passed (14). Only the three screen pins are red; the control and every existing row stay green. The restore left the blob equal to HEAD599051a346e0andgit diff HEADempty, and afterwards the marker count on disk is 0 and the anchor count is 1.Gates (at
b6e912aab4, every run of the heavy ones under the verify lock; seconds are shared-box)turbo run build --filter='@object-ui/app-shell^...' --concurrency=2:Tasks: 28 successful, 28 total,VERDICT command-exit 0.pnpm --filter @object-ui/app-shell type-check: the script echoed@object-ui/app-shell@17.6.0 type-check,VERDICT command-exit 0.tsc -p tsconfig.test.json --listFileslists the new pin file (1 hit).git grepover app-shell tests for imports ofFlowExprIssue,FlowObjectListField,FlowNodeConfigField,FlowKeyValueField,FlowNodeInspector,flow-scope,useFlowScope,flow-expr-problems):Test Files 24 passed (24),Tests 299 passed (299). This narrowing is declared. Tests that reach these modules only transitively are not in that set; the fullpnpm testis CI's run.--format json): 6 files, 0 errors, 1 warning. The warning isreact-hooks/refson therows.mapline ofFlowObjectListField.tsx, and it is pre-existing: the base blob linted alone shows the same rule, 1 warning.eslint.config.jshas noparserOptions.project, noprojectServiceand no type-checked preset (0 hits), and no import-resolution plugin. So type-aware linting is off, and this diff cannot move a verdict on an untouched file. The repo-levelpnpm lintis CI's run.check-changeset-presence✅ (9 files changed, 6 published source, 1 changeset added).check-control-bytes✅.check-new-cross-file-line-citations:VERDICT … 0 new citation(s).check-pending-changeset-literals✅.check-changeset-no-major✅.check-changeset-fixed✅.check-vi-mock-specifiers✅.check-vi-mock-override-shape✅.check-vi-mock-inherit✅.check-test-path-roots✅.check-changeset-claims(report-only) names two pending changesets that citeflow-scope.ts:6296-conditionbuilder-subject-vocabulary.mdandflow-entry-condition-builder.md. Both paragraphs are still true. They describefieldPrefix: onStart ? '' : 'record.'andincludePrevious, and that text reads 1 and 5 occurrences at both base and head. This diff adds one union member and a comment toScopeGroupIdand nothing else.check-changeset-overwrite(report-only) records the modification of10743-studio-screen-visiblewhen-live.md, case 2: a deliberate prose correction with the declaration unchanged (@object-ui/app-shell: patchat base and now).NOT GOVERNED — 9 path(s).check-readme-exports, because app-shell's owndistis not built here (only its dependency closure). The README edit is prose inside an existing bullet and adds no fenced import block. CI's README Export Check covers it. Console Performance Budget (eager closure) is CI's.Serial
The claim read open PRs at 14:25Z and none touched these files. Before the last push,
origin/mainwas fetched into the private refrefs/issue-10772/mainatbff63cc12e(3 commits and 47 files past base).git merge-tree --write-treeagainst HEAD exited 0 (tree13994de4a0). The intersection of main's moved files with this PR's 9 files is empty, and none of main's moved files is undermetadata-admin/inspectors/,metadata-admin/previews/orScreenView.Acceptance notes
context.node.config.fields), the same node the Problems panel judges. A field row renamed in the cell is picked up on that row's flush, on blur or Enter, not keystroke by keystroke.recordas a bare token, becausescreenPredicateRootsadmits it (record.discountresolves asdiscountdoes). The section carries no per-token detail, since the rule yields names only.record.zzz > 0is clean on every surface (the rootrecordis admitted) while the runner faults on it. The inline cell now inherits that same reading. objectui#10743 remains closed as delivered.useFlowScope("Flow variables", "Trigger record"). The screen sentence is the Problems panel's English literal, and the flow wording is localized, as recorded on objectui#10743.registerFlowand the resume door narrow to the declared scope, is finding(service-automation,lint): the resume door evaluates a screen field'svisibleWhenover the run's variables, wider than the declared scope (the screen's own field names), and nothing refuses an undeclared name at authoring objectstack#20178. It is unchanged by this PR.Generated by Claude Code