@zalom/plastic 2.0.0-alpha.10 → 2.0.0-alpha.12
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.
- package/agents/plastic-enforcer.md +3 -1
- package/agents/plastic-executor.md +9 -3
- package/hooks/statusline +4 -27
- package/package.json +1 -1
- package/scripts/doctor.rb +46 -3
- package/scripts/lib/report_screen.rb +28 -5
- package/scripts/report-screen +49 -12
- package/scripts/verify-intent +2 -1
- package/skills/auto/SKILL.md +6 -4
- package/skills/intent-executing/SKILL.md +9 -5
- package/skills/intent-executing/implementer-prompt.md +6 -1
|
@@ -31,7 +31,9 @@ deliberately; the auto pipeline never dispatches them.
|
|
|
31
31
|
`plastic-intent-executing`'s `plan-reviewer-prompt.md`; fold every finding into the spec, the
|
|
32
32
|
matrix, and the tests.
|
|
33
33
|
4. **Dispatch one executor, tests first** - the executor commits the matrix's tests red, then
|
|
34
|
-
builds, then drives the full suite green; you verify
|
|
34
|
+
builds, then drives the full suite green; you verify tick-versus-diff at the
|
|
35
|
+
post-execution review and again before the merge. A mismatch is a review finding, not a
|
|
36
|
+
cleanup you perform silently.
|
|
35
37
|
5. **Review by risk** - dispatch the post-execution reviewer only when the auto skill's risk
|
|
36
38
|
rule fires; otherwise the green suite is the review.
|
|
37
39
|
6. **Close** - `outcome.md`, then `plastic-intent-ending`, which releases the worktree, clears
|
|
@@ -20,7 +20,11 @@ valid lifecycle artifacts. Honor it as your live state; do not re-derive or cont
|
|
|
20
20
|
any other change.
|
|
21
21
|
2. **Implement the actions** - make the code changes for each action in order, inside the
|
|
22
22
|
worktree the preamble names.
|
|
23
|
-
3. **
|
|
23
|
+
3. **Tick with the commit** - commit after each logical unit of work, and in the same step
|
|
24
|
+
tick the checklist item that unit lands: mark its box `[x]` and move the line to
|
|
25
|
+
`## Completed`, then append the savepoint `Commit` line
|
|
26
|
+
(`scripts/savepoint-note <intent_dir> --kind Commit --text "<sha> <what it proves>"`). A
|
|
27
|
+
commit without its tick is incomplete.
|
|
24
28
|
4. **Record insights** - capture durable discoveries and report them in the `insights:` field;
|
|
25
29
|
persist each to `## Insights` via the `insight-append` helper
|
|
26
30
|
(`scripts/insight-append <intent_dir> <text> --stage Exec --author "plastic-executor (autonomous)"`),
|
|
@@ -33,7 +37,8 @@ valid lifecycle artifacts. Honor it as your live state; do not re-derive or cont
|
|
|
33
37
|
real `ACTION_N.md` with its failure-mode matrix, pasted in by the lead. Execute the action
|
|
34
38
|
files in order.
|
|
35
39
|
2. Write the matrix's tests; commit red.
|
|
36
|
-
3. Work one action at a time,
|
|
40
|
+
3. Work one action at a time, ticking its checklist item in the same commit that lands it
|
|
41
|
+
(box marked, line moved); prefer safe, non-destructive routes.
|
|
37
42
|
4. Run the full suite, iterate to zero failures and zero errors; commit green.
|
|
38
43
|
5. Produce (output handoff): the code changes, a checked-off `checklist.md`, and `## Insights`.
|
|
39
44
|
6. Report (see `## Completion Report`); the lead applies the risk rule and may dispatch a
|
|
@@ -46,7 +51,8 @@ preamble's `REPORT_CONTRACT` and `skills/auto/references/agent-report-contract.m
|
|
|
46
51
|
finish silently. Carry the common envelope (role, intent id, stage, status, artifacts written,
|
|
47
52
|
verification, checklist deltas, deviations, blockers, insights) plus the executor payload:
|
|
48
53
|
|
|
49
|
-
- Actions implemented this turn, mapped to checklist items checked off (checked / total)
|
|
54
|
+
- Actions implemented this turn, mapped to checklist items checked off (checked / total);
|
|
55
|
+
checked / total must equal the items whose commits exist
|
|
50
56
|
- A summary of the code changed (files and the shape of the change)
|
|
51
57
|
- Test result: the red commit's failing count, then the full-suite command and its pass / fail
|
|
52
58
|
counts
|
package/hooks/statusline
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
# plastic-hook-version: 4.0.0
|
|
3
3
|
# StatusLine hook - Plastic owns the full statusline (no chaining).
|
|
4
4
|
# Renders: {model} - ctx {pct}% ({used}/{size}) - 5h {p}% - 7d {p}% - ${cost}
|
|
5
|
-
# -
|
|
6
|
-
# Every segment but
|
|
5
|
+
# - Plastic {version}[ -> {next}] - {path}
|
|
6
|
+
# Every segment but the Plastic version comes from the stdin payload.
|
|
7
7
|
# Pure bash (macOS 3.2 compatible). No ruby, no jq. Reads stdin once; small file reads
|
|
8
8
|
# only. The stdin JSON is walked in a single awk pass (below); nothing else in this
|
|
9
9
|
# script forks a second process per field, which is what keeps a render cheap.
|
|
@@ -17,7 +17,6 @@ C_OK='' # default - meter below 70%
|
|
|
17
17
|
C_WARN=$'\033[33m' # yellow - meter at 70% and above
|
|
18
18
|
C_CRIT=$'\033[38;2;231;76;60m' # red - meter at 90% and above
|
|
19
19
|
C_COST=$'\033[37m' # white - session cost
|
|
20
|
-
C_CLAUDISH=$'\033[38;2;249;140;30m' # orange - claudish rewrites
|
|
21
20
|
C_VER=$'\033[37m' # white - "Plastic {version}" and update arrow
|
|
22
21
|
C_NEXT=$'\033[33m' # yellow - next version
|
|
23
22
|
C_PATH=$'\033[38;2;128;134;144m' # gray - path (matches dim UI text)
|
|
@@ -309,40 +308,18 @@ if [ -n "$COST_RAW" ]; then
|
|
|
309
308
|
[ -n "$COST_FMT" ] && [ "$COST_FMT" != "0.00" ] && COST_SEG="${C_COST}\$${COST_FMT}${RST}"
|
|
310
309
|
fi
|
|
311
310
|
|
|
312
|
-
# --- claudish rewrites for THIS session (fork ledger, optional) ---
|
|
313
|
-
# Tab separated, one call per line; column 11 is the session id. Rows written
|
|
314
|
-
# before that column existed have 9 or 10 fields and never match, so an old
|
|
315
|
-
# ledger renders no segment instead of a wrong one.
|
|
316
|
-
CL_SEG=""
|
|
317
|
-
CL_LOG="${CLAUDISH_LOCAL_DIR:-$HOME/.claude/claudish-local}/usage.log"
|
|
318
|
-
if [ -n "$SID" ] && [ -f "$CL_LOG" ]; then
|
|
319
|
-
CL=$(awk -F'\t' -v sid="$SID" '
|
|
320
|
-
NF >= 11 && $11 == sid { n++; t += $5 + $6 }
|
|
321
|
-
END {
|
|
322
|
-
if (n > 0) {
|
|
323
|
-
if (t >= 1000) {
|
|
324
|
-
s = sprintf("%.1f", t / 1000); sub(/\.0$/, "", s); printf "%d %sk", n, s
|
|
325
|
-
} else {
|
|
326
|
-
printf "%d %d", n, t
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}' "$CL_LOG" 2>/dev/null)
|
|
330
|
-
[ -n "$CL" ] && CL_SEG="${C_CLAUDISH}claudish ${CL%% *} rw / ${CL#* }${RST}"
|
|
331
|
-
fi
|
|
332
|
-
|
|
333
311
|
# --- Assemble segments in order, joined by " . " ---
|
|
334
312
|
PARTS=""
|
|
335
313
|
add() { [ -z "$1" ] && return; if [ -z "$PARTS" ]; then PARTS="$1"; else PARTS="$PARTS$SEP$1"; fi; }
|
|
336
314
|
|
|
337
|
-
# Order: identity first (model), then this session's spend (context, meters, cost,
|
|
338
|
-
#
|
|
315
|
+
# Order: identity first (model), then this session's spend (context, meters, cost),
|
|
316
|
+
# then the volatile-length values last (version, path) so the line does
|
|
339
317
|
# not visually jump as they change.
|
|
340
318
|
[ -n "$MODEL" ] && add "${C_MODEL}${MODEL}${RST}"
|
|
341
319
|
add "$CTX_SEG"
|
|
342
320
|
add "$M5"
|
|
343
321
|
add "$M7"
|
|
344
322
|
add "$COST_SEG"
|
|
345
|
-
add "$CL_SEG"
|
|
346
323
|
if [ -n "$VERSION" ]; then
|
|
347
324
|
vseg="${C_VER}Plastic ${VERSION}${RST}"
|
|
348
325
|
[ -n "$NEXT" ] && vseg="${vseg}${C_VER} "$'\342\206\222'" ${RST}${C_NEXT}${NEXT}${RST}"
|
package/package.json
CHANGED
package/scripts/doctor.rb
CHANGED
|
@@ -30,6 +30,7 @@ require_relative "lib/power_tools"
|
|
|
30
30
|
require_relative "lib/preflight"
|
|
31
31
|
require_relative "lib/ruby_probe"
|
|
32
32
|
require_relative "lib/doctor_session_ledger"
|
|
33
|
+
require_relative "lib/intent_screen"
|
|
33
34
|
|
|
34
35
|
# Diagnostic engine, instantiable with an injected store/agent map so tests can
|
|
35
36
|
# run it hermetically (no eval, no global-constant rewriting).
|
|
@@ -1161,9 +1162,11 @@ end
|
|
|
1161
1162
|
#
|
|
1162
1163
|
# Doctor's fourth check scope, invoked by `--intent <id>`. Never a store-wide sweep:
|
|
1163
1164
|
# resolves exactly one intent directory (mirrors scripts/end-intent's resolve_intent_dir /
|
|
1164
|
-
# scripts/project-links's --intent disambiguation) and returns
|
|
1165
|
-
# FAIL-severity,
|
|
1166
|
-
# binding advisory-only ruling
|
|
1165
|
+
# scripts/project-links's --intent disambiguation) and returns six checks, four
|
|
1166
|
+
# FAIL-severity, two WARN-severity: intent_savepoint_truthful stays WARN per intent 134's
|
|
1167
|
+
# binding advisory-only ruling (see spec.md D2/D8 - do NOT escalate it to FAIL), and
|
|
1168
|
+
# intent_ticks_lag is WARN-only per intent 329's ruling that a lagging tick warns rather
|
|
1169
|
+
# than blocks.
|
|
1167
1170
|
def check_intent_end(id, store: nil, disposition: nil)
|
|
1168
1171
|
intent_dir, scope = resolve_single_intent_dir(id, store: store)
|
|
1169
1172
|
unless intent_dir
|
|
@@ -1185,6 +1188,7 @@ end
|
|
|
1185
1188
|
intent_structure_check(intent_dir),
|
|
1186
1189
|
intent_lifecycle_artifacts_check(intent_dir, disposition),
|
|
1187
1190
|
intent_checklist_complete_check(intent_dir),
|
|
1191
|
+
intent_ticks_lag_check(intent_dir),
|
|
1188
1192
|
intent_links_projection_check_for(id, scope),
|
|
1189
1193
|
intent_savepoint_truthful_check(intent_dir, index_path: index_path),
|
|
1190
1194
|
]
|
|
@@ -1263,6 +1267,45 @@ end
|
|
|
1263
1267
|
end
|
|
1264
1268
|
end
|
|
1265
1269
|
|
|
1270
|
+
# Intent 329: the checklist is the only input to the state screen's Progress bar, so an
|
|
1271
|
+
# intent whose commit ledger has entries and whose checklist has no ticked item is
|
|
1272
|
+
# reporting 0 progress on work that already landed. Advisory only (WARN), like
|
|
1273
|
+
# intent_savepoint_truthful: a lagging tick is a lead's review finding, never a machine
|
|
1274
|
+
# refusal. The commit count comes from this intent's own savepoint.md Commit ledger
|
|
1275
|
+
# (intent 317 D17), never from git: git's detected base is the repo default branch, which
|
|
1276
|
+
# is not the base a 2.0 intent branch forks from.
|
|
1277
|
+
def intent_ticks_lag_check(intent_dir)
|
|
1278
|
+
items = IntentScreen.checklist_items(intent_dir)
|
|
1279
|
+
if items.empty?
|
|
1280
|
+
return check(category: "intent_end", name: "intent_ticks_lag", status: "pass",
|
|
1281
|
+
message: "n/a: checklist.md has no items to tick")
|
|
1282
|
+
end
|
|
1283
|
+
|
|
1284
|
+
ticked = items.count { |i| i[:done] }
|
|
1285
|
+
commits = savepoint_commit_count(intent_dir)
|
|
1286
|
+
|
|
1287
|
+
if commits.positive? && ticked.zero?
|
|
1288
|
+
check(category: "intent_end", name: "intent_ticks_lag", status: "warn",
|
|
1289
|
+
message: "ticks lag the branch: #{commits} commit(s) recorded, " \
|
|
1290
|
+
"0 of #{items.size} checklist items ticked")
|
|
1291
|
+
else
|
|
1292
|
+
check(category: "intent_end", name: "intent_ticks_lag", status: "pass",
|
|
1293
|
+
message: "#{ticked} of #{items.size} ticked, #{commits} commit(s) recorded")
|
|
1294
|
+
end
|
|
1295
|
+
end
|
|
1296
|
+
|
|
1297
|
+
# Count `Commit` lines in the intent's savepoint ledger, through the one regex that parses
|
|
1298
|
+
# a savepoint line (IntentScreen::SAVEPOINT_RE; field 2 is the kind).
|
|
1299
|
+
def savepoint_commit_count(intent_dir)
|
|
1300
|
+
path = File.join(intent_dir, "savepoint.md")
|
|
1301
|
+
return 0 unless File.exist?(path)
|
|
1302
|
+
|
|
1303
|
+
File.readlines(path).count do |line|
|
|
1304
|
+
m = line.strip.match(IntentScreen::SAVEPOINT_RE)
|
|
1305
|
+
m && m[2] == "Commit"
|
|
1306
|
+
end
|
|
1307
|
+
end
|
|
1308
|
+
|
|
1266
1309
|
def intent_links_projection_check_for(id, scope)
|
|
1267
1310
|
ctx = build_links_projection_context
|
|
1268
1311
|
node = ctx[:intents].find { |n| n[:id] == id && n[:scope] == scope }
|
|
@@ -303,10 +303,33 @@ module ReportScreen
|
|
|
303
303
|
{ kind: "red", what: "#{sha} proven test-only and red", source: "outcome.md ## Verification" }
|
|
304
304
|
end
|
|
305
305
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
306
|
+
# Fix 2026-09-01: the record is the truth of delivery (D14: never a guess).
|
|
307
|
+
# The shipped version comes from outcome.md's own ship line first ("Shipped
|
|
308
|
+
# as `v2.0.0-alpha.10`", "released as **v2.0.0-alpha.5**", "released
|
|
309
|
+
# v2.0.0-alpha.9", "Tagged v1.14.1", "Delivered in", "Release v"); the injected tag reader (git) is the
|
|
310
|
+
# fallback when the record is silent. A bare version with no ship verb
|
|
311
|
+
# ("from 1.14.1") is not a shipped version.
|
|
312
|
+
SHIP_VERSION_RE = /\b(?:shipped|released?|delivered|tagged)\b(?:\s+(?:as|in))?[\s`*]*v?(\d+\.\d+\.\d+(?:-[0-9A-Za-z]+(?:\.[0-9A-Za-z]+)*)?)/i.freeze
|
|
313
|
+
|
|
314
|
+
def self.shipped_version(intent_dir)
|
|
315
|
+
text = outcome_text(intent_dir)
|
|
316
|
+
return nil unless text
|
|
317
|
+
m = text.match(SHIP_VERSION_RE)
|
|
318
|
+
m && m[1]
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
# The merge commit named on outcome.md's merge line, or nil. The CLI's tag
|
|
322
|
+
# reader asks git which tag contains it; the ship row prints it.
|
|
323
|
+
def self.merge_sha(intent_dir)
|
|
324
|
+
text = outcome_text(intent_dir)
|
|
325
|
+
return nil unless text
|
|
326
|
+
line = text.lines.find { |l| l =~ /\bmerge(d)?\b/i && l =~ /\b[0-9a-f]{7,40}\b/ }
|
|
327
|
+
line && line.match(/\b([0-9a-f]{7,40})\b/)[1]
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
def self.ship_row(_text, intent_dir, tag_reader)
|
|
331
|
+
sha = merge_sha(intent_dir)
|
|
332
|
+
version = shipped_version(intent_dir) || tag_reader.call(intent_dir)
|
|
310
333
|
return nil if sha.nil? && (version.nil? || version.to_s.empty?)
|
|
311
334
|
ver_text = version && !version.to_s.empty? ? "v#{version.to_s.sub(/\Av/, '')}" : NOT_RECORDED
|
|
312
335
|
sha_text = sha || NOT_RECORDED
|
|
@@ -524,7 +547,7 @@ module ReportScreen
|
|
|
524
547
|
ts = delivered_timestamp(intent_dir)
|
|
525
548
|
m = mode(intent_dir)
|
|
526
549
|
dur = duration(intent_dir)
|
|
527
|
-
version = tag_reader.call(intent_dir)
|
|
550
|
+
version = shipped_version(intent_dir) || tag_reader.call(intent_dir)
|
|
528
551
|
ver_text = version && !version.to_s.empty? ? "v#{version.to_s.sub(/\Av/, '')}" : NOT_RECORDED
|
|
529
552
|
|
|
530
553
|
lines = []
|
package/scripts/report-screen
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
# Usage:
|
|
10
10
|
# report-screen state <intent_dir> [--changed "<text>"] [--ansi]
|
|
11
11
|
# report-screen state --all <store_root> [--changed "<text>"] [--ansi]
|
|
12
|
-
# report-screen delivered <intent_dir> [--ansi]
|
|
12
|
+
# report-screen delivered <intent_dir> [--ansi] [--repo <dir>]
|
|
13
13
|
# report-screen delay <intent_dir> [--ansi]
|
|
14
14
|
#
|
|
15
15
|
# --ansi delegates to ScreenPaint (intent 317a, D1), the parser/re-layouter
|
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
# 2 - usage error, or the path/store is not what the verb expects (one line
|
|
24
24
|
# on stderr, stdout empty)
|
|
25
25
|
|
|
26
|
+
require "yaml"
|
|
27
|
+
require "shellwords"
|
|
26
28
|
require_relative "lib/report_screen"
|
|
27
29
|
require_relative "lib/intent_screen"
|
|
28
30
|
require_relative "lib/screen_paint"
|
|
@@ -32,15 +34,47 @@ def usage_abort(message)
|
|
|
32
34
|
exit 2
|
|
33
35
|
end
|
|
34
36
|
|
|
35
|
-
# The one place allowed to shell out (D2/D20): resolves the
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
# The one place allowed to shell out (D2/D20): resolves the tag that CONTAINS
|
|
38
|
+
# the intent's merge commit, in the project's own repository, so the version
|
|
39
|
+
# on the delivered screen is the release that merge shipped in. The
|
|
40
|
+
# repository comes from --repo, else from projects.yml beside the store (the
|
|
41
|
+
# installed layout, <home>/projects/<slug>/store/<id>), else the repository
|
|
42
|
+
# this script lives in (the in-repo layout). No merge sha, no repository, or
|
|
43
|
+
# no containing tag all answer nil, and the screen says "not recorded"
|
|
44
|
+
# rather than guessing from HEAD (D14). The pure module never reads git.
|
|
45
|
+
def resolve_repo(intent_dir, explicit_repo, script_dir)
|
|
46
|
+
candidates = []
|
|
47
|
+
candidates << File.expand_path(explicit_repo) if explicit_repo
|
|
48
|
+
if (m = intent_dir.match(%r{\A(.*)/projects/([^/]+)/store/[^/]+\z}))
|
|
49
|
+
home, slug = m[1], m[2]
|
|
50
|
+
projects_yml = File.join(home, "projects.yml")
|
|
51
|
+
if File.exist?(projects_yml)
|
|
52
|
+
data = begin
|
|
53
|
+
YAML.safe_load(File.read(projects_yml))
|
|
54
|
+
rescue StandardError
|
|
55
|
+
nil
|
|
56
|
+
end
|
|
57
|
+
entry = data.is_a?(Hash) && data["projects"].is_a?(Hash) ? data["projects"][slug] : nil
|
|
58
|
+
path = entry.is_a?(Hash) ? entry["path"].to_s : ""
|
|
59
|
+
candidates << File.expand_path(path) unless path.empty?
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
candidates << File.expand_path("..", script_dir)
|
|
63
|
+
candidates.find { |c| File.exist?(File.join(c, ".git")) }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def git_tag_reader(explicit_repo:, script_dir:)
|
|
67
|
+
lambda do |intent_dir|
|
|
68
|
+
sha = ReportScreen.merge_sha(intent_dir)
|
|
69
|
+
return nil unless sha
|
|
70
|
+
repo = resolve_repo(intent_dir, explicit_repo, script_dir)
|
|
71
|
+
return nil unless repo
|
|
72
|
+
tags = `git -C #{repo.shellescape} tag --contains #{sha.shellescape} 2>/dev/null`
|
|
73
|
+
versions = tags.lines.map(&:strip).reject(&:empty?).filter_map do |tag|
|
|
74
|
+
v = tag.sub(/\Av/, "")
|
|
75
|
+
Gem::Version.correct?(v) ? [Gem::Version.new(v), tag] : nil
|
|
76
|
+
end
|
|
77
|
+
versions.min_by(&:first)&.last
|
|
44
78
|
end
|
|
45
79
|
end
|
|
46
80
|
|
|
@@ -49,6 +83,7 @@ verb = args.shift
|
|
|
49
83
|
changed = nil
|
|
50
84
|
ansi = false
|
|
51
85
|
template_path = nil
|
|
86
|
+
repo_flag = nil
|
|
52
87
|
positional = []
|
|
53
88
|
|
|
54
89
|
while (arg = args.shift)
|
|
@@ -60,6 +95,8 @@ while (arg = args.shift)
|
|
|
60
95
|
ansi = true
|
|
61
96
|
when "--all"
|
|
62
97
|
positional << "--all"
|
|
98
|
+
when "--repo"
|
|
99
|
+
repo_flag = args.shift or usage_abort("--repo needs a path")
|
|
63
100
|
when "--template"
|
|
64
101
|
template_path = args.shift or usage_abort("--template needs a path")
|
|
65
102
|
else
|
|
@@ -104,8 +141,8 @@ when "delivered"
|
|
|
104
141
|
usage_abort("usage: report-screen delivered <intent_dir>") unless target
|
|
105
142
|
intent_dir = File.expand_path(target)
|
|
106
143
|
usage_abort("#{intent_dir} is not an intent directory") unless IntentScreen.intent_dir?(intent_dir)
|
|
107
|
-
|
|
108
|
-
|
|
144
|
+
out = ReportScreen.render_delivered(intent_dir: intent_dir,
|
|
145
|
+
tag_reader: git_tag_reader(explicit_repo: repo_flag, script_dir: __dir__))
|
|
109
146
|
$stdout.write paint(out, ansi_enabled)
|
|
110
147
|
when "delay"
|
|
111
148
|
usage_abort("usage: report-screen delay <intent_dir>") unless target
|
package/scripts/verify-intent
CHANGED
|
@@ -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
|
package/skills/auto/SKILL.md
CHANGED
|
@@ -204,7 +204,8 @@ Then How.
|
|
|
204
204
|
5. Print `ruby ~/.plastic/scripts/report-screen state <intent_dir> --changed "How written, plan review next"`
|
|
205
205
|
(D15; see `references/human-report-contract.md` for the full trigger list). This replaces
|
|
206
206
|
the old prose State/Risk/Call briefing at this boundary. In auto mode the screen informs;
|
|
207
|
-
it does not wait.
|
|
207
|
+
it does not wait. The screen opens the reply with nothing before it and no code fence: the
|
|
208
|
+
`MessageDisplay` hook paints only a reply whose first characters are the screen marker.
|
|
208
209
|
|
|
209
210
|
Then Exec.
|
|
210
211
|
|
|
@@ -216,7 +217,7 @@ Then Exec.
|
|
|
216
217
|
then builds, then drives the full suite green.
|
|
217
218
|
2. Read its return by code: DONE or DONE_WITH_CONCERNS proceeds; NEEDS_CONTEXT re-dispatches
|
|
218
219
|
with the missing context; BLOCKED stops under the error procedure.
|
|
219
|
-
3. Tick the checklist as items land (the executor does this; verify
|
|
220
|
+
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.
|
|
220
221
|
|
|
221
222
|
## Review by risk (boot 3, only when a rule fires)
|
|
222
223
|
|
|
@@ -253,7 +254,7 @@ every choice is non-destructive and the team has full autonomy.
|
|
|
253
254
|
|
|
254
255
|
Read `../plastic-conventions/references/completion-and-done.md` for what "intent done" means.
|
|
255
256
|
|
|
256
|
-
1.
|
|
257
|
+
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.
|
|
257
258
|
2. Write `outcome.md` from `~/.plastic/templates/outcome.md` with `disposition: delivered`,
|
|
258
259
|
`## Delivered` as the labeled table whose row labels match the action-file headings (317a).
|
|
259
260
|
3. Release, if configured: match the working directory against `~/.plastic/projects.yml`, read
|
|
@@ -276,7 +277,8 @@ Read `../plastic-conventions/references/completion-and-done.md` for what "intent
|
|
|
276
277
|
disarm (`/plastic-doctor check the lock status`); 6 means the structure check refused. Never
|
|
277
278
|
leave an orphaned worktree; run `git worktree prune` on a stale reference.
|
|
278
279
|
6. Print `ruby ~/.plastic/scripts/report-screen delivered <intent_dir>` once (D15): this is the
|
|
279
|
-
owner report at End, replacing the old prose Done briefing.
|
|
280
|
+
owner report at End, replacing the old prose Done briefing. Print it as the first thing in
|
|
281
|
+
the reply, nothing before it and no code fence, or the hook cannot paint it.
|
|
280
282
|
|
|
281
283
|
## Error Handling
|
|
282
284
|
|
|
@@ -108,11 +108,15 @@ Capture observations in `## Insights`. When ALL checklist items are checked:
|
|
|
108
108
|
|
|
109
109
|
## Tick-as-you-land
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
Progress` to `## Completed` in `checklist.md
|
|
113
|
-
row (Date, Items Completed, Notes).
|
|
114
|
-
|
|
115
|
-
|
|
111
|
+
A tick is two edits, made together: mark the item's box `[x]`, and move its
|
|
112
|
+
checklist item from `## In Progress` to `## Completed` in `checklist.md`;
|
|
113
|
+
then add one `## Session Log` row (Date, Items Completed, Notes). The box is
|
|
114
|
+
the half the state screen's Progress bar reads: `IntentScreen::ITEM_RE` and
|
|
115
|
+
`progress_fields` count `[x]`, not which section the line sits in, so a line
|
|
116
|
+
moved to `## Completed` with its box left unmarked still reads as zero
|
|
117
|
+
progress. Do not batch several tasks' worth of checklist updates into one
|
|
118
|
+
later edit; tick the moment the task is verified, before moving to the next
|
|
119
|
+
task.
|
|
116
120
|
|
|
117
121
|
## Verify before every owner review
|
|
118
122
|
|
|
@@ -20,12 +20,17 @@ You are implementing a specific task from a plan. You have been given the full t
|
|
|
20
20
|
2. Implement exactly what the task specifies — nothing more, nothing less.
|
|
21
21
|
3. Write tests first when the task includes test steps (TDD).
|
|
22
22
|
4. Follow the file paths specified in the task exactly.
|
|
23
|
-
5. Commit after each logical unit of work
|
|
23
|
+
5. Commit after each logical unit of work, and in the same step tick the checklist item that
|
|
24
|
+
unit lands: mark its box `[x]` and move the line to `## Completed`, then append the
|
|
25
|
+
savepoint `Commit` line
|
|
26
|
+
(`scripts/savepoint-note <intent_dir> --kind Commit --text "<sha> <what it proves>"`). A
|
|
27
|
+
commit without its tick is incomplete.
|
|
24
28
|
6. When done, self-review against this checklist:
|
|
25
29
|
- [ ] All steps in the task are completed
|
|
26
30
|
- [ ] Tests pass
|
|
27
31
|
- [ ] Code is clean and follows project conventions
|
|
28
32
|
- [ ] No unrelated changes
|
|
33
|
+
- [ ] Every landed unit's checklist item is ticked
|
|
29
34
|
|
|
30
35
|
## Report Format
|
|
31
36
|
|