gennady 0.8.4-next.6 → 0.8.4-next.8
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/ai/directives/sdd/audit.directive.xml +3 -3
- package/ai/directives/sdd/scaffold.directive.xml +4 -2
- package/ai/skills/sdd-check/SKILL.md +9 -2
- package/ai/skills/sdd-execute/SKILL.md +5 -4
- package/ai/skills/sdd-execute/scripts/check.sh +166 -4
- package/ai/skills/sdd-execute-batch/SKILL.md +3 -3
- package/dist/ai/directives/sdd/audit.directive.xml +3 -3
- package/dist/ai/directives/sdd/scaffold.directive.xml +4 -2
- package/dist/ai/skills/sdd-check/SKILL.md +9 -2
- package/dist/ai/skills/sdd-execute/SKILL.md +5 -4
- package/dist/ai/skills/sdd-execute/scripts/check.sh +166 -4
- package/dist/ai/skills/sdd-execute-batch/SKILL.md +3 -3
- package/dist/chunks/{index-CM0Gf1_N.js → index-BEggEGo7.js} +30 -27
- package/dist/gennady.js +2 -2
- package/package.json +1 -1
- package/ai/skills/sdd-execute/scripts/__tests__/verify-delegation.test.ts +0 -190
- package/dist/ai/skills/sdd-execute/scripts/__tests__/verify-delegation.test.ts +0 -190
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
Deterministic mechanical checks — file-header presence, Task-ID collision, tracker-sync — are NOT hand-coded here. They live in one tool, `sdd check`, which sdd-check (whole tree) and this directive (scoped) both consume. Single source of mechanical truth → no drift between the two SDD reviewers.
|
|
50
50
|
|
|
51
51
|
- `sdd check --files <git-diff in-scope files>` → [HEADERS] (`@file`/`@consumers`/`@tasks` presence).
|
|
52
|
-
- `sdd check --task <Task-ID>` → [TASKID] (collision for that id) + [TRACKER_SYNC] (Meta.Status vs tracker row).
|
|
52
|
+
- `sdd check --task <Task-ID>` → [TASKID] (collision for that id) + [TRACKER_SYNC] (Meta.Status vs tracker row) + [RULES] (four-section presence in the rules this ticket cites; `rule_findings` is counted apart from `findings` because a shared rule file is not this task's defect).
|
|
53
53
|
- `sdd check <root>` (no flag) → tree-wide [TASKID] orphan refs (epic mode).
|
|
54
54
|
|
|
55
55
|
Audit still owns everything the tool cannot decide mechanically: semantic `@consumers` resolvability, current-Task-ID identity, append-only `@tasks` regression vs git, section-anchor coverage, and all code-reading checks (closed-world, completeness, rules-compliance, runtime-backing, backflow).
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
| `RULES_CASCADE_MISMATCH` | a phase's `Rules:` list ≠ what scaffolder would derive now from cascade × that phase's `Target Files` + kind |
|
|
68
68
|
| `TASK_ID_DRIFT` | `@tasks` field references non-existent ticket ID (orphan); OR Task-ID duplicated across ticket files (collision); OR `@tasks` field lost prior IDs (regression of append-only) |
|
|
69
69
|
| `BDD_COVERAGE_MISMATCH` | canonical case names in ticket Test Scenario Coverage ≠ real test cases |
|
|
70
|
-
| `EXECUTION_LOG_INCOMPLETE` | mandatory closing lines missing (`ver` / `DONE` per phase, `DONE` at Round close); OR `intro` line absent for an entity that appears in code but not in module Inventory; OR a previous round was edited (round log is append-only); OR `[x]` line with unreplaced `<…>` placeholder (fabricated done) |
|
|
70
|
+
| `EXECUTION_LOG_INCOMPLETE` | mandatory closing lines missing (`ver` / `DONE` per phase, `DONE` at Round close); OR `intro` line absent for an entity that appears in code but not in module Inventory; OR a previous round was edited (round log is append-only); OR `[x]` line with unreplaced `<…>` placeholder (fabricated done). Token vocabulary and Round-close shape are decided by `sdd check` [LOG], not by eye: `unknown-token` / `unclosed-round` are findings, `retired-token` / `round-close-no-timestamp` are not (append-only history) |
|
|
71
71
|
| `INSIGHT_BACKFLOW` | Phase agent discovered something that changes contract / requirement understanding; should flow back into spec |
|
|
72
72
|
| `STALE_AFTER_PIVOT` | scope spec was reworked in `pivot` mode (Pivot Invalidation List exists) but downstream artifacts named in the list have not been refined / reopened / updated |
|
|
73
73
|
| `RULE_FILE_INCOMPLETE` | activated rule file lacks one of the universal checkable sections (`<BeliefState>` / `<AntiPatterns>` / `<VerificationHooks>` / `<RewardCriteria>`) per `AX_RULES_COMPLIANCE_AGAINST_ACTIVATED_RULES`; audit can partially proceed but the gap blocks full coverage |
|
|
@@ -172,7 +172,7 @@
|
|
|
172
172
|
- `<VerificationHooks>` → executable check commands
|
|
173
173
|
- `<RewardCriteria>` → ✅ invariants / ❌ forbidden states
|
|
174
174
|
|
|
175
|
-
|
|
175
|
+
Section presence is NOT judged by eye — `sdd check --task <Task-ID>` emits `[RULES]` for exactly this ticket's cited rules (per `AX_MECHANICAL_VIA_SDD_CHECK`). Each `INCOMPLETE` row → one `RULE_FILE_INCOMPLETE`, its `missing` column copied verbatim. Audit proceeds with the sections that exist. `<DependsOn>` is optional and unchecked.
|
|
176
176
|
|
|
177
177
|
**Per (artifact ∈ Round diff, rule ∈ union of all phases' Rules):**
|
|
178
178
|
1. Apply rule's `<Triggers>` / `<ActivationHint>` from `knowledge.xml` to decide if the rule governs this artifact. No match → skip pair.
|
|
@@ -229,7 +229,9 @@
|
|
|
229
229
|
</Axiom>
|
|
230
230
|
|
|
231
231
|
<Axiom id="AX_AUDIT_HOOK">
|
|
232
|
-
Round is complete only after `audit` returns PASS. `sdd-execute` orchestrator dispatches audit-subagent automatically after the last phase of a Round closes — operator does not invoke audit manually.
|
|
232
|
+
Round is complete only after `audit` returns PASS. `sdd-execute` orchestrator dispatches audit-subagent automatically after the last phase of a Round closes — operator does not invoke audit manually.
|
|
233
|
+
|
|
234
|
+
Closing the Round does NOT set `[x] DONE`. The ticket stays `[~] IN_PROGRESS` from Round close until audit PASS, and only then becomes `[x] DONE`. So `[x] DONE` means verified — one meaning, and the one dependents rely on: pickability reads that status, and a task whose audit has not run (or has failed) must not read as pickable.
|
|
233
235
|
</Axiom>
|
|
234
236
|
|
|
235
237
|
<Axiom id="AX_PHASES_DECLARED_IN_HEADER">
|
|
@@ -714,7 +716,7 @@
|
|
|
714
716
|
⛔ `[x]` line with any unreplaced `<…>` literal = fabricated done → `EXECUTION_LOG_INCOMPLETE` (BLOCKER).
|
|
715
717
|
|
|
716
718
|
### Post-task Hook
|
|
717
|
-
Per `AX_AUDIT_HOOK`. After last phase of a Round closes, the orchestrator dispatches `sdd-audit`.
|
|
719
|
+
Per `AX_AUDIT_HOOK`. After last phase of a Round closes, the orchestrator dispatches `sdd-audit`. Round close leaves the ticket `[~] IN_PROGRESS`; audit PASS is what sets `[x] DONE`. Until then dependents are blocked, and the status says so.
|
|
718
720
|
|
|
719
721
|
## High-Level DAG
|
|
720
722
|
Cross-scope edges + integration tickets only. Intra-scope DAGs live in per-scope READMEs.
|
|
@@ -81,10 +81,16 @@ Parse `Dependencies:` from each task ticket planning surface. Topological sort.
|
|
|
81
81
|
|
|
82
82
|
From scan [TASKS] output: check `placeholders` column for any task with >0. Flag tasks where placeholders > 0 even if status DONE. Also inspect `warnings` column for `no-execlog-section` or `anchors-mismatch`.
|
|
83
83
|
|
|
84
|
+
Token vocabulary and Round-close shape come from `sdd check` [LOG] — do not re-read logs by hand. `unknown-token` (outside the scaffold table) and `unclosed-round` (a Round close with no ticked DONE) → FAIL. `retired-token` (valid before the vocabulary was consolidated) and `round-close-no-timestamp` → INFO: rounds are append-only, so history cannot be rewritten to satisfy a later rule.
|
|
85
|
+
|
|
84
86
|
### Check 5b — Task-ID Integrity (from `sdd check` [TASKID])
|
|
85
87
|
|
|
86
88
|
Read the [TASKID] section of `sdd check`. `collision` (one Task-ID on ≥2 ticket files) → FAIL (BLOCKER). `orphan` (a code `@tasks: TSK-NN` with no ticket file) → FAIL. Empty section → PASS. Same tool sdd-audit STEP_2_5 uses.
|
|
87
89
|
|
|
90
|
+
### Check 5c — Rule File Schema (from `sdd check` [RULES])
|
|
91
|
+
|
|
92
|
+
Read the [RULES] section. Each `verdict=INCOMPLETE` row is a rule file missing one of the four checkable sections; the `missing` column names them. Report as INFO with the file list, **not** as a tree FAIL: these are shared project artifacts, tracked by `rule_findings` separately from `findings` for exactly that reason. Fixing them is its own ticket, never a task reopen.
|
|
93
|
+
|
|
88
94
|
### Check 6 — File Headers (from `sdd check --files`)
|
|
89
95
|
|
|
90
96
|
Pass recently modified source files to the shared checker instead of sampling by hand:
|
|
@@ -134,8 +140,9 @@ First: Self-Reflection. Then: Mechanical Checks. Use compact single-line-per-che
|
|
|
134
140
|
|
|
135
141
|
Rules for VERDICT line:
|
|
136
142
|
|
|
137
|
-
- All
|
|
138
|
-
- All
|
|
143
|
+
- All checks PASS AND 0 protocol violations → `✅ CLEAN — artifact tree is consistent, next pickable: TSK-NN`
|
|
144
|
+
- All checks PASS AND 0 violations but some tasks deferred/TODO → `✅ CLEAN — <N> tasks remaining in queue`
|
|
145
|
+
- Check 5c findings are INFO — they never move the verdict off `✅ CLEAN`; append `· <N> rule file(s) incomplete` to the line instead
|
|
139
146
|
- Any FAIL check OR protocol violations → `❌ NOT READY — <N> issue(s) require attention`
|
|
140
147
|
- Checks skipped (marked `—`) → treat as PASS for verdict unless evidence of gap exists
|
|
141
148
|
</Output>
|
|
@@ -97,13 +97,14 @@ Pause path (distinguish from failure — skill is awaiting operator, not broken)
|
|
|
97
97
|
#### Round close
|
|
98
98
|
- [x] `<ts>` DONE
|
|
99
99
|
```
|
|
100
|
-
Set ticket Meta Status → `[x] DONE
|
|
100
|
+
Set ticket Meta Status → `[~] IN_PROGRESS`. **Not `[x] DONE` — the round is closed, not verified.** `DONE` is set in step 6, and only on audit PASS. Dependents pick on `DONE`, so setting it here advertises a task the audit has not seen yet.
|
|
101
101
|
|
|
102
102
|
4a. **Sync Trackers** (MANDATORY, cannot skip):
|
|
103
103
|
|
|
104
|
-
- Read `tasks/<scope>/README.md`. Find the Tracker row for this Task-ID. Set its Status
|
|
105
|
-
- Read `tasks/README.md` Tracker Index. Update the scope's aggregate counts (done/total)
|
|
104
|
+
- Read `tasks/<scope>/README.md`. Find the Tracker row for this Task-ID. Set its Status to the ticket's current Meta Status. Write back.
|
|
105
|
+
- Read `tasks/README.md` Tracker Index. Update the scope's aggregate counts (done/total) — a task counts as done only at `[x] DONE`. Write back.
|
|
106
106
|
- Verify: re-read both files, confirm the changes took effect. If not → retry once.
|
|
107
|
+
- Run this step again after step 6 sets the final status.
|
|
107
108
|
|
|
108
109
|
5. **Dispatch AUDIT** (MANDATORY, always runs). Dispatch ONE subagent (`subagent_type: general-purpose`, **`model: "haiku"`** — audit is mechanical verification + fact-checking against artifacts; sonnet capability is overkill, haiku is faster and cheaper for this read-heavy task). Include in prompt the SDD tooling location: `~/Developer/gennady/ai/skills/sdd-execute/scripts/sdd` (audit may use `lint`, `verify`, `check-blockers` subcommands). With this prompt:
|
|
109
110
|
|
|
@@ -128,7 +129,7 @@ Pause path (distinguish from failure — skill is awaiting operator, not broken)
|
|
|
128
129
|
Wait for return. If dispatch fails → retry once. If fails again → mark task FAILED.
|
|
129
130
|
|
|
130
131
|
6. **Branch on audit status:**
|
|
131
|
-
- `PASS` or `PASS_WITH_ACKNOWLEDGED_RISKS` → ticket verified
|
|
132
|
+
- `PASS` or `PASS_WITH_ACKNOWLEDGED_RISKS` → ticket verified. **Only now** set Meta Status → `[x] DONE` and re-run step 4a so the trackers and the aggregate counts follow. Jump to step 9 (summary).
|
|
132
133
|
- `FAIL` AND `audit_attempt = 1` → step 7 (resolve findings).
|
|
133
134
|
- `FAIL` AND `audit_attempt = 2` → cap exhausted. Set Meta Status `[!] BLOCKED`, log `🛑 BLOCKED: audit-cap-exhausted` whose `💬 unblock:` line is the literal command `/sdd-execute <TSK-NN> --new-audit-session`, sync trackers, jump to step 9.
|
|
134
135
|
|
|
@@ -5,19 +5,37 @@
|
|
|
5
5
|
# header presence, Task-ID integrity, or tracker sync. Pure function of files on disk.
|
|
6
6
|
#
|
|
7
7
|
# Three modes:
|
|
8
|
-
# check.sh [project-root] — whole tree: TASKID + TRACKER_SYNC (all tickets) +
|
|
9
|
-
# check.sh --task <TSK-NN> [root] — one ticket: TASKID
|
|
8
|
+
# check.sh [project-root] — whole tree: TASKID + TRACKER_SYNC (all tickets) + RULES (all rule files)
|
|
9
|
+
# check.sh --task <TSK-NN> [root] — one ticket: TASKID + TRACKER_SYNC for that id + RULES for its cited rules
|
|
10
10
|
# check.sh --files <f1> [f2 ...] — header-trio presence for an explicit file list (audit passes its git-diff scope)
|
|
11
11
|
#
|
|
12
12
|
# Output sections (TSV, machine-readable, stable):
|
|
13
13
|
# [HEADERS] — file \t has_file \t has_consumers \t has_tasks \t verdict(OK|PARTIAL|NONE)
|
|
14
14
|
# [TASKID] — kind(orphan|collision) \t id \t detail
|
|
15
15
|
# [TRACKER_SYNC] — task_id \t ticket_status \t tracker_status \t match(YES|NO|NO_ROW)
|
|
16
|
+
# [RULES] — file \t belief \t anti \t hooks \t reward \t verdict(OK|INCOMPLETE) \t missing
|
|
17
|
+
# [LOG] — ticket \t round \t line \t kind \t token \t detail
|
|
18
|
+
# kinds: unknown-token | unclosed-round (counted as findings)
|
|
19
|
+
# retired-token | round-close-no-timestamp (informational: append-only
|
|
20
|
+
# history and cosmetics never fail a tree)
|
|
16
21
|
# [SUMMARY] — key=value totals + findings count
|
|
17
22
|
#
|
|
23
|
+
# [RULES] implements the mechanical half of AX_RULES_COMPLIANCE_AGAINST_ACTIVATED_RULES: a rule file
|
|
24
|
+
# must expose <BeliefState> / <AntiPatterns> / <VerificationHooks> / <RewardCriteria>. Detection is a
|
|
25
|
+
# tolerant opening-tag scan, NOT an XML parse — these files are HTML-like by design and carry prose
|
|
26
|
+
# such as `<Target Files>` and `Meta<typeof Button>` that no XML parser accepts.
|
|
27
|
+
#
|
|
28
|
+
# Rule files are the non-`*.directive.xml` entries of the cascade categories (coding / testing / infra),
|
|
29
|
+
# in the project and in plugin directive trees. `*.directive.xml` are protocols, not rules, and are
|
|
30
|
+
# exempt. Tree mode scans every rule file; task mode scans only the ones that ticket's phases cite —
|
|
31
|
+
# the "activated" set the axiom is written against.
|
|
32
|
+
#
|
|
33
|
+
# Rule findings are counted SEPARATELY from task findings (`rule_findings=`): a shared rule file is
|
|
34
|
+
# project infrastructure that no single task owns or may edit, so it must not decide a task's verdict.
|
|
35
|
+
#
|
|
18
36
|
# Exit codes:
|
|
19
37
|
# 0 — all checks clean (zero findings)
|
|
20
|
-
# 3 — one or more findings (desync / orphan / collision / partial-or-missing header)
|
|
38
|
+
# 3 — one or more findings (desync / orphan / collision / partial-or-missing header / incomplete rule)
|
|
21
39
|
# 2 — structural failure (bad root / not an SDD project)
|
|
22
40
|
# 4 — bad invocation
|
|
23
41
|
|
|
@@ -82,6 +100,7 @@ EOF
|
|
|
82
100
|
esac
|
|
83
101
|
|
|
84
102
|
FINDINGS=0
|
|
103
|
+
RULE_FINDINGS=0
|
|
85
104
|
|
|
86
105
|
# ---------------------------------------------------------------------------
|
|
87
106
|
# Mode: --files → HEADERS only
|
|
@@ -227,6 +246,148 @@ done <<< "$TASK_FILES"
|
|
|
227
246
|
# is a policy (task-generated vs hand-authored), not a mechanical fact. Header presence
|
|
228
247
|
# is meaningful only against a known in-scope file set — provided by audit via --files.
|
|
229
248
|
|
|
249
|
+
# ---------------------------------------------------------------------------
|
|
250
|
+
# [RULES] — activated rule files expose the four checkable sections
|
|
251
|
+
# ---------------------------------------------------------------------------
|
|
252
|
+
|
|
253
|
+
printf '\n[RULES]\n# file\tbelief\tanti\thooks\treward\tverdict\tmissing\n'
|
|
254
|
+
|
|
255
|
+
# Cascade categories only; `*.directive.xml` are protocols, not rules.
|
|
256
|
+
rule_files_in_tree() {
|
|
257
|
+
find -L "$ROOT_ABS/ai/directives" "$ROOT_ABS"/plugins/*/directives \
|
|
258
|
+
-type d -name node_modules -prune -o \
|
|
259
|
+
-type f -name '*.xml' ! -name '*.directive.xml' -print 2>/dev/null \
|
|
260
|
+
| grep -E '/(coding|testing|infra)/[^/]+\.xml$' | sort -u || true
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
# Task mode: the rules this ticket's phases actually cite (the "activated" set).
|
|
264
|
+
rule_files_for_task() {
|
|
265
|
+
local ticket
|
|
266
|
+
ticket=$(grep -l "^- \*\*Task-ID:\*\* $TASK_ID\$" $TASK_FILES 2>/dev/null | head -1)
|
|
267
|
+
[[ -z "$ticket" ]] && return
|
|
268
|
+
grep -ohE '(ai/directives|plugins/[a-z0-9-]+/directives)/[a-z0-9-]+/[a-z0-9._-]+\.xml' "$ticket" \
|
|
269
|
+
| grep -vE '\.directive\.xml$' | sort -u \
|
|
270
|
+
| while IFS= read -r rel; do
|
|
271
|
+
[[ -f "$ROOT_ABS/$rel" ]] && printf '%s\n' "$ROOT_ABS/$rel"
|
|
272
|
+
done
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if [[ "$MODE" == "task" ]]; then
|
|
276
|
+
RULE_FILES=$(rule_files_for_task)
|
|
277
|
+
else
|
|
278
|
+
RULE_FILES=$(rule_files_in_tree)
|
|
279
|
+
fi
|
|
280
|
+
|
|
281
|
+
if [[ -z "$RULE_FILES" ]]; then
|
|
282
|
+
printf '# none%s\n' "$([[ "$MODE" == task ]] && echo " — ticket cites no rule files")"
|
|
283
|
+
else
|
|
284
|
+
while IFS= read -r rf; do
|
|
285
|
+
[[ -z "$rf" ]] && continue
|
|
286
|
+
b=0; a=0; h=0; r=0; missing=""
|
|
287
|
+
grep -q '<BeliefState' "$rf" && b=1 || missing="${missing}BeliefState,"
|
|
288
|
+
grep -q '<AntiPatterns' "$rf" && a=1 || missing="${missing}AntiPatterns,"
|
|
289
|
+
grep -q '<VerificationHooks' "$rf" && h=1 || missing="${missing}VerificationHooks,"
|
|
290
|
+
grep -q '<RewardCriteria' "$rf" && r=1 || missing="${missing}RewardCriteria,"
|
|
291
|
+
if [[ -z "$missing" ]]; then
|
|
292
|
+
printf '%s\t1\t1\t1\t1\tOK\t-\n' "${rf#$ROOT_ABS/}"
|
|
293
|
+
else
|
|
294
|
+
printf '%s\t%d\t%d\t%d\t%d\tINCOMPLETE\t%s\n' "${rf#$ROOT_ABS/}" "$b" "$a" "$h" "$r" "${missing%,}"
|
|
295
|
+
RULE_FINDINGS=$((RULE_FINDINGS+1))
|
|
296
|
+
fi
|
|
297
|
+
done <<< "$RULE_FILES"
|
|
298
|
+
fi
|
|
299
|
+
|
|
300
|
+
# ---------------------------------------------------------------------------
|
|
301
|
+
# [LOG] — Execution Log token vocabulary + Round-close shape
|
|
302
|
+
# ---------------------------------------------------------------------------
|
|
303
|
+
|
|
304
|
+
printf '\n[LOG]\n# ticket\tround\tline\tkind\ttoken\tdetail\n'
|
|
305
|
+
|
|
306
|
+
# `retired` tokens were valid before the vocabulary was consolidated. Rounds are append-only, so
|
|
307
|
+
# their presence in an old round is history, not a defect — they are reported and NOT counted.
|
|
308
|
+
# Anything outside both sets is `unknown-token` and IS counted.
|
|
309
|
+
LOG_TMP="$(mktemp -t sdd-check-log.XXXXXX)"
|
|
310
|
+
trap 'rm -f "$COLLISION_TMP" "$LOG_TMP"' EXIT
|
|
311
|
+
|
|
312
|
+
while IFS= read -r f; do
|
|
313
|
+
[[ -z "$f" ]] && continue
|
|
314
|
+
if [[ "$MODE" == "task" ]]; then
|
|
315
|
+
[[ "$(sdd_lib_task_id "$f")" == "$TASK_ID" ]] || continue
|
|
316
|
+
fi
|
|
317
|
+
awk -v ticket="${f#$ROOT_ABS/}" '
|
|
318
|
+
BEGIN {
|
|
319
|
+
split("intro decision tried discovery insight verified ver BLOCKED DONE", v, " ")
|
|
320
|
+
for (i in v) valid[v[i]] = 1
|
|
321
|
+
# Retired when the vocabulary was consolidated (scaffold.directive names exactly these).
|
|
322
|
+
split("sync file test cov rules recon", r, " ")
|
|
323
|
+
for (i in r) retired[r[i]] = 1
|
|
324
|
+
# Blocker lifecycle markers are their own shape, not action tokens.
|
|
325
|
+
valid["🛑"] = 1; valid["✅"] = 1
|
|
326
|
+
round = "-"; inlog = 0; inclose = 0; closelines = 0; closebad = 0
|
|
327
|
+
}
|
|
328
|
+
/^## 7\. Execution Log/ { inlog = 1; next }
|
|
329
|
+
/^## [0-9]+\./ { if (inlog) inlog = 0 }
|
|
330
|
+
inlog == 0 { next }
|
|
331
|
+
/^### Round / {
|
|
332
|
+
if (inclose && closelines != 1 && closebad == 0)
|
|
333
|
+
printf "%s\t%s\t%d\tbad-round-close\t-\texpected exactly one DONE line, found %d\n", ticket, round, closeline, closelines
|
|
334
|
+
round = $3; inclose = 0; closelines = 0; closebad = 0; next
|
|
335
|
+
}
|
|
336
|
+
/^#### Round close/ { inclose = 1; closelines = 0; closebad = 0; closeline = NR; next }
|
|
337
|
+
/^#### / {
|
|
338
|
+
if (inclose && closelines != 1 && closebad == 0)
|
|
339
|
+
printf "%s\t%s\t%d\tbad-round-close\t-\texpected exactly one DONE line, found %d\n", ticket, round, closeline, closelines
|
|
340
|
+
inclose = 0; closebad = 0; next
|
|
341
|
+
}
|
|
342
|
+
# Token lines: "- [x] `<ts>` <token> ..." (blocker lines use 🛑 and are matched separately)
|
|
343
|
+
/^- \[[ x~!]\] `[^`]*` / {
|
|
344
|
+
rest = $0; sub(/^- \[[ x~!]\] `[^`]*` +/, "", rest)
|
|
345
|
+
split(rest, w, " "); tok = w[1]
|
|
346
|
+
sub(/:$/, "", tok) # a trailing colon is cosmetic, not a different token
|
|
347
|
+
if (inclose) { if (tok == "DONE") closelines++ }
|
|
348
|
+
if (tok in valid) next
|
|
349
|
+
# Every real token is lowercase except BLOCKED / DONE. A capitalised first word is a
|
|
350
|
+
# sentence from the pre-consolidation prose plan ("Implementation file:", "Tracker
|
|
351
|
+
# synced:"), which the same consolidation retired.
|
|
352
|
+
if (tok ~ /^[A-Z]/) {
|
|
353
|
+
printf "%s\t%s\t%d\tretired-token\t%s\tprose line from the pre-consolidation plan template\n", ticket, round, NR, tok
|
|
354
|
+
next
|
|
355
|
+
}
|
|
356
|
+
if (tok in retired) {
|
|
357
|
+
printf "%s\t%s\t%d\tretired-token\t%s\tvalid before the vocabulary was consolidated; round is append-only\n", ticket, round, NR, tok
|
|
358
|
+
} else {
|
|
359
|
+
printf "%s\t%s\t%d\tunknown-token\t%s\tnot in the scaffold.directive token table\n", ticket, round, NR, tok
|
|
360
|
+
}
|
|
361
|
+
next
|
|
362
|
+
}
|
|
363
|
+
# A checkbox line inside Round close that carries no timestamped token at all.
|
|
364
|
+
# Close-block lines that carry no timestamped token. A ticked DONE without a timestamp is
|
|
365
|
+
# cosmetic drift; an unticked box means the round was never actually closed.
|
|
366
|
+
inclose == 1 && /^- / {
|
|
367
|
+
if ($0 ~ /\[x\]/ && $0 ~ /DONE/) {
|
|
368
|
+
printf "%s\t%s\t%d\tround-close-no-timestamp\tDONE\tclosed, but the `<ts>` is missing\n", ticket, round, NR
|
|
369
|
+
closelines++
|
|
370
|
+
} else {
|
|
371
|
+
printf "%s\t%s\t%d\tunclosed-round\t-\tRound close carries no ticked DONE: %s\n", ticket, round, NR, substr($0, 1, 40)
|
|
372
|
+
closebad = 1
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
END {
|
|
376
|
+
if (inclose && closelines != 1 && closebad == 0)
|
|
377
|
+
printf "%s\t%s\t%d\tbad-round-close\t-\texpected exactly one DONE line, found %d\n", ticket, round, closeline, closelines
|
|
378
|
+
}
|
|
379
|
+
' "$f" >> "$LOG_TMP"
|
|
380
|
+
done <<< "$TASK_FILES"
|
|
381
|
+
|
|
382
|
+
if [[ -s "$LOG_TMP" ]]; then
|
|
383
|
+
cat "$LOG_TMP"
|
|
384
|
+
# Informational kinds record history or cosmetics; they must not fail the tree.
|
|
385
|
+
LOG_FINDINGS=$(awk -F'\t' '$4 != "retired-token" && $4 != "round-close-no-timestamp"' "$LOG_TMP" | grep -c '' || true)
|
|
386
|
+
FINDINGS=$((FINDINGS + LOG_FINDINGS))
|
|
387
|
+
else
|
|
388
|
+
printf '# none\n'
|
|
389
|
+
fi
|
|
390
|
+
|
|
230
391
|
# ---------------------------------------------------------------------------
|
|
231
392
|
# [SUMMARY]
|
|
232
393
|
# ---------------------------------------------------------------------------
|
|
@@ -234,5 +395,6 @@ done <<< "$TASK_FILES"
|
|
|
234
395
|
printf '\n[SUMMARY]\nmode=%s\n' "$MODE"
|
|
235
396
|
[[ "$MODE" == "task" ]] && printf 'task=%s\n' "$TASK_ID"
|
|
236
397
|
printf 'findings=%d\n' "$FINDINGS"
|
|
398
|
+
printf 'rule_findings=%d\n' "$RULE_FINDINGS"
|
|
237
399
|
|
|
238
|
-
[[
|
|
400
|
+
[[ $((FINDINGS + RULE_FINDINGS)) -gt 0 ]] && exit 3 || exit 0
|
|
@@ -131,7 +131,7 @@ Per-task phase tokens:
|
|
|
131
131
|
|
|
132
132
|
c. Thread next phase's Inputs from this phase's Handoff (verbatim).
|
|
133
133
|
|
|
134
|
-
After all phases DONE: close Round (append `#### Round close` block per `ROUND_CLOSE_FORMAT`: a single `DONE` line). Sync trackers
|
|
134
|
+
After all phases DONE: close Round (append `#### Round close` block per `ROUND_CLOSE_FORMAT`: a single `DONE` line). Ticket Status → `[~] IN_PROGRESS` — closed, not verified. Sync trackers to that status. `[x] DONE` is set in step e, on audit PASS only: dependents pick on `DONE`, and a later layer must not start against a task the audit has not seen.
|
|
135
135
|
|
|
136
136
|
d. Dispatch AUDIT subagent (`subagent_type: general-purpose`, **`model: "haiku"`** — audit is mechanical verification + fact-checking, haiku sufficient and cheaper). MANDATORY, always runs. Include in prompt the SDD tooling location: `~/Developer/gennady/ai/skills/sdd-execute/scripts/sdd` (audit may use `lint`, `verify`, `check-blockers` subcommands):
|
|
137
137
|
```
|
|
@@ -154,14 +154,14 @@ Per-task phase tokens:
|
|
|
154
154
|
Wait for return. If dispatch fails → retry once. If fails again → mark task FAILED.
|
|
155
155
|
|
|
156
156
|
e. Branch on audit status:
|
|
157
|
-
- `PASS` / `PASS_WITH_ACKNOWLEDGED_RISKS` → task
|
|
157
|
+
- `PASS` / `PASS_WITH_ACKNOWLEDGED_RISKS` → task verified. Only now set Ticket Status → `[x] DONE` and re-sync trackers. Continue lane (next task in batch).
|
|
158
158
|
- `FAIL` AND `audit_attempt = 1` → trigger selective phase re-run.
|
|
159
159
|
Open new Round with reason `audit-driven fix: F-NNN, F-MMM`.
|
|
160
160
|
For each phase in `phases_to_fix` (sequential, declared order subset):
|
|
161
161
|
Dispatch PHASE subagent with `Reason: fix: address audit findings F-NNN, F-MMM` and audit findings list in Inputs. Wait.
|
|
162
162
|
On BLOCKED/FAIL → STOP this task's lane; mark task FAILED.
|
|
163
163
|
After all fix phases DONE → close Round → dispatch AUDIT (round 2, fresh context). Branch again:
|
|
164
|
-
PASS → task
|
|
164
|
+
PASS → task verified: Ticket Status → `[x] DONE`, re-sync trackers.
|
|
165
165
|
FAIL (audit_attempt = 2) → STOP lane; cap exhausted. Meta Status `[!] BLOCKED`, `🛑 BLOCKED: audit-cap-exhausted` with `💬 unblock: /sdd-execute <TSK-NN> --new-audit-session`. Report as `🛑 cap-exhausted`, distinct from `❌ FAILED`. The batch never lifts the cap itself.
|
|
166
166
|
|
|
167
167
|
— Wait for all parallel task lanes in sub-batch to finish.
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
Deterministic mechanical checks — file-header presence, Task-ID collision, tracker-sync — are NOT hand-coded here. They live in one tool, `sdd check`, which sdd-check (whole tree) and this directive (scoped) both consume. Single source of mechanical truth → no drift between the two SDD reviewers.
|
|
50
50
|
|
|
51
51
|
- `sdd check --files <git-diff in-scope files>` → [HEADERS] (`@file`/`@consumers`/`@tasks` presence).
|
|
52
|
-
- `sdd check --task <Task-ID>` → [TASKID] (collision for that id) + [TRACKER_SYNC] (Meta.Status vs tracker row).
|
|
52
|
+
- `sdd check --task <Task-ID>` → [TASKID] (collision for that id) + [TRACKER_SYNC] (Meta.Status vs tracker row) + [RULES] (four-section presence in the rules this ticket cites; `rule_findings` is counted apart from `findings` because a shared rule file is not this task's defect).
|
|
53
53
|
- `sdd check <root>` (no flag) → tree-wide [TASKID] orphan refs (epic mode).
|
|
54
54
|
|
|
55
55
|
Audit still owns everything the tool cannot decide mechanically: semantic `@consumers` resolvability, current-Task-ID identity, append-only `@tasks` regression vs git, section-anchor coverage, and all code-reading checks (closed-world, completeness, rules-compliance, runtime-backing, backflow).
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
| `RULES_CASCADE_MISMATCH` | a phase's `Rules:` list ≠ what scaffolder would derive now from cascade × that phase's `Target Files` + kind |
|
|
68
68
|
| `TASK_ID_DRIFT` | `@tasks` field references non-existent ticket ID (orphan); OR Task-ID duplicated across ticket files (collision); OR `@tasks` field lost prior IDs (regression of append-only) |
|
|
69
69
|
| `BDD_COVERAGE_MISMATCH` | canonical case names in ticket Test Scenario Coverage ≠ real test cases |
|
|
70
|
-
| `EXECUTION_LOG_INCOMPLETE` | mandatory closing lines missing (`ver` / `DONE` per phase, `DONE` at Round close); OR `intro` line absent for an entity that appears in code but not in module Inventory; OR a previous round was edited (round log is append-only); OR `[x]` line with unreplaced `<…>` placeholder (fabricated done) |
|
|
70
|
+
| `EXECUTION_LOG_INCOMPLETE` | mandatory closing lines missing (`ver` / `DONE` per phase, `DONE` at Round close); OR `intro` line absent for an entity that appears in code but not in module Inventory; OR a previous round was edited (round log is append-only); OR `[x]` line with unreplaced `<…>` placeholder (fabricated done). Token vocabulary and Round-close shape are decided by `sdd check` [LOG], not by eye: `unknown-token` / `unclosed-round` are findings, `retired-token` / `round-close-no-timestamp` are not (append-only history) |
|
|
71
71
|
| `INSIGHT_BACKFLOW` | Phase agent discovered something that changes contract / requirement understanding; should flow back into spec |
|
|
72
72
|
| `STALE_AFTER_PIVOT` | scope spec was reworked in `pivot` mode (Pivot Invalidation List exists) but downstream artifacts named in the list have not been refined / reopened / updated |
|
|
73
73
|
| `RULE_FILE_INCOMPLETE` | activated rule file lacks one of the universal checkable sections (`<BeliefState>` / `<AntiPatterns>` / `<VerificationHooks>` / `<RewardCriteria>`) per `AX_RULES_COMPLIANCE_AGAINST_ACTIVATED_RULES`; audit can partially proceed but the gap blocks full coverage |
|
|
@@ -172,7 +172,7 @@
|
|
|
172
172
|
- `<VerificationHooks>` → executable check commands
|
|
173
173
|
- `<RewardCriteria>` → ✅ invariants / ❌ forbidden states
|
|
174
174
|
|
|
175
|
-
|
|
175
|
+
Section presence is NOT judged by eye — `sdd check --task <Task-ID>` emits `[RULES]` for exactly this ticket's cited rules (per `AX_MECHANICAL_VIA_SDD_CHECK`). Each `INCOMPLETE` row → one `RULE_FILE_INCOMPLETE`, its `missing` column copied verbatim. Audit proceeds with the sections that exist. `<DependsOn>` is optional and unchecked.
|
|
176
176
|
|
|
177
177
|
**Per (artifact ∈ Round diff, rule ∈ union of all phases' Rules):**
|
|
178
178
|
1. Apply rule's `<Triggers>` / `<ActivationHint>` from `knowledge.xml` to decide if the rule governs this artifact. No match → skip pair.
|
|
@@ -229,7 +229,9 @@
|
|
|
229
229
|
</Axiom>
|
|
230
230
|
|
|
231
231
|
<Axiom id="AX_AUDIT_HOOK">
|
|
232
|
-
Round is complete only after `audit` returns PASS. `sdd-execute` orchestrator dispatches audit-subagent automatically after the last phase of a Round closes — operator does not invoke audit manually.
|
|
232
|
+
Round is complete only after `audit` returns PASS. `sdd-execute` orchestrator dispatches audit-subagent automatically after the last phase of a Round closes — operator does not invoke audit manually.
|
|
233
|
+
|
|
234
|
+
Closing the Round does NOT set `[x] DONE`. The ticket stays `[~] IN_PROGRESS` from Round close until audit PASS, and only then becomes `[x] DONE`. So `[x] DONE` means verified — one meaning, and the one dependents rely on: pickability reads that status, and a task whose audit has not run (or has failed) must not read as pickable.
|
|
233
235
|
</Axiom>
|
|
234
236
|
|
|
235
237
|
<Axiom id="AX_PHASES_DECLARED_IN_HEADER">
|
|
@@ -714,7 +716,7 @@
|
|
|
714
716
|
⛔ `[x]` line with any unreplaced `<…>` literal = fabricated done → `EXECUTION_LOG_INCOMPLETE` (BLOCKER).
|
|
715
717
|
|
|
716
718
|
### Post-task Hook
|
|
717
|
-
Per `AX_AUDIT_HOOK`. After last phase of a Round closes, the orchestrator dispatches `sdd-audit`.
|
|
719
|
+
Per `AX_AUDIT_HOOK`. After last phase of a Round closes, the orchestrator dispatches `sdd-audit`. Round close leaves the ticket `[~] IN_PROGRESS`; audit PASS is what sets `[x] DONE`. Until then dependents are blocked, and the status says so.
|
|
718
720
|
|
|
719
721
|
## High-Level DAG
|
|
720
722
|
Cross-scope edges + integration tickets only. Intra-scope DAGs live in per-scope READMEs.
|
|
@@ -81,10 +81,16 @@ Parse `Dependencies:` from each task ticket planning surface. Topological sort.
|
|
|
81
81
|
|
|
82
82
|
From scan [TASKS] output: check `placeholders` column for any task with >0. Flag tasks where placeholders > 0 even if status DONE. Also inspect `warnings` column for `no-execlog-section` or `anchors-mismatch`.
|
|
83
83
|
|
|
84
|
+
Token vocabulary and Round-close shape come from `sdd check` [LOG] — do not re-read logs by hand. `unknown-token` (outside the scaffold table) and `unclosed-round` (a Round close with no ticked DONE) → FAIL. `retired-token` (valid before the vocabulary was consolidated) and `round-close-no-timestamp` → INFO: rounds are append-only, so history cannot be rewritten to satisfy a later rule.
|
|
85
|
+
|
|
84
86
|
### Check 5b — Task-ID Integrity (from `sdd check` [TASKID])
|
|
85
87
|
|
|
86
88
|
Read the [TASKID] section of `sdd check`. `collision` (one Task-ID on ≥2 ticket files) → FAIL (BLOCKER). `orphan` (a code `@tasks: TSK-NN` with no ticket file) → FAIL. Empty section → PASS. Same tool sdd-audit STEP_2_5 uses.
|
|
87
89
|
|
|
90
|
+
### Check 5c — Rule File Schema (from `sdd check` [RULES])
|
|
91
|
+
|
|
92
|
+
Read the [RULES] section. Each `verdict=INCOMPLETE` row is a rule file missing one of the four checkable sections; the `missing` column names them. Report as INFO with the file list, **not** as a tree FAIL: these are shared project artifacts, tracked by `rule_findings` separately from `findings` for exactly that reason. Fixing them is its own ticket, never a task reopen.
|
|
93
|
+
|
|
88
94
|
### Check 6 — File Headers (from `sdd check --files`)
|
|
89
95
|
|
|
90
96
|
Pass recently modified source files to the shared checker instead of sampling by hand:
|
|
@@ -134,8 +140,9 @@ First: Self-Reflection. Then: Mechanical Checks. Use compact single-line-per-che
|
|
|
134
140
|
|
|
135
141
|
Rules for VERDICT line:
|
|
136
142
|
|
|
137
|
-
- All
|
|
138
|
-
- All
|
|
143
|
+
- All checks PASS AND 0 protocol violations → `✅ CLEAN — artifact tree is consistent, next pickable: TSK-NN`
|
|
144
|
+
- All checks PASS AND 0 violations but some tasks deferred/TODO → `✅ CLEAN — <N> tasks remaining in queue`
|
|
145
|
+
- Check 5c findings are INFO — they never move the verdict off `✅ CLEAN`; append `· <N> rule file(s) incomplete` to the line instead
|
|
139
146
|
- Any FAIL check OR protocol violations → `❌ NOT READY — <N> issue(s) require attention`
|
|
140
147
|
- Checks skipped (marked `—`) → treat as PASS for verdict unless evidence of gap exists
|
|
141
148
|
</Output>
|
|
@@ -97,13 +97,14 @@ Pause path (distinguish from failure — skill is awaiting operator, not broken)
|
|
|
97
97
|
#### Round close
|
|
98
98
|
- [x] `<ts>` DONE
|
|
99
99
|
```
|
|
100
|
-
Set ticket Meta Status → `[x] DONE
|
|
100
|
+
Set ticket Meta Status → `[~] IN_PROGRESS`. **Not `[x] DONE` — the round is closed, not verified.** `DONE` is set in step 6, and only on audit PASS. Dependents pick on `DONE`, so setting it here advertises a task the audit has not seen yet.
|
|
101
101
|
|
|
102
102
|
4a. **Sync Trackers** (MANDATORY, cannot skip):
|
|
103
103
|
|
|
104
|
-
- Read `tasks/<scope>/README.md`. Find the Tracker row for this Task-ID. Set its Status
|
|
105
|
-
- Read `tasks/README.md` Tracker Index. Update the scope's aggregate counts (done/total)
|
|
104
|
+
- Read `tasks/<scope>/README.md`. Find the Tracker row for this Task-ID. Set its Status to the ticket's current Meta Status. Write back.
|
|
105
|
+
- Read `tasks/README.md` Tracker Index. Update the scope's aggregate counts (done/total) — a task counts as done only at `[x] DONE`. Write back.
|
|
106
106
|
- Verify: re-read both files, confirm the changes took effect. If not → retry once.
|
|
107
|
+
- Run this step again after step 6 sets the final status.
|
|
107
108
|
|
|
108
109
|
5. **Dispatch AUDIT** (MANDATORY, always runs). Dispatch ONE subagent (`subagent_type: general-purpose`, **`model: "haiku"`** — audit is mechanical verification + fact-checking against artifacts; sonnet capability is overkill, haiku is faster and cheaper for this read-heavy task). Include in prompt the SDD tooling location: `~/Developer/gennady/ai/skills/sdd-execute/scripts/sdd` (audit may use `lint`, `verify`, `check-blockers` subcommands). With this prompt:
|
|
109
110
|
|
|
@@ -128,7 +129,7 @@ Pause path (distinguish from failure — skill is awaiting operator, not broken)
|
|
|
128
129
|
Wait for return. If dispatch fails → retry once. If fails again → mark task FAILED.
|
|
129
130
|
|
|
130
131
|
6. **Branch on audit status:**
|
|
131
|
-
- `PASS` or `PASS_WITH_ACKNOWLEDGED_RISKS` → ticket verified
|
|
132
|
+
- `PASS` or `PASS_WITH_ACKNOWLEDGED_RISKS` → ticket verified. **Only now** set Meta Status → `[x] DONE` and re-run step 4a so the trackers and the aggregate counts follow. Jump to step 9 (summary).
|
|
132
133
|
- `FAIL` AND `audit_attempt = 1` → step 7 (resolve findings).
|
|
133
134
|
- `FAIL` AND `audit_attempt = 2` → cap exhausted. Set Meta Status `[!] BLOCKED`, log `🛑 BLOCKED: audit-cap-exhausted` whose `💬 unblock:` line is the literal command `/sdd-execute <TSK-NN> --new-audit-session`, sync trackers, jump to step 9.
|
|
134
135
|
|