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

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.
@@ -11,8 +11,16 @@
11
11
  # `now:` seam is the test seam; the CLI uses the default Time.now, which is fine
12
12
  # because determinism is covered at the library level (test/insights_test.rb).
13
13
  #
14
+ # --rule (intent 341, G8, C37): tags the entry as a rule, not just an
15
+ # observation, by prepending the literal "rule: " onto the text before it
16
+ # ever reaches Insights.append_insight; the library itself stays untouched,
17
+ # since a tag is a text-level convention, not a new field on the ledger.
18
+ # Doctor's unpromoted_rules check (scripts/doctor.rb) later lists any tagged
19
+ # entry whose exact text no skills/conventions/references/*.md chapter
20
+ # carries yet.
21
+ #
14
22
  # Usage:
15
- # insight-append <intent_dir> <text> --stage S --author A
23
+ # insight-append <intent_dir> <text> --stage S --author A [--rule]
16
24
  #
17
25
  # Exit codes: 0 (entry appended), 2 (usage).
18
26
 
@@ -21,6 +29,7 @@ require_relative "lib/insights"
21
29
  def parse_args(argv)
22
30
  stage = nil
23
31
  author = nil
32
+ rule = false
24
33
  positional = []
25
34
  i = 0
26
35
  while i < argv.length
@@ -31,21 +40,26 @@ def parse_args(argv)
31
40
  when "--author"
32
41
  author = argv[i + 1]
33
42
  i += 2
43
+ when "--rule"
44
+ rule = true
45
+ i += 1
34
46
  else
35
47
  positional << argv[i]
36
48
  i += 1
37
49
  end
38
50
  end
39
- [positional[0], positional[1], stage, author]
51
+ [positional[0], positional[1], stage, author, rule]
40
52
  end
41
53
 
42
- intent_dir, text, stage, author = parse_args(ARGV)
54
+ intent_dir, text, stage, author, rule = parse_args(ARGV)
43
55
 
44
56
  if [intent_dir, text, stage, author].any? { |v| v.nil? || v.to_s.empty? }
45
- warn "usage: insight-append <intent_dir> <text> --stage S --author A"
57
+ warn "usage: insight-append <intent_dir> <text> --stage S --author A [--rule]"
46
58
  exit 2
47
59
  end
48
60
 
61
+ text = "rule: #{text}" if rule
62
+
49
63
  entry = Insights.append_insight(File.expand_path(intent_dir), text,
50
64
  stage: stage, author: author)
51
65
  puts "appended: #{entry}"
@@ -49,9 +49,9 @@ class InstallerCore
49
49
  # hand-curated pointer rather than embedding the core wholesale, and it never drifts
50
50
  # because it only ever points, never duplicates.
51
51
  CODEX_AGENTS_MD_BODY = <<~MD.freeze
52
- Plastic is installed for this agent. Plastic is intent-driven state management: all
53
- work flows through an intent, moved through What, Why, How, then Exec. Do not jump
54
- straight to code.
52
+ Plastic is installed for this agent. Plastic is intent-driven state management: work runs
53
+ in one of three modes, direct, thinking, or auto (a team drives the runner loop:
54
+ `runner step`, `status`, `answer`). Do not jump straight to code.
55
55
 
56
56
  Standing rules:
57
57
  - Core conventions live in ~/.plastic/PLASTIC.md. Read it and follow it exactly. For
@@ -2,11 +2,13 @@
2
2
  # encoding: UTF-8
3
3
  # frozen_string_literal: true
4
4
 
5
- # skill-lint: deterministic CLI over SkillLint (intent 85b).
5
+ # skill-lint: deterministic CLI over SkillLint (intent 85b), plus one CLI-local
6
+ # check (intent 341, G8, n1, C35).
6
7
  #
7
- # Runs the five structural skill checks (body-budget, frontmatter-validity,
8
- # bare-pointer, orphan-files, references-depth) over a directory of Agent
9
- # Skills and reports every violation. Mirrors `scripts/validate-intent`'s
8
+ # Runs the five structural checks (body-budget, frontmatter-validity,
9
+ # bare-pointer, orphan-files, references-depth) via SkillLint, then this
10
+ # script's own refusal-restatement check, over a directory of Agent Skills,
11
+ # and reports every violation. Mirrors `scripts/validate-intent`'s
10
12
  # CLI-over-lib shape and exit-code contract.
11
13
  #
12
14
  # Usage:
@@ -17,6 +19,112 @@
17
19
 
18
20
  require_relative "lib/skill_lint"
19
21
 
22
+ # RefusalRestatementCheck (C35): a skill body must not restate, past a short
23
+ # run of words, a refusal rule the conventions chapter already carries; it
24
+ # must link that chapter instead. No-op when <skills_dir>/conventions/references
25
+ # does not exist, so an older tree or a fixture dir with no conventions chapter
26
+ # is unaffected.
27
+ #
28
+ # Deliberately lives in this CLI, not in scripts/lib/skill_lint.rb: C35 is a
29
+ # doctrine-duplication check, one level removed from SkillLint's five
30
+ # structural checks, and keeping it here means adding it touches only the
31
+ # files this change is scoped to.
32
+ class RefusalRestatementCheck
33
+ REFUSAL_KEYWORD_RE = /\brefus(e|es|ed|ing|al)\b/i
34
+ CONVENTIONS_LINK_RE = %r{conventions/references/|plastic-conventions}i
35
+
36
+ # How many consecutive normalized words must match, verbatim, between a
37
+ # skill's refusal paragraph and the doctrine text before it counts as a
38
+ # restatement rather than a coincidental shared phrase.
39
+ NGRAM = 6
40
+
41
+ def initialize(skills_dir)
42
+ @skills_dir = skills_dir
43
+ end
44
+
45
+ def run
46
+ doctrine = doctrine_blob
47
+ return [] unless doctrine
48
+
49
+ skill_md_paths.flat_map do |skill_md|
50
+ skill_dir = File.dirname(skill_md)
51
+ next [] if File.basename(skill_dir) == "conventions" # the source never restates itself
52
+
53
+ check_skill(skill_dir, skill_md, File.read(skill_md), doctrine)
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def skill_md_paths
60
+ Dir.glob(File.join(@skills_dir, "*", "SKILL.md")).sort
61
+ end
62
+
63
+ def doctrine_blob
64
+ chapters = Dir.glob(File.join(@skills_dir, "conventions", "references", "*.md")).sort
65
+ return nil if chapters.empty?
66
+
67
+ text = chapters.map { |f| File.read(f) }.join(" ")
68
+ " #{normalize_words(text).join(" ")} "
69
+ end
70
+
71
+ def normalize_words(text)
72
+ text.downcase.gsub("`", "").gsub(/[^a-z0-9\s-]/, " ").split(/\s+/).reject(&:empty?)
73
+ end
74
+
75
+ # Same split as SkillLint's own frontmatter/body divide: `content.split("---", 3)`.
76
+ def body_and_offset(content)
77
+ parts = content.split("---", 3)
78
+ return [content, 0] if parts.length < 3
79
+
80
+ prefix_len = parts[0].length + 3 + parts[1].length + 3
81
+ [parts[2], content[0...prefix_len].count("\n")]
82
+ end
83
+
84
+ # Blank-line-delimited paragraph blocks, so a refusal keyword and its
85
+ # doctrine echo are compared across the whole paragraph, not one line.
86
+ def paragraph_blocks(lines)
87
+ blocks = []
88
+ start = nil
89
+ lines.each_with_index do |line, i|
90
+ if line.strip.empty?
91
+ blocks << { start: start, text: lines[start..(i - 1)].join } if start
92
+ start = nil
93
+ else
94
+ start ||= i
95
+ end
96
+ end
97
+ blocks << { start: start, text: lines[start..].join } if start
98
+ blocks
99
+ end
100
+
101
+ def restated?(block_text, doctrine)
102
+ words = normalize_words(block_text)
103
+ return false if words.length < NGRAM
104
+
105
+ (0..(words.length - NGRAM)).any? do |i|
106
+ doctrine.include?(" #{words[i, NGRAM].join(" ")} ")
107
+ end
108
+ end
109
+
110
+ def check_skill(skill_dir, skill_md, content, doctrine)
111
+ name = File.basename(skill_dir)
112
+ body, offset = body_and_offset(content)
113
+
114
+ paragraph_blocks(body.lines).filter_map do |block|
115
+ next unless block[:text].match?(REFUSAL_KEYWORD_RE)
116
+ next if block[:text].match?(CONVENTIONS_LINK_RE) # links the chapter instead of restating
117
+ next unless restated?(block[:text], doctrine)
118
+
119
+ {
120
+ check: "refusal-restatement", skill: name, file: skill_md, line: offset + block[:start] + 1,
121
+ message: "this paragraph restates a refusal rule word-for-word from " \
122
+ "skills/conventions/references/; link the chapter instead of repeating its text",
123
+ }
124
+ end
125
+ end
126
+ end
127
+
20
128
  def resolve_skills_dir(args)
21
129
  if (i = args.index("--skills-dir"))
22
130
  args[i + 1]
@@ -37,14 +145,15 @@ end
37
145
 
38
146
  dir = File.expand_path(resolve_skills_dir(ARGV))
39
147
  result = SkillLint.new(skills_dir: dir).run
148
+ violations = result.violations + RefusalRestatementCheck.new(dir).run
40
149
 
41
- if result.ok?
150
+ if violations.empty?
42
151
  puts "OK: #{dir}"
43
152
  exit 0
44
153
  end
45
154
 
46
155
  warn "VIOLATIONS: #{dir}"
47
- result.violations.each do |v|
156
+ violations.each do |v|
48
157
  warn "#{v[:check]} #{v[:skill]} #{v[:file]}:#{v[:line].nil? ? "-" : v[:line]} #{v[:message]}"
49
158
  end
50
159
  exit 1
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: plastic-auto
3
3
  description: >-
4
- Autonomous intent delivery - a background team takes a registered intent from How to Done.
4
+ Autonomous intent delivery - a background team takes a registered intent from How to End.
5
5
  Use when user says "auto", "take it from here", "deliver this", or when a thinking
6
6
  conversation concludes and the user confirms autonomous execution. Requires an active intent
7
7
  in INDEX.md.
@@ -71,35 +71,29 @@ owner override. Do not proceed as the owner after an exit 1.
71
71
  Read `../plastic-conventions/references/locks-and-worktrees.md` for what the lock and the
72
72
  worktree mean and the station table behind them. Code edits happen only inside the worktree.
73
73
 
74
- ## The shape (five steps, two agent boots)
74
+ ## The shape
75
75
 
76
- Every auto delivery runs the same shape, ruled by the owner on 2026-08-29. There is no intent
77
- tier and no stage agent; depth follows the work.
76
+ Work is a graph (`graph.md`: Goal, Decisions, Graph, Status; one `nodes/*.md` per node) or,
77
+ for work small enough to skip speccing, delivered inline with no separate plan review. There
78
+ is no intent tier and no stage agent; depth follows the work.
78
79
 
79
- | Step | Who | What lands |
80
- |---|---|---|
81
- | 1. The lead writes How | this session | `plan.md`, at least one `actions/ACTION_N.md` carrying a failure-mode matrix (one row per operation: the failure and the test that catches it), `checklist.md` |
82
- | 2. Adversarial plan review | boot 1, a fresh agent on `plan-reviewer-prompt.md` | a review file; the lead folds every finding into the spec, the matrix, and the tests |
83
- | 3. Execute, tests first | boot 2, `plastic-executor` | the red commit (the matrix's tests, failing), then the code, then a green suite |
84
- | 4. Review by risk | boot 3 only when risk calls for it (below) | a pass or a list of fixes the executor applies |
85
- | 5. One suite run, then close | this session | `outcome.md`, `end-intent`, the roadmap ledger |
80
+ `runner step` computes readiness and prints a spawn block per dispatched node - agent, model,
81
+ packet path, the test command, the call cap - fenced for a session to paste into the Agent
82
+ tool; the runner never spawns (327 D42). `runner status` renders the ledger; `runner answer`
83
+ closes a `needs_decision` node.
86
84
 
87
- Two boots is the normal delivery; the third is the exception the risk rule names. The lead is
88
- this session (the `plastic-enforcer` role), never a dispatched agent.
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.
85
+ A lead is a choice, not a requirement (D8, 355). A lead earns its keep on a graph carrying a
86
+ decision node, weighing its `needs_decision` stop; a graph with none runs end to end from
87
+ `runner step` alone. When this session leads, it is the `plastic-enforcer` role, never a
88
+ dispatched agent.
95
89
 
96
90
  ## Team
97
91
 
98
- - **plastic-enforcer**: this session. Writes the Why and How record, dispatches, folds reviews,
99
- verifies, closes.
92
+ - **plastic-enforcer**: this session. Writes the Why and How record, dispatches, applies
93
+ review findings, verifies, closes.
100
94
  - **plastic-executor**: one dispatch per intent, implements the consolidated action tests first,
101
95
  ticks the checklist, appends `## Insights`, drives the suite green.
102
- - **the plan reviewer**: one dispatch before code, from `plastic-intent-executing`'s
96
+ - **the plan reviewer**: an optional dispatch before code, from `plastic-intent-executing`'s
103
97
  `plan-reviewer-prompt.md`; a fresh agent, never the lead.
104
98
  - **the post-execution reviewer**: dispatched only by the risk rule, from
105
99
  `code-quality-reviewer-prompt.md`; a fresh agent, never the maker.
@@ -154,7 +148,9 @@ Only the owner can delegate. Delegates cannot re-delegate or release.
154
148
  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
149
  Verify with `plastic-lock status` rather than assuming.
156
150
 
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`.
151
+ Solo fallback: on a harness with no agent dispatch (Codex CLI today), this session walks the
152
+ graph (or the plan) itself, still writing the matrix and the tests first and reviewing its own
153
+ plan against the matrix before code, saying so in `## Insights`.
158
154
 
159
155
  ## Stage-Aware Entry
160
156
 
@@ -168,7 +164,7 @@ ledger is missing (then rebuild it with `Savepoint.rebuild_savepoint`).
168
164
  | `Why spec.md created` | How |
169
165
  | `How plan.md created` / `How checklist.md created` / `Exec started` | Exec (verify plan, matrix, checklist) |
170
166
  | `Exec outcome.md created` | Exec done; complete the intent |
171
- | `Done delivered|abandoned` | Terminal; do not resume |
167
+ | A terminal savepoint line (`delivered` or `abandoned`) | Terminal; do not resume |
172
168
  | 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 |
173
169
 
174
170
  Filesystem fallback, in order: `checklist.md` with items checked means resume Exec from the
@@ -179,42 +175,43 @@ Announce which stage you are entering and why.
179
175
 
180
176
  ## Why (the lead)
181
177
 
182
- 1. Read `## Context` and `### Decisions`; assess the gaps.
183
- 2. Research yourself: code, docs, related intents through `## Links`, the web if needed. No
184
- questions to the human.
185
- 3. Decide: pick the best option per gap, record it in `## Context > ### Decisions` with the
186
- rationale, and log it in `## Insights` with the `(autonomous)` marker through
187
- `scripts/insight-append`.
188
- 4. Write `spec.md`. Then How.
178
+ For a graph delivery, Why is already written into `graph.md`'s Goal and Decisions; nothing
179
+ else to do here. For work with no graph: read `## Context` and `### Decisions`, assess the
180
+ gaps, research them yourself (code, docs, related intents through `## Links`, the web if
181
+ needed; no questions to the human), record each decision in `## Context > ### Decisions` with
182
+ its rationale, log it in `## Insights` with the `(autonomous)` marker through
183
+ `scripts/insight-append`, and write `spec.md` only when the intent needs one (speccing is
184
+ optional). Then How.
189
185
 
190
186
  ## How (the lead), then the plan review
191
187
 
192
- 1. Write `plan.md`: numbered steps.
193
- 2. Write at least one real `actions/ACTION_N.md` (one consolidated `ACTION_1.md` by default;
194
- several only when the work splits into independent, parallel-safe actions). Each action
195
- carries the failure-mode matrix: one row per operation, the failure mode, and the test that
196
- catches it. A `.gitkeep`-only `actions/` is not a finished How.
197
- 3. Write `checklist.md` covering every action.
198
- 4. Dispatch the plan reviewer (boot 1) with `plastic-intent-executing`'s
199
- `plan-reviewer-prompt.md`, the spawn preamble, and the intent directory. Fold every finding
200
- into the spec, the matrix, and the tests; record what was dropped and why in the action
201
- file's review fold. A REVISE verdict is folded and not re-reviewed unless a finding changes
202
- a decision.
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.
188
+ For a graph delivery, How is `graph.md` itself: no `plan.md`, no separate plan review (D1,
189
+ 341). For work with no graph: write `plan.md` (numbered steps) and at least one real
190
+ `actions/ACTION_N.md` carrying the failure-mode matrix (one row per operation, the failure
191
+ mode, the test that catches it; a `.gitkeep`-only `actions/` is not a finished How), then
192
+ `checklist.md` covering every action. The plan reviewer is optional, not a required step:
193
+ when the delivery warrants review before code, dispatch it (boot 1) with
194
+ `plastic-intent-executing`'s `plan-reviewer-prompt.md`, the spawn preamble, and the intent
195
+ directory, apply every finding to the spec, the matrix, and the tests, and record what was
196
+ dropped and why in the action file's review notes. A REVISE verdict is applied and not
197
+ re-reviewed unless a finding changes a decision.
198
+
199
+ Print `ruby ~/.plastic/scripts/report-screen plan <intent_dir>` as the first characters of
200
+ the reply, nothing before it, no fence, before dispatching the executor (see
201
+ `references/human-report-contract.md` for the full binding table). It informs; it does not wait.
206
202
 
207
203
  Then Exec.
208
204
 
209
205
  ## Exec (the executor)
210
206
 
211
- 1. Dispatch `plastic-executor` (boot 2) through `plastic-intent-executing` with the whole
212
- consolidated action pasted in: the spec decisions, the matrix, the checklist items, the
213
- worktree path from the preamble. Tests first: the executor commits the matrix's tests red,
214
- then builds, then drives the full suite green.
215
- 2. Read its return by code: DONE or DONE_WITH_CONCERNS proceeds; NEEDS_CONTEXT re-dispatches
216
- with the missing context; BLOCKED stops under the error procedure.
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.
207
+ For a graph delivery, `runner step` prints the spawn block for the next ready node; paste it
208
+ into the Agent tool, verbatim. For work with no graph, dispatch `plastic-executor` (boot 2)
209
+ through `plastic-intent-executing` with the whole consolidated action pasted in.
210
+
211
+ 1. Read the executor's return by code: DONE or DONE_WITH_CONCERNS proceeds; NEEDS_CONTEXT
212
+ re-dispatches with the missing context; BLOCKED stops under the error procedure.
213
+ 2. Tick the checklist as items land (the executor does this); verify tick-versus-diff against
214
+ the diff. A mismatch is a review finding, not a lead cleanup.
218
215
 
219
216
  ## Review by risk (boot 3, only when a rule fires)
220
217
 
@@ -224,13 +221,14 @@ holds, each checkable from disk with no judgment; otherwise the green suite is t
224
221
  1. `git diff --name-only <red-commit>..HEAD` touches a path on the risk list in
225
222
  `references/agent-architecture.md` (hooks, the lock, the arming module, the installer, a
226
223
  release file).
227
- 2. A row of any `actions/ACTION_N.md` failure-mode matrix names a test file that is not in that
228
- diff, or a test the green run did not execute.
224
+ 2. A row of any failure-mode matrix (an `actions/ACTION_N.md` or a `nodes/*.md` file) names a
225
+ test file that is not in that diff, or a test the green run did not execute.
229
226
  3. The executor's completion report carries a status other than `delivered`, or a non-empty
230
227
  `deviations` or `blockers` field.
231
228
 
232
229
  The reviewer returns a pass or a list of fixes; the executor (re-dispatched) applies them, then
233
- the suite runs once more.
230
+ the suite runs once more. On a graph, the risk rule maps onto the verify nodes named in
231
+ `graph.md`'s decisions; at most one review-fix round, never more.
234
232
  ## Project Creation
235
233
 
236
234
  If the plan calls for creating a new project, determine the path from `~/.plastic/config.yml`
@@ -29,12 +29,13 @@ in 2.0, intent 304; the lead writes the Why and How record itself):
29
29
  - **plastic-executor** (Exec): commits the matrix's tests red, writes the code, checks off
30
30
  `checklist.md`, appends `## Insights`, and drives the suite green.
31
31
  - **the plan reviewer**: a fresh agent on `plastic-intent-executing`'s
32
- `plan-reviewer-prompt.md`, dispatched once before any code exists.
32
+ `plan-reviewer-prompt.md`, an optional dispatch before any code exists.
33
33
  - **the post-execution reviewer**: a fresh agent on `code-quality-reviewer-prompt.md`,
34
34
  dispatched only when the auto skill's risk rule fires; never the maker.
35
35
 
36
- Two agent boots is the normal delivery (the plan reviewer, the executor); the post-execution
37
- reviewer is the third only when risk calls for it.
36
+ One agent boot (the executor) is the minimum delivery; the plan reviewer is a second,
37
+ optional boot when the lead calls for review before code, and the post-execution reviewer is
38
+ a third only when risk calls for it.
38
39
 
39
40
  ### Handoff Contracts
40
41
 
@@ -44,8 +45,8 @@ the code, the red and green commits, a checked-off checklist, `## Insights`, and
44
45
  report. Dispatch is sequential on a single branch, because the deliverables share files.
45
46
 
46
47
  The chain: intent `## Intent` / `## Context`, then enriched `## Context` plus `### Decisions`,
47
- then `spec.md`, then `plan.md` plus `actions/` plus `checklist.md`, then the plan review, then
48
- the code changes plus a checked-off checklist plus `## Insights`.
48
+ then `spec.md`, then `plan.md` plus `actions/` plus `checklist.md`, then an optional plan
49
+ review, then the code changes plus a checked-off checklist plus `## Insights`.
49
50
 
50
51
  ### Spawn Preamble (L2 live-state injection)
51
52
 
@@ -88,9 +89,10 @@ not revoke the registered delegate's authorization.
88
89
 
89
90
  ### Review Ownership
90
91
 
91
- The lead owns every review decision: it dispatches the plan reviewer before code, folds the
92
- findings itself, and decides from the risk rule whether the post-execution reviewer runs. It
93
- never delegates that decision, and neither reviewer is ever the maker of what it reviews.
92
+ The lead owns every review decision: it dispatches the plan reviewer before code when one
93
+ runs, takes the review into its own record, and decides from the risk rule whether the
94
+ post-execution reviewer runs. It never delegates that decision, and neither reviewer is ever
95
+ the maker of what it reviews.
94
96
  Nothing blocks a write in 2.0 (the gate hooks were removed, intent 302); the lock, the
95
97
  worktree, and the record are how the team keeps one delivery in one place.
96
98
 
@@ -78,7 +78,7 @@ an executor's intermediate commit, or an agent going idle is NOT one of them:
78
78
 
79
79
  | Trigger | Scope |
80
80
  |---|---|
81
- | A savepoint line lands (a stage boundary: Why, How, Exec started, outcome written, Done) | that intent |
81
+ | A savepoint line lands (a stage boundary: Why, How, Exec started, outcome written, End) | that intent |
82
82
  | A review verdict returns (plan review or post-execution review), naming what it changed | that intent |
83
83
  | A blocker or needs-input is logged | that intent |
84
84
  | A merge or a release lands | that intent |
@@ -1,16 +1,16 @@
1
- # Completion and Done
1
+ # Completion and the End Tail
2
2
 
3
3
  This chapter holds what "intent done" means and the End-stage tail.
4
4
 
5
5
  #### What "intent done" means (intent 93)
6
6
 
7
- Done is one law with three signals, and they must agree. INDEX `## Completed` /
7
+ Completion is one law with three signals, and they must agree. INDEX `## Completed` /
8
8
  `## Abandoned` is the single canonical terminal marker: it is the store-wide ledger a fresh
9
9
  session reads first, so it wins on any conflict. `outcome.md` is the "deliverable exists"
10
- signal, and the savepoint `Done delivered|abandoned` line is the audit echo. All three must
11
- agree; when they disagree, INDEX is authoritative and `doctor` flags the mismatch (the
10
+ signal, and the savepoint's terminal `delivered|abandoned` line is the audit echo. All three
11
+ must agree; when they disagree, INDEX is authoritative and `doctor` flags the mismatch (the
12
12
  `done_signals` check: `outcome.md` real but still under `## Active`, or terminal without a
13
- real `outcome.md`, or a terminal intent whose savepoint carries no `Done` line).
13
+ real `outcome.md`, or a terminal intent whose savepoint carries no terminal disposition line).
14
14
 
15
15
  `outcome.md` is mandatory at every terminal transition, delivered and abandoned alike. It
16
16
  self-declares its disposition through a `disposition: delivered|abandoned` frontmatter
@@ -18,8 +18,8 @@ header. The delivered path authors it with the result; the abandoned path author
18
18
  the abandonment reason and no longer leaves the scaffolded placeholder sentinel in place.
19
19
 
20
20
  The canonical End tail runs in this order, and the QMD reindex is always LAST, after the
21
- purge: `outcome.md -> INDEX terminal -> savepoint Done -> commit -> disarm (Worktree.release
22
- -> Lock.release -> purge) -> QMD reindex`. Running the reindex last keeps the index from
21
+ purge: `outcome.md -> INDEX terminal -> the terminal savepoint line -> commit -> disarm
22
+ (Worktree.release -> Lock.release -> purge) -> QMD reindex`. Running the reindex last keeps the index from
23
23
  ever referencing a bridge or lock that disarm is about to remove.
24
24
 
25
25
  `scripts/end-intent` performs this order's disarm step (verify the code worktree is clean,
@@ -84,13 +84,13 @@ Provisioning fails open for intents that touch no project code (pure research or
84
84
  intents in the global store, or a non-git repo): those get the lock only, and the worktree
85
85
  block stays unprovisioned. The fail-open path is always logged, never silent.
86
86
 
87
- Cleanup is part of Done: the End tail merges the branch, then removes the worktree. Never leave
87
+ Cleanup is part of the End tail: it merges the branch, then removes the worktree. Never leave
88
88
  an orphaned worktree behind, and clear a stale worktree reference with `git worktree prune`.
89
89
 
90
90
 
91
91
  #### Intent delivery, station by station
92
92
 
93
- How one auto-team intent travels from boarding to Done, and what the lock, the pointer, and
93
+ How one auto-team intent travels from boarding to the End tail, and what the lock, the pointer, and
94
94
  the record hook do at each station. Nothing in the third column blocks; the fourth column is
95
95
  what gets written down.
96
96
 
@@ -101,7 +101,7 @@ what gets written down.
101
101
  | Why | `spec.md` | owner writes refresh the lease (lock file mtime heartbeat) | savepoint `Why started`, `Why spec.md created` |
102
102
  | How | `plan.md`, `actions/ACTION_N.md` (at least one), `checklist.md` | heartbeat on writes | savepoint `How started`, `How plan.md created`, `How checklist.md created`, `Exec started` |
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
- | 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 |
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) | the savepoint's terminal `delivered` (or `abandoned`) line; 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
106
 
107
107
  ## The write guard is not residue
@@ -8,7 +8,7 @@ Plastic separates two different things an earlier doctrine blurred under one wor
8
8
  "immutable." WORK is the delivered CONTENT an intent produced: the code and project files a
9
9
  delivery changed, the research it recorded, the outcome it wrote. Once the intent is terminal
10
10
  (Completed or Abandoned), that content is immutable - the only way to change it is another
11
- intent that continues or reverts it. Editing a Done intent's own artifacts so it looks like it
11
+ intent that continues or reverts it. Editing a terminal intent's own artifacts so it looks like it
12
12
  delivered something different, or that parts are missing, is forbidden (the book analogy:
13
13
  never rewrite the text on the pages of an old, valuable book).
14
14
 
@@ -18,7 +18,7 @@
18
18
  core_files -> "Core Files"
19
19
  project_stores -> "Project Stores"
20
20
  deprecations -> "Deprecations"
21
- done_signals -> "Done Signals"
21
+ done_signals -> "Completion Signals"
22
22
  session_ledger -> "Session Ledger" (global store only)
23
23
  4. For each check within a category, emit one line with the status icon
24
24
  and the check message. If the check has non-empty details, list them
@@ -12,7 +12,7 @@ Classify from the last line alone, then verify only that line's artifact is real
12
12
  | `How started` / `How plan.md created` | (How in progress) | **How** | finish `plan.md` and `checklist.md` |
13
13
  | `How checklist.md created` / `Exec started` | How | **Exec** | do the work, check off the checklist |
14
14
  | `Exec outcome.md created` | Exec | **ready to complete** | the ending procedure (`plastic-intent-ending`) |
15
- | `Done delivered` / `Done abandoned` | terminal | **report only** | immutable; ask what is next |
15
+ | A terminal savepoint line (`delivered` or `abandoned`) | terminal | **report only** | immutable; ask what is next |
16
16
  | A node or `Intent` transition line (`n1 running ...`, `Intent needs_decision ...`) | Exec | **Exec** | a graph delivery is in progress; read node status through `NodeLedger.status`, never re-derive it by eye |
17
17
 
18
18
  ## Per-stage behaviour (what "continue" means)
@@ -24,7 +24,7 @@ Classify from the last line alone, then verify only that line's artifact is real
24
24
  The first unchecked `checklist.md` item is the next step; the newest `## Insights` entry
25
25
  supplies the context.
26
26
  - **ready to complete**: `outcome.md` is real; run the ending procedure.
27
- - **Done**: terminal. Report the outcome, ask what is next. Never reopen; `INDEX.md` is
27
+ - **End**: terminal. Report the outcome, ask what is next. Never reopen; `INDEX.md` is
28
28
  authoritative.
29
29
 
30
30
  ## Notes