@zalom/plastic 1.0.3 → 1.1.1

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 (130) hide show
  1. package/PLASTIC-reference.md +11 -11
  2. package/PLASTIC.md +11 -9
  3. package/README.md +48 -1
  4. package/agents/plastic-enforcer.md +8 -5
  5. package/agents/plastic-future-intent-researcher.md +1 -1
  6. package/agents/plastic-intent-curator.md +9 -10
  7. package/agents/plastic-spec-specialist.md +9 -6
  8. package/bin/plastic.js +2 -2
  9. package/hooks/check-update +1 -1
  10. package/hooks/continue +1 -1
  11. package/package.json +1 -1
  12. package/scripts/dashboard.rb +29 -24
  13. package/scripts/doctor.rb +188 -9
  14. package/scripts/end-intent +330 -0
  15. package/scripts/hook-code-gate +1 -1
  16. package/scripts/hook-continue +2 -2
  17. package/scripts/hook-create-gate +2 -2
  18. package/scripts/hook-session-start +1 -1
  19. package/scripts/install.rb +2 -1
  20. package/scripts/lib/bridge.rb +116 -3
  21. package/scripts/lib/dashboard_banner.rb +8 -9
  22. package/scripts/lib/installer_core.rb +17 -8
  23. package/scripts/lib/legacy_bookend_amnesty.rb +35 -0
  24. package/scripts/lib/release_guard.rb +62 -0
  25. package/scripts/lib/roadmap_queue.rb +285 -0
  26. package/scripts/lib/roadmap_savepoint.rb +213 -0
  27. package/scripts/lib/store_provisioning.rb +1 -1
  28. package/scripts/lib/worktree.rb +21 -0
  29. package/scripts/new-intent +2 -1
  30. package/scripts/read-config +3 -3
  31. package/scripts/roadmap-next +44 -0
  32. package/scripts/roadmap-savepoint +64 -0
  33. package/scripts/{versions.rb → rollback.rb} +33 -41
  34. package/scripts/update.rb +1 -1
  35. package/skills/_active-intent-gate.md +1 -1
  36. package/skills/_decision-tables.md +50 -0
  37. package/skills/auto/SKILL.md +69 -68
  38. package/skills/auto/evals/evals.json +4 -4
  39. package/skills/auto/references/agent-architecture.md +2 -2
  40. package/skills/continuing/SKILL.md +23 -130
  41. package/skills/continuing/evals/evals.json +26 -80
  42. package/skills/dashboard/SKILL.md +18 -15
  43. package/skills/dashboard/references/classification.md +3 -3
  44. package/skills/dashboard/templates/dashboard-global.md +8 -23
  45. package/skills/dashboard/templates/dashboard-project.md +7 -26
  46. package/skills/doctor/SKILL.md +3 -3
  47. package/skills/install/SKILL.md +10 -10
  48. package/skills/{brainstorming → intent-brainstorming}/SKILL.md +43 -45
  49. package/skills/intent-brainstorming/evals/evals.json +67 -0
  50. package/skills/{brainstorming → intent-brainstorming}/references/design-principles.md +12 -17
  51. package/skills/intent-continuing/SKILL.md +99 -0
  52. package/skills/intent-continuing/evals/evals.json +145 -0
  53. package/skills/intent-continuing/references/context-management.md +28 -0
  54. package/skills/{creating-intent → intent-creating}/SKILL.md +3 -3
  55. package/skills/{creating-intent → intent-creating}/evals/evals.json +1 -1
  56. package/skills/{intent-discovery → intent-discovering}/SKILL.md +1 -1
  57. package/skills/intent-ending/SKILL.md +151 -0
  58. package/skills/intent-ending/evals/evals.json +74 -0
  59. package/skills/{executing-plan → intent-executing}/SKILL.md +75 -15
  60. package/skills/intent-executing/evals/evals.json +66 -0
  61. package/skills/{brainstorming-grill-me → intent-grilling}/SKILL.md +4 -4
  62. package/skills/{linking-intents → intent-linking}/SKILL.md +1 -1
  63. package/skills/{linking-intents → intent-linking}/evals/evals.json +1 -1
  64. package/skills/{lock → intent-locking}/SKILL.md +1 -1
  65. package/skills/{writing-plans → intent-planning}/SKILL.md +48 -20
  66. package/skills/intent-planning/evals/evals.json +66 -0
  67. package/skills/{writing-plans → intent-planning}/references/plan-format.md +31 -7
  68. package/skills/{research → intent-researching}/SKILL.md +2 -2
  69. package/skills/{research → intent-researching}/evals/evals.json +1 -1
  70. package/skills/{savepoint → intent-savepoint}/SKILL.md +13 -1
  71. package/skills/intent-speccing/SKILL.md +69 -0
  72. package/skills/intent-speccing/evals/evals.json +126 -0
  73. package/skills/intent-speccing/references/per-section-fill-rules.md +92 -0
  74. package/skills/intent-speccing/references/self-verify-checklist.md +38 -0
  75. package/skills/intent-starting/SKILL.md +2 -2
  76. package/skills/intent-starting/evals/evals.json +2 -2
  77. package/skills/project-continuing/SKILL.md +104 -0
  78. package/skills/project-continuing/evals/evals.json +100 -0
  79. package/skills/project-continuing/references/board-fill.md +33 -0
  80. package/skills/{creating-project → project-creating}/SKILL.md +2 -2
  81. package/skills/releasing/SKILL.md +66 -14
  82. package/skills/releasing/references/release-lines.md +105 -0
  83. package/skills/roadmap/SKILL.md +7 -1
  84. package/skills/roadmap/references/file-format.md +30 -1
  85. package/skills/roadmap/references/operations.md +26 -6
  86. package/skills/roadmap-continuing/SKILL.md +85 -0
  87. package/skills/roadmap-continuing/evals/evals.json +82 -0
  88. package/skills/roadmap-continuing/references/liveness-ranking.md +56 -0
  89. package/skills/{versions → rollback}/SKILL.md +30 -20
  90. package/skills/{creating-skills → skill-creating}/SKILL.md +2 -2
  91. package/skills/{creating-skills → skill-creating}/evals/evals.json +5 -5
  92. package/skills/{creating-skills → skill-creating}/references/progressive-disclosure.md +2 -2
  93. package/skills/{evaluating-skills → skill-evaluating}/SKILL.md +1 -1
  94. package/skills/{evaluating-skills → skill-evaluating}/evals/evals.json +3 -3
  95. package/skills/{intent-curator → store-curating}/SKILL.md +6 -7
  96. package/skills/{intent-curator → store-curating}/evals/evals.json +1 -1
  97. package/skills/{managing-index → store-indexing}/SKILL.md +6 -7
  98. package/skills/{managing-index → store-indexing}/evals/evals.json +1 -1
  99. package/skills/{add-project-store → store-provisioning}/SKILL.md +2 -2
  100. package/skills/tutorial/SKILL.md +65 -0
  101. package/skills/tutorial/evals/evals.json +186 -0
  102. package/skills/tutorial/references/track-1-guided.md +123 -0
  103. package/skills/tutorial/references/track-2-auto.md +95 -0
  104. package/skills/tutorial/references/track-3-projects-and-roadmaps.md +110 -0
  105. package/skills/uninstall/SKILL.md +2 -2
  106. package/skills/update/SKILL.md +3 -3
  107. package/templates/agents.md +7 -7
  108. package/templates/config.yml +2 -1
  109. package/templates/index.md +4 -1
  110. package/skills/brainstorming/evals/evals.json +0 -22
  111. package/skills/savepoint/references/context-management.md +0 -32
  112. /package/skills/{creating-intent → intent-creating}/references/lifecycle.md +0 -0
  113. /package/skills/{creating-intent → intent-creating}/references/wikilinks.md +0 -0
  114. /package/skills/{executing-plan → intent-executing}/code-quality-reviewer-prompt.md +0 -0
  115. /package/skills/{executing-plan → intent-executing}/implementer-prompt.md +0 -0
  116. /package/skills/{executing-plan → intent-executing}/spec-reviewer-prompt.md +0 -0
  117. /package/skills/{linking-intents → intent-linking}/references/zettelkasten.md +0 -0
  118. /package/skills/{continuing → intent-savepoint}/references/context-management.md +0 -0
  119. /package/skills/{creating-project → project-creating}/references/hubs-projects.md +0 -0
  120. /package/skills/{creating-project → project-creating}/references/project-scaffolding.md +0 -0
  121. /package/skills/{creating-skills → skill-creating}/references/agents.md +0 -0
  122. /package/skills/{creating-skills → skill-creating}/references/evals.md +0 -0
  123. /package/skills/{creating-skills → skill-creating}/references/hooks.md +0 -0
  124. /package/skills/{creating-skills → skill-creating}/references/scripts.md +0 -0
  125. /package/skills/{creating-skills → skill-creating}/references/skills.md +0 -0
  126. /package/skills/{creating-skills → skill-creating}/scripts/scaffold.rb +0 -0
  127. /package/skills/{evaluating-skills → skill-evaluating}/assets/eval-template.json +0 -0
  128. /package/skills/{evaluating-skills → skill-evaluating}/references/convention-checks.md +0 -0
  129. /package/skills/{evaluating-skills → skill-evaluating}/references/eval-methodology.md +0 -0
  130. /package/skills/{managing-index → store-indexing}/references/zettelkasten-linking.md +0 -0
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: plastic-creating-project
2
+ name: plastic-project-creating
3
3
  description: >-
4
4
  Create a new project from an implementation intent. Sets up project directory,
5
5
  git init, AGENTS.md with founding intent decisions, plastic-install --local,
@@ -79,7 +79,7 @@ writes `INDEX.md` and `project.yml` only if missing. It is idempotent, so it is
79
79
  safe even when the tactical mirror in step 5 already created the store directory.
80
80
  Do not create the store with an inline `mkdir`; the provisioner is the only place
81
81
  a store is made. For a project that is already registered but store-less, use the
82
- `plastic-add-project-store` skill instead.
82
+ `plastic-store-provisioning` skill instead.
83
83
 
84
84
  ### 8. Mark Global Intent(s) Completed
85
85
 
@@ -15,6 +15,7 @@ Project configuration drives the workflow - no hardcoded assumptions.
15
15
  - [ ] All tests pass (or verification skipped per config)
16
16
  - [ ] Merge feature branch to main
17
17
  - [ ] Bump version in configured version files
18
+ - [ ] Stable-cut guard passes (version files agree, no pre-release suffix; stable/latest cuts only)
18
19
  - [ ] Commit version bump
19
20
  - [ ] Create annotated tag
20
21
  - [ ] Push to remote with tags
@@ -94,6 +95,25 @@ the full rationale and the already-merged-by-hand no-op case, read
94
95
 
95
96
  ### 4. Bump Version
96
97
 
98
+ **Stable-cut guard.** Before touching any version file for a stable (no pre-release suffix,
99
+ `latest`) cut, run the guard in `scripts/lib/release_guard.rb`:
100
+
101
+ ```ruby
102
+ require "./scripts/lib/release_guard"
103
+ result = ReleaseGuard.check(
104
+ package_json: "package.json",
105
+ plugin_json: ".claude-plugin/plugin.json",
106
+ marketplace_json: ".claude-plugin/marketplace.json",
107
+ stable: true
108
+ )
109
+ raise "release guard failed: #{result.mismatches} #{result.prerelease_suffix}" unless result.ok?
110
+ ```
111
+
112
+ If it reports a mismatch or a pre-release-suffix violation, stop and resolve it before bumping
113
+ any file. For a beta or alpha cut, pass `stable: false`; only version-file agreement is checked,
114
+ a pre-release suffix is expected. Read `references/release-lines.md` for the stable-line
115
+ guarantees this guard protects.
116
+
97
117
  Determine which files to update from project.yml:
98
118
 
99
119
  - If `release.version_files` is set: update ALL listed files (they must stay in sync).
@@ -214,26 +234,30 @@ gh release edit <tag-name> --latest
214
234
 
215
235
  ### 8. Complete Active Intent
216
236
 
217
- A release IS a delivery. The active intent that drove this work must be completed as part of the release process. This is NOT optional.
237
+ A release IS a delivery. The active intent that drove this work must be completed as part of the release process. This is NOT optional. The mechanical close (outcome/INDEX/savepoint/commit) is `plastic-intent-ending`'s job, not this skill's: run its backing script rather than restating that prose here.
218
238
 
219
- 1. Read `~/.plastic/INDEX.md` find active intent(s) related to this release
239
+ 1. Read `~/.plastic/INDEX.md` (or the project's INDEX.md) - find active intent(s) related to this release.
220
240
  2. For each active intent being delivered:
221
- a. Write `outcome.md` with detailed results
222
- b. Write `## Outcome` summary in the intent file (reference the release tag)
223
- c. Update `## Insights` with final observations
224
- d. Move from `## Active` to `## Completed` in INDEX.md (with today's date)
225
- e. Update clusters to show `_(completed)_`
226
- 3. Auto-commit: `cd ~/.plastic && git add . && git commit -m "feat: complete intent <ID> - delivered in <tag-name>"`
241
+ a. Write a real `outcome.md` (never leave the scaffold placeholder), `disposition: delivered`, referencing the release tag.
242
+ b. Update `## Insights` with final observations.
243
+ c. Run the mechanical close (steps 1-4 of `plastic-intent-ending`): this stamps the intent file's `## Outcome` summary, moves the INDEX.md line to `## Completed` (dated today, with a rich entry description via `--index-note`), appends the savepoint `Done` bookend, and commits the store, all in one call:
244
+ ```bash
245
+ ruby ~/.plastic/scripts/end-intent --store <store_path> --id <ID> --disposition delivered \
246
+ --outcome-summary "delivered in <tag-name>: <one-line summary>" \
247
+ --index-note "<tag-name>, <mode/tier>; <what shipped>; <suite result>"
248
+ ```
249
+ d. Update clusters to show `_(completed)_` (the store-curating skill's job on its next pass).
227
250
 
228
251
  **If no active intent exists for this release**, that itself is a problem - work happened outside the intent system. Log it and move on, but flag it.
229
252
 
230
253
  ### 9. Clean Up the Intent's Worktrees (merge-then-remove)
231
254
 
232
- A release is the merge-then-remove path for the intent's worktrees (intent 73c3): the
233
- intent's code branch is merged back into the default branch BEFORE the worktree is removed.
234
- Drive it through `Worktree.finish` with `merge: true`, which merges the code branch, then
235
- removes both worktrees (code + paired store), prunes both repos, and clears the worktree block
236
- from the bridge:
255
+ This is the release branch of `plastic-intent-ending`'s Step 5 disarm (`merge: true`), not a
256
+ separate concern: a release is the merge-then-remove path for the intent's worktrees (intent
257
+ 73c3), so the intent's code branch is merged back into the default branch BEFORE the worktree
258
+ is removed. Drive it through `Worktree.finish` with `merge: true`, which merges the code
259
+ branch, then removes both worktrees (code + paired store), prunes both repos, and clears the
260
+ worktree block from the bridge:
237
261
 
238
262
  ```bash
239
263
  ruby -r ~/.plastic/scripts/lib/worktree -r ~/.plastic/scripts/lib/bridge -e \
@@ -241,13 +265,39 @@ ruby -r ~/.plastic/scripts/lib/worktree -r ~/.plastic/scripts/lib/bridge -e \
241
265
  ```
242
266
 
243
267
  (Uses `discover_bridge`, not a bare session-keyed `Bridge.read`, because a session can own more
244
- than one live bridge now intent 131 and `discover_bridge` resolves the right one for this cwd.)
268
+ than one live bridge now (intent 131) and `discover_bridge` resolves the right one for this cwd.)
245
269
 
246
270
  Honor the worktree-cleanup rule: never leave an orphaned worktree, and run `git worktree
247
271
  prune` in the affected repo if you hit a stale reference. For why this is the one place the
248
272
  merge-vs-remove policy lands on merge, and the fail-open/idempotent guarantees of `finish`,
249
273
  read `references/promotion-and-tagging.md`.
250
274
 
275
+ ## Release lines and channels
276
+
277
+ Two lanes get code to a release, on top of the workflow above.
278
+
279
+ - **Default lane.** Branch, merge to main, cut stable, publish to npm `latest`. This is the
280
+ workflow in the steps above, unchanged. Use it for additive, suite-verifiable,
281
+ low-blast-radius work.
282
+ - **Beta-verified lane.** Branch, merge to `beta`, publish to the npm `beta` channel, verify in
283
+ real use, then merge to main and cut stable. Use it for work that changes operational
284
+ substrate, or carries data, migration, lock, or state-format risk, or that a hermetic suite
285
+ cannot fully validate on its own.
286
+
287
+ **Stable-line guarantees.** An external `latest` user can rely on:
288
+
289
+ - `main` is always green and releasable; no pending revert awaiting re-land sits on `main`.
290
+ - A stable release carries no pre-release suffix, publishes to `latest`, and the newest release
291
+ always carries the GitHub "Latest" badge.
292
+ - The three version files always agree, checked by `scripts/lib/release_guard.rb` (see Bump
293
+ Version above).
294
+ - A stable cut collects only intents that cleared their lane's verification bar.
295
+ - Channel semantics are fixed: `latest` is stable, `beta` is the verification line, `alpha` is
296
+ experimental.
297
+
298
+ Read `references/release-lines.md` for the full lane-routing detail, the version-line map, and
299
+ the intent-41 re-land playbook.
300
+
251
301
  ## Conventions
252
302
 
253
303
  - **Annotated tags only** - `git tag -a`, never lightweight tags
@@ -262,6 +312,8 @@ read `references/promotion-and-tagging.md`.
262
312
 
263
313
  ## References
264
314
 
315
+ - Read `references/release-lines.md` for the two release lanes, the stable-line guarantees,
316
+ the version-line map, and the intent-41 re-land playbook before starting any release
265
317
  - When promoting a pre-release across channels (`--promote beta`/`--promote stable`) or
266
318
  tagging a historical release retroactively, read `references/promotion-and-tagging.md`
267
319
  for the exact commands and rules first
@@ -0,0 +1,105 @@
1
+ # Release Lines and Channels
2
+
3
+ The two release lanes, the version-line map, and the intent-41 re-land playbook: the deep
4
+ material behind SKILL.md's "Release lines and channels" section.
5
+
6
+ ## Table of Contents
7
+
8
+ - [The two lanes](#the-two-lanes)
9
+ - [Routing rule](#routing-rule)
10
+ - [Stable-line guarantees](#stable-line-guarantees)
11
+ - [Version-line map](#version-line-map)
12
+ - [Intent 41 re-land playbook](#intent-41-re-land-playbook)
13
+
14
+ ## The two lanes
15
+
16
+ **Default lane.** Branch, merge to `main` with `--no-ff`, cut stable, publish to npm `latest`.
17
+ This is the workflow SKILL.md documents step by step. It is the path for additive,
18
+ suite-verifiable, low-blast-radius work: new skills, prose, deterministic scripts, anything a
19
+ green Minitest run can fully vouch for.
20
+
21
+ **Beta-verified lane.** Branch, merge to the `beta` branch, publish to the npm `beta` dist-tag,
22
+ verify in real use, then merge `beta` into `main` and cut stable. It sits on top of the existing
23
+ promotion mechanics (`--promote beta` / `--promote stable`, linear only, see
24
+ `promotion-and-tagging.md`); it names when to use them, not new machinery.
25
+
26
+ ## Routing rule
27
+
28
+ Work rides the beta-verified lane when it changes operational substrate, carries data,
29
+ migration, lock, or state-format risk, or cannot be fully validated by a hermetic suite alone.
30
+ Everything else merges straight to main.
31
+
32
+ Intent 41's DB layer is the archetypal beta-lane case: it replaces the bridge, lock, and session
33
+ file formats with a new persistent SQLite substrate. A green suite proves the code correct; it
34
+ cannot prove the new substrate survives real, uncontrolled usage, so real-use verification on
35
+ beta comes first.
36
+
37
+ The manual-first roadmap's eight 1.1.0 intents (158a, 163, 161, 164, 165, 168, 166, 159) are all
38
+ default-lane: skill directory renames, prose rewrites, deterministic step scripts. Additive, and
39
+ fully suite-verified.
40
+
41
+ ## Stable-line guarantees
42
+
43
+ What an external `latest` user can rely on:
44
+
45
+ 1. `main` is always green and releasable. No pending revert awaiting re-land sits on `main`.
46
+ When something needs beta verification, it comes out of `main` the same day that need is
47
+ found (the 226023f precedent), never left half-landed.
48
+ 2. A stable release carries no pre-release suffix, publishes to npm `latest`, and the newest
49
+ stable release always carries the GitHub "Latest" badge (`gh release create --latest` on
50
+ every cut).
51
+ 3. The three repo version files (`package.json`, `.claude-plugin/plugin.json`,
52
+ `.claude-plugin/marketplace.json`) always agree. Checked mechanically by
53
+ `scripts/lib/release_guard.rb`.
54
+ 4. A stable cut collects only intents that cleared their lane's bar: default-lane intents by a
55
+ green suite, beta-lane intents by suite green plus their lane's own verification (real-use
56
+ signal, owner sign-off).
57
+ 5. Channel semantics are fixed: `latest` is stable and what an external user should run; `beta`
58
+ is the verification line, published but expected to move; `alpha` is experimental,
59
+ pre-verification.
60
+
61
+ ## Version-line map
62
+
63
+ | Line | State | What lands here |
64
+ |---|---|---|
65
+ | `1.1.x` | Current stable line (main) | Additive or low-risk work merged straight to main; interim stable cuts, including 171's wave-6 cut, stay in this line |
66
+ | `1.2.0-beta.1` | On beta (`9ec194b`, unpublished) | Intent 41's DB layer, restored over 1.1.0 by revert-of-revert (`c48601a` then `9ec194b`) |
67
+ | `1.2.0` | Reserved | The stable graduation of the DB layer, once beta verification passes; not claimed by any interim `1.1.x` cut |
68
+
69
+ A beta-graduated substrate change claims its reserved minor at the moment it actually merges to
70
+ main, not before. Nothing else on the `1.1.x` line is blocked waiting for `1.2.0`.
71
+
72
+ ## Intent 41 re-land playbook
73
+
74
+ Written for the wave-6 cut intent (171) and any future reader to pick a version without
75
+ re-deriving this decision.
76
+
77
+ **Current state.** The revert-of-revert already sits on the `beta` branch at `9ec194b`, on top
78
+ of 1.1.0, versioned `1.2.0-beta.1` (`c48601a`). There is nothing left to execute on the git side;
79
+ this playbook describes what happens next, not a pending action.
80
+
81
+ **Preconditions**, both required before any npm publish of `1.2.0-beta.1`:
82
+
83
+ - (a) One documentation pass over beta-line skills and docs for the hybrid savepoint contract:
84
+ on beta, only the terminal Done bookend still writes a live `savepoint.md`; every other
85
+ milestone lives in `savepoint_events` plus a committed JSONL export. Beta-line prose that
86
+ still assumes an always-live ledger needs updating first, so a beta-line reader does not
87
+ mistake an empty ledger for a broken one.
88
+ - (b) The owner's manual verification of the DB layer in real use. This is a dogfood signal,
89
+ distinct from the independently-reviewed green suite that already exists on beta.
90
+
91
+ **Trigger**, owner-gated: the owner publishes `1.2.0-beta.1` to the npm `beta` dist-tag. This is
92
+ explicitly not this intent's, nor any agent's, call to make.
93
+
94
+ **Verification.** An external tester plus the owner verify the DB layer on the beta channel.
95
+
96
+ **Completion.** Once verified, `beta` merges into `main`, `1.2.0` is cut stable, and it publishes
97
+ to npm `latest`.
98
+
99
+ **Version mechanics.** `1.2.0` is reserved for this graduation. The `1.1.x` line stays the
100
+ stable line until `1.2.0` actually lands. `1.2.0-beta.1` graduates to `1.2.0` stable by dropping
101
+ the pre-release suffix; nothing else about the version number changes.
102
+
103
+ **Consumed by 171.** The wave-6 consistency-dividend cut stays in the `1.1.x` line. It does not
104
+ ride intent 41 and needs no further derivation: intent 41 keeps its own `1.2.0` line on beta,
105
+ independent of whatever `1.1.x` number 171 lands on.
@@ -21,7 +21,10 @@ wave entry mirrors that intent's status in `INDEX.md` (`queued`/`delivering`/`de
21
21
  **`INDEX.md` is the single writer of intent status; on any conflict INDEX wins and the roadmap
22
22
  entry is corrected to match.**
23
23
 
24
- The skill operates on the file directly via Read/Edit; no helper script.
24
+ The skill operates on the roadmap file directly via Read/Edit. The one deterministic helper it
25
+ uses is the savepoint ledger writer (`scripts/roadmap-savepoint`, `append`/`rebuild`); every verb's
26
+ closing step calls `append` after its Read/Edit, and the roadmap `.md` file itself stays
27
+ Read/Edit-only.
25
28
 
26
29
  ## Verbs
27
30
 
@@ -50,3 +53,6 @@ verb above.
50
53
  - Additive: this skill introduces no gate, lock, or hook, and does not change `INDEX.md`'s section
51
54
  list or the intent frontmatter schema.
52
55
  - Closing a roadmap moves it to `roadmaps/archived/{slug}.md` so `roadmaps/` lists only live ones.
56
+ - Every verb also appends a machine ledger line to the roadmap's name-paired
57
+ `roadmaps/{slug}.savepoint.md`, the derived counterpart to the human `## Log`; see
58
+ `references/file-format.md` for its shape and location.
@@ -11,7 +11,9 @@ roadmap.
11
11
 
12
12
  `roadmaps/` lists only live (open or in-flight) roadmaps. Once a roadmap's `## Goal` is reached,
13
13
  its file moves to `roadmaps/archived/{slug}.md` (see Close/archive in `operations.md`); the
14
- `archived/` subdirectory is scaffolded once, alongside `roadmaps/`, with a `.gitkeep`.
14
+ `archived/` subdirectory is scaffolded once, alongside `roadmaps/`, with a `.gitkeep`. Its
15
+ name-paired ledger, `roadmaps/{slug}.savepoint.md` (see Savepoint ledger below), moves alongside
16
+ it in the same Close/archive step.
15
17
 
16
18
  ## The four sections (in order)
17
19
 
@@ -63,6 +65,33 @@ that entry-intent's `outcome.md`:
63
65
  The log line never restates `outcome.md` detail; it points at it (lossless-by-reference). This
64
66
  complements, and does not replace, `INDEX.md`'s `## Completed` section or `CHANGELOG.md`.
65
67
 
68
+ ## Savepoint ledger
69
+
70
+ `roadmaps/{slug}.savepoint.md` is the name-paired sibling of `roadmaps/{slug}.md`: the machine
71
+ counterpart to the human `## Log`, moving to `roadmaps/archived/{slug}.savepoint.md` alongside its
72
+ roadmap on close (see Close/archive). It is created lazily by the first `append` call; there is no
73
+ template to scaffold.
74
+
75
+ Line shape, one event per line, append-only, newest at the bottom:
76
+
77
+ ```
78
+ <UTC-iso8601> <event> <detail>
79
+ ```
80
+
81
+ Two-space fields, mirroring the intent-dir cycle-step ledger (`savepoint.md`). The controlled event
82
+ vocabulary: `created`, `dispatched`, `parked`, `merged`, `release`, `handoff`, `closed`, and
83
+ optionally `added`, `reordered`, `wave`. The `(event, detail)` pair is the idempotency key, so
84
+ re-appending the same pair is a no-op.
85
+
86
+ `## Log` and the ledger record the same events in two voices: the Log is the dated, one-sentence,
87
+ EM-to-CTO-plain-language record a human reads cold; the ledger is the terse, machine-timestamped,
88
+ controlled-vocabulary record a coordinator reads at a glance. Both are append-only; neither edits
89
+ the other.
90
+
91
+ The ledger is derived and rebuildable (`ruby ~/.plastic/scripts/roadmap-savepoint rebuild --roadmap
92
+ roadmaps/{slug}.md`, reconstructing it from `## Log`), never a status source: `INDEX.md` stays the
93
+ single writer of intent status, exactly as for the roadmap file itself.
94
+
66
95
  ## Worked example
67
96
 
68
97
  ```
@@ -20,7 +20,10 @@ next" in under a minute, just from this one file.
20
20
  status mirroring that intent's current `INDEX.md` status.
21
21
  6. Append the first `## Log` line, a short `YYYY-MM-DD HH:MM UTC`-prefixed plain-language note
22
22
  that the roadmap was created.
23
- 7. Refresh the QMD index for this roadmap (no-op when QMD is absent), in the background so it
23
+ 7. Append the ledger event (derived, idempotent, safe to re-run; never writes INDEX or roadmap
24
+ status; creates `roadmaps/<slug>.savepoint.md` lazily): `ruby ~/.plastic/scripts/roadmap-savepoint
25
+ append --roadmap roadmaps/<slug>.md --event created --detail "<slug>: <title>"`.
26
+ 8. Refresh the QMD index for this roadmap (no-op when QMD is absent), in the background so it
24
27
  never blocks: `ruby ~/.plastic/scripts/qmd-sync reindex --store <roadmaps-dir> --async`.
25
28
 
26
29
  ## Add / reorder entries
@@ -34,6 +37,10 @@ next" in under a minute, just from this one file.
34
37
  entry is eligible to run.
35
38
  - After any add/reorder, append a `## Log` line describing the change (e.g.
36
39
  `- <YYYY-MM-DD HH:MM UTC> added 132 to wave 2`).
40
+ - Append the ledger event (derived, idempotent, safe to re-run; never writes INDEX or roadmap
41
+ status): `ruby ~/.plastic/scripts/roadmap-savepoint append --roadmap roadmaps/<slug>.md --event
42
+ added --detail "<id> to wave N"` for an add, or `--event reordered` for a reorder (describe the
43
+ move in `<detail>`).
37
44
  - Refresh the QMD index for this roadmap (no-op when QMD is absent), in the background so it
38
45
  never blocks: `ruby ~/.plastic/scripts/qmd-sync reindex --store <roadmaps-dir> --async`.
39
46
 
@@ -49,7 +56,12 @@ next" in under a minute, just from this one file.
49
56
  one-line EM-to-CTO entry described in `file-format.md` (date, what shipped and its impact in
50
57
  plain language, then a link to that intent's `outcome.md`). For other transitions, write a
51
58
  short dated plain-language line (no codenames, no jargon).
52
- 5. Refresh the QMD index for this roadmap (no-op when QMD is absent), in the background so it
59
+ 5. Append the ledger event, only when the status token actually changed (derived, idempotent,
60
+ never writes INDEX or roadmap status): map the new status to its mechanized event (`delivered`
61
+ -> `merged`, `delivering` -> `dispatched`, `blocked`/`abandoned` -> `parked`), then `ruby
62
+ ~/.plastic/scripts/roadmap-savepoint append --roadmap roadmaps/<slug>.md --event <event>
63
+ --detail "<intent-id>"` (add a sha in `<detail>` when one is known).
64
+ 6. Refresh the QMD index for this roadmap (no-op when QMD is absent), in the background so it
53
65
  never blocks: `ruby ~/.plastic/scripts/qmd-sync reindex --store <roadmaps-dir> --async`.
54
66
 
55
67
  ## Append a log line
@@ -60,6 +72,10 @@ next" in under a minute, just from this one file.
60
72
  A delivery event follows the EM-to-CTO one-line shape with an `outcome.md` link (see
61
73
  `file-format.md`); bookkeeping events (created, an intent added to a wave, a wave completed, a
62
74
  roadmap closed) are short dated plain-language lines.
75
+ - Append the matching ledger event (derived, idempotent, never writes INDEX or roadmap status):
76
+ when the line records a release cut, `ruby ~/.plastic/scripts/roadmap-savepoint append --roadmap
77
+ roadmaps/<slug>.md --event release --detail "<version>"`; otherwise append the mechanized event
78
+ matching the bookkeeping line just written (see the per-verb event mapping on this page).
63
79
  - Refresh the QMD index for this roadmap (no-op when QMD is absent), in the background so it
64
80
  never blocks: `ruby ~/.plastic/scripts/qmd-sync reindex --store <roadmaps-dir> --async`.
65
81
 
@@ -80,9 +96,13 @@ next" in under a minute, just from this one file.
80
96
  `abandoned` with a recorded reason, plus whatever else the goal states).
81
97
  2. Create `roadmaps/archived/` beside `roadmaps/` (both siblings of `INDEX.md`) if it does not
82
98
  exist yet.
83
- 3. Move the file: `roadmaps/{slug}.md` -> `roadmaps/archived/{slug}.md`. `roadmaps/` itself then
84
- lists only live (open or in-flight) roadmaps.
85
- 4. Append the final `## Log` line before or as part of the move:
99
+ 3. Append the ledger closed event, while the roadmap is still at its live path (derived,
100
+ idempotent, never writes INDEX or roadmap status): `ruby ~/.plastic/scripts/roadmap-savepoint
101
+ append --roadmap roadmaps/<slug>.md --event closed --detail "<slug>"`.
102
+ 4. Move BOTH files: `roadmaps/{slug}.md` -> `roadmaps/archived/{slug}.md` AND
103
+ `roadmaps/{slug}.savepoint.md` -> `roadmaps/archived/{slug}.savepoint.md`. `roadmaps/` itself
104
+ then lists only live (open or in-flight) roadmaps.
105
+ 5. Append the final `## Log` line before or as part of the move:
86
106
  `- <YYYY-MM-DD HH:MM UTC> roadmap closed`.
87
- 5. Refresh the QMD index for this roadmap (no-op when QMD is absent), in the background so it
107
+ 6. Refresh the QMD index for this roadmap (no-op when QMD is absent), in the background so it
88
108
  never blocks: `ruby ~/.plastic/scripts/qmd-sync reindex --store <roadmaps-dir> --async`.
@@ -0,0 +1,85 @@
1
+ ---
2
+ name: plastic-roadmap-continuing
3
+ description: >-
4
+ Use when the user wants to continue or resume a roadmap, pick up a mid-flight delivery batch,
5
+ asks "where is the roadmap", or wants to resume the wave that was shipping, including an
6
+ indirect ask that never names a roadmap directly (for example "where did that batch of
7
+ tickets land"). This is the roadmap route of plastic-continuing: it finds the tier's
8
+ mid-flight roadmap, presents its state, then asks how to proceed exactly once.
9
+ user-invocable: true
10
+ ---
11
+
12
+ # Roadmap Continuing - resume the mid-flight roadmap
13
+
14
+ `plastic-roadmap-continuing` is the roadmap route of `plastic-continuing`. It finds the tier's
15
+ mid-flight roadmap, presents its state, then asks the user how to proceed, exactly once.
16
+
17
+ Before intent 158a1 there was no automated way to do this: the `171` (consistency-dividend)
18
+ roadmap handoff had to be resumed by hand, carried as a free-prose note in `171`'s own
19
+ `## Insights`. This skill closes that gap.
20
+
21
+ ## Find the mid-flight roadmap
22
+
23
+ 1. Determine the tier (project vs. global) and enumerate that tier's live `roadmaps/*.md`
24
+ (exclude `roadmaps/archived/`). Read via Read/glob, or `plastic-roadmap`'s Read/consume
25
+ verb. See `plastic-roadmap`'s `references/file-format.md` for the file grammar; do not
26
+ duplicate it here.
27
+ 2. For each candidate, also read its paired ledger `roadmaps/<slug>.savepoint.md` when present
28
+ (see `plastic-roadmap`'s `references/file-format.md#savepoint-ledger`): its last line(s) are a
29
+ cheaper, precise last-event signal (for example `dispatched 134` or `merged 172`), read
30
+ alongside the existing `## Waves`/`## Log` judgment. The ledger is read-only here, a derived
31
+ signal, never a new status field; INDEX.md stays the sole status writer.
32
+ 3. Rank liveness by calling the shared reader in which mode (one implementation across the
33
+ auto loop and this skill):
34
+
35
+ ```bash
36
+ ruby ~/.plastic/scripts/roadmap-next --roadmaps-dir <tier>/roadmaps --which
37
+ ```
38
+
39
+ Read `state` and the winning `roadmap`. When `state` is `tie`, `tie_candidates` lists the
40
+ equally-live roadmaps to present side by side; the single "auto or guided?" ask below
41
+ doubles as the resolution. `roadmap-next` liveness-ranks the same way this skill used to do
42
+ by eye (a `delivering` or `blocked` entry wins, else the newest ledger or `## Log`
43
+ timestamp), now deterministically. See `references/liveness-ranking.md` for the algorithm it
44
+ implements.
45
+ 4. A genuine tie (two candidates equally live) is presented to the user and resolved by the
46
+ single ask below, not silently picked.
47
+
48
+ ## Present state
49
+
50
+ Present the chosen roadmap's `## Goal`, the current wave with each entry's mirrored status, the
51
+ ledger's newest line(s) (the last mechanized event) alongside the newest `## Log` line, before any
52
+ ask, so the coordinator sees the machine last-event at a glance.
53
+
54
+ ## Ask once
55
+
56
+ Ask "auto or guided?" exactly once, after presenting state, mirroring
57
+ `plastic-intent-starting`'s single-ask contract:
58
+ - **guided** -> continue step by step with the user.
59
+ - **auto** -> hand off to `plastic-auto` to drive the next wave or entry.
60
+
61
+ Never re-ask. No new roadmap or INDEX status field is invented anywhere in this flow.
62
+
63
+ ## The shared reader
64
+
65
+ Liveness ranking and frontier selection live in one place, `scripts/lib/roadmap_queue.rb`
66
+ (intent 148), behind the `scripts/roadmap-next` CLI. This skill calls it in which mode rather
67
+ than ranking roadmaps in prose, so the auto loop (`plastic-auto`) and this skill share exactly
68
+ one implementation (no forked ranking logic). 158a1 originally added no script because the
69
+ benefit was marginal for a read-time judgment; the auto-loop consumer flipped that calculus by
70
+ making the ranking load-bearing and deterministic. The reader is read-only: it consumes the
71
+ roadmap `.md`, the 134 `<slug>.savepoint.md` ledger, and INDEX.md, and writes nothing. INDEX.md
72
+ stays the single status writer.
73
+
74
+ ## Caller contract: who writes the ledger
75
+
76
+ This skill is a reader, not a writer, of `roadmaps/<slug>.savepoint.md`. The coordinator flows
77
+ (`plastic-auto`, the enforcer, and this skill's own resume-and-hand-off path) call `ruby
78
+ ~/.plastic/scripts/roadmap-savepoint append` at their own dispatch, merge, park, handoff, and
79
+ release points, the same events `plastic-roadmap`'s verbs append at their closing steps. A
80
+ resuming coordinator therefore both reads the ledger here and writes to it as it drives the next
81
+ wave or entry.
82
+
83
+ ## References
84
+
85
+ - `references/liveness-ranking.md` - the read-time ranking algorithm and the tie rule.
@@ -0,0 +1,82 @@
1
+ {
2
+ "skill_name": "plastic-roadmap-continuing",
3
+ "notes": "Intent 158a1. New roadmap route, closing the gap that forced the 171 (consistency-dividend) roadmap handoff to be resumed by hand. Scopes: description triggering (1-3) and behavior/convention compliance (4-8), the latter checked against SKILL.md.",
4
+ "results": {
5
+ "triggering": { "cases": 3, "passed": 3, "run": "2026-07-10, one subagent per case" },
6
+ "behavior": { "cases": 5, "passed": 5, "evidence": "convention checks against skills/roadmap-continuing/SKILL.md and references/liveness-ranking.md" }
7
+ },
8
+ "evals": [
9
+ {
10
+ "id": 1, "scope": "triggering", "set": "train",
11
+ "prompt": "continue the roadmap",
12
+ "expected_output": "Activates plastic-roadmap-continuing.",
13
+ "files": [],
14
+ "assertions": [
15
+ { "type": "code", "check": "router CHOICE == plastic-roadmap-continuing", "observed": "plastic-roadmap-continuing", "result": "pass" }
16
+ ]
17
+ },
18
+ {
19
+ "id": 2, "scope": "triggering", "set": "train",
20
+ "prompt": "resume the delivery batch we were shipping",
21
+ "expected_output": "Activates plastic-roadmap-continuing.",
22
+ "files": [],
23
+ "assertions": [
24
+ { "type": "code", "check": "router CHOICE == plastic-roadmap-continuing", "observed": "plastic-roadmap-continuing", "result": "pass" }
25
+ ]
26
+ },
27
+ {
28
+ "id": 3, "scope": "triggering", "set": "validation",
29
+ "prompt": "where did that batch of tickets land",
30
+ "expected_output": "Activates plastic-roadmap-continuing (indirect trigger: a roadmap-resume request that never names 'roadmap' or 'continue').",
31
+ "files": [],
32
+ "assertions": [
33
+ { "type": "code", "check": "router CHOICE == plastic-roadmap-continuing", "observed": "plastic-roadmap-continuing", "result": "pass" }
34
+ ]
35
+ },
36
+ {
37
+ "id": 4, "scope": "behavior", "set": "train",
38
+ "prompt": "Does the skill rank liveness correctly when a wave entry is delivering or blocked?",
39
+ "expected_output": "A roadmap with any delivering/blocked wave entry wins the ranking outright over every other candidate.",
40
+ "files": ["skills/roadmap-continuing/references/liveness-ranking.md"],
41
+ "assertions": [
42
+ { "type": "convention", "check": "delivering/blocked-wins rule documented as step 2 of the algorithm", "observed": "present", "result": "pass" }
43
+ ]
44
+ },
45
+ {
46
+ "id": 5, "scope": "behavior", "set": "train",
47
+ "prompt": "Does the skill fall back to newest Log date when no candidate is delivering/blocked?",
48
+ "expected_output": "Among remaining candidates, the most recent ## Log entry timestamp wins.",
49
+ "files": ["skills/roadmap-continuing/references/liveness-ranking.md"],
50
+ "assertions": [
51
+ { "type": "convention", "check": "newest-Log-date fallback documented as step 3", "observed": "present", "result": "pass" }
52
+ ]
53
+ },
54
+ {
55
+ "id": 6, "scope": "behavior", "set": "train",
56
+ "prompt": "Does the skill present the roadmap state before asking?",
57
+ "expected_output": "The '## Present state' section (Goal, current wave, newest Log line) runs before the '## Ask once' section.",
58
+ "files": ["skills/roadmap-continuing/SKILL.md"],
59
+ "assertions": [
60
+ { "type": "convention", "check": "Present state precedes Ask once in document order", "observed": "present", "result": "pass" }
61
+ ]
62
+ },
63
+ {
64
+ "id": 7, "scope": "behavior", "set": "validation",
65
+ "prompt": "Does the skill ask 'auto or guided?' exactly once?",
66
+ "expected_output": "Exactly one ask, after presenting state; never re-asked.",
67
+ "files": ["skills/roadmap-continuing/SKILL.md"],
68
+ "assertions": [
69
+ { "type": "convention", "check": "the literal phrase 'auto or guided' appears on exactly one line of SKILL.md", "observed": "one occurrence", "result": "pass" }
70
+ ]
71
+ },
72
+ {
73
+ "id": 8, "scope": "behavior", "set": "validation",
74
+ "prompt": "Does the skill invent a new roadmap or INDEX status field, or add a new script?",
75
+ "expected_output": "No. Liveness is computed at read time from existing files; INDEX.md stays the sole status writer; the enumeration/ranking is prose, not a helper script.",
76
+ "files": ["skills/roadmap-continuing/SKILL.md", "skills/roadmap-continuing/references/liveness-ranking.md"],
77
+ "assertions": [
78
+ { "type": "convention", "check": "no new field or script introduced; 'No new script' section present", "observed": "present", "result": "pass" }
79
+ ]
80
+ }
81
+ ]
82
+ }
@@ -0,0 +1,56 @@
1
+ # Liveness Ranking (read time, no new field)
2
+
3
+ Depth reference for "Find the mid-flight roadmap" in `SKILL.md`. This is the full algorithm the
4
+ body summarizes. Since intent 148, this algorithm is IMPLEMENTED in
5
+ `scripts/lib/roadmap_queue.rb` behind the `scripts/roadmap-next` CLI; it is no longer a by-eye
6
+ procedure. This page documents what that reader does, and is the specification the reader
7
+ satisfies.
8
+
9
+ ## Why read-time, not a stored field
10
+
11
+ INDEX.md stays the sole writer of intent status; the roadmap file mirrors it (see
12
+ `plastic-roadmap`'s `references/file-format.md`). Adding a "mid-flight" flag to the roadmap
13
+ file or to INDEX.md would create a second thing to keep in sync for a question that is cheap to
14
+ answer by reading what is already there. So liveness is computed fresh, every call, from the
15
+ tier's live `roadmaps/*.md` files (excluding `roadmaps/archived/`), by `RoadmapQueue` (intent
16
+ 148) rather than by eye.
17
+
18
+ ## The algorithm
19
+
20
+ 1. **Enumerate.** List every `roadmaps/*.md` at the tier (project or global), skipping
21
+ `roadmaps/archived/`.
22
+ 2. **Delivering/blocked wins outright.** If any candidate roadmap has at least one `## Waves`
23
+ entry whose mirrored status token is `delivering` or `blocked`, it is in flight right now.
24
+ That candidate wins the ranking immediately; skip the rest of the ranking for it.
25
+ 3. **Otherwise, newest `## Log` entry wins.** Among the remaining candidates (none have a
26
+ `delivering`/`blocked` entry), read each file's last `## Log` line (append-only, newest at
27
+ the bottom) and rank by that line's `YYYY-MM-DD HH:MM UTC` timestamp. The most recent wins.
28
+ When a candidate's paired `roadmaps/<slug>.savepoint.md` (intent 134) is present, its last
29
+ line is a cheaper, machine-timestamped read of the same fact (the ledger is derived from `##
30
+ Log`, so the two should already agree); reading it first is an optimization, not a second
31
+ source of truth, so a missing or stale ledger never blocks falling back to `## Log` itself.
32
+ 4. **Genuine tie -> present, do not silently pick.** If two or more candidates are equally live
33
+ (for example two roadmaps both idle with `## Log` entries on the same timestamp, or two both
34
+ showing `delivering` entries with no other signal to separate them), do not choose for the
35
+ user. Present both/all tied candidates' state side by side, then let the single "auto or
36
+ guided?" ask (asked once regardless of how many candidates were presented) double as the
37
+ resolution: the user's answer implicitly picks by naming which roadmap to continue, or the
38
+ agent asks a short one-line disambiguation immediately before that same single ask, never a
39
+ second separate prompt.
40
+
41
+ ## What this closes
42
+
43
+ Before this skill existed, nothing resumed a mid-flight roadmap automatically. The `171`
44
+ (consistency-dividend) roadmap handoff had to be resumed by hand: a free-prose "SESSION
45
+ HANDOFF" note written into `171`'s own `## Insights`, because nothing read `## Waves` +
46
+ `## Log` and reconstructed where the batch stood. This ranking, now a deterministic reader
47
+ rather than a by-eye judgment, is the mechanism that replaces that hand-carried note.
48
+
49
+ ## Grammar pointer (do not duplicate)
50
+
51
+ The roadmap file's four sections, entry line shape, and status vocabulary
52
+ (`queued|delivering|delivered|abandoned|blocked`) are owned by `plastic-roadmap`:
53
+ `skills/roadmap/references/file-format.md` for the shape, and
54
+ `skills/roadmap/references/operations.md#read--consume` for how a reader (human or
55
+ coordinator) is meant to walk `## Waves` and `## Log`. This page assumes that grammar and adds
56
+ only the liveness-ranking judgment on top of it.