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.
- package/CHANGELOG.md +21 -0
- package/README.md +42 -20
- package/agents/ll-executor.md +1 -0
- package/assets/preamble.md +29 -35
- package/bin/install.js +4 -1
- package/hooks/ll-precompact.js +29 -1
- package/hooks/ll-skills-check-update.js +6 -6
- package/hooks/ll-state.js +30 -2
- package/package.json +3 -2
- package/scripts/evals/README.md +57 -0
- package/scripts/evals/cases/auto-dry-run/assert.sh +35 -0
- package/scripts/evals/cases/auto-dry-run/case.json +8 -0
- package/scripts/evals/cases/auto-dry-run/prompt.txt +1 -0
- package/scripts/evals/cases/auto-empty-repo/assert.sh +25 -0
- package/scripts/evals/cases/auto-empty-repo/case.json +8 -0
- package/scripts/evals/cases/auto-empty-repo/fixture/.gitkeep +0 -0
- package/scripts/evals/cases/auto-empty-repo/prompt.txt +1 -0
- package/scripts/evals/cases/decide-final-round/assert.sh +32 -0
- package/scripts/evals/cases/decide-final-round/case.json +8 -0
- package/scripts/evals/cases/decide-final-round/fixture/README.md +3 -0
- package/scripts/evals/cases/decide-final-round/prompt.txt +1 -0
- package/scripts/evals/cases/executor-block/assert.sh +33 -0
- package/scripts/evals/cases/executor-block/case.json +8 -0
- package/scripts/evals/cases/executor-block/prompt.txt +14 -0
- package/scripts/evals/cases/goal-autonomous/assert.sh +35 -0
- package/scripts/evals/cases/goal-autonomous/case.json +8 -0
- package/scripts/evals/cases/goal-autonomous/fixture/PLAN.md +42 -0
- package/scripts/evals/cases/goal-autonomous/fixture/PROGRESS.md +20 -0
- package/scripts/evals/cases/goal-autonomous/fixture/ROADMAP.md +29 -0
- package/scripts/evals/cases/goal-autonomous/fixture/package.json +8 -0
- package/scripts/evals/cases/goal-autonomous/fixture/src/money.js +6 -0
- package/scripts/evals/cases/goal-autonomous/fixture/test/reconcile.test.js +8 -0
- package/scripts/evals/cases/goal-autonomous/prompt.txt +1 -0
- package/scripts/evals/cases/implement-review-gate/assert.sh +35 -0
- package/scripts/evals/cases/implement-review-gate/case.json +8 -0
- package/scripts/evals/cases/implement-review-gate/prompt.txt +1 -0
- package/scripts/evals/cases/implement-stops-at-next/assert.sh +39 -0
- package/scripts/evals/cases/implement-stops-at-next/case.json +9 -0
- package/scripts/evals/cases/implement-stops-at-next/prompt.txt +1 -0
- package/scripts/evals/cases/preamble-no-ritual/assert.sh +17 -0
- package/scripts/evals/cases/preamble-no-ritual/case.json +8 -0
- package/scripts/evals/cases/preamble-no-ritual/fixture/README.md +3 -0
- package/scripts/evals/cases/preamble-no-ritual/fixture/src/a.ts +3 -0
- package/scripts/evals/cases/preamble-no-ritual/prompt.txt +1 -0
- package/scripts/evals/cases/router-execute/assert.sh +12 -0
- package/scripts/evals/cases/router-execute/case.json +8 -0
- package/scripts/evals/cases/router-execute/prompt.txt +1 -0
- package/scripts/evals/cases/router-research/assert.sh +11 -0
- package/scripts/evals/cases/router-research/case.json +8 -0
- package/scripts/evals/cases/router-research/fixture/README.md +3 -0
- package/scripts/evals/cases/router-research/prompt.txt +1 -0
- package/scripts/evals/cases/router-small/assert.sh +21 -0
- package/scripts/evals/cases/router-small/case.json +8 -0
- package/scripts/evals/cases/router-small/fixture/README.md +17 -0
- package/scripts/evals/cases/router-small/prompt.txt +1 -0
- package/scripts/evals/cases/scout-no-plan/assert.sh +41 -0
- package/scripts/evals/cases/scout-no-plan/case.json +8 -0
- package/scripts/evals/cases/scout-no-plan/prompt.txt +8 -0
- package/scripts/evals/cases/verifier-weakened-test/assert.sh +19 -0
- package/scripts/evals/cases/verifier-weakened-test/case.json +8 -0
- package/scripts/evals/cases/verifier-weakened-test/prompt.txt +13 -0
- package/scripts/evals/cases/verifier-weakened-test/setup.sh +19 -0
- package/scripts/evals/fixtures/manual-contract/out.json +29 -0
- package/scripts/evals/fixtures/manual-contract/out.txt +5 -0
- package/scripts/evals/fixtures/manual-contract/with-skill.json +46 -0
- package/scripts/evals/lib/assert.sh +107 -0
- package/scripts/evals/lib/extract.js +73 -0
- package/scripts/evals/run.sh +369 -0
- package/scripts/fixtures/auto-closed/PLAN.md +5 -0
- package/scripts/fixtures/auto-closed/PROGRESS.md +20 -0
- package/scripts/fixtures/auto-closed/ROADMAP.md +6 -0
- package/scripts/fixtures/auto-closed/docs/DELIVERY.md +3 -0
- package/scripts/fixtures/auto-decisions/decisions/DEC-0001-taken-alone.md +13 -0
- package/scripts/fixtures/auto-decisions/decisions/DEC-0002-owner.md +13 -0
- package/scripts/fixtures/auto-noroadmap/PLAN.md +20 -0
- package/scripts/fixtures/auto-noroadmap/PROGRESS.md +11 -0
- package/scripts/fixtures/auto-verify-next/PLAN.md +5 -0
- package/scripts/fixtures/auto-verify-next/PROGRESS.md +18 -0
- package/scripts/fixtures/auto-verify-next/ROADMAP.md +5 -0
- package/scripts/fixtures/auto-verify-next/phases/01/PLAN.md +6 -0
- package/scripts/fixtures/evals-auto/auto-dry-run/pass.txt +18 -0
- package/scripts/fixtures/evals-auto/auto-empty-repo/pass.txt +2 -0
- package/scripts/fixtures/evals-auto/goal-autonomous/pass.txt +29 -0
- package/scripts/fixtures/lint-bad/folded-description/SKILL.md +13 -0
- package/scripts/fixtures/lint-bad/model-invocation-false/SKILL.md +10 -0
- package/scripts/fixtures/next-bad/skills/ll-bad/SKILL.md +30 -0
- package/scripts/fixtures/next-good/skills/ll-good/SKILL.md +26 -0
- package/scripts/fixtures/project/PROGRESS.md +4 -0
- package/scripts/lint-contract.cjs +495 -0
- package/scripts/lint-prompts.sh +396 -0
- package/scripts/ll-tools.js +465 -447
- package/scripts/smoke-test.sh +380 -1
- package/skills/ll-auto/SKILL.md +74 -0
- package/skills/ll-auto/references/run.md +75 -0
- package/skills/ll-auto/references/stages.md +66 -0
- package/skills/ll-auto/scripts/ll-auto.js +345 -0
- package/skills/ll-brainstorm/SKILL.md +5 -4
- package/skills/ll-brainstorm/references/decision-policy.md +3 -0
- package/skills/ll-close/SKILL.md +5 -5
- package/skills/ll-close/references/delivery.md +3 -1
- package/skills/ll-decide/SKILL.md +13 -11
- package/skills/ll-decide/references/decision-policy.md +3 -0
- package/skills/ll-decide/references/interview.md +10 -0
- package/skills/ll-decide/references/plan-skeleton.md +14 -14
- package/skills/ll-decide/references/premise-gate.md +7 -0
- package/skills/ll-goal/SKILL.md +22 -4
- package/skills/ll-goal/references/goal-template.md +57 -0
- package/skills/ll-implement/SKILL.md +4 -2
- package/skills/ll-implement/references/decision-policy.md +3 -0
- package/skills/ll-oncall/SKILL.md +3 -2
- package/skills/ll-refine/SKILL.md +3 -2
- package/skills/ll-research/SKILL.md +3 -2
- package/skills/ll-resume/SKILL.md +4 -3
- package/skills/ll-update/SKILL.md +6 -1
- 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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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
|
+
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"
|