@manhquy/flow-skill 0.7.1-next.0 → 0.7.2

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 (38) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +5 -5
  3. package/README_VN.md +5 -5
  4. package/package.json +1 -1
  5. package/skills/flow/SKILL.md +108 -221
  6. package/skills/flow/_templates/01-research.md +3 -2
  7. package/skills/flow/_templates/02-scope.md +2 -0
  8. package/skills/flow/_templates/03-prd.md +2 -1
  9. package/skills/flow/_templates/05-contract.md +1 -0
  10. package/skills/flow/_templates/card.md +5 -1
  11. package/skills/flow/law/CLAUDE.md +6 -5
  12. package/skills/flow/law/CODING.md +37 -0
  13. package/skills/flow/references/agent-detection.md +11 -9
  14. package/skills/flow/references/agent-stage-mapping.md +47 -12
  15. package/skills/flow/references/auto-run.md +37 -7
  16. package/skills/flow/references/clarify.md +7 -7
  17. package/skills/flow/references/command-dispatch.md +51 -51
  18. package/skills/flow/references/concierge.md +2 -2
  19. package/skills/flow/references/debt-and-halts.md +20 -5
  20. package/skills/flow/references/gate-00.md +10 -0
  21. package/skills/flow/references/gate-01.md +18 -0
  22. package/skills/flow/references/gate-02.md +16 -0
  23. package/skills/flow/references/gate-03.md +10 -0
  24. package/skills/flow/references/gate-04.md +12 -0
  25. package/skills/flow/references/gate-05.md +33 -0
  26. package/skills/flow/references/gate-assess.md +13 -0
  27. package/skills/flow/references/gate-card.md +25 -0
  28. package/skills/flow/references/gate-consistency.md +24 -0
  29. package/skills/flow/references/gate-constitution.md +19 -0
  30. package/skills/flow/references/gate-debt.md +5 -0
  31. package/skills/flow/references/gate-eval.md +6 -3
  32. package/skills/flow/references/gate-examples.md +78 -0
  33. package/skills/flow/references/gate-rules.md +40 -241
  34. package/skills/flow/references/gate-shared.md +37 -0
  35. package/skills/flow/references/ground-truth-gates.md +1 -1
  36. package/skills/flow/references/mode-work.md +13 -10
  37. package/skills/flow/runner/flow.sh +223 -24
  38. package/skills-manifest.json +16 -2
@@ -2,17 +2,20 @@
2
2
 
3
3
  `MODE` file at project root (default `teach`). Set with `/flow mode work`.
4
4
 
5
- - **teach** — the operator writes every artifact; you only gatekeep. Default.
6
- - **work** — you interview the operator ONCE, draft stages 00-05 yourself, pause only for
5
+ - **teach** — the operator writes every artifact; the host only gatekeeps. Default.
6
+ - **work** — interview the operator ONCE, draft stages 00-05, pause only for
7
7
  scope sign-off, deliver the card set as one summary. **Gates and done-rules are identical
8
- to teach** — you still pass every gate, you just also author.
8
+ to teach** — every gate still passes; the host also authors.
9
9
 
10
10
  ## The work-mode shape (interview once -> draft -> one pause -> summary)
11
11
 
12
- 1. **Interview once.** Ask a single tight batch (use `AskUserQuestion`): the idea in one
13
- line, who has the pain (a real named person/group), the rough budget/time, the stack if
14
- they have a preference, and the one channel for the first users. Don't drip questions
15
- across stages.
12
+ 1. **Interview once.** One tight batch — numbered questions, not a drip across stages:
13
+ 1. Idea in one line?
14
+ 2. Who has the pain (a real named person/group)?
15
+ 3. Rough budget/time?
16
+ 4. Stack preference, if any?
17
+ 5. One channel for the first users?
18
+ Host-neutral: use whatever ask/prompt surface the host has.
16
19
  2. **Draft 00 -> 01 -> 02.** Fill idea, do real research (delegate to `researcher` per
17
20
  `agent-stage-mapping.md` — actually open competitors, quote real complaints with links),
18
21
  and produce the scope table with honest Impact + Grade. Run each gate with `flow.sh next`.
@@ -33,8 +36,8 @@
33
36
 
34
37
  ## Rules that still hold in work mode
35
38
  - Every gate must pass mechanically (`flow.sh`) AND semantically (`gate-rules.md`). Drafting
36
- does not lower the bar — self-challenge before presenting (you are now the author AND under
37
- review, so apply the adversarial lens to your own draft).
39
+ does not lower the bar — self-challenge the draft before presenting. Self-challenge is
40
+ color, not a verdict: it never substitutes for `flow.sh` + `gate-rules.md`.
38
41
  - Research must be real (opened competitors, quoted complaints with links) — no fabrication.
39
42
  This is the highest-risk stage for an AI author; verify every quote has a source.
40
43
  - Scope honesty: do not grade-launder your own C features to B. Call C a C, justify the path.
@@ -43,5 +46,5 @@
43
46
  can still halt or add a bullet (a policy-encoding `## Assumptions` line with no operator/ADR
44
47
  authority is an open decision, not a silent default). Never invent auth / tenancy / retention
45
48
  / billing to clear FILL.
46
- - Done is still world-state evidence; you cannot mark a card done without real proof.
49
+ - Done is still world-state evidence; a card cannot be marked done without real proof.
47
50
  - Write durable records (intake/decision/story) as you go, same as teach mode.
@@ -171,6 +171,7 @@ current_stage_idx() { # highest CONTIGUOUS-from-00 stage index, or -1 if 00 miss
171
171
  # Prints violations; returns 0 = clean, 1 = violations found.
172
172
  scan_gate() {
173
173
  local file="$1" found=0 unchecked fills
174
+ _MIDTIER_FAILS=0
174
175
  if [ ! -f "$file" ]; then
175
176
  echo " missing file: $file"
176
177
  return 1
@@ -187,9 +188,132 @@ scan_gate() {
187
188
  printf '%s\n' "$fills" | sed 's/^/ L/'
188
189
  found=1
189
190
  fi
191
+ case "$(basename "$file")" in
192
+ 01-research.md|02-scope.md|03-prd.md|05-contract.md)
193
+ if ! _scan_midtier "$file"; then
194
+ found=1
195
+ fi
196
+ ;;
197
+ esac
190
198
  return $found
191
199
  }
192
200
 
201
+ # Materialize a ## heading body into stdout (one awk; caller assigns to a var).
202
+ # Copy of cmd_clarify's heading walk: start at heading, stop at the next ##.
203
+ _heading_slice() { # $1=file $2=heading prefix after "## "
204
+ local file="$1" heading="$2"
205
+ awk -v h="$heading" '
206
+ {
207
+ line = $0
208
+ sub(/\r$/, "", line)
209
+ }
210
+ line ~ ("^##[[:space:]]+" h) { f=1; next }
211
+ /^##[[:space:]]/ { f=0 }
212
+ f { print line }
213
+ ' "$file"
214
+ }
215
+
216
+ _midtier_hit() {
217
+ echo " [x] $1"
218
+ _MIDTIER_FAILS=$((_MIDTIER_FAILS + 1))
219
+ }
220
+
221
+ _midtier_entry_n() { # stdin = ## What exists already -> numbered or bullet entries
222
+ awk '
223
+ /^[[:space:]]*[0-9]+\./ { c++; next }
224
+ /^[[:space:]]*- / { c++ }
225
+ END { print c + 0 }
226
+ '
227
+ }
228
+
229
+ _midtier_l_above_a() { # stdin = ## Features in v1 body; exit 1 if a joined bullet is L + B/C
230
+ awk '
231
+ function flush() {
232
+ if (buf == "") return
233
+ low = tolower(buf)
234
+ hasL = (low ~ /impact[[:space:]]*:?[[:space:]]*l([^a-z]|$)/ || low ~ /(^|[^a-z])l-impact/)
235
+ hasBC = (low ~ /grade[[:space:]]*:?[[:space:]]*[bc]([^a-z]|$)/)
236
+ if (hasL && hasBC) bad++
237
+ buf = ""
238
+ }
239
+ /^[[:space:]]*- / { flush(); buf = $0; next }
240
+ /^[[:space:]]*$/ { flush(); next }
241
+ buf != "" { buf = buf " " $0; next }
242
+ { flush() }
243
+ END { flush(); exit (bad > 0) ? 1 : 0 }
244
+ '
245
+ }
246
+
247
+ _midtier_adjectives() { # stdin = Features or NFR body; print first listed adjective
248
+ awk '
249
+ /^[[:space:]]*- \[[ xX]\]/ { next }
250
+ {
251
+ line = tolower($0)
252
+ n = split("fast secure intuitive robust prominent", w, " ")
253
+ for (i = 1; i <= n; i++) {
254
+ if (line ~ "(^|[^a-z])" w[i] "([^a-z]|$)") { print w[i]; exit }
255
+ }
256
+ }
257
+ '
258
+ }
259
+
260
+ _midtier_od_n() { # stdin = ## Open decisions body -> markdown bullet count (checked or not)
261
+ awk '/^[[:space:]]*- / { c++ } END { print c + 0 }'
262
+ }
263
+
264
+ _midtier_open_decisions() { # $1=file
265
+ local body n
266
+ body="$(_heading_slice "$1" "Open decisions")"
267
+ n="$(printf '%s\n' "$body" | _midtier_od_n)"
268
+ if [ "$n" -gt 5 ]; then
269
+ _midtier_hit "more than 5 ## Open decisions bullets ($n)"
270
+ fi
271
+ }
272
+
273
+ _scan_midtier() { # $1=file; prints [x] lines; return 1 if any hit
274
+ local file="$1" base body n pt adj
275
+ base="$(basename "$file")"
276
+ case "$base" in
277
+ 01-research.md)
278
+ if [ -f "$PROJECT_TYPE_FILE" ]; then
279
+ pt="$(tr -d '\r' < "$PROJECT_TYPE_FILE" | awk 'NF{print; exit}')"
280
+ if [ "$pt" = "web" ]; then
281
+ body="$(_heading_slice "$file" "What exists already")"
282
+ n="$(printf '%s\n' "$body" | _midtier_entry_n)"
283
+ if [ "$n" -lt 3 ]; then
284
+ _midtier_hit "fewer than 3 entries under ## What exists already (typed web, got $n)"
285
+ fi
286
+ fi
287
+ fi
288
+ ;;
289
+ 02-scope.md)
290
+ body="$(_heading_slice "$file" "Features in v1")"
291
+ if ! printf '%s\n' "$body" | _midtier_l_above_a; then
292
+ _midtier_hit "L-impact feature above grade A in ## Features in v1"
293
+ fi
294
+ _midtier_open_decisions "$file"
295
+ ;;
296
+ 03-prd.md)
297
+ body="$(_heading_slice "$file" "Features")"
298
+ adj="$(printf '%s\n' "$body" | _midtier_adjectives)"
299
+ if [ -n "$adj" ]; then
300
+ _midtier_hit "unquantified adjective '$adj' in ## Features"
301
+ else
302
+ body="$(_heading_slice "$file" "Non-functional requirements")"
303
+ adj="$(printf '%s\n' "$body" | _midtier_adjectives)"
304
+ if [ -n "$adj" ]; then
305
+ _midtier_hit "unquantified adjective '$adj' in ## Non-functional requirements"
306
+ fi
307
+ fi
308
+ _midtier_open_decisions "$file"
309
+ ;;
310
+ 05-contract.md)
311
+ _midtier_open_decisions "$file"
312
+ ;;
313
+ esac
314
+ [ "$_MIDTIER_FAILS" -eq 0 ]
315
+ }
316
+
193
317
  _python() {
194
318
  # prefer python3, and only accept an interpreter that is actually Python 3.x (the harness +
195
319
  # repo_map.py are py3-only — a py2 `python` must NOT be selected or it fails silently).
@@ -437,6 +561,18 @@ planning_complete() { # 0 = yes: each stage is clean, OR debt-skipped (a skipped
437
561
  return 0
438
562
  }
439
563
 
564
+ # Files exist (or debt-skipped). Used by project-type lock so a midtier-dirty
565
+ # 01 cannot unlock a type flip after stages 00-05 are on disk.
566
+ planning_artifacts_present() {
567
+ local s
568
+ for s in $STAGES; do
569
+ if [ ! -f "$FLOW_DIR/$s.md" ]; then
570
+ stage_skipped "$s" || return 1
571
+ fi
572
+ done
573
+ return 0
574
+ }
575
+
440
576
  # project type (web|cli|library|skill); absent => web. Adapts done-evidence + guidance.
441
577
  get_project_type() {
442
578
  local t; t="$(cat "$PROJECT_TYPE_FILE" 2>/dev/null | tr -d '\r' | awk 'NF{print; exit}')"
@@ -759,7 +895,7 @@ cmd_status() {
759
895
  echo " auto: $_ast$([ "$_ast" = ACTIVE ] && echo " (receipts enforced)" || true)"
760
896
  lock_warn
761
897
  echo
762
- echo "NEXT -> $(_next_action)"
898
+ _emit_next
763
899
  echo
764
900
  if [ -f "$FLOW_DIR/00-inspect.md" ]; then
765
901
  if scan_gate "$FLOW_DIR/00-inspect.md" >/dev/null 2>&1; then
@@ -856,7 +992,9 @@ _resume_valid_lines() {
856
992
  cmd_resume() {
857
993
  local idx; idx="$(current_stage_idx)"
858
994
  if [ "$idx" -lt 0 ]; then
859
- echo "nothing to resume - $(_next_action)"
995
+ _na="$(_next_action)"
996
+ echo "nothing to resume - $_na"
997
+ echo "NEXT_VERB=$(_next_verb_from "$_na")"
860
998
  return 0
861
999
  fi
862
1000
 
@@ -874,7 +1012,7 @@ cmd_resume() {
874
1012
  echo
875
1013
  _gate_state_brief "$idx"
876
1014
  echo
877
- echo "NEXT -> $(_next_action)"
1015
+ _emit_next
878
1016
  return 0
879
1017
  fi
880
1018
 
@@ -966,7 +1104,7 @@ cmd_resume() {
966
1104
  echo
967
1105
 
968
1106
  # ---- NEXT (shared with `status` via _next_action - the two verbs can never disagree) ----
969
- echo "NEXT -> $(_next_action)"
1107
+ _emit_next
970
1108
  }
971
1109
 
972
1110
  cmd_next() {
@@ -1005,7 +1143,7 @@ cmd_next() {
1005
1143
  # attribute the failing event to THIS stage (so usage top-fail-stage + propose can see it)
1006
1144
  # and record WHICH checks failed, so a chronically-failing stage is diagnosable.
1007
1145
  FLOW_LOG_STAGE_TO="$cur"
1008
- FLOW_LAST_GATE_FAIL="fill:$(grep -c '\[FILL' "$FLOW_DIR/$cur.md" 2>/dev/null || echo 0),unchecked:$(grep -cE '^[[:space:]]*- \[ \]' "$FLOW_DIR/$cur.md" 2>/dev/null || echo 0)"
1146
+ FLOW_LAST_GATE_FAIL="fill:$(grep -c '\[FILL' "$FLOW_DIR/$cur.md" 2>/dev/null || echo 0),unchecked:$(grep -cE '^[[:space:]]*- \[ \]' "$FLOW_DIR/$cur.md" 2>/dev/null || echo 0),midtier:${_MIDTIER_FAILS:-0}"
1009
1147
  echo
1010
1148
  echo "Fix the above, then run '/flow next' again. (Kill at a gate is also valid.)"
1011
1149
  return 1
@@ -1179,6 +1317,27 @@ _next_action() {
1179
1317
  echo "run '/flow check' then ship per stage 09"
1180
1318
  }
1181
1319
 
1320
+ # Closed advisory enum from _next_action prose only. Hosts must not auto-exec auto/skip.
1321
+ _next_verb_from() { # $1 = _next_action text
1322
+ local a="$1"
1323
+ case "$a" in
1324
+ *"fix gate:"*) echo fix-gate ;;
1325
+ *"/flow card start"*) echo card-start ;;
1326
+ *"/flow card"*) echo card ;;
1327
+ *"/flow check"*) echo check ;;
1328
+ *"/flow next"*) echo next ;;
1329
+ *"in flight"*) echo card-start ;;
1330
+ *) echo none ;;
1331
+ esac
1332
+ }
1333
+
1334
+ _emit_next() {
1335
+ local a
1336
+ a="$(_next_action)"
1337
+ echo "NEXT -> $a"
1338
+ echo "NEXT_VERB=$(_next_verb_from "$a")"
1339
+ }
1340
+
1182
1341
  _set_card_status() { # $1=file $2=value -> rewrite the ^status: line (portable substitute; temp+mv)
1183
1342
  local f="$1" v="$2"
1184
1343
  sed "s/^status:.*/status: $v/" "$f" > "$f.tmp" 2>/dev/null || { rm -f "$f.tmp"; return 1; }
@@ -1590,12 +1749,13 @@ cmd_project_type() {
1590
1749
  fi
1591
1750
  case "$arg" in
1592
1751
  web|cli|library|skill)
1593
- # After planning is complete AND an explicit type file exists, refuse silent
1752
+ # After planning artifacts exist AND an explicit type file exists, refuse silent
1594
1753
  # type flips unless FLOW_FORCE=1 (D6). Default-web with no file is not "locked".
1595
- if planning_complete 2>/dev/null && [ -f "$PROJECT_TYPE_FILE" ]; then
1754
+ # Gate cleanliness is NOT required: a midtier-dirty 01 must not unlock a flip.
1755
+ if planning_artifacts_present 2>/dev/null && [ -f "$PROJECT_TYPE_FILE" ]; then
1596
1756
  local cur; cur="$(get_project_type)"
1597
1757
  if [ -n "$cur" ] && [ "$cur" != "$arg" ] && [ "${FLOW_FORCE:-0}" != "1" ]; then
1598
- echo "FAIL: project type is locked to '$cur' after planning completes (would change done-evidence lens)."
1758
+ echo "FAIL: project type is locked to '$cur' once planning artifacts exist (would change done-evidence lens)."
1599
1759
  echo " re-set with FLOW_FORCE=1 if intentional, and record a DEBT.md line for the change."
1600
1760
  return 1
1601
1761
  fi
@@ -3162,17 +3322,26 @@ _eval_heading_pattern() {
3162
3322
  esac
3163
3323
  }
3164
3324
 
3165
- # Extract one stage's ritual text: from its heading line up to (not including) the next '## '
3166
- # heading, or EOF. Prints nothing on a bad stage/missing file - caller MUST assert non-empty
3167
- # before any billable call (a silent empty extraction would judge against no rule at all).
3325
+ # Extract one stage's ritual text from the mapped file (01→gate-01.md, 02→gate-02.md,
3326
+ # card→gate-card.md): from its heading line up to (not including) the next '## '
3327
+ # heading, or EOF. Prints nothing on a bad stage/missing file - caller MUST assert
3328
+ # non-empty before any billable call (a silent empty extraction would judge against
3329
+ # no rule at all).
3168
3330
  _eval_extract_section() { # $1 = stage (01|02|card)
3169
- local pat; pat="$(_eval_heading_pattern "$1")" || return 1
3170
- [ -f "$GATE_RULES_FILE" ] || return 1
3331
+ local pat src
3332
+ pat="$(_eval_heading_pattern "$1")" || return 1
3333
+ case "$1" in
3334
+ 01) src="$SCRIPT_DIR/../references/gate-01.md" ;;
3335
+ 02) src="$SCRIPT_DIR/../references/gate-02.md" ;;
3336
+ card) src="$SCRIPT_DIR/../references/gate-card.md" ;;
3337
+ *) return 1 ;;
3338
+ esac
3339
+ [ -f "$src" ] || return 1
3171
3340
  awk -v pat="$pat" '
3172
3341
  $0 ~ pat { f=1; print; next }
3173
3342
  f && /^## / { f=0 }
3174
3343
  f { print }
3175
- ' "$GATE_RULES_FILE"
3344
+ ' "$src"
3176
3345
  }
3177
3346
 
3178
3347
  # Usability probe: zero cost if `claude` is absent; exactly one minimal billable call if present.
@@ -3227,12 +3396,19 @@ _eval_isolated_run() {
3227
3396
  }
3228
3397
 
3229
3398
 
3230
- # Build the judge prompt for one fixture. Returns 1 (writes nothing usable) if the gate-rules.md
3231
- # section extraction came back empty.
3399
+ # Build the judge prompt for one fixture. The challenge block is the extract output
3400
+ # (already the judge bytes; `_eval_gate_rules_sha` is not stdin). Returns 1 if empty.
3232
3401
  _eval_build_prompt() { # $1=outfile $2=stage $3=artifact-file $4=nonce
3233
- local outfile="$1" stage="$2" artifact="$3" nonce="$4" section
3402
+ local outfile="$1" stage="$2" artifact="$3" nonce="$4" section shared
3234
3403
  section="$(_eval_extract_section "$stage")" || return 1
3235
3404
  [ -n "$section" ] || return 1
3405
+ # Shared OD/authority lives in 02/03/05 challenges. Extract maps 01/02/card only;
3406
+ # appending shared onto 01/card lets OD rules false-FLAG research/evidence.
3407
+ if [ "$stage" = "02" ]; then
3408
+ shared="$SCRIPT_DIR/../references/gate-shared.md"
3409
+ [ -f "$shared" ] && section="$section
3410
+ $(cat "$shared")"
3411
+ fi
3236
3412
  {
3237
3413
  printf 'You are reviewing a build-process artifact against the quality-gate challenge below.\n'
3238
3414
  printf 'Read the challenge, then the artifact, then decide honestly: does the artifact\n'
@@ -3311,11 +3487,27 @@ _eval_nonce_epoch() { # $1=run_id -> epoch seconds (or empty)
3311
3487
  printf '%s' "$1" | awk -F- 'NF>=2 { print $(NF-1) }'
3312
3488
  }
3313
3489
 
3314
- # CRLF-normalized gate-rules.md hash: a raw-byte hash would differ per checkout line-endings
3315
- # (git autocrlf) and produce a false "prose changed" drift alarm across identical content.
3490
+ # CRLF-normalized hash of the explicit gate-rules corpus (index + shared + 11
3491
+ # section files). Never glob `gate-*.md` (would pull gate-eval.md + gate-examples.md).
3492
+ # A raw-byte hash would differ per checkout line-endings (git autocrlf).
3316
3493
  _eval_gate_rules_sha() {
3317
- [ -f "$GATE_RULES_FILE" ] || { printf 'unknown'; return; }
3318
- tr -d '\r' < "$GATE_RULES_FILE" | cksum | awk '{print $1}'
3494
+ local ref="$SCRIPT_DIR/../references"
3495
+ [ -f "$ref/gate-rules.md" ] || { printf 'unknown'; return; }
3496
+ {
3497
+ cat "$ref/gate-rules.md"
3498
+ [ -f "$ref/gate-shared.md" ] && cat "$ref/gate-shared.md"
3499
+ [ -f "$ref/gate-assess.md" ] && cat "$ref/gate-assess.md"
3500
+ [ -f "$ref/gate-00.md" ] && cat "$ref/gate-00.md"
3501
+ [ -f "$ref/gate-01.md" ] && cat "$ref/gate-01.md"
3502
+ [ -f "$ref/gate-02.md" ] && cat "$ref/gate-02.md"
3503
+ [ -f "$ref/gate-03.md" ] && cat "$ref/gate-03.md"
3504
+ [ -f "$ref/gate-04.md" ] && cat "$ref/gate-04.md"
3505
+ [ -f "$ref/gate-05.md" ] && cat "$ref/gate-05.md"
3506
+ [ -f "$ref/gate-card.md" ] && cat "$ref/gate-card.md"
3507
+ [ -f "$ref/gate-consistency.md" ] && cat "$ref/gate-consistency.md"
3508
+ [ -f "$ref/gate-constitution.md" ] && cat "$ref/gate-constitution.md"
3509
+ [ -f "$ref/gate-debt.md" ] && cat "$ref/gate-debt.md"
3510
+ } | tr -d '\r' | cksum | awk '{print $1}'
3319
3511
  }
3320
3512
 
3321
3513
  # CRLF-normalized assembler-output hash (same recipe as _eval_gate_rules_sha). Covers
@@ -3781,6 +3973,9 @@ _eval_routing_print_scorecard() { # $1=run_id
3781
3973
  '
3782
3974
  }
3783
3975
 
3976
+ _eval_skip_unmeasured() { # $1 = kind (eval / routing eval / converge eval)
3977
+ echo "SKIP: 'claude' CLI not found on PATH - $1 needs it to run the LLM judge. Zero calls made."
3978
+ }
3784
3979
  # NOTE: defined with the `function name { }` form (no parens) rather than this file's usual
3785
3980
  # `name() { }` style, solely so the literal 4-byte substring the shipped verb name is built
3786
3981
  # from never appears immediately followed by '(' in the source - a blind text-pattern security
@@ -3812,7 +4007,8 @@ function cmd_eval_routing { # same arg shape as cmd_eval, called only when --sta
3812
4007
  local probe; probe="$(_eval_isolated_run _eval_probe)"
3813
4008
  case "$probe" in
3814
4009
  absent)
3815
- echo "SKIP: 'claude' CLI not found on PATH - routing eval needs it to run the LLM judge. Zero calls made."
4010
+ _eval_skip_unmeasured "routing eval"
4011
+ echo "semantic layer unmeasured on this host"
3816
4012
  return 0 ;;
3817
4013
  fail)
3818
4014
  echo "SKIP: 'claude' CLI is present but the sentinel probe did not come back clean (one minimal"
@@ -4123,7 +4319,7 @@ function cmd_eval_converge { # same arg shape as cmd_eval, called only when --st
4123
4319
 
4124
4320
  local probe; probe="$(_eval_isolated_run _eval_probe)"
4125
4321
  case "$probe" in
4126
- absent) echo "SKIP: 'claude' CLI not found on PATH - converge eval needs it to run the LLM judge. Zero calls made."; return 0 ;;
4322
+ absent) _eval_skip_unmeasured "converge eval"; echo "semantic layer unmeasured on this host"; return 0 ;;
4127
4323
  fail) echo "SKIP: 'claude' CLI present but the sentinel probe did not come back clean (one minimal probe call was made). Retry once 'claude -p' runs headless."; return 0 ;;
4128
4324
  esac
4129
4325
 
@@ -4238,6 +4434,8 @@ _eval_guard_unbounded_darwin() { # $1=replay_mode (0/1); return 1 = refused
4238
4434
  local replay_mode="${1:-0}"
4239
4435
  [ "$replay_mode" -eq 0 ] || return 0
4240
4436
  [ "${FLOW_EVAL_UNBOUNDED:-}" = "1" ] && return 0
4437
+ # No judge binary => no stuck call to bound. Probe SKIP (unmeasured) owns this case.
4438
+ command -v claude >/dev/null 2>&1 || return 0
4241
4439
  local darwin=0
4242
4440
  if [ "${FLOW_EVAL_FORCE_DARWIN:-}" = "1" ]; then
4243
4441
  darwin=1
@@ -4378,7 +4576,8 @@ function cmd_eval {
4378
4576
  local probe; probe="$(_eval_isolated_run _eval_probe)"
4379
4577
  case "$probe" in
4380
4578
  absent)
4381
- echo "SKIP: 'claude' CLI not found on PATH - eval needs it to run the LLM judge. Zero calls made."
4579
+ _eval_skip_unmeasured "eval"
4580
+ echo "semantic layer unmeasured on this host"
4382
4581
  return 0 ;;
4383
4582
  fail)
4384
4583
  echo "SKIP: 'claude' CLI is present but the sentinel probe did not come back clean (one minimal"
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "source": "../skills/flow",
3
3
  "destRelative": "skills/flow",
4
- "fileCount": 103,
5
- "syncedAt": "2026-08-20T13:35:30.768Z",
4
+ "fileCount": 117,
5
+ "syncedAt": "2026-09-11T03:27:04.868Z",
6
6
  "fileList": [
7
7
  "SKILL.md",
8
8
  "_templates/00-idea.md",
@@ -69,6 +69,7 @@
69
69
  "harness/schema/012-usage-ephemeral.sql",
70
70
  "harness/schema/014-graph-executor.sql",
71
71
  "law/CLAUDE.md",
72
+ "law/CODING.md",
72
73
  "law/DESIGN.md",
73
74
  "law/RETRO.md",
74
75
  "playbooks/README.md",
@@ -94,8 +95,21 @@
94
95
  "references/flow-catalog.tsv",
95
96
  "references/flow-topology.json",
96
97
  "references/forge-idea.md",
98
+ "references/gate-00.md",
99
+ "references/gate-01.md",
100
+ "references/gate-02.md",
101
+ "references/gate-03.md",
102
+ "references/gate-04.md",
103
+ "references/gate-05.md",
104
+ "references/gate-assess.md",
105
+ "references/gate-card.md",
106
+ "references/gate-consistency.md",
107
+ "references/gate-constitution.md",
108
+ "references/gate-debt.md",
97
109
  "references/gate-eval.md",
110
+ "references/gate-examples.md",
98
111
  "references/gate-rules.md",
112
+ "references/gate-shared.md",
99
113
  "references/ground-truth-gates.md",
100
114
  "references/host-agnostic-parallel.md",
101
115
  "references/loop-harness-2026-principles.md",