Summary
The shell from #193 ships two pieces of non-functional surface:
- Six of the seven workspaces are declared
enabled: true, but five of them render
WorkspacePlaceholderPane — an operator can switch to a workspace that contains nothing.
- The Select and Hand toolbar buttons are
checkable and dispatch no command. Select is
checked: true by default, Hand is unchecked, and both toggle independently of each other and of
anything else, so the toolbar reports a tool state that no code observes.
This is the "Consider" finding #11 of the hostile-PDF audit of
4acb0560cffef7a49f6e460b7c76326906271959, split out because it is product surface (UI + state)
rather than a defect, and because the right answer is a scope decision, not a code fix.
Evidence
ProductQuickAccessibilitySmoke/qml/Workspace.qml:63-69 — the workspace rail:
{ label: qsTr("Document"), workspace: EditorHost.Document, enabled: true },
{ label: qsTr("Preflight"), workspace: EditorHost.Preflight, enabled: true },
{ label: qsTr("Production Preview"), workspace: EditorHost.ProductionPreview, enabled: true },
{ label: qsTr("Pages / Production"), workspace: EditorHost.Pages, enabled: true },
{ label: qsTr("Inspect"), workspace: EditorHost.Inspect, enabled: true },
{ label: qsTr("Fix"), workspace: EditorHost.Fix, enabled: true },
{ label: qsTr("Compare"), workspace: EditorHost.Compare, enabled: false }
ProductQuickAccessibilitySmoke/qml/Workspace.qml:111-143 — five WorkspacePlaceholderPane
instances (the sixth instance is the Compare placeholder at :143, behind the disabled entry), so five
enabled workspaces are placeholders.
ProductQuickAccessibilitySmoke/qml/ShellToolBar.qml:86-96 — the tool buttons, next to neighbours that
all dispatch:
ToolButton { text: qsTr("Select"); checkable: true; checked: true; Accessible.name: qsTr("Select tool") }
ToolButton { text: qsTr("Hand"); checkable: true; Accessible.name: qsTr("Hand tool") }
Every other button in that file uses enabled: root.commandEnabled("<id>") /
onClicked: root.invoke("<id>") (see ShellToolBar.qml:55-83 and :100-106), and the smoke test
asserts the command-backed ones. Select/Hand have no id and no handler.
Proposed approach (the scope decision this issue asks for)
- Either wire both tools to real commands in the action policy (
agent-policy.json is not the
right file — the shell action source is docs/loop-shell.json / docs/loop-shell-actions.json,
both covered by the plugins and schemas_contracts modules) and make them a mutually exclusive
pair bound to the actual tool state, or remove them from the toolbar until the tools exist.
- For the workspaces: keep
enabled: true only for workspaces that do something. A placeholder behind
an enabled entry is the same defect at the navigation level as a checkable button that dispatches
nothing.
Acceptance criteria
- No enabled workspace entry leads to a placeholder pane: either the entry is disabled/hidden, or the
workspace has real content. Pick one policy and state it in docs/LOOP_SHELL_CONTRACT.md.
- Select/Hand either dispatch a command with an observable effect on the tool state, or are absent.
If kept, they must be mutually exclusive (checking one unchecks the other) and their checked state
must be derived from the same state the canvas/interaction code reads — not independent QML booleans.
- Regression coverage so this cannot silently reappear:
- extend
UnitTests/tst_shellworkspacetest.cpp so every workspace entry with enabled: true is
asserted to resolve to a non-placeholder pane;
- extend
UnitTests/tst_shellinspectordispatch.cpp (or the toolbar's existing test) so every
checkable toolbar control is asserted to have a command binding;
ProductQuickAccessibilitySmoke still passes (it is the accessibility gate for these controls).
check-change.py proof stays green: these QML files are in the quick module's path list, so the
proof must rebuild/run the quick module tests after the change.
- Update
docs/LOOP_SHELL_CONTRACT.md to match whatever is decided — the contract document currently
describes the shell UI as implemented.
Out of scope
Summary
The shell from #193 ships two pieces of non-functional surface:
enabled: true, but five of them renderWorkspacePlaceholderPane— an operator can switch to a workspace that contains nothing.checkableand dispatch no command. Select ischecked: trueby default, Hand is unchecked, and both toggle independently of each other and ofanything else, so the toolbar reports a tool state that no code observes.
This is the "Consider" finding #11 of the hostile-PDF audit of
4acb0560cffef7a49f6e460b7c76326906271959, split out because it is product surface (UI + state)rather than a defect, and because the right answer is a scope decision, not a code fix.
Evidence
ProductQuickAccessibilitySmoke/qml/Workspace.qml:63-69— the workspace rail:ProductQuickAccessibilitySmoke/qml/Workspace.qml:111-143— fiveWorkspacePlaceholderPaneinstances (the sixth instance is the Compare placeholder at :143, behind the disabled entry), so five
enabled workspaces are placeholders.
ProductQuickAccessibilitySmoke/qml/ShellToolBar.qml:86-96— the tool buttons, next to neighbours thatall dispatch:
Every other button in that file uses
enabled: root.commandEnabled("<id>")/onClicked: root.invoke("<id>")(seeShellToolBar.qml:55-83and:100-106), and the smoke testasserts the command-backed ones. Select/Hand have no id and no handler.
Proposed approach (the scope decision this issue asks for)
agent-policy.jsonis not theright file — the shell action source is
docs/loop-shell.json/docs/loop-shell-actions.json,both covered by the
pluginsandschemas_contractsmodules) and make them a mutually exclusivepair bound to the actual tool state, or remove them from the toolbar until the tools exist.
enabled: trueonly for workspaces that do something. A placeholder behindan enabled entry is the same defect at the navigation level as a checkable button that dispatches
nothing.
Acceptance criteria
workspace has real content. Pick one policy and state it in
docs/LOOP_SHELL_CONTRACT.md.If kept, they must be mutually exclusive (checking one unchecks the other) and their checked state
must be derived from the same state the canvas/interaction code reads — not independent QML booleans.
UnitTests/tst_shellworkspacetest.cppso every workspace entry withenabled: trueisasserted to resolve to a non-placeholder pane;
UnitTests/tst_shellinspectordispatch.cpp(or the toolbar's existing test) so everycheckabletoolbar control is asserted to have a command binding;ProductQuickAccessibilitySmokestill passes (it is the accessibility gate for these controls).check-change.pyproof stays green: these QML files are in thequickmodule's path list, so theproof must rebuild/run the
quickmodule tests after the change.docs/LOOP_SHELL_CONTRACT.mdto match whatever is decided — the contract document currentlydescribes the shell UI as implemented.
Out of scope
scope). This issue is only about not presenting them as ready.
EditorHost's internal structure (separate issue).