@zalom/plastic 2.0.0-alpha.13 → 2.0.0-alpha.15

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 (41) hide show
  1. package/hooks/message-display +55 -2
  2. package/package.json +1 -1
  3. package/scripts/dashboard.rb +238 -8
  4. package/scripts/doctor.rb +291 -4
  5. package/scripts/lib/dashboard_screen.rb +40 -0
  6. package/scripts/lib/doctor_core.rb +97 -2
  7. package/scripts/lib/hook_replay.rb +211 -0
  8. package/scripts/lib/installer_core.rb +23 -3
  9. package/scripts/lib/message_display.rb +267 -47
  10. package/scripts/lib/report_screen.rb +837 -18
  11. package/scripts/lib/roadmap_queue.rb +19 -2
  12. package/scripts/lib/roadmap_savepoint.rb +36 -7
  13. package/scripts/lib/savepoint.rb +12 -0
  14. package/scripts/lib/screen_paint.rb +240 -11
  15. package/scripts/lib/screens/dashboard.rb +20 -0
  16. package/scripts/lib/screens/plan.rb +18 -0
  17. package/scripts/lib/screens/roadmap.rb +15 -0
  18. package/scripts/lib/verify_intent.rb +33 -0
  19. package/scripts/report-screen +41 -7
  20. package/scripts/savepoint-note +11 -9
  21. package/skills/auto/SKILL.md +9 -9
  22. package/skills/auto/references/human-report-contract.md +79 -8
  23. package/skills/dashboard/SKILL.md +13 -2
  24. package/skills/dashboard/templates/dashboard-global.md +1 -1
  25. package/skills/dashboard/templates/dashboard-project.md +2 -2
  26. package/skills/doctor/SKILL.md +10 -4
  27. package/skills/intent-continuing/SKILL.md +19 -21
  28. package/skills/intent-continuing/references/board-fill.md +9 -0
  29. package/skills/intent-ending/SKILL.md +6 -4
  30. package/skills/intent-executing/SKILL.md +2 -0
  31. package/skills/intent-speccing/SKILL.md +7 -4
  32. package/skills/roadmap/SKILL.md +9 -0
  33. package/skills/roadmap/references/file-format.md +10 -0
  34. package/templates/dashboard-screen.md +22 -0
  35. package/templates/display-fixture.md +21 -0
  36. package/templates/intent-screen.md +1 -1
  37. package/templates/report-plan.md +15 -0
  38. package/templates/report-roadmap-delivered.md +10 -0
  39. package/templates/report-roadmap-plan.md +9 -0
  40. package/templates/report-roadmap-state.md +9 -0
  41. package/templates/report-state.md +1 -1
@@ -2,15 +2,16 @@
2
2
  # encoding: UTF-8
3
3
  # frozen_string_literal: true
4
4
 
5
- # savepoint-note - the writer CLI for the two savepoint kinds intent 317 adds:
6
- # Review (one line per plan-review or post-execution-review verdict) and
7
- # Commit (one line per commit landing during Exec). D17: there is no automatic
8
- # seam for either (session-commit writes the day ledger, not the intent
9
- # ledger; the executor's own commits are plain git), so this is an explicit
10
- # thin wrapper on Savepoint.append_review_savepoint / append_commit_savepoint.
5
+ # savepoint-note - the writer CLI for three savepoint kinds: Review (one line per
6
+ # plan-review or post-execution-review verdict) and Commit (one line per commit landing
7
+ # during Exec), both from intent 317, D17; and Report (one line per report screen printed,
8
+ # intent 331f). None has an automatic seam (session-commit writes the day ledger, not the
9
+ # intent ledger; the executor's own commits are plain git; a printed screen is a skill's own
10
+ # reply, not a file write), so this is an explicit thin wrapper on
11
+ # Savepoint.append_review_savepoint / append_commit_savepoint / append_report_savepoint.
11
12
  #
12
13
  # Usage:
13
- # savepoint-note <intent_dir> --kind Review|Commit --text "<text>"
14
+ # savepoint-note <intent_dir> --kind Review|Commit|Report --text "<text>"
14
15
  #
15
16
  # --text is normalized (D21): runs of two or more spaces collapse to one, so a
16
17
  # free-text kind that happens to contain a double space cannot key the dedup
@@ -46,12 +47,12 @@ while (arg = args.shift)
46
47
  end
47
48
  end
48
49
 
49
- usage_abort("usage: savepoint-note <intent_dir> --kind Review|Commit --text \"<text>\"") unless positional.length == 1
50
+ usage_abort("usage: savepoint-note <intent_dir> --kind Review|Commit|Report --text \"<text>\"") unless positional.length == 1
50
51
 
51
52
  intent_dir = File.expand_path(positional.first)
52
53
  usage_abort("#{intent_dir} is not an intent directory") unless File.exist?(Savepoint.intent_file(intent_dir))
53
54
 
54
- KINDS = %w[Review Commit].freeze
55
+ KINDS = %w[Review Commit Report].freeze
55
56
  usage_abort("--kind must be one of #{KINDS.join(', ')}, got #{kind.inspect}") unless KINDS.include?(kind)
56
57
  usage_abort("--text is required") if text.nil? || text.empty?
57
58
  usage_abort("--text must not contain a newline") if text.include?("\n")
@@ -62,6 +63,7 @@ usage_abort("--text is empty after normalization") if normalized.empty?
62
63
  case kind
63
64
  when "Review" then Savepoint.append_review_savepoint(intent_dir, normalized)
64
65
  when "Commit" then Savepoint.append_commit_savepoint(intent_dir, normalized)
66
+ when "Report" then Savepoint.append_report_savepoint(intent_dir, normalized)
65
67
  end
66
68
 
67
69
  exit 0
@@ -201,11 +201,9 @@ Then How.
201
201
  into the spec, the matrix, and the tests; record what was dropped and why in the action
202
202
  file's review fold. A REVISE verdict is folded and not re-reviewed unless a finding changes
203
203
  a decision.
204
- 5. Print `ruby ~/.plastic/scripts/report-screen state <intent_dir> --changed "How written, plan review next"`
205
- (D15; see `references/human-report-contract.md` for the full trigger list). This replaces
206
- the old prose State/Risk/Call briefing at this boundary. In auto mode the screen informs;
207
- it does not wait. The screen opens the reply with nothing before it and no code fence: the
208
- `MessageDisplay` hook paints only a reply whose first characters are the screen marker.
204
+ 5. Print `ruby ~/.plastic/scripts/report-screen plan <intent_dir>` as the first characters of
205
+ the reply, nothing before it, no fence, before dispatching the executor (see
206
+ `references/human-report-contract.md` for the full binding table). It informs; it does not wait.
209
207
 
210
208
  Then Exec.
211
209
 
@@ -276,10 +274,12 @@ Read `../plastic-conventions/references/completion-and-done.md` for what "intent
276
274
  pass `--discard-worktree-changes` deliberately). 3: the lock survived the disarm
277
275
  (`/plastic-doctor check the lock status`). 6: the structure check refused. Never leave an
278
276
  orphaned worktree; run `git worktree prune` on a stale reference.
279
- 6. Print `ruby ~/.plastic/scripts/report-screen delivered <intent_dir>` once (D15): the owner
280
- report at End, replacing the old prose Done briefing. A mid-batch status ask instead runs
281
- `report-screen session <tier_root> --session "$CLAUDE_CODE_SESSION_ID"` (intent 330). Print
282
- it as the first thing in the reply, no code fence, or the hook cannot paint it.
277
+ 6. Print `ruby ~/.plastic/scripts/report-screen delivered <intent_dir>` once (D15/331f), and
278
+ `report-screen state` at each of the five triggers in `references/human-report-contract.md`
279
+ (a review verdict, a blocker, a merge/release, or an owner status ask; a mid-batch ask
280
+ instead runs `report-screen session <tier_root> --session "$CLAUDE_CODE_SESSION_ID"`, intent
281
+ 330). Print each as the first characters of the reply: nothing before it, no fence, or the
282
+ hook cannot paint it.
283
283
 
284
284
  ## Error Handling
285
285
 
@@ -1,9 +1,12 @@
1
- # Human Report Contract (the three report screens, intent 317)
1
+ # Human Report Contract (the report screens, intent 317)
2
2
 
3
3
  D15: the prose EM-to-CTO briefing this doc used to define is retired. The orchestrator now
4
- prints one of three report screens, filled from the record by `scripts/report-screen`, never
4
+ prints one of these report screens, filled from the record by `scripts/report-screen`, never
5
5
  written by eye:
6
6
 
7
+ - **`report-screen plan <intent_dir>`** - the pre-delivery report (intent 331b), printed once
8
+ at the How boundary, before the executor is dispatched: Asked, Decisions, Steps, Mode,
9
+ Reviewer, then the Steps table (Step, Action, What) and the Risks table.
7
10
  - **`report-screen state <intent_dir> [--changed "<text>"]`** - the mid-delivery report. One
8
11
  intent's field table (Store, Status, Stage, Savepoint, Progress, Next, Insight) plus a
9
12
  `Changed` row naming what caused the print, and its Steps table.
@@ -18,6 +21,55 @@ written by eye:
18
21
  with delivery", "what is the status"): one `delivered` screen per intent this session
19
22
  completed, oldest first, then the `state --all` roster. Intent 330's ruling: a status ask
20
23
  answers with what actually shipped, not the in-flight roster alone.
24
+ - **`dashboard.rb continue|project <slug> --screen`** - the dashboard screen (intent 331d):
25
+ Active, In delivery, Delivered, Roadmap, Sessions, Changed, then the Where-we-are and
26
+ Where-we-go-next tables. A separate script from the other four (`dashboard.rb`, not
27
+ `report-screen`), since it aggregates across a whole store or project rather than one
28
+ intent; it prints on `continue` and on loading a project, not as a delivery trigger.
29
+
30
+ ## Binding table (intent 331f)
31
+
32
+ Every skill that shows state names its own report verb, one row per skill and trigger. Each
33
+ bound skill's file carries the SAME rule next to its verb: print the screen as the first
34
+ characters of the reply, nothing before it, no fence, or the hook cannot paint it.
35
+
36
+ | Skill | Trigger | Verb |
37
+ |---|---|---|
38
+ | `plastic-intent-continuing` | project route (continue, load project) | `dashboard.rb ... --screen` |
39
+ | `plastic-intent-continuing` | a named intent | `report-screen state` |
40
+ | `plastic-intent-continuing` | "where are we" (a status ask) | `report-screen session` |
41
+ | `plastic-intent-continuing` | "why so long" | `report-screen delay` |
42
+ | `plastic-intent-continuing` | a roadmap route | `report-screen roadmap ... state` |
43
+ | `plastic-auto` | the How boundary, before the executor | `report-screen plan` |
44
+ | `plastic-auto` | each of the five triggers | `report-screen state` |
45
+ | `plastic-auto` | close | `report-screen delivered` |
46
+ | `plastic-intent-ending` | the close | `report-screen delivered` |
47
+ | `plastic-intent-speccing` | the action files are written | `report-screen plan` |
48
+ | `plastic-roadmap` | create | `report-screen roadmap ... plan` |
49
+ | `plastic-roadmap` | read | `report-screen roadmap ... state` |
50
+ | `plastic-roadmap` | close | `report-screen roadmap ... delivered` |
51
+ | `plastic-dashboard` | any invocation | `dashboard.rb ... --screen` |
52
+ | `plastic-intent-executing` | after the red commit, and after the suite | `report-screen state` |
53
+
54
+ ## A roadmap's own three reports (intent 331c)
55
+
56
+ A roadmap gets the same pre-, in-, and post-delivery shape as an intent, through
57
+ `report-screen roadmap <roadmap.md> plan|state|delivered [--ansi] [--store-root <dir>]`:
58
+
59
+ - **`roadmap plan`** - the pre-delivery report: the Goal's first sentence, the batch (or legacy
60
+ wave) count and intent count, the batch order, and when the roadmap was created; then the
61
+ full entries table.
62
+ - **`roadmap state`** - the in-delivery report: Goal, a Progress bar over intents delivered of
63
+ intents total (never batches), the frontier batch, who is delivering it and their lead, the
64
+ next queued entry, and the last ledger event; then the entries table with each entry's own
65
+ checklist progress and lead.
66
+ - **`roadmap delivered`** - the post-delivery report: a meta line (closed time, or `in progress`
67
+ when the goal is not yet reached; intent count; duration) directly under the title, the
68
+ delivered table with each entry's merge sha, and the `## Log` table.
69
+
70
+ Every cell traces to the roadmap file, `INDEX.md` (which always wins on status), the roadmap's
71
+ own savepoint ledger, or (falling back when no ledger file exists) the roadmap's `## Log` -
72
+ never a second parser: `RoadmapQueue`'s own public `roadmap` reader supplies every entry.
21
73
 
22
74
  ## The five triggers for `state`
23
75
 
@@ -42,9 +94,9 @@ on harness name to decide.
42
94
 
43
95
  ## Depth for small work
44
96
 
45
- For small work in auto mode, only the How-boundary `state` screen prints mid-flight (its
46
- `Changed` row names what the What and Why steps did, since there is no separate briefing per
47
- stage any more). Larger work prints `state` at every trigger in the table above. This is a
97
+ For small work in auto mode, only the How-boundary `plan` screen prints mid-flight (intent
98
+ 331f moved this print off `state`, since there is no separate briefing per stage any more).
99
+ Larger work prints `state` at every trigger in the table above. This is a
48
100
  depth cut, not a different report: the screen's shape never changes, only how often it fires.
49
101
  A delivery still ends with `outcome.md` plus one `delivered` screen.
50
102
 
@@ -77,6 +129,25 @@ In guided mode, `state` prints at each stage boundary and the human decides befo
77
129
  stage starts.
78
130
 
79
131
  In auto mode, `state` prints at every trigger for larger work; for small work only the How
80
- boundary prints (see `## Depth for small work` above). The orchestrator takes the go-ahead
81
- itself and moves on, except at the existing hard stops (destructive action without a safe
82
- alternative, project-path confirm).
132
+ boundary's `plan` screen prints (see `## Depth for small work` above). The orchestrator takes
133
+ the go-ahead itself and moves on, except at the existing hard stops (destructive action without
134
+ a safe alternative, project-path confirm).
135
+
136
+ ## Column vocabulary (D5, intent 331f)
137
+
138
+ Owner ruling 2026-09-05 11:05 UTC: "What" is never a column name, because What is a stage, not
139
+ a value. The id column reads `Graph ID`; the title column reads `Intent`. Every Steps table
140
+ reads `Step | Status | Detail` (the plan screen's own Steps table reads
141
+ `Step | Action | Detail`); every Risks table reads `N | Risk`; the Delivered/Evidence/Needs-you
142
+ tables on the `delivered` screen read `Row | Detail | Proven by`, `Kind | Detail | Source`, and
143
+ `N | Need | Reason`. The plan screen's Asked row prints the intent title before its first
144
+ colon, never the whole intent line. This applies to every screen the family prints: `state`,
145
+ `roster`, `session`, `delivered`, `delay`, `plan`, `roadmap` (`plan`/`state`/`delivered`), and
146
+ `dashboard`. `outcome.md`'s own `| Row | What |` heading is an AUTHORING convention inside the
147
+ file a human writes, never a rendered header, and stays unchanged.
148
+
149
+ ## Width bound (D7, intent 331f)
150
+
151
+ No rendered row passes 115 visible columns. A long cell (the roadmap Goal, an intent title, an
152
+ Asked line) truncates on a word boundary with a single ellipsis; `ReportScreen.fit_screen`
153
+ shrinks a table's widest column first, floor 8, before it ever truncates a whole row.
@@ -7,7 +7,8 @@ user-invocable: false
7
7
  # Dashboard — Plastic Work Cockpit
8
8
 
9
9
  A deterministic overview of the intent store(s). It answers three questions at a glance:
10
- **where we are** (recently worked), **where we go next** (the most-valuable next work), and
10
+ **where we are** (recently worked; `Graph ID | Intent | Stage | Progress | Lead`),
11
+ **where we go next** (the most-valuable next work; `Rank | Graph ID | Intent | Reason`), and
11
12
  **how to conduct it** (a disposition per intent). The human-facing surface is **Markdown**,
12
13
  because the user's UI renders Markdown natively but collapses raw tool-call stdout.
13
14
 
@@ -22,6 +23,16 @@ state → byte-identical payload, regardless of model. Do NOT hand-summarize int
22
23
  - `plastic-intent-continuing` lands on the board on a bare resume
23
24
  - `plastic-auto` reads `--json` to choose the next dispatchable intent
24
25
 
26
+ ## The screen surface (intent 331d/331f)
27
+
28
+ `dashboard.rb project <slug> --screen` (or `continue --screen` for the global board) is the
29
+ default surface on every invocation: print it as the first characters of the reply, nothing
30
+ before it, no fence, or the hook cannot paint it. It carries a title, six fields (Active, In
31
+ delivery, Delivered, Roadmap, Sessions, Changed), then the Where-we-are and Where-we-go-next
32
+ tables, its own grammar and painted form standing in for the filled Markdown template below.
33
+ `plastic-intent-continuing`'s project route prints it this way. The Markdown board (Step 1-4
34
+ below) stays available as the deeper prose surface a reader can ask for.
35
+
25
36
  ## Procedure (the Markdown board — default human surface)
26
37
 
27
38
  ### Step 1 — Get the data payload
@@ -70,7 +81,7 @@ Fill mechanically, no rewriting, no re-sorting:
70
81
  re-truncate, or reword them. Never emit `<br>`.
71
82
  - `next_work` → `| {id} | {what} | {value} | {disposition} | {flags_label} |`
72
83
  - `active` → `| {id} | {what} | {stage} | {worker} | {activity} |`
73
- Empty list → one full-width row with `_(none)_` in the Id column and every other cell blank,
84
+ Empty list → one full-width row with `_(none)_` in the Graph ID column and every other cell blank,
74
85
  matching that table's column count (e.g. `| _(none)_ | | | | |` for the 5-column next_work
75
86
  table, `| _(none)_ | | | |` for the 5-column active table). Neither list carries an overflow
76
87
  "+N more" row anymore (D5, intent 202): the true pool size rides on the payload as
@@ -11,7 +11,7 @@
11
11
 
12
12
  ## Most-valuable next work
13
13
 
14
- | Id | What | Value | Disposition | Flags |
14
+ | Graph ID | Intent | Value | Disposition | Flags |
15
15
  | --- | --- | --- | --- | --- |
16
16
  {{next_work.rows}}
17
17
 
@@ -4,13 +4,13 @@
4
4
 
5
5
  **Active**
6
6
 
7
- | Id | What | Stage | Worker | Activity |
7
+ | Graph ID | Intent | Stage | Worker | Activity |
8
8
  | --- | --- | --- | --- | --- |
9
9
  {{active.rows}}
10
10
 
11
11
  **Most-valuable next work**
12
12
 
13
- | Id | What | Value | Disposition | Flags |
13
+ | Graph ID | Intent | Value | Disposition | Flags |
14
14
  | --- | --- | --- | --- | --- |
15
15
  {{next_work.rows}}
16
16
 
@@ -78,10 +78,15 @@ project alone.
78
78
  Runs the install-wide surface: agent registration, core files (including config-honoring
79
79
  drift), manifest sync is core-only and not part of this run, deprecation checks, config-ask
80
80
  checks, install-integrity checks, skill-lint (advisory), QMD reachability (unscoped, every
81
- collection), and the global store's own conventions/done-signals content. **Never carries a
82
- per-project finding**; that is `--store <slug>`'s job (see above). This is what
83
- `/plastic-doctor` invokes, and it also runs automatically after every `plastic-update`
84
- (informational, does not block or revert the update).
81
+ collection), the global store's own conventions/done-signals content, and the `display`
82
+ category (intent 331e): `display_hook_registered` (also runs at `--core`), `display_hook_paints`
83
+ (replays the shipped display fixture through the installed MessageDisplay hook and expects a
84
+ painted screen back, a pass when a known defeater like `NO_COLOR` is active, never a fail),
85
+ `display_not_defeated` (warns per active defeater and always names the undetectable verbose
86
+ transcript view), and `display_surfaces_documented` (the harness-adapters doc still names every
87
+ surface class). **Never carries a per-project finding**; that is `--store <slug>`'s job (see
88
+ above). This is what `/plastic-doctor` invokes, and it also runs automatically after every
89
+ `plastic-update` (informational, does not block or revert the update).
85
90
 
86
91
  ## When to Use
87
92
 
@@ -167,6 +172,7 @@ Use the `fix_hint` value to determine the correct action:
167
172
  | "Remove each listed .tmp/<session>/ directory after confirming that session is gone" | For each listed directory, confirm no live session uses it (a live session rewrites its heartbeat on every prompt and edit), then remove that directory by hand; never remove an unlisted one |
168
173
  | "For a day directory missing its <day>.md, run `file-session-intent --day <day> ...`" | Run `ruby ~/.plastic/scripts/file-session-intent --day <day> --carry-to <today> --store <store>` for the named day; rename or remove an entry that is not a `YYYYMMDD` day directory |
169
174
  | "Run scripts/project-links ... PRESERVES ... --drop-unbacked-links" | Run `ruby ~/.plastic/scripts/maintenance-run --tool project-links --intent <id> --apply` for the one flagged id (never run bare `project-links` against a real store outside the rare owner-approved batch exception, D2) |
175
+ | "Re-run the Plastic installer to repair the hook registration ... (plastic-install --repair)" (`display_hook_registered`) | Run `npx -y @zalom/plastic@<channel> install --reinstall --claude` (the `plastic-install` skill's repair mode), then re-run doctor |
170
176
 
171
177
  For fixes the agent cannot handle automatically, explain what the user needs
172
178
  to do manually. The `revisions.md` remedy is curator-applied (a move-and-record
@@ -45,32 +45,29 @@ specific intent or roadmap named.").
45
45
 
46
46
  ## Project route: land on the board
47
47
 
48
- Land on the Markdown board through the `plastic-dashboard` skill; rendering belongs there.
49
- Run the data payload and fill the matching template:
50
- - project loaded: `ruby ~/.plastic/scripts/dashboard.rb project <slug> --data`
51
- - otherwise (the global fallback): `ruby ~/.plastic/scripts/dashboard.rb continue --data`
52
-
53
- Fill the template from `plastic-dashboard`'s `templates/` and present the filled Markdown in
54
- your reply, every time: tool-call stdout and hook context are invisible to the user. Read
55
- `references/board-fill.md` for the fill mechanics and the store-health line when filling the
56
- board. The board load runs the scoped store check (`doctor --store <scope>`); its result
57
- arrives in the payload as `store_health` and is shown as one line of data, never a blocker.
58
-
59
- Priority order on the board: active intents first, then project context (governing plus
60
- tactical intents in a registered project), then stale future intents for triage, then fresh
61
- future intents as next work. A future intent older than `stale_threshold_days` (default 3) is
62
- surfaced for triage without action: activate, abandon, or leave. Activating moves it to
48
+ Print `ruby ~/.plastic/scripts/dashboard.rb project <slug> --screen` (or `continue --screen`
49
+ for the global fallback) as the first characters of the reply: nothing before it, no fence, or
50
+ the hook cannot paint it (intent 331d/331f). It carries a title, six fields (Active, In
51
+ delivery, Delivered, Roadmap, Sessions, Changed), then the Where-we-are and Where-we-go-next
52
+ tables. The board load runs the scoped store check (`doctor --store <scope>`); its result
53
+ rides in the payload as `store_health` and prints as one line of data, never a blocker.
54
+
55
+ Priority order on the underlying data: active intents first, then project context (governing
56
+ plus tactical intents in a registered project), then stale future intents for triage, then
57
+ fresh future intents as next work. A future intent older than `stale_threshold_days` (default
58
+ 3) is surfaced for triage without action: activate, abandon, or leave. Activating moves it to
63
59
  `## Active` in `INDEX.md` and auto-commits. The board's ranked next-work order is computed by
64
60
  `dashboard.rb`; cite the rule names only (Effort, Value, Flags, Override, Caps) and read
65
61
  `plastic-dashboard`'s `references/classification.md` for their definitions.
66
62
 
67
63
  When the tier root (the directory holding `INDEX.md`) has a mid-flight roadmap
68
64
  (`ruby ~/.plastic/scripts/roadmap-next --roadmaps-dir <root>/roadmaps` reports a `state`
69
- other than `none`), say so in one line and offer the roadmap route; the board still presents
65
+ other than `none`), say so in one line and offer the roadmap route; the screen still presents
70
66
  project state and stops.
71
67
 
72
68
  Then stop: "here is the state, what next?". Do not start executing work. When the user names
73
- an intent, take the intent route.
69
+ an intent, take the intent route. Read `references/board-fill.md` only when the reader asks
70
+ for the deeper prose board (`plastic-dashboard`'s Markdown surface still exists for that ask).
74
71
 
75
72
  ## Intent route: resume one intent from its ledger
76
73
 
@@ -139,10 +136,11 @@ For a live intent's directory:
139
136
  `delivering` or `blocked` entry wins, else the newest ledger or `## Log` timestamp.
140
137
  `roadmaps/<slug>.savepoint.md` is a derived signal read here, never a status field;
141
138
  `INDEX.md` stays the sole status writer.
142
- 2. **Present state:** the roadmap's `## Goal`, the current batch with each entry's mirrored
143
- status, the ledger's newest line beside the newest `## Log` line. Read
144
- `../plastic-conventions/references/roadmaps.md` for the file format and the status-mirror
145
- rule when a roadmap file needs interpreting.
139
+ 2. **Print state.** Print `ruby ~/.plastic/scripts/report-screen roadmap <roadmap.md> state` as
140
+ the first characters of the reply: nothing before it, no fence, or the hook cannot paint it.
141
+ It carries Goal, Progress, Frontier, Delivering, Next, and Changed, then the entries table -
142
+ never hand-typed. Read `../plastic-conventions/references/roadmaps.md` for the file format
143
+ and the status-mirror rule when a roadmap file needs interpreting.
146
144
  3. Then continue with the next dispatchable entry in the session's mode: direct work on it,
147
145
  or `plastic-auto` when the owner says auto. The coordinator that drives a batch appends
148
146
  to `roadmaps/<slug>.savepoint.md` at its dispatch, merge, park, and handoff points with
@@ -41,3 +41,12 @@ The project route's default target is the project board. When no project is load
41
41
  case where this route is reached without a registered project in scope), fall back to the
42
42
  global board payload (`dashboard.rb continue --data`) rather than failing. This mirrors the
43
43
  router's D6 default: a bare "continue" always lands somewhere useful.
44
+
45
+ ## The screen surface (intent 331d)
46
+
47
+ `dashboard.rb project <slug> --screen` (or `continue --screen`) prints the identical state -
48
+ Active, In delivery, Delivered, Roadmap, Sessions, Changed, then the Where-we-are and
49
+ Where-we-go-next tables - as a screen with its own grammar instead of a filled Markdown
50
+ template. It replaces this fill mechanism once intent 331f wires the project route to print
51
+ it first, the way the intent route already prints the intent screen first today; until then,
52
+ this page's fill rules stay the route's own surface.
@@ -144,11 +144,13 @@ ruby ~/.plastic/scripts/qmd-sync reindex --store <store-root> --async
144
144
  No-op when QMD is absent. Runs in the background so it never blocks the
145
145
  turn.
146
146
 
147
- ### Step 7. EM-to-CTO report
147
+ ### Step 7. Print `delivered`
148
148
 
149
- Brief the human like an engineering manager to a CTO: impact and risk first,
150
- in plain language, the decision left to them (merge, release, or accept).
151
- See `outcome.md` for the details; do not restate it verbatim.
149
+ Print `ruby ~/.plastic/scripts/report-screen delivered <intent_dir>` as the first characters
150
+ of the reply: nothing before it, no fence, or the hook cannot paint it. Asked, Delivered (with
151
+ its Proven-by column), Evidence, and Needs you come straight from the record - the EM-to-CTO
152
+ report, impact and risk first, in plain language, with the decision left to the human (merge,
153
+ release, or accept). See `outcome.md` for the details; do not restate it verbatim.
152
154
 
153
155
  ## Abandoned is the same procedure
154
156
 
@@ -63,6 +63,8 @@ Dispatch ONE executor subagent and give it the whole delivery: every task's full
63
63
 
64
64
  After each commit lands (the red commit and every commit after it), append a `Commit` line to the savepoint ledger: `ruby ~/.plastic/scripts/savepoint-note <intent_dir> --kind Commit --text "<sha> <what it proves>"` (intent 317, D17). This is what feeds `report-screen delay`; a commit with no line is a gap the delay report cannot explain.
65
65
 
66
+ Print `ruby ~/.plastic/scripts/report-screen state <intent_dir> --changed "<what just landed>"` as the first characters of the reply, nothing before it, no fence, right after the red commit and again once the suite goes green (intent 331f).
67
+
66
68
  Read its response by code:
67
69
  - DONE or DONE_WITH_CONCERNS → proceed to Step 3.
68
70
  - NEEDS_CONTEXT → provide the missing context, re-dispatch the executor.
@@ -111,10 +111,13 @@ When the rulings are enough to build from:
111
111
  rulings say more than the record already does.
112
112
  3. **Self-verify.** Read `references/self-verify-checklist.md` before presenting; fix any
113
113
  failing check and re-verify from the top.
114
- 4. **Present and hand off.** Present `spec.md` and the action files. Then offer the routes:
115
- run it now inline when the work is small enough for direct mode; hand to `plastic-auto`
116
- when the owner says auto and the checklist above passes (all decisions resolved, scope
117
- bounded, dependencies named, success criteria defined); or keep thinking.
114
+ 4. **Present and hand off.** Print `ruby ~/.plastic/scripts/report-screen plan <intent_dir>` as
115
+ the first characters of the reply: nothing before it, no fence, or the hook cannot paint it.
116
+ It carries Asked, Decisions, Steps, Mode, Reviewer, then the Steps and Risks tables, filled
117
+ from `spec.md` and the action files just written, never restated by eye. Then offer the
118
+ routes: run it now inline when the work is small enough for direct mode; hand to
119
+ `plastic-auto` when the owner says auto and the checklist above passes (all decisions
120
+ resolved, scope bounded, dependencies named, success criteria defined); or keep thinking.
118
121
 
119
122
  Report, in this order: which files were written (`spec.md` new or rewritten, the action
120
123
  files), the count of acceptance criteria, which `## Insights` rulings superseded an earlier
@@ -47,6 +47,15 @@ Read `../plastic-conventions/references/roadmaps.md` for the roadmap file format
47
47
  semantics, and the status-mirror rule that this skill's own file-format reference builds on. This
48
48
  path resolves relative to this skill's own installed directory.
49
49
 
50
+ ## Reports (intent 331f)
51
+
52
+ Each verb prints its report screen as the first characters of the reply: nothing before it, no
53
+ fence, or the hook cannot paint it.
54
+
55
+ - Create prints `ruby ~/.plastic/scripts/report-screen roadmap <roadmap.md> plan`.
56
+ - Read / consume prints `ruby ~/.plastic/scripts/report-screen roadmap <roadmap.md> state`.
57
+ - Close / archive prints `ruby ~/.plastic/scripts/report-screen roadmap <roadmap.md> delivered`.
58
+
50
59
  ## Notes
51
60
 
52
61
  - File location and the four-section shape are identical across tiers; do not invent a different
@@ -96,6 +96,16 @@ The ledger is derived and rebuildable (`ruby ~/.plastic/scripts/roadmap-savepoin
96
96
  roadmaps/{slug}.md`, reconstructing it from `## Log`), never a status source: `INDEX.md` stays the
97
97
  single writer of intent status, exactly as for the roadmap file itself.
98
98
 
99
+ ## Screens read this format (intent 331c)
100
+
101
+ `report-screen roadmap <roadmap.md> plan|state|delivered` reads exactly the shapes above and
102
+ nothing else: `## Goal`'s first sentence, the `## Batches` (or legacy `## Waves`) grouping and its
103
+ entries (through `RoadmapQueue`'s own reconciled reader - INDEX still wins), and the events from
104
+ the savepoint ledger, falling back to `## Log` classified through the same keyword vocabulary when
105
+ no ledger file exists (an archived roadmap moved before intent 134 shipped, `manual-first.md`
106
+ among them). A screen never invents a status, a time, or a merge sha the file, `INDEX.md`, or the
107
+ ledger did not already carry - the same `not recorded` floor the intent screens use.
108
+
99
109
  ## Worked example
100
110
 
101
111
  ```
@@ -0,0 +1,22 @@
1
+ ## ▶ {{scope}} · dashboard
2
+
3
+ | | | |
4
+ | --- | --- | --- |
5
+ | **Active** | {{active}} | intents |
6
+ | **In delivery** | {{in_delivery}} | with a fresh lock |
7
+ | **Delivered** | {{delivered}} | in the last 7 days |
8
+ | **Roadmap** | {{roadmap}} | frontier batch |
9
+ | **Sessions** | {{sessions}} | alive |
10
+ | **Changed** | {{changed}} | newest savepoint |
11
+
12
+ **Where we are**
13
+
14
+ | Graph ID | Intent | Stage | Progress | Lead |
15
+ | --- | --- | --- | --- | --- |
16
+ {{where_we_are.rows}}
17
+
18
+ **Where we go next**
19
+
20
+ | Rank | Graph ID | Intent | Reason |
21
+ | --- | --- | --- | --- |
22
+ {{where_we_go_next.rows}}
@@ -0,0 +1,21 @@
1
+ <!-- Doctor's display self-test fixture (intent 331e). Replayed through the
2
+ installed MessageDisplay hook by `display_hook_paints` to prove painting
3
+ still works; this is NOT a report-screen scaffold (no {{...}} mustache
4
+ placeholders) and ships no data of its own. -->
5
+
6
+ ## ▶ 331e · Doctor display check
7
+
8
+ | | | |
9
+ | --- | --- | --- |
10
+ | **Store** | project:plastic | the plastic project store |
11
+ | **Status** | Active | listed under ## Active in INDEX.md |
12
+ | **Stage** | Exec | What, Why, How, Exec delivered; the work is open |
13
+ | **Progress** | ██████████░░░░░░░░░░ 3 / 6 | 3 steps open |
14
+
15
+ **Steps**
16
+
17
+ | Step | Status | What |
18
+ | --- | --- | --- |
19
+ | S1 | done | Tests red |
20
+ | S2 | done | check_display_registration in doctor_core.rb |
21
+ | S3 | open | The three full-run checks in doctor.rb |
@@ -12,6 +12,6 @@
12
12
 
13
13
  **Steps**
14
14
 
15
- | Step | Status | What |
15
+ | Step | Status | Detail |
16
16
  | --- | --- | --- |
17
17
  {{steps.rows}}
@@ -0,0 +1,15 @@
1
+ ## ▶ {{id}} · {{name}} · plan
2
+
3
+ | | | |
4
+ | --- | --- | --- |
5
+ {{fields.rows}}
6
+
7
+ **Steps**
8
+
9
+ | Step | Action | Detail |
10
+ | --- | --- | --- |
11
+ {{steps.rows}}
12
+
13
+ **Risks**
14
+
15
+ {{risks.block}}
@@ -0,0 +1,10 @@
1
+ ## ✔ {{slug}} · roadmap · delivered
2
+ {{meta}}
3
+
4
+ **Delivered**
5
+
6
+ {{delivered.table}}
7
+
8
+ **Log**
9
+
10
+ {{log.table}}
@@ -0,0 +1,9 @@
1
+ ## ▶ {{slug}} · roadmap · plan
2
+
3
+ | | | |
4
+ | --- | --- | --- |
5
+ {{fields.rows}}
6
+
7
+ **Batches**
8
+
9
+ {{entries.table}}
@@ -0,0 +1,9 @@
1
+ ## ▶ {{slug}} · roadmap
2
+
3
+ | | | |
4
+ | --- | --- | --- |
5
+ {{fields.rows}}
6
+
7
+ **Batches**
8
+
9
+ {{entries.table}}
@@ -6,6 +6,6 @@
6
6
 
7
7
  **Steps**
8
8
 
9
- | Step | Status | What |
9
+ | Step | Status | Detail |
10
10
  | --- | --- | --- |
11
11
  {{steps.rows}}