@manhquy/flow-skill 0.4.1 → 0.5.1

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.
@@ -16,7 +16,7 @@
16
16
 
17
17
  set -u
18
18
 
19
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
19
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
20
20
  TEMPLATE_DIR="$SCRIPT_DIR/../_templates"
21
21
  LAW_DIR="$SCRIPT_DIR/../law"
22
22
  PLAYBOOKS_DIR="$SCRIPT_DIR/../playbooks"
@@ -59,6 +59,10 @@ LOCK_FILE="$ROOT/flow/.lock"
59
59
  LOCK_DIR="$ROOT/flow/.lock.d" # atomic mkdir claim dir (W5 guard); winner then writes $LOCK_FILE metadata
60
60
  HARNESS_PY="$SCRIPT_DIR/../harness/flow_harness.py"
61
61
 
62
+ # Attestations library (risk, receipts, auto policy) — optional-soft: missing file is fatal for v0.28+.
63
+ # shellcheck source=attestations.sh
64
+ . "$SCRIPT_DIR/attestations.sh"
65
+
62
66
  # Eval (LLM semantic-gate behavioral harness; opt-in, billable - see 'eval' command).
63
67
  # FLOW_EVAL_MANIFEST is a TEST-ONLY override (e.g. a synthetic CRLF manifest fixture) - it does
64
68
  # NOT widen the v1 trust boundary: artifact paths still resolve as $EVAL_DIR/fixtures/<id>/<rel>,
@@ -740,6 +744,8 @@ cmd_status() {
740
744
  echo " project: $ROOT"
741
745
  echo " mode: $(cat "$MODE_FILE" 2>/dev/null | tr -d '\r' || echo teach) (default teach)"
742
746
  echo " type: $(get_project_type) (done = $(done_def_for_type "$(get_project_type)"))"
747
+ local _ast; _ast="$(_att_auto_state_read 2>/dev/null || echo INACTIVE)"
748
+ echo " auto: $_ast$([ "$_ast" = ACTIVE ] && echo " (receipts enforced)" || true)"
743
749
  lock_warn
744
750
  echo
745
751
  echo "NEXT -> $(_next_action)"
@@ -845,11 +851,16 @@ cmd_resume() {
845
851
 
846
852
  echo "flow resume"
847
853
  echo " project: $ROOT"
854
+ local _ast; _ast="$(_att_auto_state_read 2>/dev/null || echo INACTIVE)"
855
+ echo " auto: $_ast"
848
856
  echo
849
857
 
850
858
  if [ ! -s "$EVENTS_FILE" ]; then
851
859
  echo "no telemetry - showing gate state only"
852
860
  echo
861
+ local _ast; _ast="$(_att_auto_state_read 2>/dev/null || echo INACTIVE)"
862
+ echo "auto: $_ast"
863
+ echo
853
864
  _gate_state_brief "$idx"
854
865
  echo
855
866
  echo "NEXT -> $(_next_action)"
@@ -949,6 +960,21 @@ cmd_resume() {
949
960
 
950
961
  cmd_next() {
951
962
  lock_acquire next || return 1
963
+ # v0.28: warning-only stage semantic receipt guidance (never hard-blocks next)
964
+ if _att_git_ok 2>/dev/null; then
965
+ local _cur_stage _rp _st
966
+ _cur_stage="$(stage_name_at "$(current_stage_idx)" 2>/dev/null || true)"
967
+ if [ -n "$_cur_stage" ] && _att_is_stage "$_cur_stage" 2>/dev/null; then
968
+ _rp="$(_att_receipt_path semantic_gate stage "$_cur_stage" 2>/dev/null || true)"
969
+ if [ -n "$_rp" ]; then
970
+ _st="$(_att_receipt_status "$_rp" 2>/dev/null || echo missing)"
971
+ case "$_st" in
972
+ current) : ;;
973
+ *) echo "WARNING: stage $_cur_stage semantic receipt is $_st (auto will require a current pass; see references/attestations.md)" ;;
974
+ esac
975
+ fi
976
+ fi
977
+ fi
952
978
  local idx; idx="$(current_stage_idx)"
953
979
  if [ "$idx" -lt 0 ]; then
954
980
  mkdir -p "$FLOW_DIR"
@@ -1171,17 +1197,63 @@ cmd_card_done() { # CLI-owned flip to done, gated by the SAME done-rules as '/fl
1171
1197
  if [ -z "$file" ] || [ ! -f "$file" ]; then echo "FAIL: card not found for '$arg' (looked for ${file:-?})"; return 1; fi
1172
1198
  local id orig; id="$(basename "$file" .md)"; FLOW_LOG_CARD="$id"; orig="$(card_status "$file")"
1173
1199
  if [ -z "$orig" ]; then echo "FAIL: $id has no 'status:' line — run '/flow check $id' to see what's missing."; return 1; fi
1200
+
1201
+ # Attested auto: validate receipts BEFORE status mutation; integration-checkout owned.
1202
+ local enforce=0
1203
+ if _att_auto_is_enforcing; then
1204
+ enforce=1
1205
+ if ! _att_is_main_worktree; then
1206
+ local mainp; mainp="$(_att_main_worktree_path)"
1207
+ echo "FAIL: active auto card done is integration-checkout owned."
1208
+ echo " cd ${mainp:-<main>} && bash <skill>/runner/flow.sh card done $id"
1209
+ return 1
1210
+ fi
1211
+ _att_auto_lock_acquire || return 1
1212
+ local lname; lname="$(_att_subject_lock_name semantic_gate "$id")"
1213
+ local lname2; lname2="$(_att_subject_lock_name live_verify "$id")"
1214
+ _att_lock_acquire "$lname" || { _att_auto_lock_release; return 1; }
1215
+ _att_lock_acquire "$lname2" || { _att_lock_release "$lname"; _att_auto_lock_release; return 1; }
1216
+ if ! _att_enforce_card "$id" 1 1; then
1217
+ _att_lock_release "$lname2"; _att_lock_release "$lname"; _att_auto_lock_release
1218
+ return 1
1219
+ fi
1220
+ # prospective done evidence without mutating status
1221
+ if ! {
1222
+ local st0; st0="$(card_status "$file")"
1223
+ # temporary view: require verify boxes + evidence as if done
1224
+ if grep -qE '^[[:space:]]*- \[ \]' "$file" 2>/dev/null; then
1225
+ echo "FAIL: Verify has unchecked boxes"; false
1226
+ elif grep -q '\[FILL' "$file" 2>/dev/null; then
1227
+ echo "FAIL: unfilled [FILL]"; false
1228
+ else
1229
+ local ev score
1230
+ ev="$(_evidence_body "$file")"
1231
+ if _evidence_is_empty "$ev"; then echo "FAIL: empty Evidence"; false
1232
+ else
1233
+ score="$(_evidence_signal_score "$ev" "${FLOW_PROJECT_ROOT:-$PWD}")"
1234
+ [ "$score" -ge 2 ] || { echo "FAIL: Evidence multi-signal floor ($score/2)"; false; }
1235
+ fi
1236
+ fi
1237
+ }; then
1238
+ _att_lock_release "$lname2"; _att_lock_release "$lname"; _att_auto_lock_release
1239
+ echo "FAIL: $id prospective done-evidence gate failed (status unchanged)."
1240
+ return 1
1241
+ fi
1242
+ fi
1243
+
1174
1244
  # On INT/TERM after flip-to-done: restore todo and abort (fail-closed). Never continue
1175
1245
  # into durable complete after a partial restore.
1176
1246
  # shellcheck disable=SC2064
1177
1247
  trap '_set_card_status "'"$file"'" "todo" 2>/dev/null || true; trap - INT TERM; exit 130' INT TERM
1178
1248
  if ! _set_card_status "$file" done; then
1179
1249
  trap - INT TERM
1250
+ [ "$enforce" = "1" ] && { _att_lock_release "$lname2"; _att_lock_release "$lname"; _att_auto_lock_release; }
1180
1251
  echo "FAIL: could not write status for $id"
1181
1252
  return 1
1182
1253
  fi
1183
1254
  if cmd_check "$id"; then # cmd_check enforces evidence/verify AND records the durable done-trace
1184
1255
  trap - INT TERM
1256
+ [ "$enforce" = "1" ] && { _att_lock_release "$lname2"; _att_lock_release "$lname"; _att_auto_lock_release; }
1185
1257
  _inflight_clear "$id"
1186
1258
  # card-verify-live: the done boundary is the EVIDENCE gate passing, not the merge
1187
1259
  # (merge != shipped) - dependents unblock on card status, matching cmd_ready.
@@ -1190,6 +1262,7 @@ cmd_card_done() { # CLI-owned flip to done, gated by the SAME done-rules as '/fl
1190
1262
  return 0
1191
1263
  fi
1192
1264
  trap - INT TERM
1265
+ [ "$enforce" = "1" ] && { _att_lock_release "$lname2"; _att_lock_release "$lname"; _att_auto_lock_release; }
1193
1266
  # Always force todo on gate fail (even if orig was hollow done) — never leave hollow done.
1194
1267
  _set_card_status "$file" todo
1195
1268
  echo
@@ -1432,6 +1505,22 @@ cmd_check() {
1432
1505
  fi
1433
1506
  fi
1434
1507
 
1508
+ # Attestation: warn when inactive; hard-require when auto active/stale/invalid
1509
+ local need_live=0 enforce=0
1510
+ [ "$st" = "done" ] && need_live=1
1511
+ if _att_auto_is_enforcing; then enforce=1; fi
1512
+ if ! _att_enforce_card "$id" "$need_live" "$enforce"; then
1513
+ found=1
1514
+ fi
1515
+ # risk advisory (manual)
1516
+ if [ "$enforce" != "1" ]; then
1517
+ local rv; rv="$(_card_risk_validate "$file" manual 2>/dev/null || echo invalid)"
1518
+ case "$rv" in
1519
+ unknown) echo " note: risk=unknown — classify before /flow auto" ;;
1520
+ invalid:*) echo " note: risk metadata invalid ($rv)" ;;
1521
+ esac
1522
+ fi
1523
+
1435
1524
  if [ "$found" -eq 0 ]; then
1436
1525
  echo "PASS: $id is valid (status: $st)."
1437
1526
  # card-review boundary: the gate verdict IS the evidence the executor records
@@ -1612,6 +1701,7 @@ cmd_ready() {
1612
1701
  echo "FAIL: planning not complete - no cards to schedule yet."
1613
1702
  return 1
1614
1703
  fi
1704
+ local any_buildable=0
1615
1705
  local total; total="$(highest_card)"
1616
1706
  if [ "$total" -le 0 ]; then echo "No cards created yet. Run '/flow card'."; return 0; fi
1617
1707
  echo "flow ready - buildable todo cards (deps met). Operator dispatches; runner advises."
@@ -1637,34 +1727,117 @@ cmd_ready() {
1637
1727
  elif ! _card_done_evidence_ok "$depfile"; then
1638
1728
  ok=0
1639
1729
  echo " note: dep $(basename "$depfile" .md) is status=done but ## Evidence fails world-state signal (re-check or paste real proof)"
1730
+ elif _att_auto_is_enforcing; then
1731
+ depid="$(basename "$depfile" .md)"
1732
+ if ! _att_accepted_semantic card "$depid" || ! _att_accepted_live "$depid"; then
1733
+ ok=0
1734
+ echo " note: dep $depid missing current semantic/live receipts (auto active)"
1735
+ fi
1640
1736
  fi
1641
1737
  done
1642
1738
  if [ "$ok" -eq 1 ]; then
1643
1739
  echo " BUILDABLE $id (deps: ${deps:-none})"
1644
1740
  _card_allowed_files "$f" | sed 's/^/ allowed: /'
1741
+ any_buildable=1
1645
1742
  else
1646
1743
  echo " blocked $id (deps unmet or evidence floor failed: ${deps:-none})"
1647
1744
  fi
1648
1745
  done
1746
+ # Auto-active: if any todo cards exist but none are buildable, exit non-zero so
1747
+ # automation cannot treat a fully receipt-blocked graph as green.
1748
+ if _att_auto_is_enforcing; then
1749
+ local any_todo=0
1750
+ for f in "$CARDS_DIR"/C-*.md; do
1751
+ [ -e "$f" ] || continue
1752
+ [ "$(card_status "$f")" = "todo" ] && any_todo=1
1753
+ done
1754
+ if [ "${any_todo:-0}" -eq 1 ] && [ "${any_buildable:-0}" -eq 0 ]; then
1755
+ return 1
1756
+ fi
1757
+ fi
1649
1758
  return 0
1650
1759
  }
1651
1760
 
1652
1761
  cmd_auto() {
1762
+ # flow auto [stop] — activate/refresh attested auto policy, or clear it
1763
+ local sub="${1:-}"
1764
+ if [ "$sub" = "stop" ]; then
1765
+ if [ -n "${2:-}" ]; then echo "usage: /flow auto stop"; return 2; fi
1766
+ _att_auto_lock_acquire || return 1
1767
+ _att_auto_clear
1768
+ _att_auto_lock_release
1769
+ echo "PASS: auto state cleared (manual warning-only mode)."
1770
+ return 0
1771
+ fi
1772
+ if [ -n "$sub" ]; then echo "usage: /flow auto | /flow auto stop"; return 2; fi
1773
+
1653
1774
  lock_acquire auto || return 1
1654
- echo "flow auto - preflight"
1775
+ _att_auto_lock_acquire || return 1
1776
+ echo "flow auto - preflight (attested execution)"
1777
+
1778
+ if ! _att_git_ok; then
1779
+ echo "FAIL: /flow auto requires a Git repository."; _att_auto_lock_release; return 1
1780
+ fi
1781
+ if ! _att_is_main_worktree; then
1782
+ local mainp; mainp="$(_att_main_worktree_path)"
1783
+ echo "FAIL: activate auto only from the main worktree (not a linked/detached checkout)."
1784
+ echo " cd ${mainp:-<main>} && FLOW_PROJECT_ROOT=${mainp:-} bash <skill>/runner/flow.sh auto"
1785
+ _att_auto_lock_release; return 1
1786
+ fi
1787
+ local br; br="$(git -C "$ROOT" rev-parse --abbrev-ref HEAD 2>/dev/null | tr -d '\r')"
1788
+ if [ -z "$br" ] || [ "$br" = "HEAD" ]; then
1789
+ echo "FAIL: detached HEAD — checkout an integration branch first."
1790
+ _att_auto_lock_release; return 1
1791
+ fi
1792
+ if ! _att_supervisor_capable; then
1793
+ echo "FAIL: reliable process-group supervisor unavailable — live auto refused on this platform."
1794
+ _att_auto_lock_release; return 1
1795
+ fi
1655
1796
  if ! planning_complete; then
1656
1797
  echo "FAIL: planning not complete. Finish stages 00-05 first."
1657
- return 1
1798
+ _att_auto_lock_release; return 1
1658
1799
  fi
1659
1800
  if [ "$(highest_card)" -le 0 ]; then
1660
1801
  echo "FAIL: no cards. Run '/flow card' to create the build cards first."
1661
- return 1
1662
- fi
1663
- echo "PASS: preflight ok ($(highest_card) cards, planning complete)."
1802
+ _att_auto_lock_release; return 1
1803
+ fi
1804
+
1805
+ echo "--- risk set ---"
1806
+ if ! _att_risk_preflight; then
1807
+ echo "FAIL: risk preflight blocked activation (classify every card; security-class needs DEBT ack)."
1808
+ _att_auto_lock_release; return 1
1809
+ fi
1810
+
1811
+ echo "--- Stage 05 semantic receipt ---"
1812
+ if ! _att_accepted_semantic stage 05-contract; then
1813
+ echo "FAIL: need current accepted semantic_gate receipt for 05-contract."
1814
+ echo " mint: flow attest semantic --stage 05-contract --revision HEAD --owner <committed-manifest>"
1815
+ _att_auto_lock_release; return 1
1816
+ fi
1817
+ # Cleanliness last among preflight diagnostics so risk/receipt messages still print.
1818
+ if ! _att_require_clean_for_consume; then
1819
+ echo "FAIL: dirty worktree — auto activation requires clean tree (except .flow/, locks, status/Evidence)."
1820
+ _att_auto_lock_release; return 1
1821
+ fi
1822
+ local cfp; cfp="$_ATT_R_subject_fingerprint"
1823
+ local rfp; rfp="$(_att_risk_fingerprint)"
1824
+ local by; by="$(_att_sanitize_label "${FLOW_SESSION_ID:-session}")"
1825
+ [ -n "$by" ] || by="session"
1826
+ _ATT_W_activated_at="$(_att_now_rfc3339)"
1827
+ _ATT_W_activated_by="$by"
1828
+ _ATT_W_integration_branch="$br"
1829
+ _ATT_W_risk_fingerprint="$rfp"
1830
+ _ATT_W_contract_fingerprint="$cfp"
1831
+ if ! _att_auto_write; then
1832
+ echo "FAIL: could not write auto-state"
1833
+ _att_auto_lock_release; return 1
1834
+ fi
1835
+ _att_auto_lock_release
1836
+ echo "PASS: auto ACTIVE on branch '$br' ($(highest_card) cards)."
1837
+ echo " check/card done/ready/merged workspace remove now require current receipts."
1838
+ echo " stop: /flow auto stop"
1664
1839
  echo
1665
- echo "Autonomous orchestration is driven by the /flow SKILL.md AUTO PRINCIPLES"
1666
- echo "(subagent per card, planner review + verify, worktree isolation, Tier-C halts"
1667
- echo "for security-class debt, state in card files + AUTO-LOG.md)."
1840
+ echo "Orchestration remains skill-driven (AUTO principles); receipts are the mechanical trust floor."
1668
1841
  echo "Run '/flow ready' to see parallel-safe groups."
1669
1842
  return 0
1670
1843
  }
@@ -2401,16 +2574,17 @@ _ws_enter() {
2401
2574
  }
2402
2575
 
2403
2576
  _ws_remove() {
2404
- local branch="" force=0
2577
+ local branch="" force=0 card_arg=""
2405
2578
  while [ $# -gt 0 ]; do
2406
2579
  case "$1" in
2407
2580
  --force) force=1 ;;
2581
+ --card) shift; card_arg="${1:-}" ;;
2408
2582
  --*) echo "workspace remove: unknown arg '$1'"; return 1 ;;
2409
2583
  *) [ -z "$branch" ] && branch="$1" || { echo "workspace remove: extra arg '$1'"; return 1; } ;;
2410
2584
  esac
2411
2585
  shift
2412
2586
  done
2413
- [ -n "$branch" ] || { echo "usage: /flow workspace remove <branch> [--force]"; return 1; }
2587
+ [ -n "$branch" ] || { echo "usage: /flow workspace remove <branch> [--force] [--card C-NNN]"; return 1; }
2414
2588
  lock_acquire workspace || return 1
2415
2589
  local rec wt rmout rc
2416
2590
  rec="$(_ws_latest_by_branch "$branch")"
@@ -2423,6 +2597,30 @@ _ws_remove() {
2423
2597
  # remove never journals a merge for a card still under active work.
2424
2598
  local _gcard _gcreated
2425
2599
  _gcard="$(_ws_get "$rec" card_id)"; _gcreated="$(_ws_get_num "$rec" created_at)"
2600
+ # Attested auto: merged worktrees require semantic+live receipts for mapped card
2601
+ if _att_auto_is_enforcing && _att_git_ok; then
2602
+ local tip head_oid card_id merged=0
2603
+ tip="$(git -C "$wt" rev-parse HEAD 2>/dev/null | tr -d '\r')"
2604
+ head_oid="$(_att_full_commit HEAD)"
2605
+ if [ -n "$tip" ] && [ -n "$head_oid" ] && { [ "$tip" = "$head_oid" ] || _att_is_ancestor "$tip" "$head_oid"; }; then
2606
+ merged=1
2607
+ fi
2608
+ if [ "$merged" -eq 1 ]; then
2609
+ card_id="$card_arg"
2610
+ [ -n "$card_id" ] || card_id="$(_ws_get "$rec" card_id)"
2611
+ card_id="$(printf '%s' "$card_id" | tr -d '\r')"
2612
+ if [ -z "$card_id" ] || [ "$card_id" = "null" ] || [ "$card_id" = "none" ]; then
2613
+ echo "FAIL: auto-active merged remove needs card identity (registry or --card C-NNN)."
2614
+ return 1
2615
+ fi
2616
+ card_id="$(_att_norm_card_id "$card_id")" || { echo "FAIL: bad --card"; return 1; }
2617
+ if ! _att_accepted_semantic card "$card_id" || ! _att_accepted_live "$card_id"; then
2618
+ echo "FAIL: merged worktree remove blocked — card $card_id needs current semantic+live receipts (or /flow auto stop)."
2619
+ return 1
2620
+ fi
2621
+ fi
2622
+ fi
2623
+
2426
2624
  if _graph_on && [ -f "$wt/.flow/events.jsonl" ]; then
2427
2625
  # Lifecycle-unique key: worktree paths are recycled, so a bare-path cursor would
2428
2626
  # swallow the next lifecycle's lines. Prefix = destination sink (usage/prune group it).
@@ -3549,13 +3747,13 @@ function cmd_eval {
3549
3747
  --timeout) shift; timeout="${1:-120}" ;;
3550
3748
  --report) report_mode=1 ;;
3551
3749
  --keep-going) keep_going=1 ;;
3552
- *) echo "usage: /flow eval [--stage 01|02|card|routing] [--fixture <id>] [--n 3] [--timeout <seconds>] [--keep-going] [--report]"; return 1 ;;
3750
+ *) echo "usage: /flow eval [--stage 01|02|05|card|routing] [--fixture <id>] [--n 3] [--timeout <seconds>] [--keep-going] [--report]"; return 1 ;;
3553
3751
  esac
3554
3752
  shift 2>/dev/null || true
3555
3753
  done
3556
3754
  case "$n" in ''|*[!0-9]*|0) echo "eval: --n must be a positive integer (got '$n')"; return 1 ;; esac
3557
3755
  case "$timeout" in ''|*[!0-9]*|0) echo "eval: --timeout must be a positive integer seconds value (got '$timeout')"; return 1 ;; esac
3558
- case "$stage_filter" in ""|01|02|card|routing) : ;; *) echo "eval: --stage must be one of 01|02|card|routing (got '$stage_filter')"; return 1 ;; esac
3756
+ case "$stage_filter" in ""|01|02|05|card|routing) : ;; *) echo "eval: --stage must be one of 01|02|05|card|routing (got '$stage_filter')"; return 1 ;; esac
3559
3757
  # Backoff between the in-run retry attempts. Default 5s; tests set 0 so the mock-suite is not
3560
3758
  # slowed by 15s+ per degraded-path case across 3-OS CI. Bare-int validation only - a bogus
3561
3759
  # value (`abc`) silently falls back to the default rather than aborting the batch.
@@ -3880,7 +4078,8 @@ usage: bash flow.sh <command> [args]
3880
4078
  workspace <verb> Multi-agent worktree isolation: add|list|enter|remove|check|doctor (one worktree per agent)
3881
4079
  loop-prep <card> Plumbing for ck-loop: isolated worktree + numeric Verify command + param block (thin wrapper; ck-loop is the engine)
3882
4080
  loop-log <card> Record a finished ck-loop run (iterations/start/end/outcome) into usage-log telemetry
3883
- auto Preflight an autonomous run (orchestration in SKILL.md)
4081
+ auto [stop] Activate attested auto (risk + Stage 05 receipt) or stop
4082
+ attest <verb> Mint/status/recover attestation receipts (semantic|live-verify|status|recover)
3884
4083
  recall Read back prior knowledge (debt/retro/playbooks/prev-card/harness) before working
3885
4084
  unlock Clear this project's concurrency lock (after a crashed/abandoned session)
3886
4085
  harness <args> Passthrough to the durable layer CLI (intake/story/trace/decision/backlog/query)
@@ -3895,7 +4094,7 @@ usage: bash flow.sh <command> [args]
3895
4094
  doctor Check the environment (bash/python/grep/git) across macOS/Linux/Windows
3896
4095
  eval [opts] Behavioral eval: does the LLM semantic gate flag a hollow-but-mechanically-clean
3897
4096
  fixture? Opt-in, BILLABLE (skips cleanly with zero calls if 'claude' CLI absent).
3898
- [--stage 01|02|card|routing] [--fixture <id>] [--n 3] [--timeout <seconds>]
4097
+ [--stage 01|02|05|card|routing] [--fixture <id>] [--n 3] [--timeout <seconds>]
3899
4098
  [--report] offline: last complete batch's scorecard + drift, zero calls
3900
4099
  --stage routing: SEPARATE judge (concierge routing, not gate-rules FLAG/PASS);
3901
4100
  hard-capped at 90 calls/batch, own results stream, own --report
@@ -4054,6 +4253,17 @@ cmd="${1:-status}"
4054
4253
  shift 2>/dev/null || true
4055
4254
  FLOW_LOG_CMD="$cmd"
4056
4255
  FLOW_LOG_ARGS="$*"
4256
+ # Attestation privacy: never persist full argv (owner paths / potential secrets).
4257
+ if [ "$cmd" = "attest" ]; then
4258
+ _att_sub="${1:-}"
4259
+ _att_subj=""
4260
+ case "$_att_sub" in
4261
+ semantic|live-verify|status|recover) _att_subj="${2:-}" ;;
4262
+ esac
4263
+ # strip flag-like tokens from subject slot
4264
+ case "$_att_subj" in --*) _att_subj="" ;; esac
4265
+ FLOW_LOG_ARGS="${_att_sub}${_att_subj:+ ${_att_subj}}"
4266
+ fi
4057
4267
  FLOW_LOG_START="$(_now)"
4058
4268
  trap '_log_on_exit' EXIT
4059
4269
  case "$cmd" in
@@ -4071,7 +4281,8 @@ case "$cmd" in
4071
4281
  workspace) cmd_workspace "$@" ;;
4072
4282
  loop-prep) cmd_loop_prep "$@" ;;
4073
4283
  loop-log) cmd_loop_log "$@" ;;
4074
- auto) cmd_auto ;;
4284
+ auto) cmd_auto "$@" ;;
4285
+ attest) cmd_attest "$@" ;;
4075
4286
  recall) cmd_recall ;;
4076
4287
  unlock) cmd_unlock ;;
4077
4288
  retro) cmd_retro ;;
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "source": "../skills/flow",
3
3
  "destRelative": "skills/flow",
4
- "fileCount": 84,
5
- "syncedAt": "2026-08-11T08:09:29.734Z",
4
+ "fileCount": 88,
5
+ "syncedAt": "2026-08-11T13:52:41.584Z",
6
6
  "fileList": [
7
7
  "SKILL.md",
8
8
  "_templates/00-idea.md",
@@ -18,6 +18,8 @@
18
18
  "eval/fixtures/f01b/flow/01-research.md",
19
19
  "eval/fixtures/f02a/flow/02-scope.md",
20
20
  "eval/fixtures/f02b/flow/02-scope.md",
21
+ "eval/fixtures/f05a/flow/05-contract.md",
22
+ "eval/fixtures/f05b/flow/05-contract.md",
21
23
  "eval/fixtures/fcda/.flow/.gitkeep",
22
24
  "eval/fixtures/fcda/cards/C-001.md",
23
25
  "eval/fixtures/fcdb/.flow/.gitkeep",
@@ -67,6 +69,7 @@
67
69
  "references/agent-detection.md",
68
70
  "references/agent-stage-mapping.md",
69
71
  "references/antigravity-integration.md",
72
+ "references/attestations.md",
70
73
  "references/auto-run.md",
71
74
  "references/claudekit-skills.md",
72
75
  "references/codex-integration.md",
@@ -86,6 +89,7 @@
86
89
  "references/project-types.md",
87
90
  "references/stage-state-machine.md",
88
91
  "references/ui-patterns-tcr.md",
92
+ "runner/attestations.sh",
89
93
  "runner/flow.cmd",
90
94
  "runner/flow.sh"
91
95
  ]