@zalom/plastic 2.0.0-alpha.2 → 2.0.0-alpha.21

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 (127) hide show
  1. package/agents/plastic-enforcer.md +3 -1
  2. package/agents/plastic-executor.md +9 -3
  3. package/bin/test +24 -4
  4. package/hooks/call-budget +4 -0
  5. package/hooks/hooks.json +24 -0
  6. package/hooks/message-display +134 -0
  7. package/hooks/statusline +4 -27
  8. package/package.json +2 -2
  9. package/scripts/agent-report +8 -2
  10. package/scripts/dashboard.rb +297 -18
  11. package/scripts/doctor.rb +652 -5
  12. package/scripts/end-intent +219 -0
  13. package/scripts/hook-call-budget +222 -0
  14. package/scripts/hook-capture +25 -113
  15. package/scripts/hook-message-display +81 -0
  16. package/scripts/hook-record +12 -4
  17. package/scripts/hook-session-start +45 -7
  18. package/scripts/index-projection +74 -0
  19. package/scripts/intent-screen +77 -0
  20. package/scripts/lib/action_graph_shim.rb +277 -0
  21. package/scripts/lib/arm.rb +26 -1
  22. package/scripts/lib/atomic_write.rb +31 -0
  23. package/scripts/lib/compact_instructions.rb +5 -5
  24. package/scripts/lib/core_integrity.rb +71 -0
  25. package/scripts/lib/dashboard_screen.rb +40 -0
  26. package/scripts/lib/day_summary.rb +7 -2
  27. package/scripts/lib/doctor_core.rb +102 -5
  28. package/scripts/lib/doctor_session_ledger.rb +52 -0
  29. package/scripts/lib/graph_edges.rb +137 -0
  30. package/scripts/lib/graph_file.rb +246 -0
  31. package/scripts/lib/graph_tree.rb +98 -0
  32. package/scripts/lib/guarded_append.rb +155 -0
  33. package/scripts/lib/hook_registry.rb +28 -2
  34. package/scripts/lib/hook_replay.rb +211 -0
  35. package/scripts/lib/index_projection.rb +201 -0
  36. package/scripts/lib/installer_core.rb +141 -6
  37. package/scripts/lib/intent_screen.rb +309 -0
  38. package/scripts/lib/intent_screen_ansi.rb +262 -0
  39. package/scripts/lib/message_display.rb +586 -0
  40. package/scripts/lib/meter_watch.rb +179 -0
  41. package/scripts/lib/node_file.rb +214 -0
  42. package/scripts/lib/node_ids.rb +99 -0
  43. package/scripts/lib/node_ledger.rb +377 -0
  44. package/scripts/lib/node_packet.rb +908 -0
  45. package/scripts/lib/node_return.rb +199 -0
  46. package/scripts/lib/node_worktree.rb +337 -0
  47. package/scripts/lib/outcome_report.rb +440 -0
  48. package/scripts/lib/packet_wrapper.rb +132 -0
  49. package/scripts/lib/ready_set.rb +462 -0
  50. package/scripts/lib/release_guard.rb +16 -0
  51. package/scripts/lib/report_screen.rb +1967 -0
  52. package/scripts/lib/roadmap_graph.rb +210 -0
  53. package/scripts/lib/roadmap_migration.rb +95 -0
  54. package/scripts/lib/roadmap_queue.rb +155 -5
  55. package/scripts/lib/roadmap_render.rb +150 -0
  56. package/scripts/lib/roadmap_savepoint.rb +62 -12
  57. package/scripts/lib/runner_absorb.rb +620 -0
  58. package/scripts/lib/runner_answer.rb +206 -0
  59. package/scripts/lib/runner_core.rb +194 -0
  60. package/scripts/lib/runner_dispatch.rb +506 -0
  61. package/scripts/lib/runner_policy.rb +173 -0
  62. package/scripts/lib/runner_proposals.rb +275 -0
  63. package/scripts/lib/runner_rewind.rb +201 -0
  64. package/scripts/lib/runner_sweep.rb +231 -0
  65. package/scripts/lib/savepoint.rb +149 -12
  66. package/scripts/lib/screen_paint.rb +555 -0
  67. package/scripts/lib/screens/dashboard.rb +20 -0
  68. package/scripts/lib/screens/plan.rb +18 -0
  69. package/scripts/lib/screens/roadmap.rb +15 -0
  70. package/scripts/lib/session_git.rb +49 -18
  71. package/scripts/lib/session_ledger.rb +128 -0
  72. package/scripts/lib/session_usage.rb +190 -0
  73. package/scripts/lib/verify_intent.rb +33 -0
  74. package/scripts/lib/work_graph_validator.rb +201 -0
  75. package/scripts/meter-watch +57 -0
  76. package/scripts/node-packet +92 -0
  77. package/scripts/node-transition +291 -0
  78. package/scripts/outcome-report +74 -0
  79. package/scripts/plastic-lock +8 -1
  80. package/scripts/read-config +3 -3
  81. package/scripts/ready-set +126 -0
  82. package/scripts/release-check +118 -0
  83. package/scripts/report-screen +281 -0
  84. package/scripts/roadmap-graph +119 -0
  85. package/scripts/roadmap-savepoint +7 -0
  86. package/scripts/runner +397 -0
  87. package/scripts/savepoint-note +69 -0
  88. package/scripts/session-usage +56 -0
  89. package/scripts/spawn-preamble +9 -2
  90. package/scripts/validate-work-graph +39 -0
  91. package/scripts/verify-intent +2 -1
  92. package/skills/auto/SKILL.md +41 -34
  93. package/skills/auto/references/human-report-contract.md +136 -54
  94. package/skills/conventions/references/locks-and-worktrees.md +12 -0
  95. package/skills/dashboard/SKILL.md +13 -2
  96. package/skills/dashboard/templates/dashboard-global.md +1 -1
  97. package/skills/dashboard/templates/dashboard-project.md +2 -2
  98. package/skills/doctor/SKILL.md +10 -4
  99. package/skills/intent-continuing/SKILL.md +51 -41
  100. package/skills/intent-continuing/references/board-fill.md +9 -0
  101. package/skills/intent-continuing/references/boarding-matrix.md +6 -5
  102. package/skills/intent-continuing/references/context-management.md +1 -1
  103. package/skills/intent-ending/SKILL.md +36 -16
  104. package/skills/intent-executing/SKILL.md +21 -5
  105. package/skills/intent-executing/implementer-prompt.md +6 -1
  106. package/skills/intent-speccing/SKILL.md +7 -4
  107. package/skills/releasing/SKILL.md +39 -0
  108. package/skills/releasing/references/promotion-and-tagging.md +10 -6
  109. package/skills/releasing/references/release-lines.md +1 -1
  110. package/skills/roadmap/SKILL.md +26 -0
  111. package/skills/roadmap/references/file-format.md +10 -0
  112. package/templates/config.yml +3 -3
  113. package/templates/dashboard-screen.md +22 -0
  114. package/templates/display-fixture.md +21 -0
  115. package/templates/graph.md +16 -0
  116. package/templates/intent-screen.md +17 -0
  117. package/templates/node-decision.md +11 -0
  118. package/templates/node-research.md +11 -0
  119. package/templates/node-verify.md +13 -0
  120. package/templates/node-work.md +22 -0
  121. package/templates/outcome.md +19 -1
  122. package/templates/report-plan.md +15 -0
  123. package/templates/report-roadmap-delivered.md +10 -0
  124. package/templates/report-roadmap-plan.md +9 -0
  125. package/templates/report-roadmap-state.md +9 -0
  126. package/templates/report-state.md +11 -0
  127. package/templates/roadmap.md +13 -0
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # frozen_string_literal: true
4
+
5
+ # validate-work-graph - deterministic CLI over WorkGraphValidator (intent 334, n4).
6
+ #
7
+ # Checks whether one intent directory's graph.md and nodes/ form a valid work
8
+ # graph: needs targets resolve, node files reconcile with the declared graph,
9
+ # per-kind body sections are present, and (above the trivial bar) a verify
10
+ # node gates two or more work nodes with a failure-mode matrix per work node.
11
+ # Modelled on scripts/validate-intent: errors to stderr, same exit-code shape.
12
+ #
13
+ # Usage:
14
+ # validate-work-graph <intent_dir>
15
+ #
16
+ # Exit codes: 0 (valid), 1 (invalid or unreadable; report on stderr),
17
+ # 2 (usage - no argument given).
18
+
19
+ require_relative "lib/work_graph_validator"
20
+
21
+ intent_dir = ARGV.find { |a| !a.start_with?("--") }
22
+
23
+ if intent_dir.nil?
24
+ warn "usage: validate-work-graph <intent_dir>"
25
+ exit 2
26
+ end
27
+
28
+ dir = File.expand_path(intent_dir)
29
+ result = WorkGraphValidator.validate(dir)
30
+
31
+ if result[:ok]
32
+ puts "OK: #{dir}"
33
+ exit 0
34
+ end
35
+
36
+ warn "INVALID: #{dir}"
37
+ result[:missing].each { |m| warn "missing: #{m}" }
38
+ result[:errors].each { |e| warn e }
39
+ exit 1
@@ -15,7 +15,8 @@
15
15
  # other flags exist.
16
16
  #
17
17
  # Checks, all run every invocation (the fourth only when --suite is given):
18
- # 1. doctor - Doctor#run_intent_check(id, store: scope), fail-open on a crash
18
+ # 1. doctor - Doctor#run_intent_check(id, store: scope), fail-open on a crash; the doctor
19
+ # scan includes the intent_ticks_lag warning (intent 329)
19
20
  # 2. em-dash - added lines only of `git diff <base>...HEAD`, never the whole tree
20
21
  # 3. diffstat - `git diff --stat <base>...HEAD`, never a failure on its own
21
22
  # 4. suite - the supplied --suite command, run with RUBYOPT cleared
@@ -13,20 +13,18 @@ user-invocable: true
13
13
  Announce: "Taking over intent [ID] - [name] for autonomous delivery."
14
14
 
15
15
  **Advisory (not a rule).** At auto-mode start, recommend once that the user run this
16
- orchestrating main session on the best available thinking model (Fable, Opus, or whatever
17
- supersedes them). This is advice only: it changes no behavior. Dispatched agents keep their
18
- configured model and never resolve to Fable unless an explicit `agents.models.<name>` config
19
- override names Fable for that role. The two advisors, `plastic-advisor` and
20
- `plastic-faux-advisor`, are consultation roles the user or the main session summons
21
- deliberately; the auto pipeline never dispatches them.
16
+ orchestrating session on the best available thinking model (Fable, Opus, or whatever supersedes
17
+ them); this is advice only, and dispatched agents keep their configured model, never resolving
18
+ to Fable without an explicit `agents.models.<name>` config override. `plastic-advisor` and
19
+ `plastic-faux-advisor` are consultation roles the user or this session summons deliberately;
20
+ the auto pipeline never dispatches them.
22
21
 
23
22
  ## Precondition
24
23
 
25
24
  An active intent MUST exist in INDEX.md. If none exists, refuse: "No active intent found.
26
25
  Create one first with /plastic-intent-creating."
27
26
 
28
- If several active intents exist, ask the user which one to deliver (the one question auto asks
29
- at boarding, before delivery starts).
27
+ If several active intents exist, ask which to deliver (the one question auto asks at boarding).
30
28
 
31
29
  **Picking work when no intent is specified.** If the user says "auto" without naming an intent
32
30
  and none is active, consult the roadmap first (the primary planning surface), then fall back to
@@ -42,9 +40,8 @@ frontier batch is still delivering, report it and wait, never dispatch a later b
42
40
  `exhausted` means fall back to `ruby ~/.plastic/scripts/dashboard.rb all --json` and work its
43
41
  `dispatchable_queue` in `rank` order, leaving `human_only` and `next_big_thing` for the user.
44
42
 
45
- QMD-first (when available): when the user describes the work rather than naming an intent, run
46
- `ruby ~/.plastic/scripts/qmd-sync search "<terms>"` before scanning the store, then open the
47
- authoritative intent file for the hit you take over. The command is a no-op when QMD is absent.
43
+ QMD-first (when available): when the user describes the work instead of naming an intent, run
44
+ `ruby ~/.plastic/scripts/qmd-sync search "<terms>"` first, then open the hit's authoritative intent file; a no-op when QMD is absent.
48
45
 
49
46
  ## Take the intent (do this FIRST)
50
47
 
@@ -67,8 +64,9 @@ Replace `<STORE>` (`~/.plastic/projects/<slug>/store` or `~/.plastic/store`) and
67
64
  nonblank `CLAUDE_CODE_SESSION_ID` as Claude, otherwise passes no identity and the verb keys the
68
65
  lock by a derived session key. Never guess identity from an absent runtime variable; an
69
66
  unknown harness or thread stays unknown. Exit 1 means the lock is held, stale, excluded, or
70
- corrupt; the message names the `plastic-doctor` verb that resolves it. Do not proceed as the
71
- owner after an exit 1.
67
+ corrupt - or `inline_refused`: a conversation session may not arm an intent at all (owner rule
68
+ 2026-08-31); dispatch the delivery team instead. `--allow-inline` exists only for an explicit
69
+ owner override. Do not proceed as the owner after an exit 1.
72
70
 
73
71
  Read `../plastic-conventions/references/locks-and-worktrees.md` for what the lock and the
74
72
  worktree mean and the station table behind them. Code edits happen only inside the worktree.
@@ -89,6 +87,12 @@ tier and no stage agent; depth follows the work.
89
87
  Two boots is the normal delivery; the third is the exception the risk rule names. The lead is
90
88
  this session (the `plastic-enforcer` role), never a dispatched agent.
91
89
 
90
+ A lead is a choice, not a requirement (D8, 355). `runner step` computes the plan and prints a
91
+ spawn block per node - agent, model, packet path, the test command, the call cap - fenced for a
92
+ session to paste into the Agent tool; the runner never spawns (327 D42). A lead earns its keep
93
+ on a graph carrying a decision node, weighing its `needs_decision` stop; a graph with none runs
94
+ end to end from `runner step` alone.
95
+
92
96
  ## Team
93
97
 
94
98
  - **plastic-enforcer**: this session. Writes the Why and How record, dispatches, folds reviews,
@@ -147,13 +151,10 @@ each one as a delegate before (or when) it needs to write into the intent dir:
147
151
 
148
152
  Only the owner can delegate. Delegates cannot re-delegate or release.
149
153
 
150
- Headless note: in a headless or background run the session id may be unset; the arm verb then
151
- keys the lock by a derived key and the record hook still writes the savepoint ledger from the
152
- written path. Verify the lock with `plastic-lock status` rather than assuming.
154
+ Headless note: in a headless or background run the session id may be unset; the arm verb then keys the lock by a derived key and the record hook still writes the ledger.
155
+ Verify with `plastic-lock status` rather than assuming.
153
156
 
154
- Solo fallback: on a harness with no agent dispatch (Codex CLI today), this session walks the
155
- five steps itself: it still writes the matrix, still writes the tests first, and reviews its own
156
- plan against the matrix before code, saying so in `## Insights`.
157
+ Solo fallback: on a harness with no agent dispatch (Codex CLI today), this session walks the five steps itself, still writing the matrix and the tests first and reviewing its own plan against the matrix before code, saying so in `## Insights`.
157
158
 
158
159
  ## Stage-Aware Entry
159
160
 
@@ -168,6 +169,7 @@ ledger is missing (then rebuild it with `Savepoint.rebuild_savepoint`).
168
169
  | `How plan.md created` / `How checklist.md created` / `Exec started` | Exec (verify plan, matrix, checklist) |
169
170
  | `Exec outcome.md created` | Exec done; complete the intent |
170
171
  | `Done delivered|abandoned` | Terminal; do not resume |
172
+ | A node or `Intent` transition line (`n1 running ...`, `Intent needs_decision ...`) | Exec; a graph delivery is in progress - drive it through `scripts/runner`'s three public verbs, `step` (one turn of the dispatch loop), `status` (renders ledger state, safe to poll constantly), and `answer` (closes a `needs_decision` node) - read node status through `NodeLedger.status` before dispatching anything, never re-derive it by eye |
171
173
 
172
174
  Filesystem fallback, in order: `checklist.md` with items checked means resume Exec from the
173
175
  first unchecked item; `plan.md` plus `checklist.md` means enter Exec; `spec.md` alone means
@@ -183,9 +185,7 @@ Announce which stage you are entering and why.
183
185
  3. Decide: pick the best option per gap, record it in `## Context > ### Decisions` with the
184
186
  rationale, and log it in `## Insights` with the `(autonomous)` marker through
185
187
  `scripts/insight-append`.
186
- 4. Write `spec.md`.
187
-
188
- Then How.
188
+ 4. Write `spec.md`. Then How.
189
189
 
190
190
  ## How (the lead), then the plan review
191
191
 
@@ -200,9 +200,9 @@ Then How.
200
200
  into the spec, the matrix, and the tests; record what was dropped and why in the action
201
201
  file's review fold. A REVISE verdict is folded and not re-reviewed unless a finding changes
202
202
  a decision.
203
- 5. Notify the user (the one mid-flight briefing, per `references/human-report-contract.md`):
204
- State, the plan shape and what it builds; Risk, the riskiest row of the matrix; Call,
205
- proceeding to build. In auto mode this briefing informs; it does not wait.
203
+ 5. Print `ruby ~/.plastic/scripts/report-screen plan <intent_dir>` as the first characters of
204
+ the reply, nothing before it, no fence, before dispatching the executor (see
205
+ `references/human-report-contract.md` for the full binding table). It informs; it does not wait.
206
206
 
207
207
  Then Exec.
208
208
 
@@ -214,7 +214,7 @@ Then Exec.
214
214
  then builds, then drives the full suite green.
215
215
  2. Read its return by code: DONE or DONE_WITH_CONCERNS proceeds; NEEDS_CONTEXT re-dispatches
216
216
  with the missing context; BLOCKED stops under the error procedure.
217
- 3. Tick the checklist as items land (the executor does this; verify it).
217
+ 3. Tick the checklist as items land (the executor does this); verify tick-versus-diff against the diff. A mismatch is a review finding, not a lead cleanup.
218
218
 
219
219
  ## Review by risk (boot 3, only when a rule fires)
220
220
 
@@ -251,8 +251,9 @@ every choice is non-destructive and the team has full autonomy.
251
251
 
252
252
  Read `../plastic-conventions/references/completion-and-done.md` for what "intent done" means.
253
253
 
254
- 1. Verify every checklist item is checked and the suite is green once on the branch.
255
- 2. Write `outcome.md` from `~/.plastic/templates/outcome.md` with `disposition: delivered`.
254
+ 1. This is the merge gate: verify every checklist item is checked, verify tick-versus-diff against the diff, and confirm the suite is green once on the branch.
255
+ 2. Write `outcome.md` from `~/.plastic/templates/outcome.md` with `disposition: delivered`,
256
+ `## Delivered` as the labeled table whose row labels match the action-file headings (317a).
256
257
  3. Release, if configured: match the working directory against `~/.plastic/projects.yml`, read
257
258
  `project.yml`'s `release` block, and act on `on_complete` (`commit`, `commit_and_push`,
258
259
  `manual`), `verify` (green proceeds; red follows `on_red`: `fix_and_retry` up to twice,
@@ -268,10 +269,16 @@ Read `../plastic-conventions/references/completion-and-done.md` for what "intent
268
269
  --session "$CLAUDE_CODE_SESSION_ID" \
269
270
  --index-note "<what shipped>; <suite result>"
270
271
  ```
271
- Exit 4 means a live foreign session holds the lock; 5 means the worktree is dirty (commit
272
- first, or pass `--discard-worktree-changes` deliberately); 3 means the lock survived the
273
- disarm (`/plastic-doctor check the lock status`); 6 means the structure check refused. Never
274
- leave an orphaned worktree; run `git worktree prune` on a stale reference.
272
+ Exit 4: a live foreign session holds the lock. 5: the worktree is dirty (commit first, or
273
+ pass `--discard-worktree-changes` deliberately). 3: the lock survived the disarm
274
+ (`/plastic-doctor check the lock status`). 6: the structure check refused. Never leave an
275
+ orphaned worktree; run `git worktree prune` on a stale reference.
276
+ 6. Print `ruby ~/.plastic/scripts/report-screen delivered <intent_dir>` once (D15/331f), and
277
+ `report-screen state` at each of the five triggers in `references/human-report-contract.md`
278
+ (a review verdict, a blocker, a merge/release, or an owner status ask; a mid-batch ask
279
+ instead runs `report-screen session <tier_root> --session "$CLAUDE_CODE_SESSION_ID"`, intent
280
+ 330). Print each as the first characters of the reply: nothing before it, no fence, or the
281
+ hook cannot paint it.
275
282
 
276
283
  ## Error Handling
277
284
 
@@ -284,8 +291,8 @@ leaves the project broken.
284
291
 
285
292
  - Read `references/agent-architecture.md` for the team model, the risk list, the headless note,
286
293
  and the solo fallback when dispatching or when a harness has no agent dispatch.
287
- - Read `references/human-report-contract.md` for the State/Risk/Call briefing before sending the
288
- How briefing.
294
+ - Read `references/human-report-contract.md` for the three report screens and the five
295
+ triggers before printing the How or Completion screen above.
289
296
  - Read `references/agent-report-contract.md` for the completion report format when reading a
290
297
  dispatched agent's return or synthesizing one.
291
298
  - Read `references/end-tail.md` for what `Arm.disarm` does at the End tail and why the reindex
@@ -1,72 +1,154 @@
1
- # Human Report Contract (per-stage EM-to-CTO briefing)
2
-
3
- This doc defines how the orchestrator briefs the human at each of the five stage boundaries
4
- (What, Why, How, Exec, Done) in auto mode; for small work only the How boundary fires (see
5
- `## Depth for small work`). It is the outward, human-facing counterpart to the
6
- internal report contract in `references/agent-report-contract.md`. Voice: an engineering
7
- manager briefing a CTO. Lead with impact, name the risk, leave the decision.
8
-
9
- ## The skeleton
10
-
11
- One fixed 3-line shape, reused at every stage:
12
-
13
- 1. **State**: what happened and what it means, impact first, one line.
14
- 2. **Risk**: the one thing that could bite, or "nothing flagged."
15
- 3. **Call**: the decision left to you, or the go-ahead I am taking.
16
-
17
- This is a shape, not a rigid template. Keep the order (State, then Risk, then Call) and keep it
18
- short. The words can flex to fit the stage.
19
-
20
- ## Per-stage content
21
-
22
- - **What**: State = the work I picked up and why it matters now. Risk = scope uncertainty.
23
- Call = confirm this is worth doing, or I proceed.
24
- - **Why**: State = the approach I chose, one line. Risk = the main trade-off. Call = the one
25
- decision I need (approve, or pick an option).
26
- - **How**: State = the plan shape (task count and what it builds). Risk = the riskiest task or
27
- dependency. Call = approve the plan to build.
28
- - **Exec**: State = what got built and the test result. Risk = residual failures or deviations.
29
- Call = go to review, or done.
30
- - **Done**: State = the delivered impact. Risk = residual risk. Call = the decision left to you
31
- (merge, release, accept).
1
+ # Human Report Contract (the report screens, intent 317)
2
+
3
+ D15: the prose EM-to-CTO briefing this doc used to define is retired. The orchestrator now
4
+ prints one of these report screens, filled from the record by `scripts/report-screen`, never
5
+ written by eye:
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.
10
+ - **`report-screen state <intent_dir> [--changed "<text>"]`** - the mid-delivery report. One
11
+ intent's field table (Store, Status, Stage, Savepoint, Progress, Next, Insight) plus a
12
+ `Changed` row naming what caused the print, and its Steps table.
13
+ - **`report-screen state --all <store_root>`** - the roster across every in-delivery intent,
14
+ most recently changed first, then one collapsed block (Stage, Next, Changed, first three
15
+ open steps) per intent.
16
+ - **`report-screen delivered <intent_dir>`** - the post-delivery report, printed once at close:
17
+ Asked, Delivered (with a Proven-by column), Evidence, Needs you.
18
+ - **`report-screen delay <intent_dir>`** - printed only on request ("why did X take so long"):
19
+ the delivery as a timeline plus the derived `Where the time went` line.
20
+ - **`report-screen session <tier_root>`** - the answer to an UNNAMED status ask ("where are we
21
+ with delivery", "what is the status"): one `delivered` screen per intent this session
22
+ completed, oldest first, then the `state --all` roster. Intent 330's ruling: a status ask
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.
73
+
74
+ ## The five triggers for `state`
75
+
76
+ Print `state` (one intent, or `--all` for the roster) on any of these; a checklist tick alone,
77
+ an executor's intermediate commit, or an agent going idle is NOT one of them:
78
+
79
+ | Trigger | Scope |
80
+ |---|---|
81
+ | A savepoint line lands (a stage boundary: Why, How, Exec started, outcome written, Done) | that intent |
82
+ | A review verdict returns (plan review or post-execution review), naming what it changed | that intent |
83
+ | A blocker or needs-input is logged | that intent |
84
+ | A merge or a release lands | that intent |
85
+ | The owner asks ("where are we", "state of X", "continue X") | all in delivery, or the one named |
86
+
87
+ `delivered` prints exactly once, at Completion. `delay` prints only when the owner asks why a
88
+ delivery took long.
89
+
90
+ Every verb prints the same plain Markdown on every harness (owner ruling 2026-08-31); where a
91
+ harness can paint it (Claude Code, through 316a's message-display hook), it substitutes a
92
+ painted rendering of that same output, never a different one, and no skill or script branches
93
+ on harness name to decide.
32
94
 
33
95
  ## Depth for small work
34
96
 
35
- For small work in auto mode the mid-flight briefings collapse to one. Only the How briefing fires, and
36
- it folds in what the What and Why briefings would have said: the work picked up and the approach
37
- chosen go into its State line. The Exec briefing folds into the final owner report at End. Larger
38
- work sends all four. The shape does not change: still State, then Risk, then Call, and the per-stage
39
- content above still says what each line covers. This is a depth cut, not a new report. A delivery
40
- still ends with `outcome.md` plus one owner report.
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
100
+ depth cut, not a different report: the screen's shape never changes, only how often it fires.
101
+ A delivery still ends with `outcome.md` plus one `delivered` screen.
41
102
 
42
103
  ## One report per audience
43
104
 
44
- A delivery produces exactly two artifacts: `outcome.md` (authored by `plastic-intent-ending`)
45
- and one EM-to-CTO owner report at the End stage. No stage or skill restates a delivery
46
- already written to `outcome.md`; point at it instead. Skills do not open with a banner that
47
- names the skill or restates the intent id and name the owner just typed. Announce only what
48
- the reader cannot already know: an error, a result, a choice with its reason, or a handoff.
105
+ A delivery produces exactly two artifacts: `outcome.md` (generated by `scripts/end-intent`
106
+ from `graph.md`, `nodes/`, and the ledger when the intent has one, intent 339; hand-authored
107
+ by `plastic-intent-ending` otherwise) and one `delivered` screen at the End stage. No stage or skill restates a delivery already
108
+ written to `outcome.md`; point at it instead. Skills do not open with a banner that names the
109
+ skill or restates the intent id and name the owner just typed. Announce only what the reader
110
+ cannot already know: an error, a result, a choice with its reason, or a handoff.
49
111
 
50
112
  ## Boundary vs intent 74
51
113
 
52
114
  Intent 74's report contract (`references/agent-report-contract.md`) is the INTERNAL,
53
115
  machine-checked handoff from a dispatched specialist back to the orchestrator: a structured
54
- envelope plus a per-role payload. This contract is the OUTWARD human briefing, orchestrator to
55
- user, in prose. Different direction, different audience, different form. The orchestrator
56
- CONSUMES the intent 74 report to WRITE the human briefing defined here. The two never merge.
116
+ envelope plus a per-role payload. This contract is the OUTWARD screen shown to the owner.
117
+ Different direction, different audience, different form. The orchestrator reads the intent 74
118
+ report and reflects it into the record (savepoint, outcome.md) that `report-screen` then
119
+ renders. The two never merge.
57
120
 
58
121
  ## Brevity: point, don't repeat
59
122
 
60
- Surface rules are owned by the `writing-style` skill. This contract does not restate them, in full
61
- or in summary. It defines the report's shape only: what to say, in what order, and when to stop.
62
- Apply the `writing-style` skill for the wording.
123
+ Surface rules are owned by the `writing-style` skill. This contract does not restate them. Its
124
+ job is naming which screen prints when, not the wording inside it - `report-screen` derives
125
+ every cell from the record (D14), so there is no prose left to style here.
63
126
 
64
127
  ## Emission: guided vs auto
65
128
 
66
- In guided mode, the briefing lands at each stage boundary and the human acts on the Call line
67
- before the next stage starts.
129
+ In guided mode, `state` prints at each stage boundary and the human decides before the next
130
+ stage starts.
131
+
132
+ In auto mode, `state` prints at every trigger for larger work; for small work only the How
133
+ boundary's `plan` screen prints (see `## Depth for small work` above). The orchestrator takes
134
+ the go-ahead itself and moves on, except at the existing hard stops (destructive action without
135
+ a safe alternative, project-path confirm).
136
+
137
+ ## Column vocabulary (D5, intent 331f)
138
+
139
+ Owner ruling 2026-09-05 11:05 UTC: "What" is never a column name, because What is a stage, not
140
+ a value. The id column reads `Graph ID`; the title column reads `Intent`. Every Steps table
141
+ reads `Step | Status | Detail` (the plan screen's own Steps table reads
142
+ `Step | Action | Detail`); every Risks table reads `N | Risk`; the Delivered/Evidence/Needs-you
143
+ tables on the `delivered` screen read `Row | Detail | Proven by`, `Kind | Detail | Source`, and
144
+ `N | Need | Reason`. The plan screen's Asked row prints the intent title before its first
145
+ colon, never the whole intent line. This applies to every screen the family prints: `state`,
146
+ `roster`, `session`, `delivered`, `delay`, `plan`, `roadmap` (`plan`/`state`/`delivered`), and
147
+ `dashboard`. `outcome.md`'s own `| Row | What |` heading is an AUTHORING convention inside the
148
+ file a human writes, never a rendered header, and stays unchanged.
149
+
150
+ ## Width bound (D7, intent 331f)
68
151
 
69
- In auto mode, for larger work the orchestrator still emits the briefing at each boundary, as a
70
- running EM-to-CTO account. For small work only the How briefing fires; see `## Depth for small work` above for what it
71
- folds in. The Call line becomes the go-ahead the orchestrator takes itself and moves on, except at
72
- the existing hard stops (destructive action without a safe alternative, project-path confirm).
152
+ No rendered row passes 115 visible columns. A long cell (the roadmap Goal, an intent title, an
153
+ Asked line) truncates on a word boundary with a single ellipsis; `ReportScreen.fit_screen`
154
+ shrinks a table's widest column first, floor 8, before it ever truncates a whole row.
@@ -103,3 +103,15 @@ what gets written down.
103
103
  | Exec | code on the intent branch, checklist checked off | heartbeat; code edits confined to the provisioned worktree; delegates write under the owner's lock | checklist boxes; savepoint milestones; the day-ledger line promotes when a project file lands |
104
104
  | End (done) | mandatory `outcome.md` (`disposition: delivered\|abandoned`), INDEX moves to Completed or Abandoned | ordered End tail: verify, merge and remove worktrees, disarm clears `delivery.lock`, then the pointer is purge-eligible, and the QMD reindex runs LAST (after purge); `end-intent` backfills a placeholder `outcome.md` from the record and its structure check reports (never refuses) | savepoint `Done delivered` (or `abandoned`); takeover audits, if any, remain in savepoint.md |
105
105
  | Maintenance (Future, Terminal, or Active-with-a-stale-or-no-lock) | `revisions.md` move-and-record entries | detects (never acquires) `delivery.lock`; defers and reports while the target's lock is FRESH (`Lock.fresh?`); a stale or absent lock is not-active, maintenance proceeds | append-only, rule-tagged `revisions.md` entry written in the same operation as the change, or the change is refused; lands via a fresh branch off store main merged back as one closed op, never `git add -A` |
106
+
107
+ ## The write guard is not residue
108
+
109
+ `<type>.write.lock` (usually `delivery.write.lock`) is a deliberate sibling
110
+ inode used only for `flock`: no owner, no timestamp, no content, and it is
111
+ NEVER unlinked - deleting it while a writer holds the flock hands the next
112
+ writer a fresh inode at the same path, so two writers hold "the" guard at
113
+ once (see `scripts/lib/lock.rb`, the write-guard comment). A zero-byte
114
+ `*.write.lock` in a completed intent directory is by design; no cleaner may
115
+ sweep it, and it is already inside the store's `*.lock` gitignore rule.
116
+ (Intent 317a, A2: a review misread it as stale residue and nearly shipped
117
+ the sweep.)
@@ -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