You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
finding(app-shell): useAutoRunCreate strips ?runAction=create_environment even when the toolbar has no create action, destroying the deep link unrecoverably #4123
Observation recorded while investigating #3803 (whose own premise did not survive measurement — see that card). Filed separately because it is a different defect from #3803's hypothesis and is out of that card's scope.
Fact
packages/app-shell/src/environment/EnvironmentListToolbar.tsx arms useAutoRunCreate from the presence of any toolbar action, not from the presence of the create action:
toolbarActions is filtered only by locations.includes('list_toolbar'). So when the toolbar renders actions but none of them is create_environment, shouldRun still becomes true, and the effect strips runAction from the URL — while renderedActions attaches autoTrigger to nothing, because that only happens for a.name === CREATE_ACTION.
Measured on origin/main (sha bfdf3d419) with the real action:bar + action:button runner, a toolbar carrying a single non-create action and ?runAction=create_environment in the URL:
no-create-action: urlParam=null execute=0
The param is gone and nothing ran. Because consumption is modelled as "strip the URL", the signal is unrecoverable — a reload cannot retry the deep link, which is exactly the "one-shot, so refresh does not re-open" property working against the user here.
Why it may matter
This is the #844 welcome-page flow ("Create your environment" CTA deep-linking into the list). The user lands on the list, no dialog opens, and the URL no longer carries the intent.
Reachability in a real deployment is not demonstrated and is the open question for triage: it needs a toolbar that has at least one list_toolbar action but no create_environment. Two candidate paths, neither confirmed against real cloud metadata:
the cloud does not serve create_environment for this org/plan while still serving other toolbar actions;
create_environment declares requiredPermissions the caller lacks, so action:bar's capability gate (ADR-0066 D4) filters it out of the rendered bar — note the toolbar's own toolbarActions is computed before that gate, so the two disagree by construction.
The second path is the interesting one: the arming condition and the rendering condition are evaluated by different code with different filters, so they can diverge whenever the bar drops an action the toolbar counted. Filed as observation-class (finding, no pm:queue) per objectstack#4949 — severity self-assessed at filing time is unreliable, so triage should grade it.
Sketch of a fix direction (not implemented)
Arm on the create action specifically rather than on toolbarActions.length — gate useAutoRunCreate on whether toolbarActions actually contains an action named create_environment, so the URL is only consumed when there is something to trigger. Whether the capability-gate divergence should also be closed (toolbar and bar applying the same filter) is a separate design question.
Findings triage: promoted — finding removed, pm:queue on (labels changed with this comment).
Premise re-verified at origin/main @ 92c0b1f: EnvironmentListToolbar.tsx:146 still arms on toolbarActions.length > 0 ? ctaKind : null, and the count/render divergence the card describes (toolbar counts before the capability gate, action:bar filters after) is unchanged.
Why promoted rather than held for the reachability question: the defect mechanism is measured with the real runner (urlParam=null execute=0), the failure destroys a user-intent signal unrecoverably (the one-shot strip), and the fix direction is narrow and safe regardless of which reachability path is live — arm on the presence of the create action itself instead of any toolbar action. That fix is correct even if today's cloud metadata never hits the divergence; the arming condition is simply wrong as written. The larger design question (should toolbar and bar share one filter) can stay out of scope, as the body already suggests.
Direction (investigate-then-implement): FIRST measure the open reachability question the card poses — can ADR-0066 D4's capability gate filter the create action out AFTER the toolbar counted it (arming and rendering using different filters by construction)? Whatever the answer, the fix direction is already sound because the current failure mode is strictly wrong: arming on toolbarActions.length > 0 strips ?runAction=create_environment unrecoverably while triggering nothing. Re-key the arm on the CREATE ACTION'S presence in the SAME post-filter list the bar renders (one predicate, one list — arming and rendering cannot disagree by construction), pin the measured D4-filtered case (deep link + create action filtered out → param SURVIVES or degrades recoverably, never silently swallowed), and keep the #3803-verified consumption ordering untouched (runner consumes before the parent strips — don't disturb that machinery, it was measured correct).
Phase 1 answered the card's open question by measurement with the real component stack: the ADR-0066 D4 capability gate is the divergence path (toolbar filtered placement only; the bar additionally applies mayInvoke), reproduced as the card's exact urlParam=null execute=0 signature with ordinary metadata. The fix is the structural one: the toolbar joins useCapabilityGate — the shared hook built precisely for surfaces that filter their own lists, which this was a fourth surface bypassing — so arming and rendering read ONE list and cannot disagree by construction. Three judgment calls, each defended correctly: the unsatisfiable-arm degradation LEAVES the URL (consumption is the strip; a preserved one-shot intent is honored by the next capable mount — pinned), the ?runAction=X generalization was DECLINED after measuring that no generic contract exists, and the two sibling affordances (skeleton, upgrade CTA) moved to the gated list because leaving them would re-create the two-lists bug in miniature. #3803's verified ordering untouched and re-pinned; the reverse verification's 3-red/7-green split is attribution, not a gap, and was predicted.
#4162 (autoTrigger silently dropped by action:menu on overflow — measured one layer deeper, probe deleted before commit) is a genuine design fork and is correctly held observation-class. Flipping ready + auto-merge.
Activity
os-zhuang commentedon Aug 10, 2026
Findings triage: promoted —
findingremoved,pm:queueon (labels changed with this comment).origin/main@92c0b1f:EnvironmentListToolbar.tsx:146still arms ontoolbarActions.length > 0 ? ctaKind : null, and the count/render divergence the card describes (toolbar counts before the capability gate,action:barfilters after) is unchanged.urlParam=null execute=0), the failure destroys a user-intent signal unrecoverably (the one-shot strip), and the fix direction is narrow and safe regardless of which reachability path is live — arm on the presence of the create action itself instead of any toolbar action. That fix is correct even if today's cloud metadata never hits the divergence; the arming condition is simply wrong as written. The larger design question (should toolbar and bar share one filter) can stay out of scope, as the body already suggests.?runAction=create_environment的 autoTrigger 可能被无关 re-render 抹掉 #3803 the investigation that spawned this.本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
yinlianghui commentedon Aug 10, 2026
Claim: PM loop round 6 (rolling slot refill)
Session:
session_017Qqyix2QcnpUC9XeYVDzx3· Branch:claude/issue-4123-autorun-arm-predicate· Worktree:objectui-issue-4123File surface:
packages/app-shell/src/environment/EnvironmentListToolbar.tsx(useAutoRunCreatearming predicate) + tests. Serial constraints: disjoint from #7100 (metadata-admin), #3782 (docs/scripts), #3811 (console routes + i18n packs), #4149 (root doc) in flight; no i18n keys involved.Container & model: S,
mode:subagent,model: opusDirection (investigate-then-implement): FIRST measure the open reachability question the card poses — can ADR-0066 D4's capability gate filter the create action out AFTER the toolbar counted it (arming and rendering using different filters by construction)? Whatever the answer, the fix direction is already sound because the current failure mode is strictly wrong: arming on
toolbarActions.length > 0strips?runAction=create_environmentunrecoverably while triggering nothing. Re-key the arm on the CREATE ACTION'S presence in the SAME post-filter list the bar renders (one predicate, one list — arming and rendering cannot disagree by construction), pin the measured D4-filtered case (deep link + create action filtered out → param SURVIVES or degrades recoverably, never silently swallowed), and keep the #3803-verified consumption ordering untouched (runner consumes before the parent strips — don't disturb that machinery, it was measured correct).Generated by Claude Code
yinlianghui commentedon Aug 10, 2026
ACCEPT (objectui seat PM, session
session_017Qqyix2QcnpUC9XeYVDzx3, review of record) — PR #4166.Phase 1 answered the card's open question by measurement with the real component stack: the ADR-0066 D4 capability gate is the divergence path (toolbar filtered placement only; the bar additionally applies
mayInvoke), reproduced as the card's exacturlParam=null execute=0signature with ordinary metadata. The fix is the structural one: the toolbar joinsuseCapabilityGate— the shared hook built precisely for surfaces that filter their own lists, which this was a fourth surface bypassing — so arming and rendering read ONE list and cannot disagree by construction. Three judgment calls, each defended correctly: the unsatisfiable-arm degradation LEAVES the URL (consumption is the strip; a preserved one-shot intent is honored by the next capable mount — pinned), the?runAction=Xgeneralization was DECLINED after measuring that no generic contract exists, and the two sibling affordances (skeleton, upgrade CTA) moved to the gated list because leaving them would re-create the two-lists bug in miniature. #3803's verified ordering untouched and re-pinned; the reverse verification's 3-red/7-green split is attribution, not a gap, and was predicted.#4162 (autoTrigger silently dropped by action:menu on overflow — measured one layer deeper, probe deleted before commit) is a genuine design fork and is correctly held observation-class. Flipping ready + auto-merge.
Generated by Claude Code
fix(app-shell): arm the create deep link on the create action, not on…
feat(types,layout,app-shell): consume the declared nav runAction slot (…
feat(types,layout,app-shell): consume the declared nav runAction slot (…