@manhquy/flow-skill 0.1.0-rc.3 → 0.1.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 CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  All notable changes to `@manhquy/flow-skill`. Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versioning: [SemVer](https://semver.org/).
4
4
 
5
+ ## [0.1.0] — 2026-07-19 — GA (first stable, `latest`)
6
+
7
+ First stable release of the installer. Graduates the rc.1→rc.3 line after two live OIDC
8
+ publishes + independent verification; publishes to dist-tag **`latest`** so bare
9
+ `npx @manhquy/flow-skill` / `npm i` resolves it (no manual dist-tag promotion needed).
10
+
11
+ ### Changed
12
+ - Ships skill product **v0.24.0** (harness trust-align — honest `proof_source`, STRICT durable
13
+ modes, canonical harness skill; see root `CHANGELOG.md` `## 0.24.0`). rc.1–rc.3 shipped v0.22.0.
14
+ - No installer code change vs rc.3 — same CLI, detection, lock, and five install targets
15
+ (Claude, Codex, Antigravity, Cursor, universal `~/.agents/skills`).
16
+
5
17
  ## [0.1.0-rc.3] — 2026-07-18
6
18
 
7
19
  Ships the same skill product **v0.22.0** as rc.2, plus pipeline/UX fixes found after the first
package/README_VN.md CHANGED
@@ -10,13 +10,15 @@ Trình cài đặt một-lệnh sao chép skill [flow](https://github.com/manhqu
10
10
  ## Cài đặt
11
11
 
12
12
  ```
13
- # Kênh pre-release (hiện tại — v0.1.0-rc.2)
13
+ # Kênh pre-release (hiện tại — v0.1.0-rc.3, ships skill v0.22.0)
14
14
  npx @manhquy/flow-skill@rc
15
15
  ```
16
16
 
17
17
  Prompt tương tác hỏi cài vào agent nào. Chọn một hoặc nhiều, xác nhận, xong.
18
18
 
19
- > **Giai đoạn RC**: pin `@rc` (dist-tag) hoặc phiên bản cụ thể `@0.1.0-rc.2`. `npx @manhquy/flow-skill@0.1.x` chỉ dùng được sau khi stable `0.1.0` publish — semver range **không** match pre-release theo mặc định. Xem [SECURITY.md](./SECURITY.md).
19
+ > **Giai đoạn RC**: pin `@rc` (dist-tag) hoặc phiên bản cụ thể `@0.1.0-rc.3`. `npx @manhquy/flow-skill@0.1.x` chỉ dùng được sau khi stable `0.1.0` publish — semver range **không** match pre-release theo mặc định. Xem [SECURITY.md](./SECURITY.md).
20
+ >
21
+ > **`npm i` alone chưa đủ** — phải **chạy** CLI (`npx @manhquy/flow-skill@rc`). Hai trục version: package npm vs skill product (`ships skill v…` / `skillVersion` trong JSONL).
20
22
 
21
23
  ## Non-interactive
22
24
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@manhquy/flow-skill",
3
- "version": "0.1.0-rc.3",
3
+ "version": "0.1.0",
4
4
  "description": "Install the flow skill (buildflow gated build process) into your coding agent(s) via one npx command",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,7 +8,7 @@ keywords: [flow, buildflow, gate, build, ship, scope, prd, contract, card, deplo
8
8
  license: MIT
9
9
  metadata:
10
10
  author: flow-skill
11
- version: "0.22.0"
11
+ version: "0.24.0"
12
12
  attribution: "Methodology from ai20k-build-phase/buildflow (Tony, arealisticdreamer.com); harness/agent layers from repository-harness, claudekit-engineer, BMAD-METHOD. v0.22 concierge routing pattern adapted from BMAD-METHOD's bmad-help; forge-idea ritual adapted from BMAD-METHOD's bmad-forge-idea (both MIT, BMad Code LLC)."
13
13
  ---
14
14
 
@@ -235,7 +235,7 @@ Hard stops (iteration/token/time caps) and ground-truth gates (`flow.sh` exit, r
235
235
  - `references/gate-eval.md` — `/flow eval` behavioral proof for the semantic layer: what it
236
236
  measures (a fresh-judge lower bound, NOT the work-mode self-challenge), cost, thresholds,
237
237
  and the honest authorship-bias limitation. Read before running or relaying a scorecard.
238
- - `harness/` — durable layer (`flow.sh harness ...`): intake/story/trace/decision/backlog. See `harness/README.md`. Read it back with `/flow recall` (open debt, retro, previous-card, friction, backlog, playbooks) — this is the capture→reuse loop.
238
+ - `harness/` — durable layer (`flow.sh harness ...`): intake/story/**complete**/trace/decision/backlog. Pins: protocol floor `harness-cli-v0.1.14`, trust CLI `0.1.17` (never `0.1.16`). See `harness/README.md` + `harness/GAP-MATRIX-0.1.17.md`. Never `story update --status implemented` — use `story complete --proof-source …`.
239
239
  - `playbooks/` — paid-for stack knowledge: read before building a card on that stack, harvest the lesson after.
240
240
  - `_templates/` — the 7 artifacts the runner copies into `flow/` and `cards/`. Never edit during a run.
241
241
 
@@ -0,0 +1,41 @@
1
+ # Gap matrix: flow durable layer vs repository-harness CLI 0.1.17
2
+
3
+ **Authority:** `repository-harness` (local `D:\project\flow\repository-harness`).
4
+ **Pins:** protocol floor **`harness-cli-v0.1.14`** · trust/consumer CLI **`harness-cli-v0.1.17`** · **never** install/use **`0.1.16`** release assets (tag without published proof).
5
+ **Scope:** inventory only — does **not** claim US-101 bit-identical or protocol-v1 parity for flow Python.
6
+
7
+ Supersedes: brainstorm 260703 Thread1 (“nothing to upgrade”).
8
+
9
+ ## Schema
10
+
11
+ | Ver | Flow | Harness 0.1.17 | Notes |
12
+ |-----|------|----------------|-------|
13
+ | 001–004 | present (shared) | present | Hash-identical at last measure (2026-07-18) |
14
+ | 005 | present | present | File hash may differ on comments only — do not overclaim DDL fork |
15
+ | 006–008 | **absent** (reserved gap) | changesets / deps / hierarchy | Not adopted this plan |
16
+ | 009–012 | **usage/accessed** (flow-only) | improvement identity / links / closure | **Semantic collision** — same numbers, different DDL |
17
+ | 013 | absent | changeset content sha | Not adopted |
18
+
19
+ ## Commands / invariants
20
+
21
+ | Surface | Flow status | Harness 0.1.17 | Trust note |
22
+ |---------|-------------|----------------|------------|
23
+ | `story update --status implemented` | rejected (trust-align) | rejected (US-101) | Use `story complete` |
24
+ | `story complete` | flow-native flags + honest `proof_source` | `story complete` + live verify | Flow may complete via `card_markdown_gate` **without** setting `last_verified_result=pass` |
25
+ | `story verify` | optional shell verify_command | required for shell-proven complete | shell=True = operator-authored only |
26
+ | `query sql` | **not exposed** | read-only connection | Do not add mutating SQL |
27
+ | Rust forward | refused on flow-lineage DB | n/a | `FLOW_HARNESS_BACKEND=rust` → exit 2 when usage mirror / schema≥9 |
28
+ | Changesets / work-graph | not ported | 006–013 | Out of scope (FOMO red line) |
29
+ | `query contract --json` | not on Python CLI | protocol v1 discovery | Optional external binary smoke only |
30
+
31
+ ## Pins (consumer)
32
+
33
+ ```
34
+ HARNESS_PROTOCOL_V1_TAG = harness-cli-v0.1.14 # floor
35
+ HARNESS_CLI_TRUST_TAG = harness-cli-v0.1.17 # trust features + release proof
36
+ DO_NOT_USE = harness-cli-v0.1.16 # no assets / failed promotion
37
+ ```
38
+
39
+ ## Rust refuse-forward
40
+
41
+ Any DB with `usage_event` or `MAX(schema_version) >= 9` is **flow-lineage**. Python entrypoint must refuse forwarding to external `harness-cli` (exit 2). Never unfreeze on `.flow/harness.db` without schema re-home ≥014 (separate epic).
@@ -2,10 +2,20 @@
2
2
 
3
3
  The durable memory of `/flow`: intake classification, story packets with proof status,
4
4
  auto-scored execution traces, decision records, and the growth-rule backlog. Ported from
5
- `repository-harness` (same SQLite schema, `schema/00N-*.sql` verbatim). State lives at
5
+ `repository-harness` (shared base schema + flow-only usage extensions). State lives at
6
6
  `<project>/.flow/harness.db` and survives across sessions — this is the "external memory"
7
7
  that fights context rot.
8
8
 
9
+ ## Authority pins (repository-harness)
10
+
11
+ | Pin | Tag | Use |
12
+ |-----|-----|-----|
13
+ | Protocol floor | **`harness-cli-v0.1.14`** | protocol v1 discovery floor |
14
+ | Trust / consumer | **`harness-cli-v0.1.17`** | US-101 spirit + release proof |
15
+ | **Do not use** | `harness-cli-v0.1.16` | tag without published assets |
16
+
17
+ Gap inventory: [`GAP-MATRIX-0.1.17.md`](./GAP-MATRIX-0.1.17.md). Flow does **not** claim bit-identical US-101.
18
+
9
19
  ## Backends
10
20
 
11
21
  | Backend | When | How |
@@ -23,12 +33,36 @@ power-path for non-flow DBs; flow does not build or ship the binary.
23
33
 
24
34
  Disable the durable layer entirely with `FLOW_HARNESS_DISABLE=1` (engine still runs).
25
35
 
36
+ ### STRICT durable writes (`flow.sh`)
37
+
38
+ | Env | Behavior |
39
+ |-----|----------|
40
+ | unset | soft: engine exit 0; one-line `flow-harness: warn` on fail |
41
+ | `FLOW_HARNESS_STRICT=1` | soft exit; louder stderr |
42
+ | `FLOW_HARNESS_STRICT=fail` | propagate nonzero from durable ops on card/check |
43
+
44
+ ## Story completion (trust boundary)
45
+
46
+ - **Rejected:** `story update --status implemented`
47
+ - **Use:** `story complete --id <id> --proof-source card_markdown_gate|manual|verify_command [--evidence …]`
48
+ - `card_markdown_gate` / `manual` set status implemented with **honest** `proof_source=…` in notes — **never** forge `last_verified_result=pass`
49
+ - `verify_command` requires prior `story verify` pass
50
+
51
+ ## Versioning (harness vs npm)
52
+
53
+ - Telemetry / usage events carry **`flow_version` from the installed skill product**
54
+ (`SKILL.md` metadata), not from the npm installer package version.
55
+ - When you change harness schema or CLI behavior, bump the **skill product** version
56
+ (SKILL.md + plugin.json + portable-manifest) and run `flow.sh coherence`.
57
+ - Publishing a new npm tarball is a separate step (`npm-wrapper` sync + tag `npm@…`) —
58
+ see [`docs/release-process.md`](../../../docs/release-process.md).
59
+
26
60
  ## Commands ↔ Runtime-Substrate responsibility
27
61
 
28
62
  | Command | Responsibility (of 11) |
29
63
  |---|---|
30
64
  | `intake --type <t> --summary <s> [--flags ...] [--lane ...] [--narrow-scope]` | Task specification + risk classification |
31
- | `story add\|update\|verify\|verify-all` | Task state + Verification (mechanical proof) |
65
+ | `story add\|update\|complete\|verify\|verify-all` | Task state + Verification (mechanical proof) |
32
66
  | `trace --summary ... [--story\|--card C-NNN] [--agent ...] [--actions ...] [--files-changed ...] --outcome ...` | Observability + Failure attribution (auto-scored tier). Flags accept `-` or `_` (`--actions_taken`, `--files_changed`, `--files_read`) and `--card` is an alias of `--story`. A bad/missing flag prints a guiding "common forms" hint (not a silent exit-2). |
33
67
  | `decision add\|verify\|outcome` | Project memory (durable ADR row + companion markdown); `outcome` closes the predicted-vs-actual loop |
34
68
  | `backlog add\|close` | Entropy auditing + harness self-improvement (growth rule) |
@@ -60,7 +94,7 @@ Linking a trace to an unverified story prints a **pre-close gate** warning.
60
94
  - `/flow next` past **stage 04 (ADR)** → reminds you to record each decision durably (`decision add`) — the ADR markdown is not a durable record.
61
95
  - `/flow card` creates a card → seeds a `story` row (tracking handle).
62
96
  - `/flow check C-NNN` (todo) → `story update --status in_progress`.
63
- - `/flow check C-NNN` (done) → `story update --status implemented` + a `trace` (its **tier verdict is shown**, so thin traces are visible).
97
+ - `/flow check C-NNN` (done) → `story complete --proof-source card_markdown_gate` + a `trace` (tier verdict shown; honest provenance, no shell-verify stamp).
64
98
  - `/flow recall` → reads the durable layer back (friction + backlog + audit health) into your working context — the capture→reuse loop.
65
99
  - `/flow retro` → surfaces `propose` (deterministic improvement proposals from repeated friction/interventions + audit drift) for you to commit.
66
100
  - `/flow harness <args>` exposes the full CLI directly.
@@ -160,6 +160,21 @@ def cmd_intake(con, a):
160
160
  return 0
161
161
 
162
162
 
163
+ _PROOF_SOURCES = ("card_markdown_gate", "manual", "verify_command")
164
+ _SECRET_RE = re.compile(
165
+ r"(?i)(token|secret|passwd|password|credential|api[_-]?key|bearer|authorization|-----begin)"
166
+ )
167
+
168
+
169
+ def _mask_evidence(text):
170
+ """Redact secret-shaped free text before durable store (trust-align RT)."""
171
+ if text is None:
172
+ return None
173
+ if _SECRET_RE.search(text):
174
+ return "***redacted***"
175
+ return text
176
+
177
+
163
178
  def cmd_story(con, a):
164
179
  if a.story_cmd == "add":
165
180
  if a.lane not in D.LANES:
@@ -169,11 +184,58 @@ def cmd_story(con, a):
169
184
  print(f"PASS: story {a.id} added (lane={a.lane})")
170
185
  return 0
171
186
  if a.story_cmd == "update":
187
+ # Trust boundary (US-101 spirit, flow-native): bare implemented is forbidden.
188
+ if a.status == "implemented":
189
+ print(
190
+ "FAIL: story update --status implemented is rejected.\n"
191
+ " Use: story complete --id <id> --proof-source card_markdown_gate|manual|verify_command\n"
192
+ " (honest proof provenance; never forge last_verified_result without story verify)"
193
+ )
194
+ return 1
172
195
  n = _db.update(con, "story", "id", a.id, status=a.status,
173
196
  unit_proof=a.unit, integration_proof=a.integration,
174
- e2e_proof=a.e2e, platform_proof=a.platform, evidence=a.evidence)
197
+ e2e_proof=a.e2e, platform_proof=a.platform,
198
+ evidence=_mask_evidence(a.evidence))
175
199
  print(f"{'PASS' if n else 'FAIL'}: story {a.id} {'updated' if n else 'not found'}")
176
200
  return 0 if n else 1
201
+ if a.story_cmd == "complete":
202
+ s = _db.one(con, "SELECT * FROM story WHERE id=?", (a.id,))
203
+ if not s:
204
+ print(f"FAIL: story {a.id} not found"); return 1
205
+ src = (a.proof_source or "").strip()
206
+ if src not in _PROOF_SOURCES:
207
+ print(
208
+ "FAIL: --proof-source required: card_markdown_gate|manual|verify_command\n"
209
+ " card_markdown_gate = /flow check markdown gate (does NOT set last_verified=pass)\n"
210
+ " verify_command = requires prior story verify pass"
211
+ )
212
+ return 1
213
+ if src == "verify_command":
214
+ if s.get("last_verified_result") != "pass":
215
+ print(
216
+ f"FAIL: proof-source verify_command requires last_verified_result=pass "
217
+ f"(got {s.get('last_verified_result')!r}). Run: story verify --id {a.id}"
218
+ )
219
+ return 1
220
+ # Honest provenance: card/manual never forge last_verified_result=pass
221
+ ev = _mask_evidence(a.evidence) or s.get("evidence") or ""
222
+ note = (s.get("notes") or "").strip()
223
+ prov = f"proof_source={src}"
224
+ if prov not in note:
225
+ note = (note + "\n" + prov).strip() if note else prov
226
+ if src == "card_markdown_gate" and "last_verified_result=pass" not in (note or ""):
227
+ # explicit honesty marker for auditors
228
+ note = note + "\nverify_stamp=not_shell"
229
+ fields = dict(status="implemented", notes=note)
230
+ if ev:
231
+ fields["evidence"] = ev
232
+ # only keep last_verified_* when real verify already passed
233
+ n = _db.update(con, "story", "id", a.id, **fields)
234
+ print(
235
+ f"PASS: story {a.id} complete (status=implemented, proof_source={src})"
236
+ + ("" if src == "verify_command" else " [no shell-verify stamp]")
237
+ )
238
+ return 0 if n else 1
177
239
  if a.story_cmd in ("verify", "verify-all"):
178
240
  if a.story_cmd == "verify":
179
241
  stories = [_db.one(con, "SELECT * FROM story WHERE id=?", (a.id,))]
@@ -983,6 +1045,13 @@ def build_parser():
983
1045
  a2.add_argument("--evidence")
984
1046
  a3 = pss.add_parser("verify"); a3.add_argument("--id", required=True)
985
1047
  pss.add_parser("verify-all")
1048
+ # flow-native complete (trust-align D7): not protocol-v1 positional parity
1049
+ ac = pss.add_parser("complete", help="mark implemented with honest proof_source (not bare update)")
1050
+ ac.add_argument("--id", required=True)
1051
+ ac.add_argument("--proof-source", dest="proof_source",
1052
+ choices=("card_markdown_gate", "manual", "verify_command"),
1053
+ help="card_markdown_gate never forges last_verified=pass")
1054
+ ac.add_argument("--evidence")
986
1055
 
987
1056
  pt = sub.add_parser("trace", help="record an agent task execution trace (auto-scored)")
988
1057
  pt.add_argument("--summary", required=True); pt.add_argument("--intake", type=int); pt.add_argument("--story", "--card")
@@ -0,0 +1,9 @@
1
+ # Digests from GitHub Release harness-cli-v0.1.17 (fetched for pin policy)
2
+ # TAG harness-cli-v0.1.17
3
+ # PROTOCOL_FLOOR harness-cli-v0.1.14
4
+ # DO_NOT_USE harness-cli-v0.1.16
5
+ 5d13f0a024d9d69701534a879581c9433bc0069e04d052e5aacd93b91b3b7a43 harness-cli-linux-x64
6
+ 128c42c251fb31b58582342c09c68be6ed3329340fb1d8f179c88590a4539c97 harness-cli-linux-arm64
7
+ 902968f1383d45eb60e202eb98f8ce6c143cff73cb6f2ccc159a743ca5a70819 harness-cli-macos-x64
8
+ 71217dbe03d111775c5016ab751f8bedbff66e7fd6a4d90f5c8d7e0e4a205b47 harness-cli-macos-arm64
9
+ 2d7edff22ae25308c2ba23ab85bb9acb18d87eea28a9ca4efb2014a0f11a51a6 harness-cli-windows-x64.exe
@@ -54,7 +54,7 @@ gate): **`ck-predict` at ADR** (5-persona pre-decision debate) and **`ck-scenari
54
54
  | UI card | `ui-ux-designer` | — | inline + `law/DESIGN.md` | review vs DESIGN.md |
55
55
  | Repair / diagnostic | `debugger` | — | inline root-cause + fresh same-ladder subagent | `harness intervention add` |
56
56
  | Review | `code-reviewer` (+ `typescript-reviewer` or `python-reviewer` layered — see language-specialist lens) | `bmad-code-review` (3-layer adversarial) | inline | `harness intervention add` on red |
57
- | Deploy / git ship | `git-manager` | — | inline commit + PR guide | `harness story update --status implemented` |
57
+ | Deploy / git ship | `git-manager` | — | inline commit + PR guide | `harness story complete --id … --proof-source manual` (never bare `update --status implemented`) |
58
58
  | Docs sync | `docs-manager` | — | inline doc update | — |
59
59
  | Verify-live | `tester` / `web-testing` | `bmad-qa-generate-e2e-tests` | curl/Playwright | `harness story update --e2e 1` + `trace` |
60
60
 
@@ -34,7 +34,7 @@ for each todo card in card-number order:
34
34
  4. flow.sh check C-NNN must PASS (mechanical) + gate-rules semantic check
35
35
  5. merge to main in card order; deploy; VERIFY ON LIVE URL (merge != shipped)
36
36
  6. paste world-state evidence into the card; status: done
37
- 7. flow.sh harness story update --status implemented + trace; log AUTO-LOG.md
37
+ 7. flow.sh harness story complete --id … --proof-source manual (or card_markdown_gate) + trace; log AUTO-LOG.md
38
38
  8. remove worktree
39
39
  ```
40
40
 
@@ -180,15 +180,71 @@ _python() {
180
180
  return 1
181
181
  }
182
182
 
183
- harness_call() {
184
- # best-effort durable-layer write; NEVER breaks the engine if python/harness absent.
183
+ # Durable write honesty (plan trust-align D5/D8):
184
+ # unset FLOW_HARNESS_STRICT → soft: engine stays 0; one-line stderr warn on fail
185
+ # FLOW_HARNESS_STRICT=1 → soft exit; louder multi-line stderr
186
+ # FLOW_HARNESS_STRICT=fail → propagate nonzero from harness (card/check paths)
187
+ # harness_call_checked always returns the real harness exit (for callers that care).
188
+ _harness_run() {
189
+ # runs harness; prints stderr (masked lightly); echoes nothing; returns real rc
190
+ # usage: _harness_run <args...> sets _HARNESS_LAST_RC
191
+ _HARNESS_LAST_RC=0
185
192
  [ -n "${FLOW_HARNESS_DISABLE:-}" ] && return 0
186
193
  [ -f "$HARNESS_PY" ] || return 0
187
194
  local py; py="$(_python)"; [ -n "$py" ] || return 0
188
- FLOW_PROJECT_ROOT="$ROOT" "$py" "$HARNESS_PY" "$@" >/dev/null 2>&1
195
+ local errf out rc=0
196
+ errf="$(mktemp 2>/dev/null || echo "$ROOT/.flow/.harness-err.$$")"
197
+ mkdir -p "$ROOT/.flow" 2>/dev/null || true
198
+ # capture rc without flipping the caller's set -e state
199
+ out="$(FLOW_PROJECT_ROOT="$ROOT" "$py" "$HARNESS_PY" "$@" 2>"$errf")" || rc=$?
200
+ _HARNESS_LAST_RC=$rc
201
+ if [ "$rc" -ne 0 ]; then
202
+ local errline summary
203
+ errline="$(tr -d '\r' <"$errf" 2>/dev/null | head -n 3 | tr '\n' ' ')"
204
+ # light redact of secret-shaped stderr / never dump free-text evidence args
205
+ case "$errline" in
206
+ *token*|*secret*|*passwd*|*password*|*credential*|*api_key*|*bearer*) errline="***redacted***" ;;
207
+ esac
208
+ summary="$1"
209
+ [ -n "${2:-}" ] && summary="$summary $2"
210
+ [ -n "${3:-}" ] && summary="$summary $3"
211
+ local mode="${FLOW_HARNESS_STRICT:-}"
212
+ if [ "$mode" = "1" ] || [ "$mode" = "fail" ]; then
213
+ printf 'flow-harness: durable command failed (rc=%s) cmd=%s\nflow-harness: %s\n' \
214
+ "$rc" "$summary" "$errline" >&2
215
+ else
216
+ printf 'flow-harness: warn durable write failed (rc=%s)\n' "$rc" >&2
217
+ fi
218
+ fi
219
+ rm -f "$errf" 2>/dev/null || true
220
+ return "$rc"
221
+ }
222
+
223
+ harness_call() {
224
+ # soft durable write: NEVER breaks engine unless STRICT=fail
225
+ _harness_run "$@" || true
226
+ if [ "${FLOW_HARNESS_STRICT:-}" = "fail" ] && [ "${_HARNESS_LAST_RC:-0}" -ne 0 ]; then
227
+ return "${_HARNESS_LAST_RC}"
228
+ fi
189
229
  return 0
190
230
  }
191
231
 
232
+ harness_call_checked() {
233
+ # returns real harness exit code (and still prints STRICT-aware warnings)
234
+ _harness_run "$@"
235
+ }
236
+
237
+ # When STRICT=fail, surface durable failure from card/check call sites (D5).
238
+ _harness_or_fail() {
239
+ harness_call "$@" || {
240
+ if [ "${FLOW_HARNESS_STRICT:-}" = "fail" ]; then
241
+ echo "FAIL: durable harness write failed (FLOW_HARNESS_STRICT=fail)."
242
+ return 1
243
+ fi
244
+ return 0
245
+ }
246
+ }
247
+
192
248
  harness_available() { # 0 = durable layer usable (python + harness present, not disabled)
193
249
  [ -n "${FLOW_HARNESS_DISABLE:-}" ] && return 1
194
250
  [ -f "$HARNESS_PY" ] || return 1
@@ -973,7 +1029,7 @@ cmd_card_start() { # mark a card actively in progress (operator-visible in_progr
973
1029
  local id; id="$(basename "$file" .md)"; FLOW_LOG_CARD="$id"
974
1030
  if [ "$(card_status "$file")" = "done" ]; then echo "FAIL: $id is already done — nothing to start."; return 1; fi
975
1031
  _inflight_set "$id"
976
- harness_call story update --id "$id" --status in_progress # durable mirror (best-effort)
1032
+ _harness_or_fail story update --id "$id" --status in_progress # durable mirror (STRICT=fail propagates)
977
1033
  echo "PASS: $id marked in flight. Build it, then '/flow card done $id' (or hand-edit status: done + '/flow check $id')."
978
1034
  return 0
979
1035
  }
@@ -1033,7 +1089,7 @@ cmd_card() {
1033
1089
  [ -n "$pc" ] && printf '%s\n' "$pc" | sed 's/^/ /'
1034
1090
  [ -n "$dbt" ] && { echo " open debt:"; printf '%s\n' "$dbt" | sed 's/^/ /'; }
1035
1091
  fi
1036
- harness_call story add --id "$id" --title "$id" --lane normal # durable tracking handle
1092
+ _harness_or_fail story add --id "$id" --title "$id" --lane normal # durable tracking handle
1037
1093
  return 0
1038
1094
  }
1039
1095
 
@@ -1106,9 +1162,22 @@ cmd_check() {
1106
1162
  if [ "$found" -eq 0 ]; then
1107
1163
  echo "PASS: $id is valid (status: $st)."
1108
1164
  case "$st" in
1109
- todo) harness_call story update --id "$id" --status in_progress ;;
1110
- done) harness_call story update --id "$id" --status implemented
1111
- local tr; tr="$(harness_emit trace --summary "card $id reached done-evidence" --story "$id" --outcome completed)"
1165
+ todo) _harness_or_fail story update --id "$id" --status in_progress || return 1 ;;
1166
+ done)
1167
+ # trust-align: complete with honest card_markdown_gate provenance (D3/D7/D8)
1168
+ if ! harness_call_checked story complete --id "$id" \
1169
+ --proof-source card_markdown_gate \
1170
+ --evidence "card $id markdown gate PASS"; then
1171
+ if [ "${FLOW_HARNESS_STRICT:-}" = "fail" ]; then
1172
+ echo "FAIL: durable story complete failed (FLOW_HARNESS_STRICT=fail)."
1173
+ return 1
1174
+ fi
1175
+ fi
1176
+ # auto-trace: enrich tier-2 fields from known card context (do not fake --lane tiny)
1177
+ local tr
1178
+ tr="$(harness_emit trace --summary "card $id reached done-evidence" --story "$id" \
1179
+ --outcome completed --agent flow-check \
1180
+ --actions "check $id gate PASS" --files-changed "cards/$id.md" --friction none)"
1112
1181
  [ -n "$tr" ] && printf '%s\n' "$tr" | grep -iE 'tier|to reach' | sed 's/^/ harness: /' ;;
1113
1182
  esac
1114
1183
  return 0
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "source": "../skills/flow",
3
3
  "destRelative": "skills/flow",
4
- "fileCount": 74,
5
- "syncedAt": "2026-07-18T07:42:58.153Z",
4
+ "fileCount": 76,
5
+ "syncedAt": "2026-07-19T14:46:19.032Z",
6
6
  "fileList": [
7
7
  "SKILL.md",
8
8
  "_templates/00-idea.md",
@@ -31,11 +31,13 @@
31
31
  "eval/fixtures/routing/states/state-review-pending.txt",
32
32
  "eval/fixtures/routing/states/state-scope-stage.txt",
33
33
  "eval/manifest.tsv",
34
+ "harness/GAP-MATRIX-0.1.17.md",
34
35
  "harness/README.md",
35
36
  "harness/_db.py",
36
37
  "harness/_domain.py",
37
38
  "harness/_presence.py",
38
39
  "harness/flow_harness.py",
40
+ "harness/pins/harness-cli-v0.1.17.sha256sums",
39
41
  "harness/repo_map.py",
40
42
  "harness/schema/001-init.sql",
41
43
  "harness/schema/002-story-verify.sql",