P4: writes via chat — Reginald proposes, you approve inline #43

Merged
christian merged 1 commits from p4/chat-writes into main 2026-07-09 02:17:46 +00:00
Owner

Completes "chat is the write-path" (decisions.md D1). Ask Reginald to re-estimate or reprioritize; it formulates a proposal, you approve it inline, and the write runs through the same guarded apply_changes engine the Issue screen uses. The model never writes — it proposes; the app owns approval + execution.

Core (@commitea/core)

  • propose_change tool declaration; REGINALD_SYSTEM updated — "never claim a change is applied; you propose, the human approves."
  • proposalsFor(args, currentLabels, title) — pure: builds the concrete, non-noop ChangeProposal(s) (change + label diff) for a request, dropping invalid or unchanged axes. ChangeProposal / ProposeChangeArgs types.

App

  • model bridge executes propose_change by planning against the issue's current labels (no write) and returns the proposals with the turn.
  • useChat surfaces pending proposals + approve/dismiss; approve calls onApplyChange (AppShell's guarded handler → PUT + board/forecast refetch), dismiss leaves it.
  • ChatPanel renders each proposal as a propose-approve card (diff + Approve/Dismiss).

Verified

101 core tests green (4 proposalsFor added), desktop typecheck clean, 14 fixture e2e green.

Gated live e2e against gemma-4-26b: "Set the estimate on #3 to est/5d" → Reginald proposes "est/2d → est/5d" as an inline card and says it's proposed, not done; Dismiss leaves the repo untouched (screenshot in PR). The approve→write path is the #41 engine (separately verified change→revert).

Not in this slice (later)

  • Destructive ops via chat (close/remove-dep) need the approved:true gate surfaced in the card.
  • capture_work (big-model decomposition → Capture tray) and record_directive (→ pm-state ledger) are the remaining write tools.

🤖 Generated with Claude Code

Completes **"chat is the write-path"** (decisions.md D1). Ask Reginald to re-estimate or reprioritize; it formulates a **proposal**, you approve it **inline**, and the write runs through the same guarded `apply_changes` engine the Issue screen uses. The model never writes — it proposes; the app owns approval + execution. ## Core (`@commitea/core`) - **`propose_change`** tool declaration; `REGINALD_SYSTEM` updated — *"never claim a change is applied; you propose, the human approves."* - **`proposalsFor(args, currentLabels, title)`** — pure: builds the concrete, non-noop `ChangeProposal`(s) (change + label diff) for a request, dropping invalid or unchanged axes. `ChangeProposal` / `ProposeChangeArgs` types. ## App - model bridge executes `propose_change` by planning against the issue's current labels (**no write**) and returns the proposals with the turn. - `useChat` surfaces pending proposals + `approve`/`dismiss`; **approve** calls `onApplyChange` (AppShell's guarded handler → PUT + board/forecast refetch), **dismiss** leaves it. - `ChatPanel` renders each proposal as a propose-approve card (diff + Approve/Dismiss). ## Verified 101 core tests green (4 `proposalsFor` added), desktop typecheck clean, 14 fixture e2e green. **Gated live e2e** against `gemma-4-26b`: *"Set the estimate on #3 to est/5d"* → Reginald proposes **"est/2d → est/5d"** as an inline card and says it's *proposed*, not done; Dismiss leaves the repo untouched (screenshot in PR). The approve→write path is the #41 engine (separately verified change→revert). ## Not in this slice (later) - Destructive ops via chat (close/remove-dep) need the `approved:true` gate surfaced in the card. - `capture_work` (big-model decomposition → Capture tray) and `record_directive` (→ pm-state ledger) are the remaining write tools. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
christian added 1 commit 2026-07-09 01:38:46 +00:00
Completes "chat is the write-path" (decisions.md D1). Ask Reginald to re-estimate
or reprioritize an issue; it formulates a proposal, you approve it inline, and the
write runs through the same guarded apply_changes engine the Issue screen uses.
The model never writes — it proposes; the app owns approval + execution.

core (@commitea/core):
- propose_change tool declaration + REGINALD_SYSTEM updated ("never claim a change
  is applied; you propose, the human approves").
- proposalsFor(args, currentLabels, title): pure — builds the concrete, non-noop
  ChangeProposal(s) (change + label diff) for a propose_change request, dropping
  invalid/unchanged axes. ChangeProposal / ProposeChangeArgs types.

app:
- model bridge executes propose_change by planning against the issue's current
  labels (no write) and returns the proposals with the turn.
- useChat surfaces pending proposals + approve/dismiss; approve calls onApplyChange
  (AppShell's guarded handler → PUT + board/forecast refetch), dismiss leaves it.
- ChatPanel renders each proposal as a propose-approve card (diff + Approve/Dismiss).

Verified: 101 core tests green (4 proposalsFor added), desktop typecheck clean,
14 fixture e2e green. Gated live e2e against gemma-4-26b: "Set the estimate on #3
to est/5d" → Reginald proposes "est/2d → est/5d" as an inline card, says it's
*proposed* not done; Dismiss leaves the repo untouched. The approve→write path is
the #41 engine (separately verified change→revert).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
christian merged commit 652c8c86b9 into main 2026-07-09 02:17:46 +00:00
Sign in to join this conversation.
No description provided.