PR: #432: feat(agents): apply set_view + propose_operation in the Atlas Dock [Story-1756] by @ankitmaheshwari-com
View PR →
Story 1756 · Epic-1646 Agentic interaction · DEF-6 (parent Bug-1753) · RFD-AGT-002 §7.16 · pramaan-docs ADR-031 / RFC-APB-002

Atlas reshapes the register and proposes catalog writes — applied in the browser, confirm-first, no fabrication

The Dock-chat brain now emits two terminal intents on its turn: view_intent (a set_view reshape) and propose_operation (a confirm-first create/edit/archive). The brain holds no router or mutation credentials (RFC-APB-002 §C cl.3): it proposes; the app applies. UAT Run-2 found both intents only described their action in the browser — they never took effect. This Story is the pramaan-app consumer that closes the loop.

Repo: pramaan-app only (ADR-031 — the brain half landed in pramaan-agents #137, Closes Bug-1753 + Bug-1754).

What a counsel sees

The wire contract (consumed, not redefined)

On the dock-chat turn (atlas-dock-turn-v1), two new terminal fields, null on a plain turn:

view_intent      = {"kind":"set_view","edits":[{"op":"set_group_by","field":"status","value":null,"mode":null}]}
propose_operation = {"kind":"propose_operation","operation":"create","entity":"forum",
                     "params":{"name":"NCLT-Mumbai"},"confirm_prompt":"Create forum NCLT-Mumbai?"}

op ∈ set_group_by · set_slice_by · set_primary_sort · set_field_sum · toggle_hierarchy · toggle_field — the exact verbs of the shipped view-edits.ts. operation ∈ create | edit | archive; delete is unrepresentable by design.

How set_view applies (Transport C — client-side)

StepWhereWhat
1. Lift off the wiresrc/lib/agents/atlas-rail.tsreduceFrame maps turn.completed.view_intent → RailState.setView (reset on run.accepted), exactly as it already does for navigate_to.
2. Dispatch on the surfaceagent-dock-mount.tsxOn turn settle, dispatches {name:"set_view", toolParams:{edits}} through the existing client-tool dispatcher. Off a register surface the tool is absent → the dispatch drops (no parallel path).
3. Fold onto the loaded viewsrc/lib/documents/register/atlas-view-intent.tsPure applyAtlasViewEdits(view, edits) maps each op to its shipped view-edits.ts transform. The register’s buildRegisterModel(rows, view) re-runs over the rows already in memory.
4. Refuse what doesn’t existsameAn edit naming a field not on the surface — or one that can’t take the op — is collected in rejected and skipped; valid edits still apply. The register bridge toasts the refusals (UAT-020).

view_fields — grounding the no-invented-field guarantee

The Documents Register publishes its reshapeable column/axis set as the surface’s view_fields ({key,label}), which rides into the Dock’s current_context each turn (cpc-store → buildCurrentPageContext). Without it the brain offers no reshape and refuses; with it, it can only name fields that exist.

Coordination seam: current_context is an opaque digest the broker forwards verbatim, so adding view_fields is forward-compatible. The exact key the merged brain reads should be confirmed against pramaan-agents #137 before the end-to-end demo (the field is emitted as view_fields per the issue contract).

How propose_operation applies (confirm-first write)

StepWhereWhat
1. Lift off the wireatlas-rail.tsreduceFrame maps propose_operation → RailState.proposeOperation. A delete (or any non-create/edit/archive op) is dropped at the boundary — it can never reach a card.
2. Render the carduse-client-tool-dispatcher.tsA new proposeOperation() pushes a ProposalItem (the existing confirm card). The body is the brain’s confirm_prompt; the chrome (buttons, notes, title) is i18n.
3. Confirm runs the existing mutationsrc/lib/agents/propose-operation.tsresolveProposeOperation(op, entity) returns the generated client fn (appCreateForum, appArchiveMatterType, …) + the list url. On confirm it runs under the caller’s own session (RLS), then invalidates the list cache. Nothing runs before confirm.
4. Honest outcomesameThe generated fn Zod-parses its request at the trust boundary (HR-21/HR-22), so malformed params throw there and the app shows an honest failure — never a faked success.

delete is unrepresentable (D-10)

The operation union admits only create | edit | archive, and the executor registry has no delete path. Forums archive resolves to null too (the backend exposes only forum delete, which is unrepresentable) — so the app refuses gracefully rather than rendering a destructive control. The brain offers archive; the app applies archive.

Acceptance criteria → evidence

ACStatusEvidence
UAT-010/011/012 — group/sort/slice reshape the loaded list, no round-tripmetatlas-view-intent.test.ts (group/sort/slice + “show only X”); applied over in-memory rows via buildRegisterModel.
UAT-014/015/016/017 — create/archive propose → confirm → write; nothing before confirmmetpropose-operation.test.ts (resolver) + dispatcher renders a card whose mutation runs only in onConfirm.
UAT-018/041 + D-10 — delete refused, archive offered, no delete controlmetOp union excludes delete; reduceFrame drops it (atlas-rail.test.ts); registry has no delete path.
UAT-020 — reshape by an absent field refuses gracefullymetapplyAtlasViewEdits collects rejected + the register bridge toasts; view untouched.
No fabrication, no silent write; mutations under caller session (RLS)metset_view never fetches; writes go through generated client fns (browser→proxy→gateway), confirm-gated.
Verify gate green; i18n in both localesmettypecheck · lint (0 errors) · 824 tests · build · route-registry fresh; new keys added to en.json + hi.json.

What is not in this Story

Files changed

16 file(s), +999 / -7 lines

Path Role + -
messages/en.jsonConfig+8-2
messages/hi.jsonConfig+8-2
src/components/agents/agent-dock-mount.tsxComponent+19-0
src/components/documents/register/register-view.tsxComponent+5-0
src/components/documents/register/use-register-agent-bridge.tsComponent+96-0
src/lib/agents/atlas-rail.test.tsLibrary+101-0
src/lib/agents/atlas-rail.tsLibrary+95-0
src/lib/agents/propose-operation.test.tsLibrary+36-0
src/lib/agents/propose-operation.tsLibrary+143-0
src/lib/agents/use-client-tool-dispatcher.tsLibrary+83-1
src/lib/agents/use-dock-chat-rail.tsLibrary+5-1
src/lib/documents/register/atlas-view-intent.test.tsLibrary+116-0
src/lib/documents/register/atlas-view-intent.tsLibrary+239-0
src/lib/surface-registry/current-context.tsLibrary+20-0
src/lib/surface-registry/use-surface.tsLibrary+14-1
src/stores/cpc-store.tsSource+11-0