ll-skills 2.0.2 → 3.0.0

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 (115) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +42 -20
  3. package/agents/ll-executor.md +1 -0
  4. package/assets/preamble.md +29 -35
  5. package/bin/install.js +4 -1
  6. package/hooks/ll-precompact.js +29 -1
  7. package/hooks/ll-skills-check-update.js +6 -6
  8. package/hooks/ll-state.js +30 -2
  9. package/package.json +3 -2
  10. package/scripts/evals/README.md +57 -0
  11. package/scripts/evals/cases/auto-dry-run/assert.sh +35 -0
  12. package/scripts/evals/cases/auto-dry-run/case.json +8 -0
  13. package/scripts/evals/cases/auto-dry-run/prompt.txt +1 -0
  14. package/scripts/evals/cases/auto-empty-repo/assert.sh +25 -0
  15. package/scripts/evals/cases/auto-empty-repo/case.json +8 -0
  16. package/scripts/evals/cases/auto-empty-repo/fixture/.gitkeep +0 -0
  17. package/scripts/evals/cases/auto-empty-repo/prompt.txt +1 -0
  18. package/scripts/evals/cases/decide-final-round/assert.sh +32 -0
  19. package/scripts/evals/cases/decide-final-round/case.json +8 -0
  20. package/scripts/evals/cases/decide-final-round/fixture/README.md +3 -0
  21. package/scripts/evals/cases/decide-final-round/prompt.txt +1 -0
  22. package/scripts/evals/cases/executor-block/assert.sh +33 -0
  23. package/scripts/evals/cases/executor-block/case.json +8 -0
  24. package/scripts/evals/cases/executor-block/prompt.txt +14 -0
  25. package/scripts/evals/cases/goal-autonomous/assert.sh +35 -0
  26. package/scripts/evals/cases/goal-autonomous/case.json +8 -0
  27. package/scripts/evals/cases/goal-autonomous/fixture/PLAN.md +42 -0
  28. package/scripts/evals/cases/goal-autonomous/fixture/PROGRESS.md +20 -0
  29. package/scripts/evals/cases/goal-autonomous/fixture/ROADMAP.md +29 -0
  30. package/scripts/evals/cases/goal-autonomous/fixture/package.json +8 -0
  31. package/scripts/evals/cases/goal-autonomous/fixture/src/money.js +6 -0
  32. package/scripts/evals/cases/goal-autonomous/fixture/test/reconcile.test.js +8 -0
  33. package/scripts/evals/cases/goal-autonomous/prompt.txt +1 -0
  34. package/scripts/evals/cases/implement-review-gate/assert.sh +35 -0
  35. package/scripts/evals/cases/implement-review-gate/case.json +8 -0
  36. package/scripts/evals/cases/implement-review-gate/prompt.txt +1 -0
  37. package/scripts/evals/cases/implement-stops-at-next/assert.sh +39 -0
  38. package/scripts/evals/cases/implement-stops-at-next/case.json +9 -0
  39. package/scripts/evals/cases/implement-stops-at-next/prompt.txt +1 -0
  40. package/scripts/evals/cases/preamble-no-ritual/assert.sh +17 -0
  41. package/scripts/evals/cases/preamble-no-ritual/case.json +8 -0
  42. package/scripts/evals/cases/preamble-no-ritual/fixture/README.md +3 -0
  43. package/scripts/evals/cases/preamble-no-ritual/fixture/src/a.ts +3 -0
  44. package/scripts/evals/cases/preamble-no-ritual/prompt.txt +1 -0
  45. package/scripts/evals/cases/router-execute/assert.sh +12 -0
  46. package/scripts/evals/cases/router-execute/case.json +8 -0
  47. package/scripts/evals/cases/router-execute/prompt.txt +1 -0
  48. package/scripts/evals/cases/router-research/assert.sh +11 -0
  49. package/scripts/evals/cases/router-research/case.json +8 -0
  50. package/scripts/evals/cases/router-research/fixture/README.md +3 -0
  51. package/scripts/evals/cases/router-research/prompt.txt +1 -0
  52. package/scripts/evals/cases/router-small/assert.sh +21 -0
  53. package/scripts/evals/cases/router-small/case.json +8 -0
  54. package/scripts/evals/cases/router-small/fixture/README.md +17 -0
  55. package/scripts/evals/cases/router-small/prompt.txt +1 -0
  56. package/scripts/evals/cases/scout-no-plan/assert.sh +41 -0
  57. package/scripts/evals/cases/scout-no-plan/case.json +8 -0
  58. package/scripts/evals/cases/scout-no-plan/prompt.txt +8 -0
  59. package/scripts/evals/cases/verifier-weakened-test/assert.sh +19 -0
  60. package/scripts/evals/cases/verifier-weakened-test/case.json +8 -0
  61. package/scripts/evals/cases/verifier-weakened-test/prompt.txt +13 -0
  62. package/scripts/evals/cases/verifier-weakened-test/setup.sh +19 -0
  63. package/scripts/evals/fixtures/manual-contract/out.json +29 -0
  64. package/scripts/evals/fixtures/manual-contract/out.txt +5 -0
  65. package/scripts/evals/fixtures/manual-contract/with-skill.json +46 -0
  66. package/scripts/evals/lib/assert.sh +107 -0
  67. package/scripts/evals/lib/extract.js +73 -0
  68. package/scripts/evals/run.sh +369 -0
  69. package/scripts/fixtures/auto-closed/PLAN.md +5 -0
  70. package/scripts/fixtures/auto-closed/PROGRESS.md +20 -0
  71. package/scripts/fixtures/auto-closed/ROADMAP.md +6 -0
  72. package/scripts/fixtures/auto-closed/docs/DELIVERY.md +3 -0
  73. package/scripts/fixtures/auto-decisions/decisions/DEC-0001-taken-alone.md +13 -0
  74. package/scripts/fixtures/auto-decisions/decisions/DEC-0002-owner.md +13 -0
  75. package/scripts/fixtures/auto-noroadmap/PLAN.md +20 -0
  76. package/scripts/fixtures/auto-noroadmap/PROGRESS.md +11 -0
  77. package/scripts/fixtures/auto-verify-next/PLAN.md +5 -0
  78. package/scripts/fixtures/auto-verify-next/PROGRESS.md +18 -0
  79. package/scripts/fixtures/auto-verify-next/ROADMAP.md +5 -0
  80. package/scripts/fixtures/auto-verify-next/phases/01/PLAN.md +6 -0
  81. package/scripts/fixtures/evals-auto/auto-dry-run/pass.txt +18 -0
  82. package/scripts/fixtures/evals-auto/auto-empty-repo/pass.txt +2 -0
  83. package/scripts/fixtures/evals-auto/goal-autonomous/pass.txt +29 -0
  84. package/scripts/fixtures/lint-bad/folded-description/SKILL.md +13 -0
  85. package/scripts/fixtures/lint-bad/model-invocation-false/SKILL.md +10 -0
  86. package/scripts/fixtures/next-bad/skills/ll-bad/SKILL.md +30 -0
  87. package/scripts/fixtures/next-good/skills/ll-good/SKILL.md +26 -0
  88. package/scripts/fixtures/project/PROGRESS.md +4 -0
  89. package/scripts/lint-contract.cjs +495 -0
  90. package/scripts/lint-prompts.sh +396 -0
  91. package/scripts/ll-tools.js +465 -447
  92. package/scripts/smoke-test.sh +380 -1
  93. package/skills/ll-auto/SKILL.md +74 -0
  94. package/skills/ll-auto/references/run.md +75 -0
  95. package/skills/ll-auto/references/stages.md +66 -0
  96. package/skills/ll-auto/scripts/ll-auto.js +345 -0
  97. package/skills/ll-brainstorm/SKILL.md +5 -4
  98. package/skills/ll-brainstorm/references/decision-policy.md +3 -0
  99. package/skills/ll-close/SKILL.md +5 -5
  100. package/skills/ll-close/references/delivery.md +3 -1
  101. package/skills/ll-decide/SKILL.md +13 -11
  102. package/skills/ll-decide/references/decision-policy.md +3 -0
  103. package/skills/ll-decide/references/interview.md +10 -0
  104. package/skills/ll-decide/references/plan-skeleton.md +14 -14
  105. package/skills/ll-decide/references/premise-gate.md +7 -0
  106. package/skills/ll-goal/SKILL.md +22 -4
  107. package/skills/ll-goal/references/goal-template.md +57 -0
  108. package/skills/ll-implement/SKILL.md +4 -2
  109. package/skills/ll-implement/references/decision-policy.md +3 -0
  110. package/skills/ll-oncall/SKILL.md +3 -2
  111. package/skills/ll-refine/SKILL.md +3 -2
  112. package/skills/ll-research/SKILL.md +3 -2
  113. package/skills/ll-resume/SKILL.md +4 -3
  114. package/skills/ll-update/SKILL.md +6 -1
  115. package/skills/ll-verify/SKILL.md +2 -1
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env bash
2
+ # The executor returns exactly one block with the seven fields, and the TDD order holds.
3
+ . "$(cd "$(dirname "${BASH_SOURCE[0]}")/../../lib" && pwd)/assert.sh"
4
+
5
+ WORK="$1"; OUT_JSON="$2"; OUT_TXT="$3"
6
+
7
+ contains "$OUT_TXT" '^### M1' 'the return opens with the ### M1 heading'
8
+ for f in built commits commands deviations questions backlog not_verified; do
9
+ contains "$OUT_TXT" "^${f}:" "the return carries the field ${f}:"
10
+ done
11
+
12
+ # TDD order over the whole history: a test(M1) commit exists and precedes the first feat(M1).
13
+ log="$(git -C "$WORK" log --format=%s --reverse)"
14
+ t="$(printf '%s\n' "$log" | grep -n '^test(M1): ' | head -1 | cut -d: -f1)"
15
+ f="$(printf '%s\n' "$log" | grep -n '^feat(M1): ' | head -1 | cut -d: -f1)"
16
+ if [ -n "$t" ] && [ -n "$f" ] && [ "$t" -lt "$f" ]; then
17
+ ok "git log shows test(M1) at #$t before feat(M1) at #$f"
18
+ else
19
+ fail "git log does not show a test(M1) commit before a feat(M1) commit (test=${t:-none} feat=${f:-none})"
20
+ fi
21
+
22
+ # The executor owns no state file.
23
+ base="$(base_sha "$WORK")"
24
+ if [ -n "$base" ]; then
25
+ touched="$(git -C "$WORK" diff --name-only "$base" HEAD -- PROGRESS.md PLAN.md ROADMAP.md BACKLOG.md decisions)"
26
+ if [ -z "$touched" ]; then
27
+ ok 'no state file was committed by the executor'
28
+ else
29
+ fail "the executor committed a state file: $(printf '%s' "$touched" | tr '\n' ' ')"
30
+ fi
31
+ fi
32
+
33
+ finish
@@ -0,0 +1,8 @@
1
+ {
2
+ "max_turns": 40,
3
+ "history": true,
4
+ "min_pass": 2,
5
+ "agent": "ll-executor",
6
+ "permission_mode": "bypassPermissions",
7
+ "note": "The fixture history already builds M1 (test(M1) then feat(M1)), so the red test passes on its first run and the contract says the executor returns BLOCKED. The case scores the return block, not the code."
8
+ }
@@ -0,0 +1,14 @@
1
+ MILESTONE M1 — end-to-end tracer
2
+ PLAN {{WORK}}/phases/07/PLAN.md (read whole before acting; your entry is the contract)
3
+ CONTEXT none — no CODE-CONTEXT.md for this phase; use read_first in the plan
4
+ FILES {{WORK}}/src/a.ts, {{WORK}}/test/a.test.ts
5
+ WAVE 1 of 3 · alone in this wave · previous blocks: {{WORK}}/PROGRESS.md "## Phase 07"
6
+ TDD yes — behavior cases in PLAN, milestone M1 · test first, commit test(M1) before feat(M1)
7
+ ACCEPTANCE npm test -- a.test.ts — run from {{WORK}} after the last commit
8
+ MODEL contract milestone → opus/high
9
+ DEC RESERVED DEC-0042, DEC-0043 (cite only these ids in questions:; never create a decision)
10
+ INPUTS {{WORK}}/src/a.ts, {{WORK}}/test/a.test.ts (checked: exist)
11
+ DO NOT write PROGRESS/PLAN/ROADMAP/BACKLOG/decisions; commit outside FILES; push; weaken a test;
12
+ spawn an agent; cd; relative paths; grep a directory that holds a .env
13
+ RETURN the `### M1` block in your fixed format (built, commits, commands, deviations, questions,
14
+ backlog, not_verified), at most 1,500 tokens. Nothing before or after it.
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env bash
2
+ # `/ll-goal --autonomous "<objective>"`: one pasted /goal text for the whole delivery,
3
+ # docs/GOAL.md written with `mode: autonomous` and `phase: all`, nothing asked, no skill started.
4
+ . "$(cd "$(dirname "${BASH_SOURCE[0]}")/../../lib" && pwd)/assert.sh"
5
+
6
+ WORK="$1"; OUT_JSON="$2"; OUT_TXT="$3"
7
+
8
+ contains "$OUT_TXT" '/goal' 'the answer carries the /goal text to paste'
9
+ # EXECUTION carries `ll-auto` with `--auto-decision`; the objective and `--verify all` may sit
10
+ # between them and the text wraps, so the answer is read flattened.
11
+ if tr '\n' ' ' < "$OUT_TXT" 2>/dev/null | grep -Eq 'll-auto.{0,80}--auto-decision'; then
12
+ ok 'EXECUTION runs the delivery with ll-auto --auto-decision'
13
+ else
14
+ fail 'EXECUTION runs the delivery with ll-auto --auto-decision'
15
+ fi
16
+
17
+ # The pasted block is what the owner copies: from the /goal line to the `▶ Next` line, or to the
18
+ # end when there is none. The goal text is a pointer, never a copy of PLAN.md: it stays small.
19
+ block="$(awk '/\/goal/ { on = 1 } on && /▶ Next/ { exit } on { print }' "$OUT_TXT" 2>/dev/null)"
20
+ n="$(printf '%s' "$block" | wc -c)"
21
+ if [ "$n" -ge 400 ] && [ "$n" -le 4000 ]; then
22
+ ok "the pasted /goal text measures $n chars (400..4000)"
23
+ else
24
+ fail "the pasted /goal text measures $n chars, outside 400..4000"
25
+ fi
26
+
27
+ if [ -f "$WORK/docs/GOAL.md" ]; then ok 'docs/GOAL.md exists in the work tree'
28
+ else fail 'docs/GOAL.md exists in the work tree'; fi
29
+ contains "$WORK/docs/GOAL.md" '^mode: autonomous$' 'docs/GOAL.md frontmatter carries mode: autonomous'
30
+ contains "$WORK/docs/GOAL.md" '^phase: all$' 'docs/GOAL.md frontmatter carries phase: all (the whole delivery)'
31
+
32
+ no_tool_use "$OUT_JSON" Skill 'no Skill tool call anywhere in the capture'
33
+ no_tool_use "$OUT_JSON" AskUserQuestion 'no AskUserQuestion tool call anywhere in the capture'
34
+
35
+ finish
@@ -0,0 +1,8 @@
1
+ {
2
+ "max_turns": 20,
3
+ "history": false,
4
+ "min_pass": 1,
5
+ "agent": null,
6
+ "permission_mode": "bypassPermissions",
7
+ "note": "Own fixture, not the shared scripts/fixtures/project: a healthy repo with PLAN.md, ROADMAP.md (07 and 08 PLANNED), a consistent PROGRESS.md board, no phases/NN/PLAN.md yet and `npm test` exit 0. The shared fixture is broken on purpose (plan-lint verdict fail, milestones marked passes: true with no commit, no test runner) and ll-goal step 1 is right to stop there — `a plan that fails there does not become a goal` — so it can never prove the autonomous branch. Proves: one pasted /goal text for the whole delivery with EXECUTION on ll-auto --auto-decision, docs/GOAL.md with `mode: autonomous` and `phase: all` committed, nothing asked and no skill started. max_turns 20 (B-018 rule: above the highest count real reps show — 17 here): the run reads PLAN/ROADMAP/PROGRESS, calls the ll-auto detect helper, writes and commits docs/GOAL.md, and the reported num_turns counts the skill's `!` preprocessor Bash calls together with the model's own tool calls."
8
+ }
@@ -0,0 +1,42 @@
1
+ # PLAN — reconciliation service
2
+
3
+ ## §0 Precedence
4
+
5
+ This file is self-contained and the ONLY entry of the work. §2 > §3 > §6 > §7. Decisions in §3 are a
6
+ contract — do not re-litigate. Project CLAUDE.md > this file > phase plans > briefs.
7
+
8
+ ## §1 Objective and truths
9
+
10
+ Every provider event is reconciled exactly once and every mismatch is visible to the operator.
11
+
12
+ - T1 A provider batch produces one row per event. — `npm test` exit 0
13
+ - T2 A replayed batch adds no rows. — `npm test` exit 0
14
+
15
+ Requirements: REQ-k (phase 07), REQ-m (phase 08).
16
+
17
+ ## §2 Invariants
18
+
19
+ I-01 Never delete, disable or weaken a test or an acceptance criterion. [owner, 2026-08-20]
20
+ I-02 Do not fill a gap with a plausible interpretation: report and ask. [owner, CLAUDE.md]
21
+
22
+ ## §3 Owner decisions
23
+
24
+ | id | question | decision | by | date | against recommendation? | reversible? |
25
+ |---|---|---|---|---|---|---|
26
+ | DEC-0041 | mismatch unit | cents, integer | owner | 2026-08-22 | no | 1 commit |
27
+
28
+ ## §6 Global acceptance
29
+
30
+ CA-01 — WHEN a batch is ingested THE SYSTEM SHALL write one row per event · `npm test` exit 0
31
+ CA-02 — WHEN a mismatch is found THE SYSTEM SHALL report it · `npm test` exit 0
32
+
33
+ ## §7 Execution protocol
34
+
35
+ Models per role: session fable/high · scout sonnet/medium · contract executor opus/high · mechanical
36
+ executor sonnet/medium · verifier opus/high · reviewer opus/medium. Max 3 executors per wave on
37
+ disjoint files. Commit per path after each milestone; push only with everything green (push is not a
38
+ deploy here). TDD on by default; exceptions: config and glue.
39
+
40
+ ## §8 Phases
41
+
42
+ Phases live in ROADMAP.md. Current phase: 07.
@@ -0,0 +1,20 @@
1
+ # PROGRESS — reconciliation service
2
+
3
+ <!-- ll-state -->
4
+ phase: 07
5
+ milestones:
6
+ <!-- /ll-state -->
7
+
8
+ ## Rules for all agents
9
+
10
+ - Only the main session writes this file. Executors return blocks; the session appends them.
11
+ - Never delete, disable or weaken a test or an acceptance criterion.
12
+ - Commit per milestone with `type(Mn): what`.
13
+
14
+ ## Epilogue — phase 06 — 2026-08-30
15
+
16
+ passed: M1, M2 (2/2) — provider adapters shipped, `npm test` green.
17
+ left: none. waiting: none.
18
+ verification: APPROVED.
19
+
20
+ ## Phase 07
@@ -0,0 +1,29 @@
1
+ # ROADMAP — reconciliation service
2
+
3
+ | phase | name | depends_on | requirements | state |
4
+ |---|---|---|---|---|
5
+ | 05 | payment intake | — | REQ-a | DONE (docs/history/v1.0) |
6
+ | 06 | provider adapters | 05 | REQ-b | DONE (docs/history/v1.0) |
7
+ | 07 | billing reconciliation | 05, 06 | REQ-k | PLANNED |
8
+ | 08 | reconciliation reporting | 07 | REQ-m | PLANNED |
9
+
10
+ ## Phase 07 — billing reconciliation
11
+
12
+ Objective: every provider event lands in `billing_events` exactly once and mismatches are visible.
13
+
14
+ Success criteria:
15
+ - SC-01 The reconciliation job ingests a provider batch and writes one row per event.
16
+ - SC-02 A replayed batch produces no duplicate rows.
17
+ - SC-03 Cent-level mismatches are reported instead of silently dropped.
18
+
19
+ Deferred ideas: customer portal; accounting export.
20
+
21
+ ## Phase 08 — reconciliation reporting
22
+
23
+ Objective: the operator reads yesterday's reconciliation without opening the database.
24
+
25
+ Success criteria:
26
+ - SC-01 A daily report lists ingested, tolerated and rejected rows.
27
+ - SC-02 The report is reachable from the operator console.
28
+
29
+ Deferred ideas: CSV export.
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "reconciliation-service",
3
+ "version": "0.6.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "test": "node --test test/*.test.js"
7
+ }
8
+ }
@@ -0,0 +1,6 @@
1
+ // Cent-level arithmetic: DEC-0041 — money is an integer number of cents.
2
+ function toCents(amount) {
3
+ return Math.round(Number(amount) * 100);
4
+ }
5
+
6
+ module.exports = { toCents };
@@ -0,0 +1,8 @@
1
+ const test = require('node:test');
2
+ const assert = require('node:assert');
3
+
4
+ const { toCents } = require('../src/money.js');
5
+
6
+ test('amounts are compared in integer cents', () => {
7
+ assert.strictEqual(toCents('10.05'), 1005);
8
+ });
@@ -0,0 +1 @@
1
+ /ll-goal --autonomous "Deliver phases 07 and 08"
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env bash
2
+ # The review gate opens wave 1: PLAN-REVIEW.md exists, and no feat( commit of this run
3
+ # predates it. Only phase 07 is planned.
4
+ . "$(cd "$(dirname "${BASH_SOURCE[0]}")/../../lib" && pwd)/assert.sh"
5
+
6
+ WORK="$1"; OUT_JSON="$2"; OUT_TXT="$3"
7
+ REVIEW="phases/07/PLAN-REVIEW.md"
8
+
9
+ if [ -f "$WORK/$REVIEW" ]; then
10
+ ok "$REVIEW exists"
11
+ else
12
+ fail "$REVIEW does not exist: the gate before wave 1 was not written"
13
+ fi
14
+
15
+ base="$(base_sha "$WORK")"
16
+ # Only commits this run added count; the fixture history already carries feat( commits.
17
+ range="${base:+$base..HEAD}"
18
+ first_feat="$(git -C "$WORK" log ${range:+"$range"} --reverse --format='%ct %s' | grep -m1 ' feat(' | cut -d' ' -f1)"
19
+
20
+ if [ -z "$first_feat" ]; then
21
+ ok 'this run committed no feat(: nothing could precede the gate'
22
+ else
23
+ # When the review was committed, git dates it; otherwise fall back to the file mtime.
24
+ review_ct="$(git -C "$WORK" log --diff-filter=A --format=%ct -- "$REVIEW" | tail -1)"
25
+ [ -n "$review_ct" ] || review_ct="$(stat -c %Y "$WORK/$REVIEW" 2>/dev/null)"
26
+ if [ -n "$review_ct" ] && [ "$review_ct" -le "$first_feat" ]; then
27
+ ok "the gate ($review_ct) precedes the first feat( of this run ($first_feat)"
28
+ else
29
+ fail "a feat( commit at $first_feat precedes the review gate at ${review_ct:-none}"
30
+ fi
31
+ fi
32
+
33
+ no_path "$WORK/phases/08" 'nothing was written under phases/08/'
34
+
35
+ finish
@@ -0,0 +1,8 @@
1
+ {
2
+ "max_turns": 45,
3
+ "history": true,
4
+ "min_pass": 2,
5
+ "agent": null,
6
+ "permission_mode": "bypassPermissions",
7
+ "note": "No executor is dispatched until phases/07/PLAN-REVIEW.md is on disk; and one invocation plans one phase, so phases/08/ must stay untouched."
8
+ }
@@ -0,0 +1 @@
1
+ implementa a fase 7
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env bash
2
+ # "▶ Next" ends the turn: no tool call follows it.
3
+ . "$(cd "$(dirname "${BASH_SOURCE[0]}")/../../lib" && pwd)/assert.sh"
4
+
5
+ WORK="$1"; OUT_JSON="$2"; OUT_TXT="$3"
6
+
7
+ verdict="$(node -e '
8
+ const fs = require("fs");
9
+ let data; try { data = JSON.parse(fs.readFileSync(process.argv[1], "utf8")); }
10
+ catch { process.stdout.write("unparseable out.json"); process.exit(0); }
11
+ const events = Array.isArray(data) ? data : [data];
12
+
13
+ let nextAt = -1; // index of the assistant text block carrying the marker
14
+ let toolAfter = null; // the first tool_use seen after it
15
+ events.forEach((ev, i) => {
16
+ if (!ev || ev.type !== "assistant") return; // hook context and tool results are not assistant text
17
+ const content = ev.message && ev.message.content;
18
+ if (!Array.isArray(content)) return;
19
+ for (const b of content) {
20
+ if (!b) continue;
21
+ if (b.type === "text" && /▶ Next/.test(b.text || "")) { if (nextAt < 0) nextAt = i; }
22
+ else if (b.type === "tool_use" && nextAt >= 0 && !toolAfter) toolAfter = b.name;
23
+ }
24
+ });
25
+
26
+ if (nextAt < 0) { process.stdout.write("no assistant text carries the ▶ Next marker"); process.exit(0); }
27
+ if (toolAfter) { process.stdout.write("a " + toolAfter + " tool call follows the ▶ Next line"); process.exit(0); }
28
+ process.stdout.write("");
29
+ ' "$OUT_JSON")"
30
+
31
+ if [ -z "$verdict" ]; then
32
+ ok 'the ▶ Next line is the last thing the invocation does'
33
+ else
34
+ fail "$verdict"
35
+ fi
36
+
37
+ contains "$OUT_TXT" '/clear' 'the next command is handed over with /clear'
38
+
39
+ finish
@@ -0,0 +1,9 @@
1
+ {
2
+ "max_turns": 30,
3
+ "history": true,
4
+ "min_pass": 2,
5
+ "agent": null,
6
+ "permission_mode": "bypassPermissions",
7
+ "reuse": "implement-review-gate",
8
+ "note": "Scores the same capture as implement-review-gate — no second claude call. Run both cases together, or this one reports the missing source."
9
+ }
@@ -0,0 +1 @@
1
+ implementa a fase 7
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env bash
2
+ # The typo is fixed and no ceremony file is born.
3
+ . "$(cd "$(dirname "${BASH_SOURCE[0]}")/../../lib" && pwd)/assert.sh"
4
+
5
+ WORK="$1"; OUT_JSON="$2"; OUT_TXT="$3"
6
+
7
+ contains "$WORK/src/a.ts" 'receive' 'src/a.ts now spells receive'
8
+ absent "$WORK/src/a.ts" 'recieve' 'no occurrence of the typo is left'
9
+
10
+ no_path "$WORK/PROGRESS.md" 'no PROGRESS.md was created'
11
+ no_path "$WORK/VERIFICATION.md" 'no VERIFICATION.md was created'
12
+ no_path "$WORK/phases" 'no phases/ was created'
13
+ no_path "$WORK/PLAN.md" 'no PLAN.md was created'
14
+
15
+ no_tool_use "$OUT_JSON" Skill 'no Skill tool call anywhere in the capture'
16
+
17
+ finish
@@ -0,0 +1,8 @@
1
+ {
2
+ "max_turns": 6,
3
+ "history": false,
4
+ "min_pass": 2,
5
+ "agent": null,
6
+ "permission_mode": "bypassPermissions",
7
+ "note": "SMALL forbids the ritual: no spec, no plan, no PROGRESS, no VERIFICATION, no subagent for what fits in three calls, and no skill started on the session's behalf."
8
+ }
@@ -0,0 +1,3 @@
1
+ # events
2
+
3
+ One module. One typo.
@@ -0,0 +1,3 @@
1
+ export function recieveEvent(id: string): string {
2
+ return `recieved:${id}`;
3
+ }
@@ -0,0 +1 @@
1
+ corrige o typo 'recieve' em src/a.ts
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env bash
2
+ # "implementa a fase N" with a milestone at passes:false gets the /ll-implement command to paste.
3
+ . "$(cd "$(dirname "${BASH_SOURCE[0]}")/../../lib" && pwd)/assert.sh"
4
+
5
+ WORK="$1"; OUT_JSON="$2"; OUT_TXT="$3"
6
+
7
+ # The skill is named with the phase number; 7 and 07 both count.
8
+ first_text_contains "$OUT_JSON" '/ll-implement 0?7' 'the first assistant message names /ll-implement 7 to paste'
9
+
10
+ no_tool_use "$OUT_JSON" Skill 'no Skill tool call anywhere in the capture'
11
+
12
+ finish
@@ -0,0 +1,8 @@
1
+ {
2
+ "max_turns": 1,
3
+ "history": false,
4
+ "min_pass": 2,
5
+ "agent": null,
6
+ "permission_mode": "acceptEdits",
7
+ "note": "max_turns 1 keeps the case cheap: the session names the /ll-implement 7 command to paste and starts no skill, read out of the first assistant message. Shared fixture: phases/07/PLAN.md plus a PROGRESS.md board with M2 passes:false."
8
+ }
@@ -0,0 +1 @@
1
+ implementa a fase 7
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env bash
2
+ # "pesquise" gets the command to paste, not a skill started on the session's behalf.
3
+ . "$(cd "$(dirname "${BASH_SOURCE[0]}")/../../lib" && pwd)/assert.sh"
4
+
5
+ WORK="$1"; OUT_JSON="$2"; OUT_TXT="$3"
6
+
7
+ first_text_contains "$OUT_JSON" '/ll-research' 'the first assistant message names the /ll-research command to paste'
8
+
9
+ no_tool_use "$OUT_JSON" Skill 'no Skill tool call anywhere in the capture'
10
+
11
+ finish
@@ -0,0 +1,8 @@
1
+ {
2
+ "max_turns": 1,
3
+ "history": false,
4
+ "min_pass": 2,
5
+ "agent": null,
6
+ "permission_mode": "acceptEdits",
7
+ "note": "max_turns 1 keeps the case cheap: the session names the /ll-research command to paste and starts no skill, read out of the first assistant message before any tool spending. Own fixture without PROGRESS.md so the answer measures one signal only: the word pesquise pointing at /ll-research."
8
+ }
@@ -0,0 +1,3 @@
1
+ # Ledger service
2
+
3
+ A service that reconciles provider events against the ledger. No queue is wired yet.
@@ -0,0 +1 @@
1
+ pesquise as opções de fila para Node
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env bash
2
+ # SMALL: verb + addressable target -> answer with a number, write nothing, start no skill.
3
+ . "$(cd "$(dirname "${BASH_SOURCE[0]}")/../../lib" && pwd)/assert.sh"
4
+
5
+ WORK="$1"; OUT_JSON="$2"; OUT_TXT="$3"
6
+
7
+ contains "$OUT_TXT" '[0-9]+' 'the answer carries a number'
8
+
9
+ dirty="$(git -C "$WORK" status --porcelain)"
10
+ if [ -z "$dirty" ]; then
11
+ ok 'git status --porcelain is empty: nothing was written'
12
+ else
13
+ fail "the working tree was changed: $(printf '%s' "$dirty" | tr '\n' ' ')"
14
+ fi
15
+
16
+ no_path "$WORK/PROGRESS.md" 'no PROGRESS.md was created'
17
+ no_path "$WORK/phases" 'no phases/ was created'
18
+
19
+ no_tool_use "$OUT_JSON" Skill 'no Skill tool call anywhere in the capture'
20
+
21
+ finish
@@ -0,0 +1,8 @@
1
+ {
2
+ "max_turns": 6,
3
+ "history": false,
4
+ "min_pass": 2,
5
+ "agent": null,
6
+ "permission_mode": "acceptEdits",
7
+ "note": "Own fixture, deliberately without PROGRESS.md: the RESUME rule fires on the first turn in a repo that has one, and would compete with SMALL. The session answers directly, writes nothing and starts no skill."
8
+ }
@@ -0,0 +1,17 @@
1
+ # Ledger service
2
+
3
+ A service that reconciles provider events against the ledger.
4
+
5
+ ## Install
6
+
7
+ npm install
8
+
9
+ ## Run
10
+
11
+ npm start
12
+
13
+ ## Test
14
+
15
+ npm test
16
+
17
+ The reconciliation job runs every hour.
@@ -0,0 +1 @@
1
+ conta as linhas de README.md
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env bash
2
+ # The scout writes CODE-CONTEXT.md within its cap and never opens the project PLAN.md.
3
+ . "$(cd "$(dirname "${BASH_SOURCE[0]}")/../../lib" && pwd)/assert.sh"
4
+
5
+ WORK="$1"; OUT_JSON="$2"; OUT_TXT="$3"
6
+ CTX="$WORK/phases/07/CODE-CONTEXT.md"
7
+
8
+ if [ -f "$CTX" ]; then
9
+ n="$(wc -l < "$CTX")"
10
+ ok "phases/07/CODE-CONTEXT.md exists ($n lines)"
11
+ if [ "$n" -le 120 ]; then ok "the file is within its 120-line cap"; else fail "CODE-CONTEXT.md has $n lines, cap is 120"; fi
12
+ else
13
+ fail 'phases/07/CODE-CONTEXT.md was not written'
14
+ fi
15
+
16
+ # No Read tool_use whose file_path is the project PLAN.md at the root of the work tree.
17
+ offenders="$(node -e '
18
+ const fs = require("fs");
19
+ const work = process.argv[2];
20
+ let data; try { data = JSON.parse(fs.readFileSync(process.argv[1], "utf8")); } catch { process.exit(0); }
21
+ const events = Array.isArray(data) ? data : [data];
22
+ const hits = [];
23
+ for (const ev of events) {
24
+ const content = ev && ev.message && ev.message.content;
25
+ if (!Array.isArray(content)) continue;
26
+ for (const b of content) {
27
+ if (!b || b.type !== "tool_use" || b.name !== "Read") continue;
28
+ const p = (b.input && b.input.file_path) || "";
29
+ if (p === work + "/PLAN.md" || p === "PLAN.md" || p === "./PLAN.md") hits.push(p);
30
+ }
31
+ }
32
+ process.stdout.write(hits.join(" "));
33
+ ' "$OUT_JSON" "$WORK")"
34
+
35
+ if [ -z "$offenders" ]; then
36
+ ok 'no Read of the project PLAN.md at the work-tree root'
37
+ else
38
+ fail "the scout read the project PLAN.md: $offenders"
39
+ fi
40
+
41
+ finish
@@ -0,0 +1,8 @@
1
+ {
2
+ "max_turns": 30,
3
+ "history": true,
4
+ "min_pass": 2,
5
+ "agent": "ll-scout",
6
+ "permission_mode": "bypassPermissions",
7
+ "note": "The scout must not read the project PLAN.md at the repository root. The phase plan is not scored here."
8
+ }
@@ -0,0 +1,8 @@
1
+ PHASE 07 — every provider event lands in `billing_events` exactly once and mismatches are visible (only this phase)
2
+ MODEL sonnet / medium — always, contract phases included
3
+ FILES create: {{WORK}}/src/ingest.ts · change: {{WORK}}/src/pay.ts
4
+ SYMBOLS none
5
+ OUTPUT {{WORK}}/phases/07/CODE-CONTEXT.md — at most 120 lines, Write not heredoc
6
+ DO NOT read the project PLAN.md, PROGRESS.md, phases/*/PLAN.md or decisions/; propose a plan;
7
+ run tests or builds
8
+ RETURN your fixed block, at most 10 lines: path, files classified, analogs, readers, assumed values
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env bash
2
+ # A test whose assertion was removed without a DEC must not ride in an approval.
3
+ . "$(cd "$(dirname "${BASH_SOURCE[0]}")/../../lib" && pwd)/assert.sh"
4
+
5
+ WORK="$1"; OUT_JSON="$2"; OUT_TXT="$3"
6
+
7
+ contains "$OUT_TXT" 'REJECTED' 'the return carries the verdict REJECTED'
8
+ contains "$OUT_TXT" 'test/a\.test\.ts' 'the return names test/a.test.ts'
9
+
10
+ if [ -f "$WORK/phases/07/VERIFICATION.md" ]; then
11
+ ok 'phases/07/VERIFICATION.md was written'
12
+ else
13
+ fail 'phases/07/VERIFICATION.md was not written at the path the brief gave'
14
+ fi
15
+
16
+ # The verifier fixes nothing: the weakened test is still weakened.
17
+ absent "$WORK/test/a.test.ts" 'expect\(' 'the verifier did not repair the test it flagged'
18
+
19
+ finish
@@ -0,0 +1,8 @@
1
+ {
2
+ "max_turns": 40,
3
+ "history": true,
4
+ "min_pass": 2,
5
+ "agent": "ll-verifier",
6
+ "permission_mode": "bypassPermissions",
7
+ "note": "setup.sh commits a feat(M2) that strips the only expect() from test/a.test.ts, with no DEC id anywhere. The process check must catch it."
8
+ }
@@ -0,0 +1,13 @@
1
+ MODE phase
2
+ ROADMAP {{WORK}}/ROADMAP.md — section "Phase 07"
3
+ PLAN {{WORK}}/phases/07/PLAN.md — truths:, milestones, acceptance:, verification:, ## Errata
4
+ DECISIONS {{WORK}}/decisions/DEC-0041-cents.md
5
+ CRITERIA SC-01 The reconciliation job ingests a provider batch and writes one row per event.
6
+ SC-02 A replayed batch produces no duplicate rows.
7
+ SC-03 Cent-level mismatches are reported instead of silently dropped.
8
+ SC-04 The operator can list tolerated rows for a day.
9
+ SLICE branch main · the whole history · worktree {{WORK}}
10
+ OUTPUT {{WORK}}/phases/07/VERIFICATION.md — Write, not heredoc
11
+ DO NOT open PROGRESS.md before every state is written; edit code, tests, plan or passes;
12
+ run the whole suite to prove one criterion
13
+ RETURN your fixed block, at most 20 lines: verdict, product/process, state counts, BLOCKS, gaps
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env bash
2
+ # Commits a feat(M2) that weakens test/a.test.ts: the only expect() is dropped and the
3
+ # test becomes unconditional. No DEC id in the message and none under decisions/.
4
+ set -euo pipefail
5
+
6
+ WORK="${1:?usage: setup.sh <workdir>}"
7
+
8
+ cat > "$WORK/test/a.test.ts" <<'TS'
9
+ import { reconcile } from '../src/a';
10
+
11
+ test('reconcile dedupes a replayed batch', () => {
12
+ reconcile(['e1', 'e1', 'e2']);
13
+ });
14
+ TS
15
+
16
+ git -C "$WORK" add test/a.test.ts
17
+ GIT_AUTHOR_DATE="2026-09-10T10:00:00+00:00" GIT_COMMITTER_DATE="2026-09-10T10:00:00+00:00" \
18
+ git -C "$WORK" -c user.name=fixture -c user.email=fixture@example.com -c commit.gpgsign=false \
19
+ commit -q -m "feat(M2): simplify the reconcile assertion"