diff --git a/.pi/memory-vault/packs/paperclip-harness/20-context/each-of-those-was-a-real-defect-not-misunderstanding-on-your.md b/.pi/memory-vault/packs/paperclip-harness/20-context/each-of-those-was-a-real-defect-not-misunderstanding-on-your.md new file mode 100644 index 0000000..dff0589 --- /dev/null +++ b/.pi/memory-vault/packs/paperclip-harness/20-context/each-of-those-was-a-real-defect-not-misunderstanding-on-your.md @@ -0,0 +1,82 @@ +--- +type: context +id: context.paperclip-harness.each-of-those-was-a-real-defect-not-misunderstanding-on-your +title: each-of-those-was-a-real-defect-not-misunderstanding-on-your +status: active +source_of_truth: false +freshness: current +last_reviewed: 2026-11-11 +tags: + - pack/paperclip-harness + - agent-memory/context + - autolearn + - rich-discovery + - repo/each-of-those-was-a-real-defect-not-misunderstanding-on-your +--- + +# each-of-those-was-a-real-defect-not-misunderstanding-on-your + +## Rich discovery update (2026-11-11 02:28:06) + +Each of those was a real defect, not misunderstanding on your part. + +## Runs were not selectable — they are now + +The cursor existed but nothing drew it, so the list looked inert. The chosen run is now marked and highlighted: + +``` +╭─ the work · 2 runs runs change facts review log merge ──·focus·╮ +│ state woken by started ended took +│ ▸ succeeded automation 15:56:28 15:56:59 31s +│ succeeded assignment 15:55:40 15:56:26 47s +``` + +`↑`/`↓` moves, `Enter` opens that run's log. The tab title now says how many runs there are, so `2 runs` versus `1 run` is visible without guessing. + +## The log no longer says "choose a run" when you cannot + +When a task opens, its newest run is chosen for you, so the log tab already has something in it. `Enter` on a different run replaces it. + +## The merge tab was showing another task's merge + +That was wrong and misleading. It now says plainly: + +``` +no merge has been run from this screen for AUD-166 + +the last merge recorded was for another task: +merge of AUD-171 started 12:53:39 + +press m to merge this task +``` + +## Why a file-only task gets merged and rebased + +Because that file is a **commit**, and the commit sits on the task's branch, not on `main`. Merging is the only step that puts it on `main`. The rebase is not a rewrite of your work — it moves the branch onto the current tip of `main` so the checks run against what would actually land. If `main` has not moved since the branch was cut, the rebase does nothing and appears as a single line in the log. + +`AUD-171` created `STATUS-2.md` and merged it: that is exactly what the merge did — put that one file on `main`, at `a784e0f`. Nothing else was touched, and the review found nothing to look at because a new two-line file gives a reviewer very little. + +## What is still true about AUD-166 + +It has two runs (`assignment`, then `automation` — Paperclip's corrective wake), no review recorded because it was never merged, and a diff. So: runs tab shows two rows, `Enter` opens either log, `change` shows the diff, `review` says none recorded, `merge` now says none has been run for it. + +## Navigation you can use without the Board + +In `Work>work`: `n` / `p` for the next or previous task (`task 6 of 13` in the header), `o` to pick from a list, `[` / `]` for tabs. Choosing a task there also updates `Reply>reply` and the rest, because it writes the same choice the Board writes. + +Committed as `f949345`; `docs/RUNS-AND-MERGE.md` now carries the explanation of runs, the merge order, and why a one-file task goes through the same gate. + +## Evidence + +- Confidence: 84% +- Reason: Update component/repository context with detailed discovered structure and configuration + +## Related + +- [[packs/paperclip-harness/00-system/pi-agent/memory-manifest|Memory Manifest]] + +## Related learned memories + +- session: [[packs/paperclip-harness/80-sessions/rich-discovery-each-of-those-was-a-real-defect-not-misunders|Rich discovery: each-of-those-was-a-real-defect-not-misunderstanding-on-your 2026-11-11 02:28:06]] +- context: [[packs/paperclip-harness/20-context/each-of-those-was-a-real-defect-not-misunderstanding-on-your|each-of-those-was-a-real-defect-not-misunderstanding-on-your]] +- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|each-of-those-was-a-real-defect-not-misunderstanding-on-your repository structure and configuration patterns]] diff --git a/.pi/memory-vault/packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns.md b/.pi/memory-vault/packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns.md index 5145534..1a426ef 100644 --- a/.pi/memory-vault/packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns.md +++ b/.pi/memory-vault/packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns.md @@ -2488,3 +2488,69 @@ Choosing a task here writes the same choice the Board writes, so `Reply>reply` a - runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|navigate tasks and runs inside Work>work and merge safely (paperclip-harness)]] - session: [[packs/paperclip-harness/80-sessions/rich-discovery-home-2026-11-11-02-17-44|Rich discovery: home 2026-11-11 02:17:44]] - context: [[packs/paperclip-harness/20-context/home|home]] + + +--- + +## Update (2026-11-11 02:28:06) + +## Structural/configuration observations (2026-11-11 02:28:06) + +Each of those was a real defect, not misunderstanding on your part. + +## Runs were not selectable — they are now + +The cursor existed but nothing drew it, so the list looked inert. The chosen run is now marked and highlighted: + +``` +╭─ the work · 2 runs runs change facts review log merge ──·focus·╮ +│ state woken by started ended took +│ ▸ succeeded automation 15:56:28 15:56:59 31s +│ succeeded assignment 15:55:40 15:56:26 47s +``` + +`↑`/`↓` moves, `Enter` opens that run's log. The tab title now says how many runs there are, so `2 runs` versus `1 run` is visible without guessing. + +## The log no longer says "choose a run" when you cannot + +When a task opens, its newest run is chosen for you, so the log tab already has something in it. `Enter` on a different run replaces it. + +## The merge tab was showing another task's merge + +That was wrong and misleading. It now says plainly: + +``` +no merge has been run from this screen for AUD-166 + +the last merge recorded was for another task: +merge of AUD-171 started 12:53:39 + +press m to merge this task +``` + +## Why a file-only task gets merged and rebased + +Because that file is a **commit**, and the commit sits on the task's branch, not on `main`. Merging is the only step that puts it on `main`. The rebase is not a rewrite of your work — it moves the branch onto the current tip of `main` so the checks run against what would actually land. If `main` has not moved since the branch was cut, the rebase does nothing and appears as a single line in the log. + +`AUD-171` created `STATUS-2.md` and merged it: that is exactly what the merge did — put that one file on `main`, at `a784e0f`. Nothing else was touched, and the review found nothing to look at because a new two-line file gives a reviewer very little. + +## What is still true about AUD-166 + +It has two runs (`assignment`, then `automation` — Paperclip's corrective wake), no review recorded because it was never merged, and a diff. So: runs tab shows two rows, `Enter` opens either log, `change` shows the diff, `review` says none recorded, `merge` now says none has been run for it. + +## Navigation you can use without the Board + +In `Work>work`: `n` / `p` for the next or previous task (`task 6 of 13` in the header), `o` to pick from a list, `[` / `]` for tabs. Choosing a task there also updates `Reply>reply` and the rest, because it writes the same choice the Board writes. + +Committed as `f949345`; `docs/RUNS-AND-MERGE.md` now carries the explanation of runs, the merge order, and why a one-file task goes through the same gate. + +## Evidence + +- Confidence: 82% +- Reason: Captured factual repo structure/configuration patterns from rich discovery + +## Related learned memories + +- session: [[packs/paperclip-harness/80-sessions/rich-discovery-each-of-those-was-a-real-defect-not-misunders|Rich discovery: each-of-those-was-a-real-defect-not-misunderstanding-on-your 2026-11-11 02:28:06]] +- context: [[packs/paperclip-harness/20-context/each-of-those-was-a-real-defect-not-misunderstanding-on-your|each-of-those-was-a-real-defect-not-misunderstanding-on-your]] +- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|each-of-those-was-a-real-defect-not-misunderstanding-on-your repository structure and configuration patterns]] diff --git a/.pi/memory-vault/packs/paperclip-harness/80-sessions/rich-discovery-each-of-those-was-a-real-defect-not-misunders.md b/.pi/memory-vault/packs/paperclip-harness/80-sessions/rich-discovery-each-of-those-was-a-real-defect-not-misunders.md new file mode 100644 index 0000000..eb6ca72 --- /dev/null +++ b/.pi/memory-vault/packs/paperclip-harness/80-sessions/rich-discovery-each-of-those-was-a-real-defect-not-misunders.md @@ -0,0 +1,85 @@ +--- +type: session +id: session.paperclip-harness.rich-discovery-each-of-those-was-a-real-defect-not-misunders +title: Rich discovery: each-of-those-was-a-real-defect-not-misunderstanding-on-your 2026-11-11 02:28:06 +status: active +source_of_truth: false +freshness: current +last_reviewed: 2026-11-11 +tags: + - pack/paperclip-harness + - agent-memory/session + - autolearn + - rich-discovery + - repo/each-of-those-was-a-real-defect-not-misunderstanding-on-your +--- + +# Rich discovery: each-of-those-was-a-real-defect-not-misunderstanding-on-your 2026-11-11 02:28:06 + +Sanitized rich discovery snapshot captured automatically from the completed turn. + + +## Final answer snapshot + +Each of those was a real defect, not misunderstanding on your part. + +## Runs were not selectable — they are now + +The cursor existed but nothing drew it, so the list looked inert. The chosen run is now marked and highlighted: + +``` +╭─ the work · 2 runs runs change facts review log merge ──·focus·╮ +│ state woken by started ended took +│ ▸ succeeded automation 15:56:28 15:56:59 31s +│ succeeded assignment 15:55:40 15:56:26 47s +``` + +`↑`/`↓` moves, `Enter` opens that run's log. The tab title now says how many runs there are, so `2 runs` versus `1 run` is visible without guessing. + +## The log no longer says "choose a run" when you cannot + +When a task opens, its newest run is chosen for you, so the log tab already has something in it. `Enter` on a different run replaces it. + +## The merge tab was showing another task's merge + +That was wrong and misleading. It now says plainly: + +``` +no merge has been run from this screen for AUD-166 + +the last merge recorded was for another task: +merge of AUD-171 started 12:53:39 + +press m to merge this task +``` + +## Why a file-only task gets merged and rebased + +Because that file is a **commit**, and the commit sits on the task's branch, not on `main`. Merging is the only step that puts it on `main`. The rebase is not a rewrite of your work — it moves the branch onto the current tip of `main` so the checks run against what would actually land. If `main` has not moved since the branch was cut, the rebase does nothing and appears as a single line in the log. + +`AUD-171` created `STATUS-2.md` and merged it: that is exactly what the merge did — put that one file on `main`, at `a784e0f`. Nothing else was touched, and the review found nothing to look at because a new two-line file gives a reviewer very little. + +## What is still true about AUD-166 + +It has two runs (`assignment`, then `automation` — Paperclip's corrective wake), no review recorded because it was never merged, and a diff. So: runs tab shows two rows, `Enter` opens either log, `change` shows the diff, `review` says none recorded, `merge` now says none has been run for it. + +## Navigation you can use without the Board + +In `Work>work`: `n` / `p` for the next or previous task (`task 6 of 13` in the header), `o` to pick from a list, `[` / `]` for tabs. Choosing a task there also updates `Reply>reply` and the rest, because it writes the same choice the Board writes. + +Committed as `f949345`; `docs/RUNS-AND-MERGE.md` now carries the explanation of runs, the merge order, and why a one-file task goes through the same gate. + +## Evidence + +- Confidence: 86% +- Reason: Preserve full sanitized discovery detail from a rich investigation turn + +## Related + +- [[packs/paperclip-harness/00-system/pi-agent/memory-manifest|Memory Manifest]] + +## Related learned memories + +- session: [[packs/paperclip-harness/80-sessions/rich-discovery-each-of-those-was-a-real-defect-not-misunders|Rich discovery: each-of-those-was-a-real-defect-not-misunderstanding-on-your 2026-11-11 02:28:06]] +- context: [[packs/paperclip-harness/20-context/each-of-those-was-a-real-defect-not-misunderstanding-on-your|each-of-those-was-a-real-defect-not-misunderstanding-on-your]] +- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|each-of-those-was-a-real-defect-not-misunderstanding-on-your repository structure and configuration patterns]] diff --git a/bin/harness b/bin/harness index 3347f9e..7f97ece 100755 Binary files a/bin/harness and b/bin/harness differ diff --git a/docs/DOCMAP.md b/docs/DOCMAP.md index 65ef02b..e7d7266 100644 --- a/docs/DOCMAP.md +++ b/docs/DOCMAP.md @@ -24,6 +24,7 @@ it is a pointer and should be deleted or replaced. | `docs/SESSIONS.md` | this project | the two kinds of session, where Pi's conversations are, and the plan for the junk TUIOS sessions | | `docs/TEST-PLAN.md` | this project | the test plan: every step, every key, every expected result | | `docs/RUNS-AND-MERGE.md` | this project | what a task, a run and a merge are, with the measured run counts | +| `docs/NEXT.md` | this project | what is left to build, in order, and what is still unproven | ## What is not a document of this project diff --git a/docs/NEXT.md b/docs/NEXT.md new file mode 100644 index 0000000..921ed52 --- /dev/null +++ b/docs/NEXT.md @@ -0,0 +1,73 @@ +# What is left to build + +Written 2026-11-11. The interface has eight workspaces and 23 panels; the work below is what is +still missing or unproven. Order is by usefulness, not by size. + +## 1. Repair>cleanup — the pane you asked for + +A fourth tab in `Repair>repair` that lists TUIOS sessions with their pane count and last-active +time, marks the ones that are attached, and kills only what you tick. Two rules it must keep: + +- **never touch `~/.pi/paperclips/`** — those are the Pi conversations, and they are the history; +- refuse any session that is attached, and refuse `paperclip-harness` by name. + +Measured today: 37 sessions, 21 of them from the closed project's tests (`harness-demo-card-*`, +`office-test-1*`). Nothing has been killed. + +## 2. A Pi session browser + +The cheap version first: a `t` entry that opens `~/.pi/paperclips` in Yazi, and one that runs +`pi --resume`. Then, if that feels like a detour after a week, a read-only transcript tab in +`Agents>agents` that reads the JSONL directly. `GET /api/agents/{id}/task-sessions` maps a task +to its session file, so neither version has to guess. + +## 3. Project>projects — switching project + +A tab listing every adopted project from a small local registry +(`~/.config/paperclip-harness/projects.toml`: id, folder, host, session), filled by `bin/office`, +with a key to switch. A project on another machine is shown as `on .27` and not offered, because +this terminal cannot open a folder that is not here. + +## 4. Run a review from the interface + +`Work>review` shows the verdicts already recorded. It should also be able to *start* one: +`v` runs `bin/review --post` in the background and the tab follows its log, the way +`Work>merge` already does. + +## 5. The old `office` scaffold + +`bin/office` writes `.harness/harness.toml` and builds the panes. The previous project also +wrote a scaffold: `settings.toml`, one file per role, `verify.sh`, the per-page notes — writing +only what is missing. That is the cheapest remaining gap in the project layer. + +## 6. Board>needs: act on a card + +The needs-you panel lists what is waiting but the action still happens elsewhere. Each card +should carry its own key: unblock, assign, open in Reply. + +## 7. Costs as a chart + +`Project>overview` already draws a sparkline of runs in Go. Spend-per-day, using the same block +characters or `tuios.dev/plot`, is the natural second chart — no TML, no web view. + +## 8. Memory per agent + +`engram` is installed and `headroom` is running as a compression proxy, but nothing in the +interface shows which agent uses which. A read-only row in `Agents>settings` is the honest first +step; a switch is only worth adding after one agent has been run both ways and measured. + +## 9. MOUSE-1 + +The key is in the environment; the software is not installed. The old project's policy stands: +triage only, never a gate, never a permit. It would order `Board>needs`, never decide a merge. + +## Unproven, and worth a test + +- opening a project **on another machine** (`bin/office --host`): written, never exercised; +- clicking a task row with the mouse in `Board>board`: the zones are wired, nobody has clicked; +- `R` with a pane that is not at its expected size; +- a task whose blocker is still open: does the agent stay away until it closes? + +## Open Paperclip tasks in this project + +One: `AUD-162`, a leftover test task in `todo` from the first day. Everything else is `done`. diff --git a/tui/agents.go b/tui/agents.go index 867e84f..0fbaed7 100644 --- a/tui/agents.go +++ b/tui/agents.go @@ -853,18 +853,18 @@ func (m agentsModel) View() string { to := min(len(body), from+visible) hints := []string{ - keyHint("[ ]", "roster, runs, log, settings, skills, extensions"), - keyHint("enter", "open a run"), - keyHint("p P w", "pause, resume, wake"), - keyHint("r", "read again"), + keyHint("[ ]", "tab"), + keyHint("enter", "open"), + keyHint("p P w", "pause/resume/wake"), + keyHint("r", "refresh"), keyHint("?", "keys"), } if m.tab == 4 || m.tab == 5 { hints = []string{ - keyHint("[ ]", "switch tab"), - keyHint("space", "turn this skill or extension on or off"), - keyHint("↑↓ j k", "move"), - keyHint("r", "read again"), + keyHint("[ ]", "tab"), + keyHint("space", "toggle"), + keyHint("↑↓", "move"), + keyHint("r", "refresh"), } } footer := hintLine(hints, m.width) diff --git a/tui/board.go b/tui/board.go index 3391a3e..2cc40cc 100644 --- a/tui/board.go +++ b/tui/board.go @@ -463,32 +463,32 @@ func (m boardModel) footerLine() string { switch m.focus { case focusTree: return hintLine([]string{ - keyHint("↑↓ or j k", "choose a task"), - keyHint("enter", "show it everywhere"), + keyHint("↑↓", "move"), + keyHint("enter", "open"), keyHint("a", "assign"), keyHint("u", "unblock"), keyHint("t", "tools"), keyHint("/", "filter"), keyHint("?", "keys"), - keyHint("tab", "next panel"), - keyHint("r", "read again"), - keyHint("R", "rebuild every pane"), - keyHint("q", "leave"), + keyHint("tab", "panel"), + keyHint("r", "refresh"), + keyHint("R", "rebuild"), + keyHint("q", "quit"), }, m.width) case focusSummary: return hintLine([]string{ - keyHint("↑↓ or j k", "choose a task"), - keyHint("tab", "next panel"), - keyHint("r", "read again"), - keyHint("q", "leave"), + keyHint("↑↓", "move"), + keyHint("tab", "panel"), + keyHint("r", "refresh"), + keyHint("q", "quit"), }, m.width) default: return hintLine([]string{ - keyHint("tab", "next panel"), - keyHint("[ ]", "switch tab"), + keyHint("tab", "panel"), + keyHint("[ ]", "tab"), keyHint("enter", "show this task everywhere"), - keyHint("r", "read again"), - keyHint("q", "leave"), + keyHint("r", "refresh"), + keyHint("q", "quit"), }, m.width) } } diff --git a/tui/frame.go b/tui/frame.go index b718239..afd1c63 100644 --- a/tui/frame.go +++ b/tui/frame.go @@ -214,9 +214,10 @@ func keyHint(keys, what string) string { return k + " " + w } -// hintLine joins key hints with a dot, dropping the ones that do not apply. +// hintLine joins key hints with a comma, because a footer is a list of keys and +// not a sentence. func hintLine(hints []string, width int) string { - joined := strings.Join(hints, dimStyle().Render(" · ")) + joined := strings.Join(hints, dimStyle().Render(", ")) if lipgloss.Width(joined) > width { return truncateVisible(joined, width) } diff --git a/tui/newtask.go b/tui/newtask.go index 2ac8337..1d100bf 100644 --- a/tui/newtask.go +++ b/tui/newtask.go @@ -288,9 +288,9 @@ func (m newTaskModel) View() string { formLines := m.formLines(m.width - 4) footer := hintLine([]string{ - keyHint("tab", "next field"), - keyHint("enter", "next, and create on the last"), - keyHint("ctrl+n", "form, guidance, preview"), + keyHint("tab", "field"), + keyHint("enter", "next/create"), + keyHint("ctrl+n", "tab"), keyHint("esc", "cancel"), }, m.width) diff --git a/tui/project.go b/tui/project.go index 1fd4ccf..d8fe234 100644 --- a/tui/project.go +++ b/tui/project.go @@ -254,11 +254,11 @@ func (m projectModel) View() string { to := min(len(body), from+visible) footer := hintLine([]string{ - keyHint("[ ]", "switch tab"), - keyHint("↑↓ or j k", "scroll"), - keyHint("r", "read again"), - keyHint("R", "rebuild every pane"), - keyHint("q", "leave"), + keyHint("[ ]", "tab"), + keyHint("↑↓", "scroll"), + keyHint("r", "refresh"), + keyHint("R", "rebuild"), + keyHint("q", "quit"), }, m.width) gap := max(2, m.width-lipgloss.Width(head)-lipgloss.Width(state)-1) diff --git a/tui/repair.go b/tui/repair.go index b3b8274..c36864d 100644 --- a/tui/repair.go +++ b/tui/repair.go @@ -302,11 +302,11 @@ func (m repairModel) View() string { to := min(len(body), from+visible) footer := hintLine([]string{ - keyHint("[ ]", "switch tab"), - keyHint("R", "rebuild every pane"), - keyHint("↑↓ or j k", "scroll"), - keyHint("r", "check again"), - keyHint("q", "leave"), + keyHint("[ ]", "tab"), + keyHint("R", "rebuild"), + keyHint("↑↓", "scroll"), + keyHint("r", "recheck"), + keyHint("q", "quit"), }, m.width) gap := max(2, m.width-lipgloss.Width(head)-lipgloss.Width(state)-1) diff --git a/tui/reply.go b/tui/reply.go index ce54553..d5b5171 100644 --- a/tui/reply.go +++ b/tui/reply.go @@ -291,18 +291,18 @@ func (m replyModel) View() string { boxLines := m.composerLines(m.width-4, composer.bodyHeight()) footer := hintLine([]string{ - keyHint("enter or tab", "write a reply"), - keyHint("s", "choose a status to send"), - keyHint("↑↓ or j k", "read the thread"), - keyHint("r", "read again"), - keyHint("R", "rebuild every pane"), - keyHint("q", "leave"), + keyHint("enter", "reply"), + keyHint("s", "status"), + keyHint("↑↓", "scroll"), + keyHint("r", "refresh"), + keyHint("R", "rebuild"), + keyHint("q", "quit"), }, m.width) if m.inBox { footer = hintLine([]string{ keyHint("enter", "send"), - keyHint("alt+enter", "new line"), - keyHint("esc", "close the box"), + keyHint("alt+enter", "newline"), + keyHint("esc", "close"), }, m.width) } if m.err != nil { diff --git a/tui/work.go b/tui/work.go index cbfb816..07b5ea1 100644 --- a/tui/work.go +++ b/tui/work.go @@ -518,15 +518,15 @@ func (m workModel) View() string { to := min(len(body), from+visible) footer := hintLine([]string{ - keyHint("[ ]", "switch tab"), - keyHint("↑↓ or j k", "scroll"), - keyHint("t", "open a tool pane"), - keyHint("o", "choose a task"), - keyHint("m", "merge this task (asks first)"), - keyHint("]", "tabs"), - keyHint("r", "read again"), - keyHint("R", "rebuild every pane"), - keyHint("q", "leave"), + keyHint("n p", "task"), + keyHint("[ ]", "tab"), + keyHint("↑↓", "scroll"), + keyHint("enter", "log"), + keyHint("o", "pick"), + keyHint("m", "merge"), + keyHint("t", "tools"), + keyHint("r", "refresh"), + keyHint("R", "rebuild"), }, m.width) return strings.Join([]string{