linersh 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/bin/liner.js +37 -0
  2. package/cli-update-docs/ABOUT.md +69 -0
  3. package/cli-update-docs/CURATION.md +261 -0
  4. package/cli-update-docs/JOB-STORY-MIGRATION.md +99 -0
  5. package/cli-update-docs/JTBD-MASTER-PROMPT-ABOUT.md +133 -0
  6. package/cli-update-docs/JTBD-MASTER-PROMPT.md +147 -0
  7. package/cli-update-docs/MIXTAPE-FORMAT.md +398 -0
  8. package/cli-update-docs/PLATFORM.md +210 -0
  9. package/cli-update-docs/README.md +107 -0
  10. package/cli-update-docs/SKILL.md +244 -0
  11. package/cli-update-docs/TUI-BACKLOG.md +155 -0
  12. package/cli-update-docs/curator-notes.md +84 -0
  13. package/cli-update-docs/quality-check-tests.md +196 -0
  14. package/cli-update-docs/source-finding-tactics.md +99 -0
  15. package/cli-update-docs/source-quality-hierarchy.md +130 -0
  16. package/cli-update-docs/synthesis-guidance.md +133 -0
  17. package/dist/App.js +29 -12
  18. package/dist/App.js.map +1 -1
  19. package/dist/agents/detect.js +14 -4
  20. package/dist/agents/detect.js.map +1 -1
  21. package/dist/agents/prompts.js +0 -18
  22. package/dist/agents/prompts.js.map +1 -1
  23. package/dist/agents/runner.js +19 -1
  24. package/dist/agents/runner.js.map +1 -1
  25. package/dist/colors.js +48 -21
  26. package/dist/colors.js.map +1 -1
  27. package/dist/components/Header.js +5 -5
  28. package/dist/components/Header.js.map +1 -1
  29. package/dist/components/KeyHints.js +9 -2
  30. package/dist/components/KeyHints.js.map +1 -1
  31. package/dist/components/LabeledBox.js +2 -2
  32. package/dist/components/LabeledBox.js.map +1 -1
  33. package/dist/components/NextSteps.js +2 -2
  34. package/dist/components/NextSteps.js.map +1 -1
  35. package/dist/open-folder.js +28 -0
  36. package/dist/open-folder.js.map +1 -0
  37. package/dist/phases.js +5 -20
  38. package/dist/phases.js.map +1 -1
  39. package/dist/progress.js +3 -6
  40. package/dist/progress.js.map +1 -1
  41. package/dist/screens/AgentSetup.js +15 -13
  42. package/dist/screens/AgentSetup.js.map +1 -1
  43. package/dist/screens/BootSplash.js +30 -15
  44. package/dist/screens/BootSplash.js.map +1 -1
  45. package/dist/screens/CompileView.js +30 -14
  46. package/dist/screens/CompileView.js.map +1 -1
  47. package/dist/screens/FramingConfirmReview.js +14 -10
  48. package/dist/screens/FramingConfirmReview.js.map +1 -1
  49. package/dist/screens/Gate1Review.js +12 -8
  50. package/dist/screens/Gate1Review.js.map +1 -1
  51. package/dist/screens/Gate2Review.js +14 -10
  52. package/dist/screens/Gate2Review.js.map +1 -1
  53. package/dist/screens/ImportPrompt.js +143 -35
  54. package/dist/screens/ImportPrompt.js.map +1 -1
  55. package/dist/screens/LocalFilePicker.js +5 -5
  56. package/dist/screens/LocalFilePicker.js.map +1 -1
  57. package/dist/screens/NewMixtapeWizard.js +14 -14
  58. package/dist/screens/NewMixtapeWizard.js.map +1 -1
  59. package/dist/screens/PhaseRunner.js +77 -54
  60. package/dist/screens/PhaseRunner.js.map +1 -1
  61. package/dist/screens/ProcessManifest.js +11 -6
  62. package/dist/screens/ProcessManifest.js.map +1 -1
  63. package/dist/screens/ProjectHub.js +97 -141
  64. package/dist/screens/ProjectHub.js.map +1 -1
  65. package/dist/screens/SourceModal.js +2 -2
  66. package/dist/screens/SourceModal.js.map +1 -1
  67. package/dist/screens/TapeBrowser.js +79 -44
  68. package/dist/screens/TapeBrowser.js.map +1 -1
  69. package/dist/screens/TapeDraftReview.js +22 -18
  70. package/dist/screens/TapeDraftReview.js.map +1 -1
  71. package/dist/screens/TapeEditor.js +5 -5
  72. package/dist/screens/TapeEditor.js.map +1 -1
  73. package/dist/screens/cassette-art.js +21 -21
  74. package/package.json +5 -4
  75. package/dist/browser-support.js +0 -62
  76. package/dist/browser-support.js.map +0 -1
  77. package/dist/screens/BrowserSetup.js +0 -181
  78. package/dist/screens/BrowserSetup.js.map +0 -1
  79. package/dist/screens/NewProjectPrompt.js +0 -66
  80. package/dist/screens/NewProjectPrompt.js.map +0 -1
  81. package/dist/screens/Settings.js +0 -72
  82. package/dist/screens/Settings.js.map +0 -1
@@ -0,0 +1,155 @@
1
+ # TUI backlog
2
+
3
+ Running list of work deferred from earlier slices. Newest at the top of each section. When something ships, move it to **Done** with the date.
4
+
5
+ ---
6
+
7
+ ## Lessons from cli-writer-6 (2026-05-22)
8
+
9
+ Captured after comparing cli-writer-3 (v0.3 methodology, 15 sources) and cli-writer-6 (v0.4 methodology, 23 sources) on the same JTBD lineage. The v0.4 methodology changes are visibly paying off (sharper JTBD, task-oriented sections, source-kind chips, framing-gap audit firing). The items below are the next layer of methodology, prompt, and UX tightening suggested by what the artifact shows.
10
+
11
+ ### Synthesis-level — generative rules deserve explicit slots
12
+
13
+ - **Require a "Generative rules" or "If you remember nothing else…" subsection in the synthesis.** v3 had five top-level operational principles (predictability, density, help-is-doc, errors-deserve-care, streams-have-meaning). v6 has the equivalent material but it's dispersed inside paragraphs, harder for the consuming AI to load as decision rules. A prompt directive in Phase 6 to surface ~5 operational generative rules — phrased as imperatives — would close this gap without changing source selection. Worked example to embed in `synthesis-guidance.md`: "Channel discipline: stdout for data, stderr for human, exit codes mean what they say. This single rule resolves most 'should I print this?' questions."
14
+ - **The "stances this corpus takes" section was great — keep it as a required header.** v6 introduced it explicitly; v3 did similar work under "Contested questions" but less decisively. Make it canonical in the synthesis template.
15
+
16
+ ### Curator notes — chip the kind into the note line
17
+
18
+ - **Render the source `kind` chip inline at the top of each curator note in MIXTAPE.md.** Today the kind is one of many bullet attributes; consuming AIs don't always carry it forward when they load a single source file. Prepending `**[principle]**` or similar to the first line of the note ("**[principle]** Read for the framing — …") would make the weighting impossible to miss when the AI loads only `sources/NN-foo.md` for a deep read. Render-only change in `output/mixtape.py`.
19
+
20
+ ### Methodology — unverified content and the verification re-check
21
+
22
+ - **Auto re-run the perspectives audit at compile time when previously-unverified sources became verified.** v6 kept two YouTube sources (Küber, Pinsker) with curator notes acknowledging transcripts were unfetched at evaluation. By compile time `yt-dlp` produced real transcripts, but the perspectives audit's "unverified does not count" verdict from Phase 5 was never revisited. A `liner verify <folder>` command (or a compile-time hook) could re-check whether unverified perspective slots are now verifiable, and flag the gap closing as a soft signal back to the curator.
23
+ - **Curator-added sources should default to a sensible kind and prompt for it before commit.** The new `[+] add own` flow leaves `kind` unset. Either default to `principle` (the synthesis-writing default per `prompts.ts`) or open a four-button kind picker after URL submission. Cheap UX add; saves the curator a tape.yaml edit pass.
24
+
25
+ ### Quality of evaluation — note-quality smell test
26
+
27
+ - **Add a Phase 5 sub-check: "is each curator note doing real work?"** Notes that read as filler (e.g., "Skim a few command pages to calibrate density and rhythm") aren't earning weight in the consuming AI's loading decisions. A simple rubric — note must (a) cite what to read for, (b) name the bar it sets, (c) flag one limitation or scope boundary — would force the agent to deepen thin notes before shipping. Belongs in `quality-check-tests.md` as a 6th test.
28
+
29
+ ### Compile-time fetcher chain
30
+
31
+ - **Wayback Machine as a fetcher tier between Playwright and the agent-summary fallback.** Cheap, no tokens, returns raw HTML the trafilatura extractor can use — full article instead of summary. Right move when richer fallback content matters for production-quality mixtapes. Discussed in the v6 session; deferred at curator's request because the agent-summary fallback is sufficient for current scope.
32
+ - **Per-source actions on compile failure** (`[d]` drop, `[o]` open in browser, `[j]` retry with render: js). Surfaces recourse on a failed source instead of forcing the curator to edit tape.yaml. Currently the only recourse is "rerun all," which is misleadingly named — see DONE entry below where the hint was tightened to "retry failed."
33
+ - **Failure detail capture.** When the web handler raises, capture the HTTP code, content-type, first ~500 bytes of body, and a category (`paywall`, `not_found`, `forbidden`, `js_required`, `tls`, `network`, `unknown`). Display on the failed source line. 80% of "why did this fail" questions resolved with no LLM call.
34
+
35
+ ### Surface improvements
36
+
37
+ - **Surface Test 5 (kind-balance) outcomes visibly in the TUI.** Make the curator see the distribution at Phase 5 completion — a `4 prescription · 6 principle · 2 example · 0 reference` line in the gate2/quality-check review screen, with the zero column flagged in yellow if undefended. Lightweight implementation: parse `working/04-quality-checks.md` for the Test 5 section and render in the existing Gate2Review surface.
38
+ - **Perspectives audit display.** Same idea — show the curator the named perspectives + stance/concerns coverage as a structured list, not just buried in markdown.
39
+ - **Library cross-reference at JTBD time (deferred — needs library).** When the library exists, surface "mixtapes in your library that match these JTBD keywords" during Phase 1 so the curator can opt to start from a related one and preserve sources/framings that worked.
40
+
41
+ ---
42
+
43
+ ## Up next (functional — needed to "get everything working")
44
+
45
+ ### Token cost surfaces (2026-05-27)
46
+
47
+ - **Remove the fake `$` cost figure from `ProcessManifest.tsx` (2026-05-28).** PhaseRunner's dollar figure was removed in 0.5.2 (see Done), but `ProcessManifest.tsx` still renders a `$` cost line aggregated from `.liner-runs/`. Same reasoning: subscription runs aren't metered API billing, so the dollar amount is invented while token counts are real. Drop the `$` line there too (or relabel as a clearly-marked estimate with a configurable rate) so the two surfaces don't diverge.
48
+ - **Cumulative token counter for the whole run.** Today the PhaseRunner shows live tokens for the current phase via the `tokens` event. There is no roll-up at the mixtape level — a curator finishes a 7-phase run with no idea what it cost in total. Aggregate token usage across all `.liner-runs/*.jsonl` entries for a project and surface a `Total tokens` line on the ProjectHub (or its own row in the ProcessManifest screen, which already aggregates similar data). Cheap because the aggregator already exists.
49
+ - **Pre-flight token estimate before kicking off a phase.** Before pressing Enter to run Phase 2 (or any agent-eligible phase), the user should see a "this phase typically costs ~X tokens" hint so they know roughly what they're committing to. Implementation idea: instrument the next several real runs to record actual per-phase token counts in `.liner-runs/`, then compute a rolling median per phase. After ~3–5 sample mixtapes, the median per-phase + per-mode (quick vs. methodology) becomes a useful baseline that ships with the package; later it should update dynamically from the user's own history. Open question: show the estimate per phase, or as a single "whole mixtape ≈ N tokens" number at wizard exit — both are useful, the latter is the bigger conversion lever. **Seed data exists:** a 2026-05-28 pass over the existing `.liner-runs` gives real per-phase medians on Opus (framing ~$0.35, candidates ~$3.2, evaluation ~$2.2, quality ~$1.1, synthesis ~$0.5, assembly ~$0.55; a full cycle ≈ 7–9M tokens, most of it cached reads). These can ship as the first baseline before per-user history kicks in.
50
+
51
+ ### Per-phase model selection — cheaper model for the heavy phases (2026-05-28, recorded, not started)
52
+
53
+ - **Run the heavy phases on a cheaper model.** Token/cost analysis across the existing mixtapes (`.liner-runs/*.jsonl`, 2026-05-28) shows a full quick-mode cycle on `claude-opus-4-7[1m]` costs **~$6.50–9.00 at API rates**, and that **candidate discovery + evaluation are ~65% of it** (cli-writer-6: candidates $3.42, evaluation $2.61, quality $1.42, synthesis $0.63, assembly $0.61, framing $0.35). Dropping those two phases to **Sonnet** (and the OpenAI equivalent — e.g. a `gpt-5-mini`-class model — for Codex) would cut a cycle roughly **5×**, from ~$9 to ~$2, with the judgment-light fetch/triage work being the safest to downgrade. Framing / JTBD-clarify already fall back to Haiku. Implementation: a per-phase model map in the agent layer (`src/agents/`), passed through `buildArgs` as `--model` for Claude and the `-m`/model flag for Codex; keep the curator's default model for synthesis/quality where taste matters most, or expose the map in `~/.liner/config.yaml`. **Caveat:** the dollar figures are API-equivalent only — on a subscription the saving is rate-limit quota, not money. Decision deferred; recorded here.
54
+
55
+ ### Agent unavailability needs a hard error, not a hang (2026-05-27)
56
+
57
+ - **Detect agent CLI auth/quota failure and fail loudly.** Observed 2026-05-27: starting a run with Codex while the underlying Codex subscription had expired produced a silent hang — the agent process was launched, didn't emit any stream events, didn't error out, and the TUI sat on the running spinner indefinitely. Same class of failure applies to revoked API keys, expired auth tokens, network blocked, model deprecated. The TUI needs a watchdog that, if no `assistant` / `tool_use` / `tokens` event arrives within ~15s of process start *and* stderr stays empty, surfaces a clear "couldn't reach <agent> — check auth/subscription" error with `[r] retry` and `[a] switch agent` actions. Likely fix is in the agent adapter (`src/agents/`), not the runner. Also worth a one-time pre-flight `--version` or `/whoami`-style call on agent selection so dead auth is caught before the curator commits to a phase.
58
+
59
+ ### Slice 3 — agent integration polish
60
+
61
+ - **Background-banner concurrent runs.** Current architecture cancels the run when the user navigates away from PhaseRunner. If we want to support "leave the agent working while I edit elsewhere," we need to lift run state to app context and add a hub banner. Not blocking — pause-and-resume is a real product question, not just an implementation one.
62
+
63
+ ### Empirical-test path (now optional, post-0.5.2)
64
+
65
+ - **Optional empirical-test capture.** The empirical test was removed as a driven TUI phase in 0.5.2 (*compiled = complete*); it now lives as methodology guidance. If we ever want to bring it back as an *opt-in* tool, it could run the same question through two agent sessions (with and without `MIXTAPE.md`) and write the comparison to an artifact — invoked explicitly, never as a step that parks the hub.
66
+
67
+ ### CLI affordances the TUI might want
68
+
69
+ - **`liner status <folder> --json`** — phase-by-phase completion report from the CLI so the TUI doesn't duplicate filesystem checks. Optional; current detection works.
70
+ - **`liner init` flags** — `--mode`, `--jtbd`, `--title`, `--description`, `--curator` so the wizard doesn't post-process the scaffolded `tape.yaml`. Optional; current writeTape works.
71
+
72
+ ---
73
+
74
+ ## Visual polish (optional, after functional work is done)
75
+
76
+ - **Boot logo screen.** Use `ink-gradient` + `ink-big-text` for a real branded splash on first paint. ~40KB extra deps.
77
+ - **Animated phase-transition flash.** When a phase moves to `complete` (status change detected on refresh), briefly flash the row with a pulsing background color.
78
+ - **Notification fade-out.** Right now notifications time out at 3500ms with a hard cut. A 200ms fade would feel more polished.
79
+ - **Custom mode picker.** Replace the current arrow + cyan-text mode chooser in the wizard with background-color chips (`[ Quick ]` / `[ Methodology ]`) styled like the brand chip.
80
+ - **Inline help overlay.** `?` key opens a modal listing every binding on the current screen. Grows in value as the keymap expands.
81
+ - **measureElement-based responsive sizing.** For artifact previews, table widths in Gate UIs, etc. The hub uses percentage widths already; this would tighten the rest.
82
+ - **Per-screen color discipline pass.** The skill says magenta = "highlights / special items." We use it for header brand and step chips; could pick one home and be more consistent.
83
+ - **`ux-intro-outro` outro.** On `q` exit, show a one-line outro (Clack-style). The chip in the header is the intro; we don't currently have an outro.
84
+
85
+ ---
86
+
87
+ ## Quality / hygiene
88
+
89
+ - **`ink-link` for clickable URLs** in error messages (e.g., the "missing agent" install hints).
90
+ - **Smoke test that mounts the TUI** — vitest currently only covers `yaml-io`. Could use `ink-testing-library` to render-test the wizard and hub.
91
+ - **Width-aware truncation.** Several places do `truncate(s, 70)` with a hardcoded width. Should derive from terminal columns.
92
+ - **Header version pin.** The version constant in `Header.tsx` is hardcoded `"0.3.0"`. Wire it to `package.json` at build time (or via a `--define` in tsc) so it can't go stale.
93
+ - **NO_COLOR + FORCE_COLOR test.** Ink respects these; we should manually verify on a real `NO_COLOR=1` run that the brand chip degrades gracefully.
94
+
95
+ ---
96
+
97
+ ## Project-level (not TUI but related)
98
+
99
+ The TUI work isn't blocking on these, but they shape what we build next.
100
+
101
+ - Curating-mixtapes skill bundle second pass (worked examples for the five companion files).
102
+ - Methodology-mode validation: a planned side-by-side CLI vs. TUI design comparison.
103
+ - First library entry (Cowork synthesis → methodology-mode mixtape folder).
104
+ - MCP server scaffolding.
105
+ - **Marketing site: state the agent requirement up front (2026-05-28).** The landing page must make clear Liner drives the curation agent through the user's *own* Claude Code or Codex subscription — it doesn't bundle or pay for inference. This is both an honesty point (no surprise "why isn't it working" when a user has neither) and a positioning point (it rides the subscription they already pay for). Put it near the install/requirements section: "Bring your own agent — works with your Claude Code or Codex subscription." Lives in `marketing/site/`.
106
+
107
+ ---
108
+
109
+ ## Done
110
+
111
+ - 2026-05-28 (0.5.2) — **Fixed the hard API-400 crash on long/resumed agent runs.** A multi-turn phase (or any resume of a failed run) died with `400 … thinking blocks in the latest assistant message cannot be modified` once Claude Code auto-compacted a conversation with interleaved thinking on. Confirmed it was *not* resume-only: a fresh framing run hit it at ~26 turns, and resume then re-hit it instantly because it replays the corrupted message. Fix: spawn the agent with `MAX_THINKING_TOKENS=0` (verified empirically that this zeroes thinking blocks on claude 2.1.146 + opus-4-7), so the failure class can't occur. Supersedes the old "Resume + extended-thinking → API 400" item, which was mis-scoped as resume-only and low-priority. Change in `runner.ts` spawn env.
112
+ - 2026-05-28 (0.5.2) — **Isolated the methodology agent from the user's global environment.** The run log showed the spawned `claude` inheriting all the user's global MCP servers (Gmail, Drive, third-party connectors), plus Bash/Task — the `--allowedTools` whitelist is a no-op under `--dangerously-skip-permissions`. Added `--strict-mcp-config` (with no `--mcp-config` → zero MCP servers) so the agent no longer loads irrelevant connectors. *Still open:* hooks/auto-memory still load (didn't touch `--setting-sources` to avoid auth/behavior risk), and Bash/Task aren't hard-denied — a follow-up could add `--disallowedTools` or drop skip-permissions. Change in `runner.ts buildArgs`.
113
+ - 2026-05-28 (0.5.2) — **Fixed the mixtape browser (`TapeBrowser`) scrollback laddering + garbled selected row.** On a small terminal the project list rendered taller AND wider than the window, so arrow-key navigation reprinted the header on every keystroke (stacked `▶ liner` rows) and the selected row's highlight bled across wrapped lines. Fixes: a terminal-sized scrolling viewport (`maxRows = termRows − 12`, windowed around the selection, with `↑/↓ N more` indicators) so total height never exceeds the terminal; each row rendered as a single `wrap="truncate"` line with terminal-responsive column widths so rows never wrap; and `Header` subtitle set to `wrap="truncate"`. The alt-screen buffer alone couldn't fix this — it doesn't help when a single frame is taller than the viewport.
114
+ - 2026-05-28 (0.5.2) — **Empirical test (Phase 7/8) removed from the driven flow.** Dropped `empirical` from `PhaseId`, `PHASE_TEMPLATES`, `PHASE_ORDER` (`TOTAL_STEPS` 11→10); removed the empirical branches in `phases.ts` and `PhaseRunner.tsx`. `everythingComplete()` collapses to `progress.step >= TOTAL_STEPS` and `coreMethodologyComplete` is gone — *compiled = complete*. The with-vs-without validation survives as methodology guidance in `docs/LINER-MASTER.md` / skill docs, not a TUI phase.
115
+ - 2026-05-28 (0.5.2) — **ProjectHub redesigned into a single summary view.** Removed the dual focus-card / TOC `l` toggle. New `StatusBox` (Ready to use / In progress / Not started), an always-visible phase checklist, and a single HEADING/purple "next · …" call-to-action line. Importing a complete mixtape now lands here showing it's ready, never on a phase prompt.
116
+ - 2026-05-28 (0.5.2) — **Import screen auto-detects `.mixtape` files.** `ImportPrompt.tsx` rewritten: scans the cwd for `*.mixtape`, renders a selectable list with file sizes, `r` re-scans, `p` switches to path entry. Dropped the opaque "archive" label. Lands on the imported mixtape's hub (folder = `basename(path).replace(/\.mixtape$/,"")`) rather than the browser or a phase prompt. Import still doesn't auto-refetch.
117
+ - 2026-05-28 (0.5.2) — **Consistent quit-key convention: `q` quits from every screen, `esc` goes back.** Added `q` = `ink.exit()` to the gates, FramingConfirmReview, TapeDraftReview (guarded against text-input mode), PhaseRunner picking/done states; split `q`(quit)/`esc`(back) on CompileView + ProcessManifest. Gate2Review's quality-checks editor moved `q`→`k`. Text-input screens still rely on esc-then-quit / Ctrl-C since a bare `q` types into the field.
118
+ - 2026-05-28 (0.5.2) — **One call-to-action per screen: HEADING "next · …" description line above a uniform navbar.** Every screen carries a single purple plain-language line spelling out what Enter does; `KeyHints` stays a uniform dim reference navbar (MUTED label, STRUCTURE key) with no per-binding highlight. Supersedes the reverted 0.5.1 "highlight the primary action" attempt.
119
+ - 2026-05-28 (0.5.2) — **Removed the misleading dollar-cost figure from PhaseRunner run summaries.** Subscription-driven runs (Claude Code / Codex) aren't metered API billing, so a `$X.XXX` figure was invented. Token counts stay (they're real). *Note: `ProcessManifest.tsx` still renders a `$` cost line — tracked below in "Up next" until removed there too.*
120
+ - 2026-05-28 (0.5.2) — **PhaseRunner scrollback laddering capped by terminal height.** On top of the 0.5.1 alt-screen buffer, the final-response panel now caps to `Math.max(4, Math.min(18, termRows - 24))` lines via `useStdout`, so the tallest renders (session-limit failure + 48-tool-call list) can't exceed the viewport and ladder.
121
+ - 2026-05-28 (0.5.2) — **Pickers accept on Enter only.** `AgentSetup.tsx` (and the picker convention) no longer treat Space as a second accept key — Space is reserved for toggle semantics. The recommended/first option stays pre-highlighted so Enter takes the safe default.
122
+ - 2026-05-28 — **Scrollback laddering killed globally via terminal alt-screen mode.** Replaces the partial 2026-05-19 PhaseRunner compaction fix and the 0.5.1 wizard Transcript padding hack with one architectural fix in `bin/liner.js`: wrap the TUI launch in `\x1b[?1049h` / `\x1b[?1049l` (terminal alt-screen). No scrollback in the alt buffer = no stacked-header artifact, regardless of how variable-height a screen is. Cleanup handlers cover normal exit, SIGINT, SIGTERM, and uncaughtException so the terminal can't be left stuck in alt mode. Falls back to no-op when stdout isn't a TTY (piped output, CI). Trade-off: the TUI session vanishes on exit (post-exit context lives in `.liner-runs/` and `MIXTAPE.md`, which were always the source of truth anyway).
123
+ - 2026-05-22 — Process manifest: aggregator over `.liner-runs/*.jsonl` produces `process.json` (tokens / cost / tool calls / fetched URLs / domains / per-run breakdown). New CLI commands `liner manifest` + `liner status`. New TUI surface `ProcessManifest.tsx`, reachable via `[p]` on ProjectHub.
124
+ - 2026-05-22 — Compile auto-start from TapeDraftReview: accepting the source checklist now navigates directly to compile (CompileView already auto-starts on mount), removing the redundant "press enter to compile" second confirmation.
125
+ - 2026-05-22 — Compile re-run hint labeled per phase: "retry failed" when partial/failed (cache makes this true in effect), "re-run" when fully succeeded.
126
+ - 2026-05-22 — Web fetcher bot-challenge auto-fallback: `WebHandler` now raises `JsRenderingRequired` (not `HandlerHardFailure`) on 4xx/5xx responses whose body matches Cloudflare / Akamai / Imperva / PerimeterX signatures. Compile's existing auto-fallback path retries via `web_js` (Playwright). New helper `looks_like_bot_challenge()` in `html_extraction.py`.
127
+ - 2026-05-22 — Agent-summary fallback at compile: when all fetcher tiers fail, compile recovers the URL from `.liner-runs/` (the agent's WebFetch summary captured during research) and writes it as the source body with `metadata.extraction = "agent-summary"`. MIXTAPE.md surfaces a `Provenance: summary captured during research` line so the curator knows. Verified live on the Medium URL in cli-writer-6.
128
+ - 2026-05-22 — Orphan source-file cleanup: `write_mixtape()` now garbage-collects `sources/NN-*.md` files from prior compiles whose slug no longer matches the current title. Safe — only touches files matching the compile-output signature; curator-added files survive.
129
+ - 2026-05-22 — Framing-gap rubric rewrite: split coverage into `stance` vs. `concerns` to stop the methodology from treating "scriptability concerns covered by humans-first sources" as full coverage of a Unix-purist stance. Three actions now possible: (a) backfill, (b) argue concerns sufficient with explicit trade-off, (c) flag bias. Editied in both `quality-check-tests.md` and the Phase 5 prompt in `prompts.ts`.
130
+ - 2026-05-22 — Source-kind balance test (Test 5): every mixtape's `kind` distribution must be defended if any kind is zero. Catches the v6 case of 0 reference sources. Documented in `quality-check-tests.md`; Phase 5 prompt enforces.
131
+ - 2026-05-22 — Methodology mode hidden from the wizard surface: new mixtapes default to quick mode, the mode-selection step is gone, ProjectHub's `[m]` toggle is removed. Underlying methodology code (gates, prompts, mode field) is preserved for forward compatibility with existing methodology-mode mixtapes.
132
+ - 2026-05-22 — "Add your own source" affordance in TapeDraftReview: `[+]` opens an inline URL prompt; the URL gets appended to the working draft as a checked, curator-added source (auto-detected web/youtube type). Surfaces in the helper text + KeyHints so the affordance is discoverable.
133
+ - 2026-05-19 — Slice 1: 8-step wizard, ProjectHub two-pane phase tracker, scaffolding helpers.
134
+ - 2026-05-19 — Slice 2: Agent adapter (Claude + Codex), PhaseRunner screen, hub `r` key.
135
+ - 2026-05-19 — Polish pass: terminal-ui audit (5 CRITICAL/HIGH fixes), brand chip header, next-steps callout, background-color row selection, wizard step chip + progress dots, KeyHints wrap.
136
+ - 2026-05-19 — Slice 3 functional: auto-launch on `LINER_AGENT=` pinning, narrowed Claude tool whitelist (`--allowedTools Read Write Edit Glob Grep WebFetch`), Gate 1 review screen (parses `02-candidate-longlist.md` by section), Gate 2 review screen (parses `03-evaluation.yaml` as keep/trim/drop + `04-quality-checks.md` findings, tabbed view). Concurrent-run guard resolved by current cancel-on-unmount architecture.
137
+ - 2026-05-19 — Stream-JSON parsing: normalized `AgentEvent` type + per-CLI parsers (Claude `--output-format stream-json --verbose`, Codex `--json`), `LineBuffer` for partial-line chunking, 14 parser unit tests. PhaseRunner redesigned around structured events — top pane shows tool calls with status glyphs, middle pane streams assistant text in a bordered box, status bar shows event count + cost + duration from `summary` events.
138
+ - 2026-05-19 — Final-message preservation: PhaseRunner emits a notification on completion containing the first line of the agent's final response (or last text block for Codex), so the message survives navigation back to the hub.
139
+ - 2026-05-19 — Tool-call expand mode: `t` key toggles between tail (last 8) and full list.
140
+ - 2026-05-19 — Phase 7 agent-driven assembly: agent prompt now writes to `working/07-tape-draft.yaml` (never touches `tape.yaml` directly). New `TapeDraftReview` screen parses the draft, shows sections + source list + curator note for the cursor, with `a` accept (merges sources into tape.yaml + deletes draft), `e` edit (loads into source editor), `d` discard. PhaseRunner auto-routes to draft review on successful assembly run; hub shows "draft pending" hint and routes `enter` on Phase 7 to the review when a draft is on disk.
141
+ - 2026-05-19 — Hub key model rewrite per CLI-research synthesis (Skip-or-Enter §2.8, Caligula condense-one-prompt, "don't hide features behind keys"): **Enter is now the single primary action per phase** — runs the agent for agent-eligible phases (or falls back to $EDITOR with notification if no agent installed); opens gate review for gates; routes to draft review on Phase 7 when a draft exists; runs compile on the compile row. `e` is the explicit manual escape hatch ($EDITOR). Removed `E`/`c`/`R` as separate top-level keys. `r` kept as a hidden alias for Enter (back-compat). Right-pane action labels read aloud naturally ("run Phase 1 with the agent", "review the candidate long-list", etc.).
142
+ - 2026-05-19 — Hot fixes: (a) `require is not defined` crash in `phases.ts` writeGateState — replaced CJS require with imported writeFileSync; (b) PhaseRunner scrollback-laddering on long agent runs caused by dynamic content overflowing terminal — compacted running view to spinner + one-line stats + latest tool only (no streamed text, no full tool list); (c) live cumulative token counter via new `tokens` event extracted from Claude `assistant.usage` / Codex `turn.completed.usage`; (d) done state now leads with a NextSteps panel and Enter advances to the next logical screen (Phase 2 → Gate 1, Phase 4 → Phase 5, Phase 5 → Gate 2, etc.); (e) Gate 1 and Gate 2 reframed — Enter = accept + auto-advance, summary leads the screen, scroll list visually demoted; (f) auto-launch when only one agent is installed (was: still showed picker).
143
+ - 2026-05-19 — Wizard placeholder pattern: stopped pre-filling draft state (curator no longer pre-populated with $USER; title/description no longer pre-populated from JTBD). Suggestions surface via TextInput placeholder; Enter on empty submit accepts the suggestion. Going back to a previously-answered step from review still shows the existing value for editing. Removes the "I have to delete the previous question's text" friction.
144
+ - 2026-05-19 — Path-aware truncation in PhaseRunner: `truncatePath` keeps the basename (e.g. `…/working/02-candidate-longlist.md`) instead of right-trimming the prefix. Tool-call previews route through `previewify()` which detects paths vs. URLs vs. plain strings.
145
+ - 2026-05-19 — PhaseRunner running view shows phase label inline ("Phase 2 — Candidate discovery · Claude Code") so users always know where they are without looking up at the header.
146
+ - 2026-05-19 — Removed `r` re-run from the done state — user feedback was it had no value (re-running an agent with the same prompt is unlikely to give a different result). Done state actions: Enter advances, b/esc backs to hub.
147
+ - 2026-05-19 — Hub focus mode: default view is now a single hero card for the current incomplete phase + a one-line progress strip showing all phases with status glyphs. `l` toggles into the full TOC list (existing two-pane view) with future-phase locking. Esc from TOC returns to focus; esc from focus backs to browser.
148
+ - 2026-05-19 — Quick mode now skips gate review screens (per CURATION.md v2.0 "Quick mode defaults gates to continue"). PhaseRunner.nextScreenFor reads `tape.mode`; quick mode auto-writes `gate1Accepted` / `gate2Accepted` to `.liner-gates.json` and routes directly from candidates → evaluation and from quality → synthesis. Methodology mode still shows the gates.
149
+ - 2026-05-19 — Gate review screens slimmed down (methodology mode): removed the scrollable candidate / evaluation list. Now a bordered summary card (counts + section breakdown) plus a NextSteps panel. Inspection is delegated to `$EDITOR` via `e` — the rendered list was never going to compete with a real editor for actual reading.
150
+ - 2026-05-19 — Editor default switched from `vi` → `nano`. New `src/editor.ts` resolves `$VISUAL` → `$EDITOR` → probes for `nano`/`pico`/`vi` on PATH. Vi is hostile if you don't already know it; nano shows its keybindings at the bottom of the screen and is on every macOS install. All four screens (ProjectHub, Gate1Review, Gate2Review, TapeEditor) route through the helper.
151
+ - 2026-05-19 — Agent resume on failure: PhaseRunner's failed-done state now offers "Press Enter to resume" (cheap continuation via `claude --continue` / `codex exec resume --last`). The previous session's conversation — prompt, tool-call results, partial work — stays in context, so the agent doesn't re-fetch anything. `r` falls back to re-run from scratch. Runner accepts `resume: true`; on resume it sends a tiny "continue from where you left off" nudge instead of re-shipping SKILL.md. Failure-state NextSteps and KeyHints now lead with "resume" instead of the misleading "continue".
152
+ - 2026-05-19 — Done state collapsed to two visible choices: `enter` (continue on success / try again on failure) + `b` (back to hub). `r` (re-run from scratch) and `t` (expand tools) remain bound as hidden power-user escapes but no longer clutter the NextSteps panel or KeyHints. Failure-state copy reworded to "try again — picks up where the agent stopped, no re-fetching" so the user isn't decoding "resume" terminology.
153
+ - 2026-05-19 — Phase list cleanup: (a) **dropped Phase 3 (Fetching)** — it was a methodology step that does nothing in Liner (the agent fetches automatically at compile time), so a row that said "✓ complete · happens at compile" was actively misleading. Removed from PhaseId, computePhases, ProjectHub.enterPhase, primaryActionLabel. (b) **Tightened future-phase lockout in TOC mode**: anything past the current incomplete phase is now blocked from entry, not just `not_started` ones — prevents out-of-order runs. (c) **Sequential status enforcement**: once a phase is non-complete, any later "complete" downgrades to ⚠ needs_review with `· earlier phases not complete` appended to the detail. Stops the swiss-cheese hub view where Phase 7 shows ✓ but Phase 2 is empty. Phase 8 (empirical, optional) is exempt from the sequential rule.
154
+ - 2026-05-19 — **Progress cursor model** (replaces per-artifact status entirely). New `src/progress.ts` owns `.liner-progress.json` (one int: `step`). Phase status is now derived purely from the cursor (`i < step → ✓`, `i === step → ▶`, `i > step → ○`), not from filesystem checks. Detail strings still pull from disk for context but don't drive the badge. `markPhaseComplete()` advances the cursor only when called for the current phase (idempotent, refuses out-of-order advance). One-time migration on hub mount walks `PHASE_ORDER` and sets step to the longest consecutive "done" prefix — handles existing projects from older builds. Wired into all advancement points: PhaseRunner done-success (except assembly), Gate1/Gate2 accept, TapeDraftReview accept (advances "assembly"), CompileView result with failed=0, quick-mode gate auto-skip in `nextScreenFor`. The legacy `enforceSequentialOrder` patch is gone — no longer needed. 12 new unit tests for progress.ts.
155
+ - 2026-05-19 — **Tee-style audit log** (`src/agents/run-log.ts`). Every agent run writes raw JSONL to `<project>/.liner-runs/<phaseId>/<isoTs>.jsonl` with a `_liner_meta` header, raw stream events, stderr lines (wrapped to avoid masquerading as JSON), and a `_liner_close` marker. Not load-bearing for resume (Claude's session.json already handles that) — gives us a per-run transcript curators can scroll back through and a forensic record when things misbehave.
@@ -0,0 +1,84 @@
1
+ # Curator notes
2
+
3
+ Loaded by the `curating-mixtapes` skill at the start of Phase 4 (Evaluation).
4
+
5
+ This file describes how to draft curator notes. Apply it whenever you're writing the `note` field for a kept or trim source. Notes are drafted in Phase 4 during evaluation and land in `tape.yaml` at Phase 7 — write them in their final form now; don't postpone the work.
6
+
7
+ Curator notes are the highest-leverage feature in the mixtape format. The note is what tells the consuming AI which sources matter for which questions. The synthesis frames the domain; the notes route the AI's attention to specific sources when a specific question arises. Without notes, the AI sees a list of sources and has to guess which ones are relevant. With good notes, the AI can route precisely.
8
+
9
+ This is what "liner notes" means in the product name. The note is doing real work.
10
+
11
+ ---
12
+
13
+ ## The three-thing template
14
+
15
+ Every good note answers three questions about its source:
16
+
17
+ 1. **Why is this source in the mixtape?** What role does it play? Is it foundational, supplementary, contested, illustrative? "Watch first — this is the foundational piece." "Skim if time permits — useful for context but not essential." "The contested counterpoint to Source 4."
18
+
19
+ 2. **Where is the high-value portion?** Most sources are not uniformly dense. A talk's first ten minutes might be setup; a paper's middle section might be the methodology no one needs; an article's three closing paragraphs might be the only part that matters. Name it. "The first ten minutes are setup; the load-bearing content starts around 10:30." "Section 3 is the substantive one." "Skip the introduction; the framework is in the second half."
20
+
21
+ 3. **What are the source's limitations?** Where is this source out of date, narrow, or biased? "Dated on platform specifics, durable on principles." "Strong perspective; read alongside Source 7 for the counterargument." "Pre-2022 — doesn't address [recent development]."
22
+
23
+ A note that addresses all three is doing its full job. A note that addresses one or two is adequate. A note that addresses none — "this is a useful resource" — is useless and shouldn't ship.
24
+
25
+ ---
26
+
27
+ ## Length
28
+
29
+ **15–40 words typically.** Shorter is fine when the source is self-explanatory. Longer is usually a sign of one of two things:
30
+
31
+ - The source needs more framing than a note should carry. Move some of the framing into the synthesis instead.
32
+ - The note is doing work the synthesis should be doing. If you're explaining a framework concept in a note, that's a synthesis problem — the note is patching for the synthesis's gap.
33
+
34
+ When a note exceeds 60 words, stop and ask which of these two patterns is happening. Fix the underlying issue rather than padding the note.
35
+
36
+ ---
37
+
38
+ ## What makes notes bad
39
+
40
+ Notes drift toward generic praise by default. These are the patterns to watch for in your own drafts.
41
+
42
+ - **"This is a useful resource."** Says nothing. Names no role, no location of value, no limitation. The AI can't route on this. Replace it with a specific answer to at least one of the three questions.
43
+ - **"Comprehensive overview of [topic]."** Implies the source is uniformly valuable, which is almost never true. Even if the source really is comprehensive, the AI needs to know which parts matter for which questions.
44
+ - **"Highly recommended."** Reviewer-style praise, not curator routing. The fact that a source was kept means it's recommended. The note's job is to say *how to use it*, not to vouch for it.
45
+ - **Restating the title or abstract.** If the title is "Designing CLIs People Love," the note shouldn't say "About designing CLIs people love." Say what *role* it plays in this corpus.
46
+ - **Pure summary.** "Argues that CLIs should follow Unix conventions." That's what the source says. The note should say what the source is *for* in this mixtape — foundational, contested, etc.
47
+
48
+ ---
49
+
50
+ ## How notes interact with the synthesis
51
+
52
+ The synthesis and the notes do different jobs.
53
+
54
+ - **The synthesis** frames the whole domain. It's what the consuming AI reads first, and it sets up the curator's view of the territory.
55
+ - **The notes** route the AI's attention to specific sources during a specific conversation. When a question comes up that one source addresses particularly well, the note is the signal that says "open this one."
56
+
57
+ This division is why notes don't need to explain the source's content — the synthesis already provided the conceptual frame. The note's job is positional, not explanatory.
58
+
59
+ A common failure mode is writing notes that try to teach the AI what the source says. That's the synthesis's job. The note's job is to tell the AI when and how to use the source.
60
+
61
+ ---
62
+
63
+ ## Quick mode vs. methodology mode
64
+
65
+ **Quick mode:** AI drafts the note during Phase 4. Use the three-thing template. Show the curator the drafted notes at Gate 2. Default is "looks good, save it." Light edits welcome.
66
+
67
+ **Methodology mode:** AI drafts a starting point. Expect the curator to rewrite each note substantively. The notes carry the curator's voice and the curator's specific framing of what each source is for. AI-drafted notes with light edits don't meet the methodology-mode bar.
68
+
69
+ In both modes, notes are required. A source without a note doesn't ship.
70
+
71
+ ---
72
+
73
+ ## Worked examples
74
+
75
+ > TODO: Insert three to five worked examples from the Cowork CLI/TUI synthesis. Each should show all three things landed. Look for notes in the Cowork material that are concrete about role, location of value, and limitations — not vague praise.
76
+ >
77
+ > Suggested examples to pull:
78
+ > - A "watch first" foundational note (likely on a Van Slyck talk or clig.dev)
79
+ > - A note with specific time-coding on a video ("the section starting at 14:30")
80
+ > - A trim note that explicitly says what to skip ("Skip the OpenStack-specific noise")
81
+ > - A "contested counterpoint" note that names the source it disagrees with
82
+ > - A note that names a temporal limitation ("dated on X, durable on Y")
83
+
84
+ > TODO: Insert one or two examples of bad notes for contrast. Pull the original AI-drafted notes from OpenClaw if they're available — those are the canonical "this is a useful resource" generic notes that Cowork rewrote.
@@ -0,0 +1,196 @@
1
+ # Quality-check tests
2
+
3
+ Loaded by the `curating-mixtapes` skill at the start of Phase 5 (Quality checks).
4
+
5
+ This file describes the four tests every mixtape should pass before moving to synthesis. Apply them deliberately, in this order. Write findings to `working/04-quality-checks.md`.
6
+
7
+ Phase 5 is the methodology's correction for single-pass curation. The first four phases work forward — frame, find, fetch, evaluate. Phase 5 works backward — looking at the whole keep-pile and asking what's wrong with it. The two passes do different work. If you skip this phase, the mixtape's blind spots ship with the mixtape.
8
+
9
+ The framing-gap test is the highest-leverage of the four and the one most curators skip.
10
+
11
+ ---
12
+
13
+ ## Setting up the phase
14
+
15
+ Before running the tests, gather the inputs in one place:
16
+
17
+ - The JTBD (from `working/01-jtbd-and-knowledge-map.md`)
18
+ - The knowledge map (same file)
19
+ - The kept and trim sources from `working/03-evaluation.yaml` — titles, sections, ratings, rationales, and the drafted curator notes
20
+
21
+ Read these together. The tests are about how the corpus *as a whole* serves the JTBD. You can't run them well by looking at sources one at a time.
22
+
23
+ ---
24
+
25
+ ## Test 1 — The redundancy test
26
+
27
+ Read each kept source's role in the mixtape. Are any two sources making essentially the same point?
28
+
29
+ If yes, keep the better one and cut the other. Volume is not a virtue. Five excellent sources beat fifteen good ones.
30
+
31
+ **The test in action:** for each kept source, write down in one sentence what unique contribution it makes to the corpus. If two sources produce the same sentence (or near-same), one of them is redundant. Drop the weaker.
32
+
33
+ Redundancy is different from coverage. Two sources covering the same topic from different angles or with different evidence is coverage, not redundancy. The test is whether the AI would generate meaningfully different output with both vs. with only one. If not, redundant.
34
+
35
+ > TODO: Insert a worked example from the Cowork synthesis where two sources were collapsed because of redundancy. The Van Slyck talk appearing in transcripts 02 and 03 is a known case — same talk uploaded twice. Show how the redundancy was named and resolved.
36
+
37
+ ---
38
+
39
+ ## Test 2 — The coverage test
40
+
41
+ Walk through the knowledge map. For each section, ask: does this section have at least one strong source?
42
+
43
+ If a section has zero sources, two responses are valid:
44
+
45
+ - **Fill it.** Return to Phase 2 for that section. Find candidates. Fetch them. Evaluate them. Then come back to Phase 5.
46
+ - **Explicitly note the gap.** Some sections of a domain genuinely don't have credible sources available, or fall outside what this mixtape is trying to do. Document this in `working/04-quality-checks.md`: "This mixtape doesn't cover X — see [other mixtape] for that, or note that the field doesn't have a canonical reference here."
47
+
48
+ A mixtape that silently omits a major area is worse than one that says explicitly "this mixtape doesn't cover X." The latter sets expectations correctly; the former misleads the consuming AI by implying the corpus is complete.
49
+
50
+ If a section has sources but they're all rated 2 or 3, that's a weak-coverage signal — the section is technically populated but the sources aren't load-bearing. Either find stronger sources or note the weakness.
51
+
52
+ > TODO: Insert a worked example. If the Cowork synthesis had a section that needed reinforcement after first-pass evaluation, show the coverage check that surfaced it and how the gap was addressed.
53
+
54
+ ---
55
+
56
+ ## Test 3 — The disagreement test
57
+
58
+ Find the strongest claim made by sources in the mixtape. Is there someone credible who disagrees?
59
+
60
+ If yes, either include the disagreement or explicitly note that the mixtape takes a position.
61
+
62
+ A corpus where every source agrees teaches the AI no nuance. The AI then can't see the contested-ness of contested questions, which means it can't represent them honestly downstream. The fix is to include at least one strong dissenting source on the most-contested point in the corpus.
63
+
64
+ If the topic is genuinely uncontested — the W3C HTML spec, for example, isn't really contested in the way a design philosophy might be — that's fine, and the working notes should say so. The test isn't "manufacture disagreement"; it's "if disagreement exists, surface it; if it doesn't, document why."
65
+
66
+ **The test in action:** identify the strongest claim in the corpus. Search for "[claim] critique" or "[claim] is wrong" or "alternative to [claim]." If you find a credible critique you haven't included, you've found your dissenting source. Add it.
67
+
68
+ > TODO: Insert a worked example from CLI/TUI research. The corpus probably had a contested-question moment — possibly around whether CLIs should follow Unix conventions strictly vs. break them deliberately, or around accessibility being assumed-by-default vs. explicitly designed-for. Surface the actual disagreement and how it was handled.
69
+
70
+ ---
71
+
72
+ ## Test 4 — The framing-gap test
73
+
74
+ Step back from individual sources. Is there a major perspective on this topic missing entirely — not just an individual source, but a whole way of thinking about the JTBD?
75
+
76
+ If yes, the framing was too narrow. Expand the knowledge map and return to Phase 2.
77
+
78
+ **This test is the highest-leverage of the four and the one most curators skip.** Single-pass curation tends to produce mixtapes that are well-covered within one narrow framing. The framing-gap test catches what the first four phases couldn't see.
79
+
80
+ ### How to run it (required steps, in order)
81
+
82
+ This test cannot be answered yes/no. Earlier versions of this methodology allowed a casual judgment ("does the framing feel wide enough?") and the answer was almost always "yes" — because the test, run that way, has no force. Run it as follows instead:
83
+
84
+ 1. **Name 2–3 candidate perspectives that could exist *outside* the corpus.** Write them down in `working/04-quality-checks.md` before looking at the keep-list. Common candidates: designer voice, accessibility-first viewpoint, security/abuse perspective, non-English-speaking practitioner, contrarian who disagrees with the dominant framing, an adjacent discipline that owns part of the problem space (e.g. for a CLI mixtape: visual-design tradition, technical-writing tradition, OS-vendor convention tradition).
85
+
86
+ The named perspectives should be specific enough to act on. "User perspective" is too vague. "iOS Human Interface Guidelines designer perspective on form-field labels" is actionable.
87
+
88
+ 2. **For each named perspective, classify coverage in two dimensions, not one.** The earlier single-axis judgment ("covered / uncovered / partial") let a corpus mark a perspective `covered` just because some kept source addressed its concerns — even when no source actually argued *for* the perspective as a stance. That collapse is the failure mode this split exists to prevent.
89
+
90
+ - **Stance** — is there a verified, fetchable source whose author explicitly *argues for* this perspective as a design center of gravity? Mark `stance-represented` or `stance-absent`.
91
+ - **Concerns** — do any kept sources address the perspective's operational concerns mechanically, even while arguing from a different stance? Mark `concerns-addressed` or `concerns-absent`.
92
+
93
+ A perspective is fully `covered` only when its stance is represented. `concerns-addressed` alone is a **soft gap** — the corpus internalizes the concern without giving the consuming AI a worked rival argument to cite. Soft gaps are real gaps; they show up later as synthesis bias.
94
+
95
+ 3. **Unverified sources DO NOT count as coverage.** A source whose Phase 4 curator note acknowledges unfetched content, broken URLs, paywalled access, or transcripts that couldn't be obtained cannot satisfy a perspective slot. "We have one designer voice, but her transcript wasn't fetchable" is the same as "we have no designer voice." Tokenism passes the test cheaply and silently — don't allow it.
96
+
97
+ 4. **For each perspective that is not `stance-represented`, take exactly one of three actions:**
98
+
99
+ a. **Search for a stance source.** Return to Phase 2 with vocabulary derived from the perspective itself: *who would argue for this position, what would they write, where would they publish?* This is different from a topic search — you're looking for an opinionated author, not a neutral reference. Examples: "Brandur Leach on terminal density," "Rob Pike on Unix philosophy," "Don Norman on visceral design," not "CLI scriptability best practices." Spend one search pass. If you find a verified source that fits, add it to the keep-list.
100
+
101
+ b. **Argue that the concerns are sufficient.** If concerns are addressed and you believe the perspective doesn't need a separate stance source — because the operational disagreement is genuinely thin — *write the argument explicitly*: "Concerns covered by [Sources N, M] inside the [dominant] stance. The dissenting stance is real but its operational implications are absorbed; no separate source needed."
102
+
103
+ This is not a free pass. The methodology requires you to *state* the trade-off. If you can't articulate why concerns are sufficient without a stance source, you don't actually have the argument and should fall back to (a) or (c).
104
+
105
+ c. **Flag the bias explicitly.** If no source is found and the concerns aren't sufficient, write in `working/04-quality-checks.md`:
106
+
107
+ > *Perspective: [name] — stance unrepresented after one search pass. Corpus argues from [dominant stance] but no source argues for [rival stance]. Recommendation: ship as-is and document the bias in the synthesis, OR weaken the JTBD claim that requires the rival stance.*
108
+
109
+ Do NOT silently leave a perspective `stance-absent` with no defense. The synthesis is what the consuming AI reads first; an undocumented bias becomes the AI's silent default.
110
+
111
+ ### The output format
112
+
113
+ `working/04-quality-checks.md` must include a top-level section like this:
114
+
115
+ ```
116
+ ## Perspectives audit
117
+
118
+ - Designer voice — stance-represented (Source 14: Gillet, "Designing for CLI", verified) ✓
119
+ - Accessibility-first viewpoint — stance-absent, concerns-absent. Search added GitHub accessibility post → now stance-represented (Source 3) ✓
120
+ - Power-user / Unix-purist stance — stance-absent, concerns-addressed by Heroku/Vercel/Van Slyck.
121
+ - Backfill attempt: searched "Brandur Leach terminals density," found brandur.org/interfaces. Verified, added (Source N). ✓
122
+ OR
123
+ - Argued sufficient: concerns covered by Heroku's grep-first rule + Vercel's stdout contract + Van Slyck's "friendly to humans AND scripts" pillar. The Unix-purist stake is that terseness should be the *center of gravity*, not a preserved capability — we're not adopting that. The corpus's framing covers the operational concerns without representing the stance; synthesis will name this trade-off explicitly.
124
+ ```
125
+
126
+ This format is checked by the TUI: a quality-checks file without a "Perspectives audit" section signals that the test wasn't run honestly.
127
+
128
+ ### Why this strictness
129
+
130
+ The earlier loose version of this test failed quietly in practice. A real session keeping one designer source whose content was never fetched produced a corpus the curator described as "engineering-heavy, one designer voice unverified" — and the quality-check still passed because "1 source ≥ 1 = covered." Naming perspectives in advance and refusing to count unverified sources is what makes the test do work instead of legitimize tokenism.
131
+
132
+ If the framing gap is real, accept the cost of going back. Phase 2 is cheap relative to shipping a mixtape with a hole in it.
133
+
134
+ > TODO: Insert the canonical worked example from the Cowork synthesis. OpenClaw's initial 50-source list was anchored in "CLI/TUI implementation" framing and missed "the entire wizard/form-design tradition (Form Design Patterns, NN/g articles, Tidwell, Cooper)." Cowork ran the framing-gap test, named the missing tradition, added 43 net-new sources, and reframed the corpus. This is the textbook framing-gap-test rescue. Pull the specific moment the gap was identified and the specific sources added.
135
+
136
+ ---
137
+
138
+ ## Test 5 — Source-kind balance
139
+
140
+ Look at the distribution of `kind` values across the keep-list. Every source in `tape.yaml` should carry one of: `reference / principle / prescription / example`.
141
+
142
+ The four kinds represent four argumentative roles. A corpus missing one of them has a structural gap, even when every knowledge-map section is technically populated:
143
+
144
+ - **0 `reference` sources** → the consuming AI has no substrate to cite when defending a convention. The mixtape becomes opinion against opinion when challenged. The fix is at least one authoritative source — a spec, an official manual, a widely-adopted standard, an RFC — that the AI can point at as "this is canon, not just our preference."
145
+ - **0 `principle` sources** → the synthesis has no philosophical anchor. The mixtape can describe rules but can't justify the worldview behind them. The fix is a stance-setting essay or manifesto.
146
+ - **0 `prescription` sources** → the AI has no concrete rules to enforce. The synthesis becomes vibes without operational consequences. The fix is a style guide, rule-set, or explicit guideline doc.
147
+ - **0 `example` sources** → the AI has no taste calibration. It can recite rules but can't recognize good when it sees it. The fix is a worked instance, case study, or annotated specimen.
148
+
149
+ Imbalance is not a failure. A 7-principle / 2-prescription / 1-reference / 0-example corpus may be exactly right for a philosophy-heavy JTBD. But a zero in any column should be a **decision, not an accident.** If you accept a zero, write the defense in `working/04-quality-checks.md`:
150
+
151
+ > *Kinds audit: 7 principle / 9 prescription / 5 example / 0 reference. Accepted: this JTBD is about voice and microcopy, not architectural conventions. No reference source is needed because the synthesis doesn't make authority claims that would require backing.*
152
+
153
+ If the zero isn't defensible, run one search pass for a source of the missing kind before shipping. The same rule as Test 4(a) applies: search for the role the kind plays (an authoritative spec, an opinionated essay, a tight rule-set, a worked example), not for the topic generically.
154
+
155
+ ### Required output
156
+
157
+ `working/04-quality-checks.md` must include a Test 5 section like this:
158
+
159
+ ```
160
+ ## Test 5 — Source-kind balance
161
+
162
+ Distribution: X reference / Y principle / Z prescription / W example
163
+
164
+ [If any kind is zero: either a backfill action OR a defense paragraph in the form above.]
165
+ ```
166
+
167
+ ---
168
+
169
+ ## What to do when a test fails
170
+
171
+ Don't paper over failures. The point of running the tests is to find problems while they're still cheap to fix.
172
+
173
+ - **Redundancy fails:** drop the weaker source, update `working/03-evaluation.yaml` to reflect the change, document the decision in `working/04-quality-checks.md`.
174
+ - **Coverage fails:** return to Phase 2 for the missing section. Fetch new candidates. Evaluate them. Come back to Phase 5 and re-run all four tests on the new keep-list.
175
+ - **Disagreement fails:** find one strong dissenting source. Fetch it. Evaluate it. Add it to the keep-list with a note that names its role as counterpoint.
176
+ - **Framing-gap fails:** this is the expensive one. Expand the knowledge map. Return to Phase 2. Find candidates for the new sections. Fetch, evaluate. Come back to Phase 5 with a substantially revised keep-list and re-run all four tests.
177
+
178
+ Each backtrack is a sign the methodology is working, not failing. The first four phases produced a corpus that worked from one angle; Phase 5 found the angle that wasn't covered. Better to find it here than in the empirical test (Phase 8) or — worse — silently, when the mixtape is in use.
179
+
180
+ ---
181
+
182
+ ## Output: `working/04-quality-checks.md`
183
+
184
+ Document each test, the finding, and the action taken. Even tests that passed without changes should be noted — "redundancy test: no redundant sources found." The working notes are part of the methodology; they show what work was actually done.
185
+
186
+ > TODO: Insert a sample `working/04-quality-checks.md` from the Cowork synthesis. The full structure with each test, the finding, and the resulting action is the most useful worked example in this file.
187
+
188
+ ---
189
+
190
+ ## A note on fresh attention
191
+
192
+ Phase 5 benefits from running with fresh attention. The first four phases build up a mental model of the corpus that biases how you see it — you remember why you kept each source, which makes redundancy easier to miss; you remember the candidate searches you ran, which makes the framing-gap easier to miss.
193
+
194
+ If the conversation has been long, consider starting a separate chat with just the JTBD, the knowledge map, and the kept-source list (titles + notes only, no source content). Run the four tests there. The fresh chat doesn't carry the gathering pass's biases.
195
+
196
+ This is optional, not required by the methodology. Mention the option to the curator. Quick mode users may prefer to continue in the same conversation for speed; methodology mode users often benefit from the reset.
@@ -0,0 +1,99 @@
1
+ # Source-finding tactics
2
+
3
+ Loaded by the `curating-mixtapes` skill at the start of Phase 2 (Candidate discovery).
4
+
5
+ This file describes the six tactics that produce better candidates than generic search. When you reach Phase 2, work through these tactics — not all of them for every mixtape, but enough that the candidate pool covers the knowledge map from multiple angles.
6
+
7
+ The goal of Phase 2 is recall, not precision. You're producing two to four times the eventual kept count. You will cut in Phase 4. Casting wide here is the methodology working as designed.
8
+
9
+ ---
10
+
11
+ ## 1. Follow the citations
12
+
13
+ Pick one excellent source you already have. Find what *it* cites — the references, the linked sources, the "see also" pointers. Then open one of those and find what *it* cites. Three or four hops in, you'll find the canonical sources nobody links to anymore because everyone assumes you've read them.
14
+
15
+ This tactic is the single highest-leverage move for discovering primary documents. It works against your popularity bias: cited-by-the-canon sources don't surface in keyword search, but they're what serious work in the field rests on.
16
+
17
+ **How to apply:** Open the most credible source you have. Scan the references, footnotes, or "further reading" section. Note every source that's cited *and* recurs in another credible source's references. Recurrence across multiple credible sources is the signal — it's how you find the references nobody links anymore.
18
+
19
+ > TODO: Insert worked example from the Cowork CLI/TUI synthesis. Look for a moment in the research where citation-chasing surfaced a canonical source that didn't show up in any initial keyword search. Form Design Patterns by Adam Silver is a candidate — it's cited across multiple Phase 1 sources but didn't surface from "CLI wizard design" searches.
20
+
21
+ ---
22
+
23
+ ## 2. Reverse-engineer experts' reading lists
24
+
25
+ Many domain experts publish their own reading lists or syllabi. These already encode someone else's curation work. Use them.
26
+
27
+ **Where to look:** Notion (search "site:notion.so reading list <topic>"), GitHub (`awesome-<topic>` repositories, individual `README.md` files in personal repos), Are.na (channels — Are.na in particular is underused for this), personal blogs, course-instructor pages.
28
+
29
+ Are.na deserves a specific note: it's a network designed for visual and textual reference-collecting. Practitioners use it to curate the kind of sources that don't make it into mainstream publications. Constrain a search with "site:are.na <topic>" and look for channels related to your JTBD.
30
+
31
+ **How to apply:** Find three to five experts in the domain. Search each one's name plus "reading list" or "syllabus" or "references." Catalog what they recommend. Cross-reference with the candidates already on your long-list — overlaps are strong signal; uniques are leads.
32
+
33
+ > TODO: Insert worked example from the Cowork CLI/TUI synthesis. Look for a tactical mention of an expert reading list that surfaced relevant work. If none exists, this section can use an example from a different domain — the methodology generalizes.
34
+
35
+ ---
36
+
37
+ ## 3. Mine course syllabi
38
+
39
+ University courses, bootcamp curricula, and serious online courses have already done curation work for their domain. A well-designed syllabus is a curated reading list optimized for learning. Use them.
40
+
41
+ **Productive queries:**
42
+
43
+ - `"<topic> syllabus" filetype:pdf`
44
+ - `"course readings" <topic>`
45
+ - `<topic> "required reading"`
46
+ - University course catalogs for the relevant department
47
+
48
+ **How to apply:** Find two to three syllabi on your topic. Note the readings that appear across multiple syllabi — those are the canonical pieces. Note the readings that appear once but are written by people you recognize — those are the practitioner-credible additions.
49
+
50
+ Course syllabi skew toward foundations. They're best for the early-section knowledge-map buckets. Recent practitioner work is rarely on them.
51
+
52
+ > TODO: Insert worked example. If no syllabus surfaced in the CLI/TUI research, note this and use a hypothetical that's specific enough to be useful.
53
+
54
+ ---
55
+
56
+ ## 4. Find who experts cite
57
+
58
+ Pick three to five acknowledged practitioners in your domain. Look at *their* references — bibliographies, acknowledgments, who they cite in their own writing. The overlap across these experts is your shortlist.
59
+
60
+ This tactic is structurally similar to citation-chasing (#1), but starts from people rather than from sources. Use it when you have a clear sense of who the credible practitioners are but no clear sense of which of their works is canonical.
61
+
62
+ **How to apply:** Identify three to five practitioners credible in the domain. Open their most recent significant work. Note the sources they cite. Open the sources cited by two or more practitioners. Those are your high-priority candidates.
63
+
64
+ > TODO: Insert worked example from CLI/TUI research. Carolyn Van Slyck, Aanand Prasad (clig.dev), Will McGugan (Textualize), and Amanda Pinsker (GitHub CLI) are candidates whose citation patterns could be traced.
65
+
66
+ ---
67
+
68
+ ## 5. Conference proceedings
69
+
70
+ Going through three years of a specific conference is more efficient than topic-by-topic search. The conference's curation has already filtered for credibility and substance.
71
+
72
+ **How to apply:** Identify one or two conferences serious in the domain. Open their proceedings, talk lists, or YouTube channels for the last three years. Skim titles and abstracts. Flag any talk whose abstract addresses a knowledge-map section.
73
+
74
+ Conference talks vary widely in density. The same talk reposted across multiple conferences is one signal of substance. Talks from speakers who are also cited by other practitioners (tactic #4) are another.
75
+
76
+ > TODO: Insert worked example. The CLI/TUI corpus has multiple Van Slyck talks across GopherCon and other venues — a real example of how conference-proceeding mining surfaced both her work and what to keep when the same talk appears at multiple conferences.
77
+
78
+ ---
79
+
80
+ ## 6. Ask the AI to find gaps, not sources
81
+
82
+ Once you have a candidate list, stop searching and ask: *what's missing from this collection for someone trying to [JTBD]?*
83
+
84
+ AI is bad at recall — at remembering and surfacing sources you don't know about. AI is good at critique — at looking at a list and noticing structural gaps. Use it for the right thing.
85
+
86
+ **How to apply:** Show the candidate list (titles and one-line rationales) along with the JTBD and knowledge map. Ask explicitly: "What perspective is missing? What discipline is underrepresented? What kind of source is this list short on?" Then go find sources to fill the gaps named.
87
+
88
+ This tactic is structurally related to the framing-gap test in Phase 5, but earlier and lower-stakes. Doing it in Phase 2 is cheaper than discovering the gap in Phase 5 and having to backtrack.
89
+
90
+ > TODO: Insert worked example from the Cowork synthesis. The Cowork run discovered that OpenClaw's initial 50-source list missed "the entire wizard/form-design tradition (Form Design Patterns, NN/g articles, Tidwell, Cooper)" — this is the canonical example of gap-finding working. Pull the specific moment where the gap was named and how it changed the candidate pool.
91
+
92
+ ---
93
+
94
+ ## What not to do
95
+
96
+ - **Don't rely on generic search alone.** The first page of search results is what your audience could also find. The point of curation is to surface what they couldn't.
97
+ - **Don't accept candidates without verifying URLs.** AI hallucinates plausible-looking URLs. Web-fetch every URL before it goes on the long-list. A 404 candidate is worse than a missing one.
98
+ - **Don't filter at Phase 2.** That's Phase 4's job. If a source might be useful, it goes on the long-list. Quality decisions come after fetching and reading.
99
+ - **Don't over-research one section while leaving others empty.** Walk the knowledge map. Each section should have a reasonable candidate pool before you go deep on any one section.