feat(pi-workflow): improve workflow usability and recovery

This commit is contained in:
jb
2026-08-26 00:20:24 -04:00
parent c291ca083c
commit ea74dbc6a7
23 changed files with 4422 additions and 913 deletions
@@ -0,0 +1,52 @@
---
status: accepted
supersedes: 0001-pi-workflow-architecture-24AUG2026.md
---
# Use drill-down overlays and bounded recovery
This decision supersedes the dashboard, dirty-source, execution-timeout, and startup-ownership assumptions in [ADR 0001](./0001-pi-workflow-architecture-24AUG2026.md). The persisted gated pipeline, worktree isolation, and independent-review decisions from ADR 0001 remain accepted.
## Context
Three managed runs exposed usability and liveness gaps:
- `512d6c31-5bde-4e93-8164-5d31fb684b00` reached Design, described prototype work, but emitted no `prototype` Assignment. The engine failed with `invalid-design-output: Design must select exactly one prototype Assignment`.
- `51b0c1cb-f5b2-47f9-8c0c-b323307b720b` was interrupted during Discovery.
- `ecb11e1e-fe38-4076-862e-739498dbe33b` completed Discovery, then remained in the feature-designer Assignment for nearly five minutes before interruption.
The prior focused dashboard did not scale cleanly from run selection through Gate decisions and long verified artifacts. Fresh-session selection returned instructions instead of entering the already implemented continuation path. A dirty source checkout blocked all starts even when the user understood that a new worktree starts from `HEAD`. Internal Git calls and child Assignments lacked complete deadlines.
Static prototypes compared a centered compact modal, a near-full-screen workspace, and shallow drill-down overlays with a dedicated reader. Direction C provided the clearest responsive behavior without a permanent side pane.
## Decision
- TUI run selection, actions, Gates, confirmations, questions, and feedback use shallow popup overlays. Escape returns one level.
- Verified plans, reports, prototype evidence, and Assignment transcripts use a sanitized full-screen reader. It shows an H1-H3 outline at 80 columns and wider, uses one document pane from 60 through 79 columns, and reports a 48x12 minimum below either boundary.
- RPC, print, and JSON interfaces remain linear and never invoke custom TUI overlays.
- A dashboard fresh-session action immediately calls the existing `/workflow continue` handler and `newSession()` flow. Noninteractive callers continue with an explicit run ID.
- One widget above Pi's editor shows the newest active run attached to the current session. Persisted state drives refresh and terminal state clears it.
- Startup may adopt a continuable run when its recorded process is dead or its lease is absent. Adoption atomically rotates the lease and Implementation Context active-parent IDs. Live processes and live Assignments remain fail-closed.
- Worktrees continue to start from a pinned source `HEAD`. Ordinary staged, unstaged, and untracked changes produce bounded path/status evidence and require explicit authorization because those changes are omitted. Unmerged paths remain blocked.
- Internal Git calls have a 30-second timeout. Approved host commands retain their three-minute timeout. Process-tree termination has a separate deadline and distinguishes command timeout exit `124` from cleanup failure exit `125`.
- Child Assignment execution has a five-minute deadline and persists timeout/interruption evidence.
- The feature-designer contract requires exactly one eligible, isolated prototype Assignment for non-trivial UI work, plus explicit implementation, verification, and independent-review Assignments.
## Consequences
- Dashboard behavior is easier to reason about because each overlay has one local task and the verified reader owns long-document navigation.
- Interactive continuation no longer requires a second command, while the persisted handoff and revision fences remain authoritative.
- Dead ownership can recover without manual state surgery. A running process or Assignment cannot be displaced based only on an old heartbeat.
- Users may proceed from a dirty source checkout without copying local changes into the worktree. Persisted evidence records what was knowingly omitted.
- Git, host-command cleanup, and child execution now have bounded failure paths rather than indefinite waits.
- Direction C has automated renderer and orchestration coverage. Its completed manual application validation is recorded below. The static frames in `docs/pi-workflow/dashboard-mocks.md` remain labeled prototype evidence, not production screenshots.
## Manual application validation
An actual Pi TUI session driven through a PTY passed these checks:
- Plan reader at `120x30`, `80x24`, `60x24`, and `47x11`.
- Selection popup at `60x24`.
- Input popup at `80x24`.
This record does not claim manual validation of other dashboard or workflow paths.
+7 -5
View File
@@ -20,7 +20,7 @@ You can also ask the assistant to use `pi_workflow` with:
- The feature request
- A unique idempotency key
The extension creates `feature/<feature-name>` in an exclusive worktree. Existing branch names are rejected rather than silently renamed.
The extension creates `feature/<feature-name>` in an exclusive worktree pinned to the source checkout's current `HEAD`. Ordinary staged, unstaged, or untracked source changes are not copied into that worktree. In TUI mode the extension shows bounded path/status evidence and requires explicit confirmation before omitting those changes. Tool, RPC, print, and JSON callers must pass `allowDirtySource: true`. Unmerged paths remain blocked. Existing branch names are rejected rather than silently renamed.
The managed flow is:
@@ -30,14 +30,16 @@ The managed flow is:
4. Choose a fresh plan-seeded session, compacted current session, or unchanged current context.
5. Implement with guarded file ownership.
6. Remove prototype-only behavior.
7. Run plan-approved verification commands and focused tests. Each host command is terminated after three minutes so an interactive or stalled command cannot block the run indefinitely.
7. Run plan-approved verification commands and focused tests. Approved host commands retain a three-minute timeout, internal Git commands have a 30-second timeout, and process-tree cleanup is bounded.
8. Complete independent specification and standards review.
The assistant must inspect the current run before each state-changing call and obtain the user's explicit Gate Decision. It must not infer approval.
## Inspect and continue
Use `/workflow` for the focused-card dashboard. It lists runs attached to the current session and shows persisted status, progress, Gate, plan, report, branch, and worktree information. Human-facing surfaces use the feature name as the run label. Analysis and legacy runs fall back to a request label of at most 48 characters, then to the run ID when no request exists. Duplicate labels in one available-run list receive ` · <run-id-prefix>`, using the shortest unique prefix of at least eight characters.
Use `/workflow` for the drill-down dashboard. TUI mode opens shallow popup overlays for the run list, run actions, Gates, confirmations, questions, and feedback. Plans, reports, prototype evidence, and Assignment transcripts open in a sanitized full-screen reader. Escape returns one level. RPC, print, and JSON modes remain linear and never open custom overlays.
The dashboard lists runs attached to the current session and shows persisted status, core-stage progress, Gate, plan, report, branch, and worktree information. While work is active, one line above Pi's editor tracks only the newest attached run and clears when no attached run remains active. Human-facing surfaces use the feature name as the run label. Analysis and legacy runs fall back to a request label of at most 48 characters, then to the run ID when no request exists. Duplicate labels in one available-run list receive ` · <run-id-prefix>`, using the shortest unique prefix of at least eight characters.
Use `/workflow continue` to select a run with a pending fresh-session handoff or normal-compaction continuation. `/workflow resume` is an alias. A run ID may be supplied directly:
@@ -46,7 +48,7 @@ Use `/workflow continue` to select a run with a pending fresh-session handoff or
/workflow resume <run-id>
```
Selection requires interactive TUI mode. In non-interactive modes, provide the run ID. Labels are presentation-only and cannot be used as lookup aliases; copyable continue and stop commands always retain the full run ID. They require no schema migration and do not change persisted paths.
Selection requires interactive TUI mode. In non-interactive modes, provide the run ID. Choosing a pending fresh-session continuation in the dashboard immediately enters the existing `newSession()` handoff path; it does not require a second command. Tool and RPC callers receive the explicit `/workflow continue <run-id>` continuation instead. Labels are presentation-only and cannot be used as lookup aliases; copyable continue and stop commands always retain the full run ID. They require no schema migration and do not change persisted paths.
## Stop active work
@@ -70,7 +72,7 @@ An analysis run uses `action: "start"` with `workflow: { mode: "analysis-script"
## Recovery
Interrupted work opens a Recovery Gate with retry, inspect, and abort choices. Completed Assignments and Decisions remain persisted. Potentially mutating interrupted Assignments are preserved and are not replayed automatically; an explicit retry creates newly fenced work where policy permits it. Startup recovery leaves an idle run already waiting at Recovery under its current parent instead of letting another Pi session claim it. If that parent's process has exited, an explicit retry from a previously attached parent session may reclaim the stale lease before continuing. Retry clears prior failed-command output and reruns verification from a pending state. Once remediation completes the Implement stage, an older interrupted mutating Assignment no longer triggers duplicate remediation on later retries.
Interrupted work opens a Recovery Gate with retry, inspect, and abort choices. Completed Assignments and Decisions remain persisted. Potentially mutating interrupted Assignments are preserved and are not replayed automatically; an explicit retry creates newly fenced work where policy permits it. Startup recovery may adopt a continuable run when its recorded owner process is dead or absent. Adoption atomically rotates the lease and Implementation Context parent IDs. A live owner or live Assignment remains fail-closed, and historical sessions remain inspection-only unless such an adoption makes one active. Retry clears prior failed-command output and reruns verification from a pending state. Once remediation completes the Implement stage, an older interrupted mutating Assignment no longer triggers duplicate remediation on later retries.
## Artifacts
+244 -111
View File
@@ -1,151 +1,284 @@
# pi-workflow dashboard mocks
# pi-workflow popup prototypes
These are static TUI direction mocks for `/workflow`. They are not implementation screenshots.
**Status:** Direction C accepted
## A. Split workspace
These static terminal frames compare popup directions for `/workflow`. They are prototype evidence, not production screenshots or manual validation of the implemented extension. All variants use Pi theme tokens, keyboard-visible focus, one border at most, and no animation.
Best for comparing Stage progress and Assignment detail without navigation.
Representative run: `pi-workflow-usability-resume`, waiting at Plan Approval after Discover and Design.
## A. Centered compact modal
A small modal preserves the surrounding conversation and keeps one decision in focus.
```text
pi-workflow 118 cols
Runs feature/search-page · waiting
> search-page waiting plan-approval · revision 12
auth-cleanup running Worktree .worktrees/pi-workflow-search-page-r1
cache-audit done Branch feature/search-page
Plan artifacts/plan-11-a31f.md
Stages Report pending
✓ Discover
✓ Design Open Gate · Plan Approval
· Prototype UI impact: non-trivial
· Implement Review the plan and UI evidence before deciding.
· Verify
· Review [a] approve [r] revise [o] open plan
↑↓ run tab pane enter action esc close
┌──────────────────────────────────────────────────────────────────────┐
│ │
│ ╭─ pi-workflow ──────────────────────────────╮ │
│ │ pi-workflow-usability-resume │ │
│ │ WAITING · Plan Approval · revision 12 │ │
│ │ │ │
│ │ ✓ Discover ✓ Design · Prototype │ │
│ │ · Implement · Verify · Review │ │
│ │ │ │
│ │ > Review plan │ │
│ │ Approve plan │ │
│ │ Request revision │ │
│ │ Close │ │
│ │ │ │
│ │ ↑↓ navigate enter select esc close │ │
│ ╰─────────────────────────────────────────────╯ │
│ │
└──────────────────────────────────────────────────────────────────────┘
```
Narrow terminal:
Strengths:
- Minimal visual interruption.
- Familiar one-step prompt behavior.
- Low chrome and clear focus.
Weaknesses:
- Long plans and detailed run state require repeated modal replacement.
- Context disappears quickly as the interaction deepens.
- Poor fit for browsing artifacts or transcripts.
### A at 60 columns
```text
pi-workflow · search-page
waiting · plan-approval · r12
✓ Discover ✓ Design · Prototype
· Implement · Verify · Review
Plan Approval
UI impact: non-trivial
[o] plan [enter] actions
╭─ pi-workflow ───────────────────────╮
│ usability-resume · WAITING │
│ Plan Approval · r12 │
│ │
│ > Review plan │
│ Approve plan │
│ Request revision │
│ Close │
│ │
│ ↑↓ enter esc │
╰─────────────────────────────────────╯
```
## B. Focused run cards
## B. Near-full-screen workspace
Minimal chrome. The list stays compact; selecting a run opens one vertically ordered detail card.
A stable workspace keeps the run list, selected run, progress, and actions visible together.
```text
pi-workflow
> search-page WAITING Plan Approval r12
auth-cleanup RUNNING Implement r31
cache-audit DONE report available r18
────────────────────────────────────────────────────────────
search-page
feature/search-page
Progress Discover ✓ Design ✓ Prototype · Implement ·
Verify · Review ·
Gate Plan Approval
non-trivial UI · 3 prototype candidates required
Artifacts plan-11-a31f.md
Worktree .worktrees/pi-workflow-search-page-r1
[enter] actions [o] artifact [esc] close
╭─ pi-workflow ────────────────────────────────────────────────────────────────╮
│ Runs │ pi-workflow-usability-resume WAITING │
│ │ feature/pi-workflow-usability-resume · r12 │
│ > usability-resume │ │
│ auth-cleanup │ Progress │
│ cache-audit │ ✓ Discover ✓ Design · Prototype · Implement │
│ │ · Verify · Review │
│ │ │
│ │ Open Gate │
│ │ Plan Approval │
│ │ Review the implementation plan before work begins. │
│ │ │
│ │ > Review plan │
│ │ Approve plan │
│ │ Request revision │
│ │ Browse artifacts │
│ │ Close │
│ │ │
│ ↑↓ run tab focus │ ↑↓ action enter select esc back │
╰──────────────────────────────────────────────────────────────────────────────╯
```
Action sheet:
Strengths:
- High information density with stable spatial context.
- Fast comparison between several active runs.
- Actions and state remain visible together.
Weaknesses:
- The permanent left pane spends space on uncommon multi-run comparison.
- Focus management and responsive collapse are more complex.
- At 80 columns the content pane becomes cramped; below 80 it must become a different UI.
### B at 80x24
```text
search-page · Plan Approval
> Inspect plan
Record approval
Request revision
Copy worktree path
Close
╭─ pi-workflow ────────────────────────────────────────────────────────────────╮
│ Runs │ usability-resume · WAITING · r12 │
│ > usability │ ✓ Discover ✓ Design · Prototype │
│ auth-cleanup │ · Implement · Verify · Review │
│ cache-audit │ │
│ │ Plan Approval │
│ │ > Review plan │
│ │ Approve plan │
│ │ Request revision │
│ │ Browse artifacts │
│ │ │
│ tab focus │ ↑↓ action enter select esc back │
╰──────────────────────────────────────────────────────────────────────────────╯
```
Prototype Gate:
### B at 60 columns
The workspace must collapse to a single run-detail pane. The run list becomes a prior drill-down view, effectively converging on direction C.
## C. Drill-down overlays with dedicated readers
Direction C uses shallow browser-style navigation. Each overlay does one job. Escape always returns one level.
### C1. Run list popup
```text
search-page · Prototype Acceptance
1 Sidebar navigation /prototype?variant=1
mobile ✓ desktop ✓ browser evidence retained
2 Command palette /prototype?variant=2
mobile ✓ desktop ✓ browser evidence retained
3 Inline workspace /prototype?variant=3
mobile ✓ desktop ✓ browser evidence retained
> Open candidate 1
Accept candidate 1
Request refinement
Abort run
╭─ pi-workflow ─────────────────────────────╮
│ > usability-resume WAITING Plan Approval│
│ auth-cleanup RUNNING Implement │
│ cache-audit DONE report ready │
│ │
│ ↑↓ navigate enter open esc close │
╰────────────────────────────────────────────╯
```
Narrow terminal uses the same vertical card and hides paths until `o`.
## C. Event timeline
Best for recovery and auditability. The primary view is an immutable history; actions belong to the current event.
### C2. Run detail popup
```text
pi-workflow · search-page WAITING
12:04 ✓ Discover 2 assignments
12:09 ✓ Questions decision recorded
12:15 ✓ Design plan revision 11
12:16 ● Plan Approval waiting for Decision
Current
UI impact non-trivial
Plan plan-11-a31f.md
Worktree feature/search-page
[enter] current actions [p] prototypes [r] report [esc]
╭─ usability-resume ───────────────────────────────────╮
│ WAITING · Plan Approval · revision 12 │
│ │
│ ✓ Discover ✓ Design · Prototype · Implement │
│ · Verify · Review │
│ │
│ > Review plan │
│ Record Gate Decision │
│ Browse prototype evidence │
│ Browse Assignment transcripts │
│ Show worktree path │
│ │
│ ↑↓ navigate enter select esc runs │
╰──────────────────────────────────────────────────────╯
```
Run list:
### C3. Plan reader at wide width
The reader uses the whole overlay. The terminal edge is the outer frame, so there is no decorative full-screen border. The left outline tracks the heading containing the top visible document line.
```text
Recent workflow events
pi-workflow plan · usability-resume line 42/216
> search-page Plan Approval 2m
auth-cleanup Implement 8m
cache-audit Completed 31m
Outline Plan
───────────────────────────── ─────────────────────────────────────────────
pi-workflow usability update # pi-workflow usability update plan
Locked decisions
> Implementation phases ## Implementation phases
Prototype overlays
Session lifecycle ### 2. Session lifecycle and recovery
Worktree safety
Popup TUI - Route the dashboard's fresh-session action
Progress widget through the existing continuation path.
Design regression
Acceptance criteria - Atomically rotate lease and context owners
during absent/dead adoption.
Primary files: dashboard.ts,
context-transition.ts, continuation.ts,
engine.ts, and focused tests.
↑↓ scroll pgup/pgdn page home/end document esc back
```
If labels collide in this available list, only the duplicates gain the shortest unique run-ID prefix (at least eight characters):
### C3 at 80x24
```text
> search-page · 12345678a Plan Approval
search-page · 12345678b Implement
cache-audit Completed
pi-workflow plan · usability-resume row 42/216
Outline Plan
────────────────────── ─────────────────────────────────────────────
Locked decisions ## Implementation phases
> Implementation
Prototype overlays ### 2. Session lifecycle and recovery
Session lifecycle - Route the dashboard's fresh-session action
Worktree safety through the existing continuation path.
Popup TUI
Progress widget - Atomically rotate lease and context owners
Acceptance criteria during absent/dead adoption.
↑↓ scroll pgup/pgdn page home/end document esc back
```
Narrow terminals preserve the same timeline and omit timestamps first.
### C3 at 60 columns
## Direction criteria
The outline hides and the document becomes the only pane. The current heading remains visible in the header.
The implementation should:
```text
pi-workflow plan · Implementation phases · row 42/216
- Start dark-mode friendly through Pi theme tokens.
- Keep the default view compact and reveal paths, evidence, and transcripts on demand.
- Show only valid actions for the current persisted Gate or continuation intent.
- Use feature-name-first presentation labels, with bounded request fallbacks and collision suffixes only when needed.
- Keep the full run ID out of ordinary prose while retaining it in copyable commands, structured details, and report metadata.
- Keep run status, revision, branch, worktree, plan, report, and prototype evidence discoverable.
- Remain usable from narrow terminals through 4K-width terminals without continuous animation.
## Implementation phases
### 2. Session lifecycle and recovery
- Route the dashboard's fresh-session action through the
existing continuation path.
- Atomically rotate lease and context owners during
absent/dead adoption.
↑↓ scroll pgup/pgdn page home/end document esc back
```
### C3 at 47x11
```text
terminal too small
pi-workflow plan needs 48x12
current terminal is 47x11
resize the terminal or press esc
```
Strengths:
- Each screen has one dominant task and a complete local keymap.
- Best responsive behavior because narrow layouts remain single-pane.
- Long plans and transcripts get dedicated virtualized readers.
- The shallow stack preserves context without permanent side-panel cost.
Weaknesses:
- Comparing several runs takes more navigation than direction B.
- Back-stack state and overlay focus/disposal require careful implementation.
## Persistent progress widget
The widget is independent of the selected popup direction and stays above Pi's editor while the newest attached run is active.
Standard:
```text
workflow usability-resume DESIGN 2/6 Gate: Plan Approval
```
Narrow:
```text
workflow usability-resume DESIGN 2/6
```
Terminal runs disappear rather than leaving a stale receipt above the editor.
## Recommendation
Use direction C. It has one border only on bounded popup cards, no redundant frame around the full-screen reader, keyboard-visible selection, and the most truthful 80-column and 60-column degradation. Direction B spends too much space on multi-run comparison, while direction A does not provide enough stable space for plans and evidence.
## Production mapping
The accepted direction maps to `extensions/pi-workflow/tui.ts` and `dashboard.ts`. The implementation uses popup overlays for bounded selections and text entry, then switches to the full-screen reader for verified plans and retained evidence. `progress.ts` owns the separate one-line widget. Pure renderer tests cover the wide, 80-column, 60-column, and below-48x12 contracts; interactive Pi validation remains a separate manual step.
## Interaction contract
- Arrow keys navigate every selection surface; Enter selects; Escape cancels or returns one level.
- Page Up/Page Down and Home/End apply only to long-document readers.
- Text inputs use Pi's `Input` or `Editor` components and propagate focus for IME positioning.
- The current selection uses position plus selected background or reverse video, never color alone.
- TUI overlays are never opened in RPC, print, or JSON mode.
- Every rendered line is truncated or wrapped by terminal cell width rather than JavaScript string length.
- No continuously repainting animation is used.
+17 -9
View File
@@ -74,6 +74,7 @@ type PiWorkflowInput =
| { mode: "analysis-script"; source: string; args?: string };
concurrency?: number;
background?: boolean;
allowDirtySource?: boolean;
idempotencyKey: string;
}
| {
@@ -151,7 +152,9 @@ Feature and feature-script starts require `featureName` as a concise lowercase k
Human-facing dashboard, selector, notification, handoff, compaction, tool, and report prose uses a shared presentation label. It prefers `featureName`; otherwise it normalizes the request to one line and bounds it to 48 characters, preserving whole words where possible and adding `…` when truncated; only a missing request falls back to `runId`. When derived labels collide within an available run list, only those labels receive ` · <prefix>`, where the run-ID prefix is the shortest unique prefix with a minimum of eight characters. This label is never persisted as identity or accepted as a lookup alias. It requires no schema migration and does not change persisted paths. The complete `runId` remains canonical for snapshots, structured fields, command arguments, paths, receipts, leases, and idempotency. Copyable `/workflow continue <run-id>` and `/workflow stop <run-id>` commands retain it, and reports include it as `Run ID` metadata beneath the readable heading.
The `pi_workflow` tool calls a single internal `execute(command)` interface. `/workflow` opens the dashboard and may accept a run ID for direct inspection. `/workflow start <message>` sends the initial request through the assistant so the normal `pi_workflow` tool path owns feature naming and idempotency; in interactive TUI mode, omitting the message opens an input prompt. `/workflow continue` presents eligible pending context transitions for selection, while `/workflow continue <run-id>` continues one directly; `/workflow resume` is an alias for both forms. `/workflow stop [run-id]` aborts a non-terminal run owned by the active parent session and presents a selector when multiple owned runs are active. The misspelled `/worlflow` alias is intentionally unsupported. Continue and stop selectors require interactive TUI mode and provide direct-run-ID guidance otherwise.
The `pi_workflow` tool calls a single internal `execute(command)` interface. `/workflow` opens a drill-down TUI dashboard and may accept a run ID for direct inspection. Run selection, actions, Gates, confirmations, questions, and feedback use bounded popup overlays. Verified plans, reports, prototype evidence, and Assignment transcripts use a sanitized full-screen reader with H1-H3 outline navigation at widths of 80 columns or more and a single document pane from 60 through 79 columns. Below 48x12 it renders only a truthful minimum-size state. RPC, print, and JSON paths remain linear and do not call `ctx.ui.custom()`.
`/workflow start <message>` sends the initial request through the assistant so the normal `pi_workflow` tool path owns feature naming and idempotency; in interactive TUI mode, omitting the message opens an input overlay. `/workflow continue` presents eligible pending context transitions for selection, while `/workflow continue <run-id>` continues one directly; `/workflow resume` is an alias for both forms. Selecting a fresh-session continuation from the dashboard routes directly through the same handler and calls `newSession()` without a second command. `/workflow stop [run-id]` aborts a non-terminal run owned by the active parent session and presents a selector when multiple owned runs are active. The misspelled `/worlflow` alias is intentionally unsupported. Continue and stop selectors require interactive TUI mode and provide direct-run-ID guidance otherwise.
Continuation performs only a pending fresh-session handoff or normal-compaction fallback after the run is safely waiting; it cannot approve plans, select prototypes, or make other Decisions. Stop treats `running` and `waiting` runs as active and excludes terminal runs and runs owned only by historical parent sessions.
@@ -346,7 +349,7 @@ Initialize
- Resolve effective configuration, validate the feature name, and validate the repository without mutation.
- Load, validate, and pin Agent Profiles from the source checkout.
- Verify that eligible discovery, design, implementation, verification, and independent review profiles exist before mutating the repository.
- For feature mode, verify that the configured worktree root is ignored by Git and that the source checkout is clean.
- For feature mode, verify that the configured worktree root is ignored by Git. Capture at most 20 sorted path/status records plus an omitted count for staged, unstaged, or untracked source changes. Unmerged paths always block creation. Ordinary changes require explicit TUI confirmation or `allowDirtySource: true` from a noninteractive caller.
- Persist a run snapshot with workspace state `creating` before invoking Git.
- Create a distinct worktree transactionally, then persist workspace state `ready`.
- On creation failure, roll back what can be removed safely, persist the failure, and leave enough intent for startup reconciliation.
@@ -405,7 +408,8 @@ Mutating Assignments run in the Workflow Run's worktree.
- Mutating child sessions do not receive `bash` or other process-execution tools. Assignment-scoped file operations reject symlink traversal and require canonical containment beneath both the worktree root and the Assignment's owned path roots.
- Plan-approved verification and generation commands run separately through a host executor using fixed executable/argument arrays, never agent-authored shell strings. The only accepted wrapper form is `env PI_OFFLINE=1 <executable> ...`; the executor unwraps it, sets that single variable, and applies the normal executable safety checks.
- The host executor sets `PYTHONDONTWRITEBYTECODE=1` so Python-backed checks do not create out-of-scope `__pycache__` artifacts.
- Every host command has a three-minute execution timeout and reports exit code `124` when terminated, preventing interactive or stalled commands from blocking a run indefinitely.
- Every host command has a three-minute execution timeout and reports exit code `124` when terminated. Internal Git probes and worktree commands have a 30-second timeout. Process-tree termination, including Windows `taskkill`, has its own deadline and reports exit code `125` when cleanup cannot be completed.
- Every child Assignment has a five-minute execution deadline. Timeout aborts the child signal and persists the Assignment as `interrupted` with `assignment-timeout` evidence rather than reporting success.
- The engine records branch, HEAD, worktree identity, and Git diff state before and after every mutating Assignment and host command.
- Out-of-scope changes, branch movement, commits, or worktree metadata changes invalidate the Assignment and open a Recovery Gate before more mutation starts.
- The scheduler reserves capacity synchronously before launching children.
@@ -480,7 +484,7 @@ feature/<feature-name>
`<feature-name>` comes from the validated `featureName` start input and describes the feature rather than the workflow mechanism. Any existing branch with that name rejects a new start. If persisted state associates the branch with a Workflow Run, the error returns its run ID and directs the caller to continue it through `inspect` or `decide`; otherwise it directs the caller to choose another descriptive name. The extension never adds a numeric or run-ID suffix silently.
The configured worktree root must already be ignored by Git. The extension verifies this with Git before persisting creation intent and fails with setup guidance rather than modifying `.gitignore` automatically. A dirty source checkout blocks creation so uncommitted work is never silently omitted.
The configured worktree root must already be ignored by Git. The extension verifies this with Git before persisting creation intent and fails with setup guidance rather than modifying `.gitignore` automatically. A worktree is created from the pinned source `HEAD`; source-only staged, unstaged, and untracked changes are not copied. The engine persists bounded path/status evidence and whether omission was explicitly allowed. TUI callers must confirm a warning that states those changes are omitted. Noninteractive callers must set `allowDirtySource: true`. Conflicts and unmerged paths always block creation.
The engine records an ownership lease for the run and refuses to adopt or share another run's worktree. The completed worktree remains available for inspection and manual integration. Removal is explicit and never part of normal completion.
@@ -512,7 +516,7 @@ Writes are atomic and mode `0600`. Serialization, transcript, source, argument,
The snapshot contains Decisions and prior Assignment outcomes, so a separate event store is unnecessary. Every `start`, `decide`, and `abort` command requires an idempotency key. The launch key and initial result are persisted before workspace creation. State-changing commands use revisions and idempotency keys to reject stale or duplicate transitions. Repeating a completed key returns its recorded result without another transition.
An active run owns a persisted lease containing process identity, active parent-session identity, heartbeat time, and worktree identity. The run retains every parent session ID attached through a handoff so `/workflow` can discover it from either session, but only the active ID may mutate the run. The narrow exception is an explicit Recovery retry from a retained parent ID after the recorded lease process has died; that retry reclaims the stale lease before applying the Decision. Startup and session recovery reconcile stale leases, child processes, workspace-creation intent, Git identity, context handoffs, compaction intents, and assignments left `running`. An idle run that already has an open Recovery Gate is left attached to its current parent so unrelated Pi sessions cannot steal ownership during startup.
An active run owns a persisted lease containing process identity, active parent-session identity, heartbeat time, and worktree identity. The run retains every parent session ID attached through a handoff so `/workflow` can discover it from either session, but only the active ID may mutate the run. Startup or explicit Recovery may adopt a continuable run only when its recorded owner process is dead or its lease is absent. Adoption atomically rotates both `lease.activeParentSessionId` and `implementationContext.activeParentSessionId`, appends the adopting session to `parentSessionIds`, and preserves revision fencing. A live process or live Assignment blocks adoption even when its heartbeat is old. Startup and session recovery reconcile child processes, workspace-creation intent, Git identity, context handoffs, compaction intents, and assignments left `running`.
Fresh-session handoff intent is durable before `newSession()`. A `session_shutdown` with reason `new` bypasses ordinary interruption recovery only when its source session matches the pending intent; that handler atomically claims the event's `targetSessionFile` and marks the intent `claimed-target-awaiting-withSession`. The claimed target's immediately following `session_start` is exempt from recovery only when its reason is `new` and `previousSessionFile` matches the source. The replacement `withSession` callback must then match the claimed target before it atomically consumes the intent, rotates the active parent-session ID, records both session IDs, and resumes delivery. Any later `session_start` caused by `startup`, `reload`, `resume`, or `fork`, or a bounded claim expiry before consumption, follows normal recovery and leaves implementation blocked.
@@ -553,7 +557,9 @@ Children cannot access recursive workflow or subagent tools or `ask_user`. `pi_w
- `store.ts`: atomic revisioned snapshots and bounded artifacts.
- `workspace.ts`: worktree creation, ownership conflict checks, and lifecycle.
- `context-transition.ts`: plan handoffs, new-session replacement, smart/default compaction callbacks, and session attachment.
- `dashboard.ts`: run inspection, continuation handoff, and prototype/report links.
- `dashboard.ts`: drill-down run actions, Gate orchestration, continuation handoff, and artifact selection.
- `tui.ts`: reusable popup inputs/selections and the full-screen verified-document reader.
- `progress.ts`: newest-attached-run projection and the bounded editor widget.
- `agents/*.md`: bundled default profiles.
Pure transition and eligibility logic stay inside the engine and profile modules rather than behind speculative adapter interfaces. Tests may inject filesystem, executor, decision, and script-runtime adapters at the composition root.
@@ -592,7 +598,7 @@ Implement the command interface, legal transitions, closed Gate Decisions, atomi
- `start`, `decide`, and `abort` require idempotency keys; launch intent is persisted before worktree creation, and a repeated completed key returns its prior result without a second transition.
- Stale revisions are rejected for `decide` and `abort`.
- Using the injected scripted Assignment executor, Questions and Plan Approval pause and resume across process restarts with the accepted UI classification intact and no dependency on live Pi child execution.
- Startup reconciliation detects stale leases and transitions abandoned `running` Assignments to `interrupted` exactly once.
- Startup reconciliation detects absent or dead ownership and transitions abandoned `running` Assignments to `interrupted` exactly once.
- Potentially mutating interrupted Assignments require an explicit Recovery Decision; completed Decisions and Assignments are not replayed.
- Feature names are validated before launch persistence; worktree branches use exactly `feature/<feature-name>`, and every existing branch collision rejects new start with recorded-run `inspect`/`decide` guidance or descriptive-name rename guidance, never a silent suffix.
- Workspace creation intent and lease are persisted before Git mutation; creation succeeds transactionally or leaves a reconciled failure that startup can recover.
@@ -618,7 +624,7 @@ Extend the Phase 2 worktree scaffold with the Implementation Context Gate, `/wor
#### Phase 4 Success Criteria
- A dirty source state or unignored worktree root blocks creation before Git mutation.
- An unignored worktree root or unmerged source state blocks creation before Git mutation. Ordinary source changes require bounded evidence and explicit authorization, then create from the persisted `HEAD` without copying those changes.
- Workspace creation intent is persisted first; creation failure rolls back safely or remains reconcilable after restart.
- Every feature run receives a distinct leased worktree and worktrees are retained until explicitly removed.
- A versioned `plan.md` is persisted before the Implementation Context Gate and revised with an accepted prototype when applicable.
@@ -655,7 +661,9 @@ Add the dashboard integration around the Phase 4 `/workflow continue` command, p
#### Phase 6 Success Criteria
- Dashboard state is derived from persisted snapshots and active runs, prior supported snapshot versions remain readable, and the existing `/workflow continue` command is presented only for a valid pending fresh-session or normal-compaction intent.
- Dashboard state is derived from persisted snapshots and active runs, prior supported snapshot versions remain readable, and continuation is presented only for a valid pending fresh-session or normal-compaction intent. Selecting a fresh-session continuation enters `newSession()` immediately.
- Bounded TUI interactions use responsive popup overlays. Verified documents use the dedicated sanitized reader with H1-H3 navigation, cell-width-safe viewports, and the locked 80-column, 60-column, and 48x12 behavior. RPC, print, and JSON remain linear.
- The widget above Pi's editor projects only the newest attached active run and clears after terminal persistence or session shutdown.
- Stable delivery keys, durable custom parent-session message receipts, and outbox reconciliation ensure each background Gate or terminal result is delivered once across reload and recovery.
- Focused tests, typecheck, full test suite, and manual Pi TUI validation of Gates, dashboard navigation, background delivery, and prototype handoff pass.
- Exposure is performed only through `config/pi-links.json`; unmanaged extension links are rejected and link reconciliation check passes before sync.
+101
View File
@@ -0,0 +1,101 @@
# pi-workflow usability update plan
Status: manual recovery plan after managed Workflow Runs `512d6c31`, `51b0c1cb`, and `ecb11e1e` failed or were interrupted before implementation.
## Locked decisions
- The interactive dashboard automatically enters a fresh plan-seeded session. Tool and RPC callers receive `/workflow continue <run-id>` instead.
- Startup may adopt a continuable run only when its prior owner is stale or dead. A live owner remains fail-closed.
- The widget above Pi's editor shows only the newest attached active run.
- Dashboard navigation, action sheets, Gates, confirmations, questions, and feedback use popup overlays in TUI mode. RPC, print, and JSON paths remain linear.
- The plan reader is a full-screen overlay with an H1-H3 outline, current-section highlight, arrows, Page Up/Page Down, Home/End, and Escape.
- The outline is visible at 80 columns and wider, hidden from 60 through 79 columns, and replaced by a truthful minimum-size message below 48x12.
- Dirty source changes require a bounded TUI warning and explicit confirmation when `allowDirtySource` is omitted. TUI starts honor an explicit `allowDirtySource: true` without prompting. Non-TUI tool, RPC, print, and JSON starts require `allowDirtySource: true`. Approval is not tied to a later status digest recheck.
- Approved host commands retain a three-minute timeout. Internal Git commands receive a 30-second timeout. Process-tree termination is bounded on every platform.
- Prototype direction C, drill-down overlays with a dedicated full-screen reader, is the baseline after comparing A, B, and C.
## Failure evidence captured during this change
- Run `512d6c31-5bde-4e93-8164-5d31fb684b00` reached design, described a prototype phase, but emitted no `prototype` assignment. The engine terminated with `invalid-design-output: Design must select exactly one prototype Assignment`.
- Run `51b0c1cb-f5b2-47f9-8c0c-b323307b720b` was interrupted during discovery.
- Run `ecb11e1e-fe38-4076-862e-739498dbe33b` completed discovery, then remained in the feature-designer assignment for nearly five minutes until interrupted.
These failures are acceptance-test inputs for assignment timeout handling and designer guidance.
## Implementation phases
### 1. Prototype overlays
Own only `docs/pi-workflow/dashboard-mocks.md` and isolated prototype artifacts. Compare:
- A: centered compact modal
- B: near-full-screen workspace with list/detail panes
- C: drill-down overlays with a dedicated full-screen plan reader
Validate wide, 80x24, 60-column, and 47x11 frames. Production TypeScript remains untouched until the prototype direction is accepted.
### 2. Session lifecycle and recovery
- Route the dashboard's fresh-session action through the existing `handleContinue()` and `ctx.newSession({ withSession })` path.
- Add an integration test proving a dashboard result triggers session replacement without a second command.
- During absent/dead startup adoption, atomically rotate both `lease.activeParentSessionId` and `implementationContext.activeParentSessionId`.
- Preserve live-owner, active-assignment, and historical-session fences.
Primary files: `dashboard.ts`, `context-transition.ts`, `continuation.ts`, `engine.ts`, and focused tests.
### 3. Worktree safety and command deadlines
- Return bounded dirty path/status evidence instead of rejecting all ordinary source dirt.
- Keep conflicts, unmerged entries, repository identity, ignored-root, branch collision, and target-path checks fail-closed.
- Create the worktree from the pinned `HEAD`; warning copy states source-only changes are omitted.
- Add `allowDirtySource` to tool/domain inputs and idempotency fingerprints.
- Apply 30-second timeouts to every internal Git invocation.
- Keep approved commands at three minutes and bound Windows `taskkill` itself.
- Preserve exit `124` for timeout and `125` for termination failure.
Primary files: `workspace.ts`, `domain.ts`, `tool.ts`, `engine.ts`, and focused tests.
### 4. Popup TUI and plan reader
- Add reusable, modeless overlay components with one earned border, visible selection, keyboard hints, width-safe rendering, and focus propagation for embedded `Input` or `Editor` children.
- Use a drill-down stack: run list to run detail to action/Gate overlay. Escape always returns one level or closes.
- Parse Markdown H1-H3 headings into a pure outline model.
- Render only the current plan viewport, not the entire artifact.
- Sanitize untrusted transcript/plan control sequences before rendering.
- Keep `ctx.ui.custom()` guarded by `ctx.mode === "tui"`.
Primary files: new `tui.ts` and tests, plus orchestration changes in `dashboard.ts`.
### 5. Persistent progress widget
- Add a pure projection for readable label, active stage, completed/total core stages, and open Gate.
- Refresh from persisted attached runs after `afterRunPersist` and `session_start`.
- Clear after terminal state and `session_shutdown`.
- Render one bounded line at narrow widths.
Primary files: new `progress.ts` and tests, plus registration in `index.ts`.
### 6. Design-contract and timeout regression
- Strengthen the bundled feature-designer instructions so non-trivial UI plans explicitly select exactly one eligible prototype assignment with isolated ownership.
- Add a focused test for the exact missing-prototype failure and guidance contract.
- Ensure assignment execution cannot wait forever; surface timeout/interruption evidence without falsely reporting success.
- Record any behavior that cannot be safely fixed in this slice in `docs/todo.md` with the three run IDs above.
Primary files: `agents/feature-designer.md`, engine/execution tests, and related runtime code.
### 7. Documentation, verification, and review
Update the README, design document, dashboard mocks, and a superseding ADR. Run focused tests, typecheck, full tests, and manual Pi validation at wide, 80x24, 60-column, and 47x11 sizes. An agent that did not implement the change performs the final standards and specification review.
## Acceptance criteria
- Fresh-session selection continues automatically in interactive Pi without restart or a second command.
- A new Pi process can adopt an absent/dead continuable run but cannot steal one from a live owner.
- Exactly one newest active-run widget is visible above the editor and clears promptly.
- Every bounded TUI interaction is an overlay; RPC/print/JSON remain usable and never call unsupported custom overlays.
- The full-screen plan reader meets the locked outline, navigation, responsive, and width contracts.
- Dirty source starts are warned and explicitly authorized while conflicts remain blocked.
- No internal Git or approved host subprocess can wait indefinitely, and process cleanup is bounded.
- The designer contract prevents the missing-prototype-assignment failure, while assignment execution has a bounded failure path.
- Focused tests, typecheck, full tests, manual Pi validation, and independent review pass.