@kontourai/flow-agents 2.2.0 → 2.4.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.
Files changed (250) hide show
  1. package/.github/CODEOWNERS +8 -0
  2. package/.github/workflows/ci.yml +32 -0
  3. package/AGENTS.md +4 -4
  4. package/CHANGELOG.md +46 -0
  5. package/CONTEXT.md +14 -0
  6. package/README.md +9 -3
  7. package/agents/dev.json +1 -1
  8. package/agents/tool-code-reviewer.json +1 -1
  9. package/agents/tool-planner.json +3 -3
  10. package/agents/tool-verifier.json +3 -3
  11. package/build/src/cli/console-learning-projection.js +3 -2
  12. package/build/src/cli/init.js +104 -21
  13. package/build/src/cli/kit.js +37 -6
  14. package/build/src/cli/pull-work-provider.js +1 -1
  15. package/build/src/cli/usage-feedback.js +3 -3
  16. package/build/src/cli/validate-hook-influence.js +1 -0
  17. package/build/src/cli/validate-workflow-artifacts.js +22 -6
  18. package/build/src/cli/workflow-artifact-cleanup-audit.js +36 -2
  19. package/build/src/cli/workflow-sidecar.d.ts +14 -7
  20. package/build/src/cli/workflow-sidecar.js +792 -69
  21. package/build/src/flow-kit/validate.d.ts +23 -0
  22. package/build/src/flow-kit/validate.js +67 -1
  23. package/build/src/index.d.ts +1 -1
  24. package/build/src/index.js +1 -1
  25. package/build/src/lib/flow-resolver.d.ts +6 -4
  26. package/build/src/lib/flow-resolver.js +125 -58
  27. package/build/src/lib/local-artifact-root.d.ts +14 -2
  28. package/build/src/lib/local-artifact-root.js +22 -5
  29. package/build/src/lib/workflow-learning-projection.js +2 -2
  30. package/build/src/runtime-adapters.d.ts +12 -0
  31. package/build/src/runtime-adapters.js +56 -16
  32. package/build/src/tools/build-universal-bundles.js +49 -16
  33. package/build/src/tools/generate-context-map.js +10 -8
  34. package/build/src/tools/validate-source-tree.js +23 -1
  35. package/console.telemetry.json +22 -0
  36. package/context/contracts/artifact-contract.md +38 -7
  37. package/context/contracts/builder-kit-workflow-state-contract.md +3 -2
  38. package/context/contracts/decision-registry-contract.md +263 -0
  39. package/context/contracts/delivery-contract.md +1 -1
  40. package/context/contracts/planning-contract.md +2 -1
  41. package/context/contracts/review-contract.md +5 -3
  42. package/context/contracts/verification-contract.md +9 -1
  43. package/context/contracts/work-item-contract.md +1 -1
  44. package/context/deferred/parallelization.md +1 -1
  45. package/context/gate-awareness.md +4 -4
  46. package/context/scripts/git-status.sh +2 -2
  47. package/context/scripts/hooks/config-protection.js +502 -2
  48. package/context/scripts/hooks/lib/config-protection-remedies.js +69 -0
  49. package/context/scripts/hooks/run-hook.js +14 -1
  50. package/context/scripts/hooks/stop-goal-fit.js +1140 -99
  51. package/context/scripts/hooks/workflow-steering.js +212 -6
  52. package/docs/adr/0007-flow-skill-kit-tool-boundary.md +2 -0
  53. package/docs/adr/0015-flow-flow-agents-boundary-reconciliation.md +35 -0
  54. package/docs/adr/0019-kit-dependency-ownership.md +62 -0
  55. package/docs/adr/0020-trust-reconcile-manifest-and-claim-classification.md +290 -0
  56. package/docs/adr/0021-assignment-leases-and-stale-claim-takeover.md +221 -0
  57. package/docs/adr/0022-fail-closed-delivery-reconciliation-with-governed-exemptions.md +283 -0
  58. package/docs/agent-system-guidebook.md +3 -3
  59. package/docs/agent-usage-feedback-loop.md +6 -6
  60. package/docs/context-map.md +9 -7
  61. package/docs/decisions/decision-records.md +57 -0
  62. package/docs/decisions/index.md +14 -0
  63. package/docs/decisions/promotion-gate.md +52 -0
  64. package/docs/developer-architecture.md +1 -1
  65. package/docs/fixture-ownership.md +3 -0
  66. package/docs/flow-kit-repository-contract.md +5 -5
  67. package/docs/getting-started.md +12 -2
  68. package/docs/integrations/harness-install.md +2 -1
  69. package/docs/kit-authoring-guide.md +64 -5
  70. package/docs/knowledge-kit.md +5 -1
  71. package/docs/learnings/2026-07-improvement-program.md +203 -0
  72. package/docs/migrations.md +6 -5
  73. package/docs/north-star.md +2 -2
  74. package/docs/operating-layers.md +4 -3
  75. package/docs/repository-structure.md +5 -5
  76. package/docs/skills-map.md +8 -8
  77. package/docs/spec/runtime-hook-surface.md +19 -15
  78. package/docs/spikes/graph-provider-2026-07.md +155 -0
  79. package/docs/standards-register.md +7 -7
  80. package/docs/trust-anchor-adoption.md +105 -4
  81. package/docs/work-item-adapters.md +1 -1
  82. package/docs/workflow-artifact-lifecycle.md +72 -9
  83. package/docs/workflow-eval-strategy.md +3 -3
  84. package/docs/workflow-shared-contracts.md +1 -1
  85. package/docs/workflow-usage-guide.md +254 -21
  86. package/evals/acceptance/DEMO-false-completion.md +20 -11
  87. package/evals/acceptance/prove-capture-teeth-declared.sh +15 -15
  88. package/evals/acceptance/prove-capture-teeth.sh +11 -11
  89. package/evals/acceptance/test_kiro_harness.sh +1 -1
  90. package/evals/ci/antigaming-suite.sh +5 -0
  91. package/evals/ci/run-baseline.sh +65 -1
  92. package/evals/fixtures/flow-kit-repository/invalid-bad-dependency/flows/review.flow.json +26 -0
  93. package/evals/fixtures/flow-kit-repository/invalid-bad-dependency/kit.json +13 -0
  94. package/evals/fixtures/flow-kit-repository/valid-with-dependency/flows/review.flow.json +26 -0
  95. package/evals/fixtures/flow-kit-repository/valid-with-dependency/kit.json +13 -0
  96. package/evals/fixtures/hook-influence/cases.json +32 -0
  97. package/evals/fixtures/pull-work-provider/github-issues.json +6 -6
  98. package/evals/fixtures/trust-reconcile-exploits/fabricated-attestation.json +59 -0
  99. package/evals/fixtures/trust-reconcile-exploits/no-label-bypass.json +36 -0
  100. package/evals/fixtures/trust-reconcile-exploits/skip-assumed-bypass.json +59 -0
  101. package/evals/fixtures/trust-reconcile-exploits/status-misassertion.json +48 -0
  102. package/evals/fixtures/trust-reconcile-exploits/waived-command-check.json +44 -0
  103. package/evals/fixtures/trust-reconcile-mixed-bundle/mixed-bundle.json +159 -0
  104. package/evals/fixtures/trust-reconcile-ws3/ws3-bundle.json +920 -0
  105. package/evals/integration/test_actor_identity.sh +254 -0
  106. package/evals/integration/test_builder_step_producers.sh +33 -23
  107. package/evals/integration/test_bundle_install.sh +22 -16
  108. package/evals/integration/test_bundle_lifecycle.sh +11 -11
  109. package/evals/integration/test_captured_fail_reconciliation.sh +50 -50
  110. package/evals/integration/test_checkpoint_signing.sh +43 -0
  111. package/evals/integration/test_claim_lookup.sh +4 -4
  112. package/evals/integration/test_codex_hook_resolution.sh +114 -0
  113. package/evals/integration/test_command_log_concurrency.sh +8 -8
  114. package/evals/integration/test_command_log_fork_classification.sh +3 -3
  115. package/evals/integration/test_command_log_integrity.sh +16 -16
  116. package/evals/integration/test_console_learning_projection.sh +1 -1
  117. package/evals/integration/test_dual_emit_flow_step.sh +145 -0
  118. package/evals/integration/test_enforcer_expects_driven.sh +12 -12
  119. package/evals/integration/test_evidence_capture_hook.sh +14 -13
  120. package/evals/integration/test_fixture_retirement_audit.sh +2 -2
  121. package/evals/integration/test_flow_agents_statusline.sh +2 -2
  122. package/evals/integration/test_flow_kit_install_git.sh +52 -0
  123. package/evals/integration/test_flow_kit_repository.sh +2 -0
  124. package/evals/integration/test_flowdef_session_activation.sh +6 -6
  125. package/evals/integration/test_flowdef_union_floor_regression.sh +429 -0
  126. package/evals/integration/test_gate_bypass_chain.sh +52 -40
  127. package/evals/integration/test_gate_lockdown.sh +97 -73
  128. package/evals/integration/test_gate_review_inquiry_records.sh +3 -3
  129. package/evals/integration/test_goal_fit_escape_hatch.sh +10 -10
  130. package/evals/integration/test_goal_fit_ghost_session.sh +104 -0
  131. package/evals/integration/test_goal_fit_hook.sh +32 -32
  132. package/evals/integration/test_goal_fit_rederive.sh +9 -9
  133. package/evals/integration/test_hook_category_behaviors.sh +103 -0
  134. package/evals/integration/test_hook_influence_cases.sh +1 -0
  135. package/evals/integration/test_install_merge.sh +262 -1
  136. package/evals/integration/test_kit_identity_trust.sh +6 -6
  137. package/evals/integration/test_liveness_conflict_injection.sh +587 -0
  138. package/evals/integration/test_liveness_heartbeat.sh +677 -0
  139. package/evals/integration/test_liveness_verdict.sh +394 -0
  140. package/evals/integration/test_local_flow_kit_install.sh +15 -0
  141. package/evals/integration/test_phase_map_and_gate_claim.sh +63 -11
  142. package/evals/integration/test_promote_gate.sh +178 -0
  143. package/evals/integration/test_publish_delivery.sh +2 -2
  144. package/evals/integration/test_pull_work_liveness_preflight.sh +386 -0
  145. package/evals/integration/test_pull_work_provider.sh +2 -2
  146. package/evals/integration/test_reconcile_soundness.sh +4 -4
  147. package/evals/integration/test_resolvefirststep_security.sh +22 -0
  148. package/evals/integration/test_runtime_adapter_activation.sh +87 -18
  149. package/evals/integration/test_session_resume_roundtrip.sh +147 -0
  150. package/evals/integration/test_sidecar_field_preservation.sh +249 -0
  151. package/evals/integration/test_trust_reconcile.sh +2 -2
  152. package/evals/integration/test_trust_reconcile_manifest.sh +79 -0
  153. package/evals/integration/test_trust_reconcile_mixed_bundle.sh +96 -0
  154. package/evals/integration/test_trust_reconcile_negatives.sh +151 -0
  155. package/evals/integration/test_usage_feedback_global.sh +5 -5
  156. package/evals/integration/test_validate_artifacts_portability.sh +60 -0
  157. package/evals/integration/test_verify_cli.sh +2 -2
  158. package/evals/integration/test_veritas_governance_kit.sh +117 -0
  159. package/evals/integration/test_workflow_artifact_cleanup_audit.sh +26 -1
  160. package/evals/integration/test_workflow_artifacts.sh +33 -0
  161. package/evals/integration/test_workflow_sidecar_writer.sh +723 -74
  162. package/evals/integration/test_workflow_steering_hook.sh +175 -5
  163. package/evals/lib/codex-provider.sh +1 -1
  164. package/evals/lib/node.sh +19 -1
  165. package/evals/run.sh +22 -0
  166. package/evals/static/test_decisions.sh +150 -0
  167. package/evals/static/test_flowdef_codeowners_coverage.sh +56 -0
  168. package/evals/static/test_package.sh +19 -10
  169. package/evals/static/test_universal_bundles.sh +48 -3
  170. package/evals/static/test_workflow_skills.sh +41 -8
  171. package/kits/builder/flows/build.flow.json +3 -74
  172. package/kits/builder/flows/publish-learn.flow.json +90 -0
  173. package/kits/builder/kit.json +11 -0
  174. package/kits/builder/skills/builder-shape/SKILL.md +1 -1
  175. package/kits/builder/skills/deliver/SKILL.md +13 -11
  176. package/kits/builder/skills/design-probe/SKILL.md +4 -4
  177. package/kits/builder/skills/evidence-gate/SKILL.md +26 -1
  178. package/kits/builder/skills/execute-plan/SKILL.md +2 -2
  179. package/kits/builder/skills/fix-bug/SKILL.md +2 -0
  180. package/kits/builder/skills/gate-review/SKILL.md +6 -6
  181. package/kits/builder/skills/idea-to-backlog/SKILL.md +1 -1
  182. package/kits/builder/skills/learning-review/SKILL.md +7 -7
  183. package/kits/builder/skills/pickup-probe/SKILL.md +5 -4
  184. package/kits/builder/skills/plan-work/SKILL.md +27 -5
  185. package/kits/builder/skills/pull-work/SKILL.md +80 -5
  186. package/kits/builder/skills/release-readiness/SKILL.md +4 -4
  187. package/kits/builder/skills/review-work/SKILL.md +24 -1
  188. package/kits/builder/skills/tdd-workflow/SKILL.md +2 -0
  189. package/kits/builder/skills/verify-work/SKILL.md +8 -1
  190. package/kits/catalog.json +6 -0
  191. package/kits/veritas-governance/adapter/readiness-to-trust-bundle.mjs +178 -0
  192. package/kits/veritas-governance/docs/README.md +75 -0
  193. package/kits/veritas-governance/fixtures/readiness/not-ready.readiness-report.json +4645 -0
  194. package/kits/veritas-governance/fixtures/readiness/ready.readiness-report.json +4403 -0
  195. package/kits/veritas-governance/flows/readiness-check.flow.json +35 -0
  196. package/kits/veritas-governance/kit.json +16 -0
  197. package/package.json +8 -4
  198. package/packaging/README.md +2 -2
  199. package/packaging/conformance/fixtures/config-protection--allow-read-state-json.json +20 -0
  200. package/packaging/conformance/fixtures/config-protection--block-write-state-json.json +20 -0
  201. package/packaging/conformance/fixtures/stop-goal-fit--block-bundle-disputed-claim.json +1 -1
  202. package/packaging/conformance/fixtures/stop-goal-fit--block-capture-contradicts-claimed-pass.json +1 -1
  203. package/packaging/manifest.json +9 -10
  204. package/schemas/decision-record.schema.json +109 -0
  205. package/schemas/workflow-evidence.schema.json +1 -1
  206. package/schemas/workflow-state.schema.json +5 -0
  207. package/scripts/README.md +8 -3
  208. package/scripts/check-content-boundary.cjs +1 -1
  209. package/scripts/check-decisions.cjs +356 -0
  210. package/scripts/ci/derive-claim-status.mjs +74 -0
  211. package/scripts/ci/trust-reconcile.js +436 -79
  212. package/scripts/git-status.sh +2 -2
  213. package/scripts/hooks/claude-telemetry-hook.js +37 -3
  214. package/scripts/hooks/codex-telemetry-hook.js +36 -2
  215. package/scripts/hooks/config-protection.js +102 -30
  216. package/scripts/hooks/evidence-capture.js +3 -3
  217. package/scripts/hooks/lib/actor-identity.js +368 -0
  218. package/scripts/hooks/lib/config-protection-remedies.js +69 -0
  219. package/scripts/hooks/lib/liveness-heartbeat.js +361 -0
  220. package/scripts/hooks/lib/liveness-policy.js +127 -0
  221. package/scripts/hooks/lib/liveness-read.js +105 -12
  222. package/scripts/hooks/lib/liveness-write.js +46 -0
  223. package/scripts/hooks/lib/local-artifact-paths.js +12 -6
  224. package/scripts/hooks/opencode-telemetry-hook.js +27 -1
  225. package/scripts/hooks/pi-telemetry-hook.js +27 -1
  226. package/scripts/hooks/stop-goal-fit.js +157 -26
  227. package/scripts/hooks/workflow-steering.js +77 -3
  228. package/scripts/install-codex-home.sh +138 -38
  229. package/scripts/statusline/flow-agents-statusline.js +2 -2
  230. package/src/cli/console-learning-projection.ts +3 -2
  231. package/src/cli/init.ts +101 -21
  232. package/src/cli/kit.ts +37 -6
  233. package/src/cli/public-api.test.mjs +58 -6
  234. package/src/cli/pull-work-provider.ts +1 -1
  235. package/src/cli/trust-bundle-policy-order.test.mjs +87 -0
  236. package/src/cli/usage-feedback.ts +3 -3
  237. package/src/cli/validate-hook-influence.ts +1 -0
  238. package/src/cli/validate-workflow-artifacts.ts +22 -6
  239. package/src/cli/veritas-readiness-adapter.test.mjs +267 -0
  240. package/src/cli/workflow-artifact-cleanup-audit.ts +35 -2
  241. package/src/cli/workflow-sidecar.ts +795 -71
  242. package/src/flow-kit/validate.ts +74 -1
  243. package/src/index.ts +6 -2
  244. package/src/lib/flow-resolver.ts +123 -55
  245. package/src/lib/local-artifact-root.ts +24 -5
  246. package/src/lib/workflow-learning-projection.ts +2 -2
  247. package/src/runtime-adapters.ts +61 -15
  248. package/src/tools/build-universal-bundles.ts +49 -16
  249. package/src/tools/generate-context-map.ts +10 -8
  250. package/src/tools/validate-source-tree.ts +23 -1
@@ -0,0 +1,249 @@
1
+ #!/usr/bin/env bash
2
+ # test_sidecar_field_preservation.sh — CLASS-level regression guard for the #270/#298/#309
3
+ # field-loss bug family (silent persistent-field drop on a state.json-writing sidecar command).
4
+ #
5
+ # #289 introduced `branch:` as a persistent identity field; #309 found init-plan's initSidecars
6
+ # rewrite could silently DROP it on a repaired/backfilled session (a live instance of the same
7
+ # "state.json fully rewritten, not merged" bug class that #270/#298 already hit for other fields).
8
+ # code-review-309 found the SAME class live again: the #309 backfill path silently reset
9
+ # created_at on a repaired session, because initSidecars always re-stamps created_at from the
10
+ # current call's timestamp instead of preserving an existing session's original creation time.
11
+ #
12
+ # Rather than adding another one-field regression test, this is an INVARIANT SWEEP: seed one
13
+ # fully-populated session, run every state.json-touching mutator subcommand once (in the order a
14
+ # real session actually calls them), and after EACH command assert that every persistent identity
15
+ # field (branch, task_slug, repo, created_at, and owner when present) is byte-identical to the
16
+ # seeded baseline — except the fields a given command explicitly owns (status, phase, updated_at,
17
+ # next_action, artifact_paths). Any FUTURE writer that starts fully rewriting state.json instead
18
+ # of merging prior contents (the root cause of this whole bug family) fails this sweep immediately,
19
+ # naming the offending command — without anyone having to think to add a bespoke field-loss test
20
+ # for it first.
21
+ #
22
+ # Deterministic, no model spend, self-cleaning.
23
+ # Usage: bash evals/integration/test_sidecar_field_preservation.sh
24
+
25
+ set -uo pipefail
26
+
27
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
28
+ source "$ROOT/evals/lib/node.sh"
29
+
30
+ WRITER="workflow-sidecar"
31
+ TMPDIR_EVAL="$(mktemp -d)"
32
+ errors=0
33
+
34
+ cleanup() { rm -rf "$TMPDIR_EVAL"; }
35
+ trap cleanup EXIT
36
+
37
+ _pass() { echo " ✓ $1"; }
38
+ _fail() { echo " ✗ $1"; errors=$((errors + 1)); }
39
+
40
+ if ! command -v jq >/dev/null 2>&1; then
41
+ echo "jq is required for this eval's field-identity assertions" >&2
42
+ exit 1
43
+ fi
44
+
45
+ SESSION_ROOT="$TMPDIR_EVAL/repo/.kontourai/flow-agents"
46
+ SLUG="sidecar-field-preservation-sweep"
47
+ SESSION_DIR="$SESSION_ROOT/$SLUG"
48
+ STATE="$SESSION_DIR/state.json"
49
+ mkdir -p "$SESSION_ROOT"
50
+
51
+ # ─── Field-identity assertion helpers ────────────────────────────────────────
52
+ # Persistent identity fields captured from the seeded baseline. `owner` is included per the
53
+ # schema (schemas/workflow-state.schema.json allows it) even though NO current sidecar writer
54
+ # path ever stamps it — no command sets `owner:` on state.json today, so the captured baseline
55
+ # value is always the jq sentinel "<absent>" and stays "<absent>" for the whole sweep. That is
56
+ # still a real (trivial) assertion: if some future writer starts adding an `owner` field without
57
+ # preserving a pre-existing one, this sweep would catch it the same way it catches every other
58
+ # persistent field. No fixture forces a synthetic owner value — that would test a code path that
59
+ # does not exist today.
60
+ FIELDS=(branch task_slug repo created_at owner)
61
+ declare -A BASELINE
62
+
63
+ _field() {
64
+ local file="$1" field="$2"
65
+ jq -r --arg f "$field" '.[$f] // "<absent>"' "$file" 2>/dev/null
66
+ }
67
+
68
+ _capture_baseline() {
69
+ local field
70
+ for field in "${FIELDS[@]}"; do
71
+ BASELINE["$field"]="$(_field "$STATE" "$field")"
72
+ done
73
+ }
74
+
75
+ _assert_preserved() {
76
+ local label="$1"
77
+ local field actual ok=1
78
+ for field in "${FIELDS[@]}"; do
79
+ actual="$(_field "$STATE" "$field")"
80
+ if [[ "$actual" != "${BASELINE[$field]}" ]]; then
81
+ _fail "$label dropped/changed persistent field '$field': expected '${BASELINE[$field]}' got '$actual'"
82
+ ok=0
83
+ fi
84
+ done
85
+ [[ "$ok" -eq 1 ]] && _pass "persistent identity fields (${FIELDS[*]}) survive $label"
86
+ }
87
+
88
+ # ─── Seed: ensure-session with an injected actor (derived branch) and a KNOWN timestamp ──────
89
+ SEED_TS="2026-06-20T08:00:00Z"
90
+ if ! flow_agents_node "$WRITER" ensure-session \
91
+ --artifact-root "$SESSION_ROOT" \
92
+ --task-slug "$SLUG" \
93
+ --actor sweep-actor \
94
+ --flow-id builder.build \
95
+ --title "Sidecar Field Preservation Sweep" \
96
+ --source-request "Seed a fully-populated session for the field-preservation invariant sweep." \
97
+ --summary "Seed session for the class-level field-preservation sweep." \
98
+ --criterion "Every state.json-touching mutator preserves persistent identity fields" \
99
+ --timestamp "$SEED_TS" >"$TMPDIR_EVAL/seed.out" 2>"$TMPDIR_EVAL/seed.err"; then
100
+ _fail "sweep setup: ensure-session failed: $(cat "$TMPDIR_EVAL/seed.out" "$TMPDIR_EVAL/seed.err")"
101
+ echo ""
102
+ echo "$errors check(s) failed."
103
+ exit 1
104
+ fi
105
+
106
+ if [[ ! -f "$STATE" ]]; then
107
+ _fail "sweep setup: ensure-session did not write state.json"
108
+ echo ""
109
+ echo "$errors check(s) failed."
110
+ exit 1
111
+ fi
112
+
113
+ _capture_baseline
114
+ if [[ "${BASELINE[branch]}" != "agent/sweep-actor/$SLUG" || "${BASELINE[created_at]}" != "$SEED_TS" || "${BASELINE[task_slug]}" != "$SLUG" ]]; then
115
+ _fail "sweep setup: seeded baseline did not carry the expected branch/created_at/task_slug (branch=${BASELINE[branch]} created_at=${BASELINE[created_at]} task_slug=${BASELINE[task_slug]})"
116
+ fi
117
+
118
+ # ─── 1. init-plan, run against a BRANCH-LESS plan artifact ───────────────────────────────────
119
+ # Mirrors the real tool-planner shape: init-plan is invoked against the plan artifact
120
+ # ("<slug>--plan-work.md"), a DIFFERENT file than "<slug>--deliver.md" that ensure-session seeded
121
+ # the branch: line into. This is the exact repro shape of the #309 regression.
122
+ PLAN_ARTIFACT="$SESSION_DIR/$SLUG--plan-work.md"
123
+ cat > "$PLAN_ARTIFACT" <<'MARKDOWN'
124
+ ---
125
+ role: plan
126
+ parent: sidecar-field-preservation-sweep--deliver
127
+ created: 2026-06-20
128
+ ---
129
+
130
+ # Plan: field-preservation sweep fixture
131
+
132
+ A plan artifact deliberately carrying no `branch:` line (mirrors real tool-planner output).
133
+
134
+ ## Definition Of Done
135
+
136
+ - **Acceptance criteria:**
137
+ - [ ] init-plan preserves persistent identity fields - Evidence: pending.
138
+ MARKDOWN
139
+ if flow_agents_node "$WRITER" init-plan "$PLAN_ARTIFACT" \
140
+ --source-request "Plan artifact carries no branch: line (mirrors tool-planner output)." \
141
+ --summary "Planning sidecars initialized from a branch-less plan artifact." \
142
+ --next-action "Advance to execution." \
143
+ --timestamp "2026-06-20T08:05:00Z" >"$TMPDIR_EVAL/init-plan.out" 2>"$TMPDIR_EVAL/init-plan.err"; then
144
+ _assert_preserved "init-plan"
145
+ else
146
+ _fail "init-plan failed: $(cat "$TMPDIR_EVAL/init-plan.out" "$TMPDIR_EVAL/init-plan.err")"
147
+ fi
148
+
149
+ # ─── 2. advance-state (--flow-definition builder.build, non-terminal) ────────────────────────
150
+ # Moves phase execution -> maps to the "execute" step in builder.build's phase_map, which also
151
+ # sets current.json active_step_id so record-gate-claim below has a reachable gate.
152
+ if flow_agents_node "$WRITER" advance-state "$SESSION_DIR" \
153
+ --status in_progress \
154
+ --phase execution \
155
+ --summary "Execution started." \
156
+ --next-action "Implement the change." \
157
+ --flow-definition builder.build \
158
+ --timestamp "2026-06-20T08:10:00Z" >"$TMPDIR_EVAL/advance-1.out" 2>"$TMPDIR_EVAL/advance-1.err"; then
159
+ _assert_preserved "advance-state (#1, builder.build execution)"
160
+ else
161
+ _fail "advance-state (#1) failed: $(cat "$TMPDIR_EVAL/advance-1.out" "$TMPDIR_EVAL/advance-1.err")"
162
+ fi
163
+
164
+ # ─── 3. record-agent-event ────────────────────────────────────────────────────────────────────
165
+ # record-agent-event does not write state.json at all today (only agents/<id>/events.jsonl and
166
+ # current.json active_agents) — this still pins that invariant: state.json must stay untouched.
167
+ if flow_agents_node "$WRITER" record-agent-event \
168
+ --artifact-root "$SESSION_ROOT" \
169
+ --agent-id tool-worker-sweep \
170
+ --kind evidence \
171
+ --status active \
172
+ --summary "Worker started the sweep's implementation pass." \
173
+ --timestamp "2026-06-20T08:15:00Z" >"$TMPDIR_EVAL/agent-event.out" 2>"$TMPDIR_EVAL/agent-event.err"; then
174
+ _assert_preserved "record-agent-event"
175
+ else
176
+ _fail "record-agent-event failed: $(cat "$TMPDIR_EVAL/agent-event.out" "$TMPDIR_EVAL/agent-event.err")"
177
+ fi
178
+
179
+ # ─── 4. record-evidence (one check) ───────────────────────────────────────────────────────────
180
+ if flow_agents_node "$WRITER" record-evidence "$SESSION_DIR" \
181
+ --verdict pass \
182
+ --check-json '{"id":"sweep-check","kind":"command","status":"pass","summary":"Sweep fixture command check."}' \
183
+ --timestamp "2026-06-20T08:20:00Z" >"$TMPDIR_EVAL/evidence.out" 2>"$TMPDIR_EVAL/evidence.err"; then
184
+ _assert_preserved "record-evidence"
185
+ else
186
+ _fail "record-evidence failed: $(cat "$TMPDIR_EVAL/evidence.out" "$TMPDIR_EVAL/evidence.err")"
187
+ fi
188
+
189
+ # ─── 5. record-critique (one finding) ─────────────────────────────────────────────────────────
190
+ if flow_agents_node "$WRITER" record-critique "$SESSION_DIR" \
191
+ --id sweep-review \
192
+ --reviewer tool-code-reviewer \
193
+ --verdict pass \
194
+ --summary "No blocking findings." \
195
+ --finding-json '{"id":"sweep-finding","severity":"low","status":"fixed","description":"No blocking issues found during sweep sanity critique."}' \
196
+ --timestamp "2026-06-20T08:25:00Z" >"$TMPDIR_EVAL/critique.out" 2>"$TMPDIR_EVAL/critique.err"; then
197
+ _assert_preserved "record-critique"
198
+ else
199
+ _fail "record-critique failed: $(cat "$TMPDIR_EVAL/critique.out" "$TMPDIR_EVAL/critique.err")"
200
+ fi
201
+
202
+ # ─── 6. record-gate-claim (a builder.build-reachable expectation) ────────────────────────────
203
+ # advance-state #1 above (--phase execution) set current.json active_step_id to "execute" via
204
+ # builder.build's phase_map. The execute-gate in kits/builder/flows/build.flow.json declares
205
+ # exactly ONE expects[] entry ("implementation-scope"), so it auto-resolves without needing
206
+ # --expectation. This IS reachable in this scratch fixture (unlike, say, the verify-gate's two
207
+ # expects entries, which would need an explicit --expectation and a route-back dance to reach
208
+ # cleanly) — so no command in this sweep needed to be skipped.
209
+ if flow_agents_node "$WRITER" record-gate-claim "$SESSION_DIR" \
210
+ --status pass \
211
+ --summary "Implementation scope recorded for the sweep fixture." \
212
+ --timestamp "2026-06-20T08:30:00Z" >"$TMPDIR_EVAL/gate-claim.out" 2>"$TMPDIR_EVAL/gate-claim.err"; then
213
+ _assert_preserved "record-gate-claim"
214
+ else
215
+ _fail "record-gate-claim failed: $(cat "$TMPDIR_EVAL/gate-claim.out" "$TMPDIR_EVAL/gate-claim.err")"
216
+ fi
217
+
218
+ # ─── 7. record-learning (correction.needed:false shape) ──────────────────────────────────────
219
+ if flow_agents_node "$WRITER" record-learning "$SESSION_DIR" \
220
+ --status learned \
221
+ --record-json '{"id":"sweep-learning","source_refs":["state.json","trust.bundle"],"outcome":"success","facts":["Field-preservation sweep completed without a persistent-field regression."],"interpretation":"Every state.json-touching mutator preserved the seeded identity fields.","routing":[{"target":"none","action":"No follow-up required.","status":"completed"}],"correction":{"needed":false,"evidence":"All persistent identity fields matched the seeded baseline after every mutator."}}' \
222
+ --summary "Learning recorded; no follow-up remains." \
223
+ --timestamp "2026-06-20T08:35:00Z" >"$TMPDIR_EVAL/learning.out" 2>"$TMPDIR_EVAL/learning.err"; then
224
+ _assert_preserved "record-learning"
225
+ else
226
+ _fail "record-learning failed: $(cat "$TMPDIR_EVAL/learning.out" "$TMPDIR_EVAL/learning.err")"
227
+ fi
228
+
229
+ # ─── 8. advance-state (second call) ──────────────────────────────────────────────────────────
230
+ # record-learning above already moved phase to "learning" (writeState), so an accepted/archived
231
+ # target here is allowed by advance-state's terminal-jump guard (prev.phase === "learning").
232
+ if flow_agents_node "$WRITER" advance-state "$SESSION_DIR" \
233
+ --status archived \
234
+ --phase learning \
235
+ --summary "Sweep session closed out." \
236
+ --next-action "None." \
237
+ --timestamp "2026-06-20T08:40:00Z" >"$TMPDIR_EVAL/advance-2.out" 2>"$TMPDIR_EVAL/advance-2.err"; then
238
+ _assert_preserved "advance-state (#2, close-out)"
239
+ else
240
+ _fail "advance-state (#2) failed: $(cat "$TMPDIR_EVAL/advance-2.out" "$TMPDIR_EVAL/advance-2.err")"
241
+ fi
242
+
243
+ echo ""
244
+ if [[ "$errors" -eq 0 ]]; then
245
+ echo "test_sidecar_field_preservation: all checks passed."
246
+ else
247
+ echo "test_sidecar_field_preservation: $errors check(s) failed."
248
+ fi
249
+ exit "$errors"
@@ -46,7 +46,7 @@ const fs = require('fs');
46
46
  const [,, bundlePath, label, passingStr] = process.argv;
47
47
  const passing = passingStr === 'true';
48
48
  const bundle = {
49
- schemaVersion: 3,
49
+ schemaVersion: 5,
50
50
  source: "test-fixture",
51
51
  claims: [
52
52
  {
@@ -55,7 +55,7 @@ const bundle = {
55
55
  value: passing ? "pass" : "fail",
56
56
  status: passing ? "verified" : "disputed",
57
57
  subjectId: "test-slug/build",
58
- surface: "flow-agents.workflow",
58
+ facet: "flow-agents.workflow",
59
59
  subjectType: "workflow-check",
60
60
  fieldOrBehavior: "build",
61
61
  createdAt: "2026-06-27T00:00:00Z",
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env bash
2
+ # test_trust_reconcile_manifest.sh — WS8 (ADR 0020) manifest anti-gaming self-check.
3
+ #
4
+ # The reconcile manifest is evals/ci/run-baseline.sh's LANE_* registry (emitted via
5
+ # `--manifest-json`). This test proves the anti-gaming property design question 1 asked
6
+ # for — "a command in the manifest must actually run in a required lane" — holds by
7
+ # construction, and STAYS holding: it asserts the manifest id set and the set of checks
8
+ # invoked by .github/workflows/ci.yml's REQUIRED jobs are IDENTICAL. The advisory
9
+ # usage-feedback lane (continue-on-error, non-blocking) is excluded from BOTH the manifest and
10
+ # this required-set comparison (ADR 0020 iteration 2).
11
+ #
12
+ # 1. Every ci.yml `run-baseline.sh --check <slug>` invocation is a manifest entry.
13
+ # → fails when a CHECKS entry is removed from EVERY LANE_* array (it drops out of
14
+ # --manifest-json but ci.yml still invokes it): the anti-gaming coverage regresses.
15
+ # 2. Every manifest entry is invoked by a required ci.yml job.
16
+ # → fails when a manifest/lane command is not wired into any required lane.
17
+ #
18
+ # Mirrors evals/ci/antigaming-suite.sh's own rationale (a protection with no required-lane
19
+ # coverage is not a real protection) applied reflexively to the manifest itself.
20
+ #
21
+ # Deterministic, no model spend, self-cleaning.
22
+ # Usage: bash evals/integration/test_trust_reconcile_manifest.sh
23
+
24
+ set -uo pipefail
25
+
26
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
27
+ RUN_BASELINE="$ROOT/evals/ci/run-baseline.sh"
28
+ CI_YML="$ROOT/.github/workflows/ci.yml"
29
+
30
+ errors=0
31
+ _pass() { echo " PASS: $1"; }
32
+ _fail() { echo " FAIL: $1"; errors=$((errors + 1)); }
33
+
34
+ echo "=== WS8 manifest self-check: manifest (run-baseline.sh LANE_*) == ci.yml required --check set ==="
35
+
36
+ if [[ ! -f "$RUN_BASELINE" ]]; then _fail "run-baseline.sh not found at $RUN_BASELINE"; fi
37
+ if [[ ! -f "$CI_YML" ]]; then _fail "ci.yml not found at $CI_YML"; fi
38
+
39
+ # Manifest ids (only lane-covered checks are emitted).
40
+ MANIFEST_JSON="$(bash "$RUN_BASELINE" --manifest-json 2>/dev/null)"
41
+ MANIFEST_IDS="$(printf '%s' "$MANIFEST_JSON" | node -e 'let d="";process.stdin.on("data",c=>d+=c).on("end",()=>{const a=JSON.parse(d);for(const e of a){if(!e.lanes||!e.lanes.length){process.stderr.write("manifest entry with no lanes: "+e.id+"\n");process.exit(3);}console.log(e.id);}})' | sort -u)"
42
+ if [[ -z "$MANIFEST_IDS" ]]; then _fail "manifest is empty"; fi
43
+
44
+ # ci.yml required --check slugs. WS8 (ADR 0020, iteration 2): the usage-feedback lane is
45
+ # advisory (continue-on-error, non-blocking) and is intentionally EXCLUDED from the reconcile
46
+ # manifest, so its --check invocations are filtered out here too — the manifest is compared
47
+ # against the REQUIRED-lane --check set only. (All five usage-feedback checks slugify to the
48
+ # `usage-feedback-*` prefix and no required-lane check does, so the filter is exact.)
49
+ CI_SLUGS="$(grep -oE 'run-baseline\.sh --check [a-z0-9-]+' "$CI_YML" | awk '{print $NF}' | grep -v '^usage-feedback-' | sort -u)"
50
+ if [[ -z "$CI_SLUGS" ]]; then _fail "no required-lane run-baseline.sh --check invocations found in ci.yml"; fi
51
+
52
+ manifest_count="$(printf '%s\n' "$MANIFEST_IDS" | grep -c . )"
53
+ ci_count="$(printf '%s\n' "$CI_SLUGS" | grep -c . )"
54
+ echo " manifest entries: $manifest_count ; ci.yml --check invocations: $ci_count"
55
+
56
+ # Direction 1: every ci.yml --check slug must be a manifest entry.
57
+ missing_in_manifest="$(comm -23 <(printf '%s\n' "$CI_SLUGS") <(printf '%s\n' "$MANIFEST_IDS"))"
58
+ if [[ -z "$missing_in_manifest" ]]; then
59
+ _pass "every ci.yml required --check invocation is a manifest (lane-covered) entry"
60
+ else
61
+ _fail "ci.yml invokes checks that are NOT in the manifest (removed from every LANE_* array?): $(echo "$missing_in_manifest" | tr '\n' ' ')"
62
+ fi
63
+
64
+ # Direction 2: every manifest entry must be invoked by a required ci.yml job.
65
+ missing_in_ci="$(comm -23 <(printf '%s\n' "$MANIFEST_IDS") <(printf '%s\n' "$CI_SLUGS"))"
66
+ if [[ -z "$missing_in_ci" ]]; then
67
+ _pass "every manifest entry is invoked by a required ci.yml job (required-lane coverage by construction)"
68
+ else
69
+ _fail "manifest entries NOT wired into any required ci.yml job: $(echo "$missing_in_ci" | tr '\n' ' ')"
70
+ fi
71
+
72
+ echo ""
73
+ if [[ $errors -eq 0 ]]; then
74
+ echo "test_trust_reconcile_manifest: all checks passed."
75
+ exit 0
76
+ else
77
+ echo "test_trust_reconcile_manifest: $errors check(s) failed."
78
+ exit 1
79
+ fi
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env bash
2
+ # test_trust_reconcile_mixed_bundle.sh — WS8 (ADR 0020) END-TO-END PROOF.
3
+ #
4
+ # The literal capability PR #264 could not demonstrate: a single trust.bundle carrying
5
+ # honest, granular, MIXED evidence passes the REAL Trust Reconcile entrypoint:
6
+ # - one CI-reconcilable claim (evidenceType test_output; execution.label is a real
7
+ # reconcile-manifest command — run-baseline.sh's "Content boundary" check),
8
+ # - one honest session-local claim (human_attestation, Surface-verified, never claimed
9
+ # to be CI-re-runnable, no waiver needed),
10
+ # - one explicitly-waived accepted_gap claim (metadata.waiver, printed loudly).
11
+ #
12
+ # Runs the REAL scripts/ci/trust-reconcile.js (not a mock), resolving the manifest from
13
+ # THIS repo's live run-baseline.sh registry (--repo-root at the repo root). The manifest
14
+ # command is re-run FRESH by the reconciler; the session-local claim is accepted on its
15
+ # Surface status; the waiver is printed on a distinct WAIVED line. Exit 0.
16
+ #
17
+ # The fresh-verify (Step 1) command is a trivial pass so the proof is fast and focused on
18
+ # the reconcile/classification/waiver behavior (same pattern as the other reconcile evals);
19
+ # the manifest-matched command is genuinely re-run against the real checkout.
20
+ #
21
+ # Deterministic, no model spend, self-cleaning.
22
+ # Usage: bash evals/integration/test_trust_reconcile_mixed_bundle.sh
23
+
24
+ set -uo pipefail
25
+
26
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
27
+ RECONCILE="$ROOT/scripts/ci/trust-reconcile.js"
28
+ FIXTURE="$ROOT/evals/fixtures/trust-reconcile-mixed-bundle/mixed-bundle.json"
29
+
30
+ errors=0
31
+ _pass() { echo " PASS: $1"; }
32
+ _fail() { echo " FAIL: $1"; errors=$((errors + 1)); }
33
+
34
+ echo "=== WS8 end-to-end proof: mixed-evidence bundle passes the real Trust Reconcile ==="
35
+
36
+ if [[ ! -f "$FIXTURE" ]]; then _fail "fixture not found at $FIXTURE"; fi
37
+
38
+ # Real reconciler entrypoint. Fresh-verify is a trivial pass; the manifest is resolved
39
+ # from this repo's live run-baseline.sh registry (via --repo-root "$ROOT").
40
+ out="$(TRUST_RECONCILE_COMMANDS="node -e 'process.exit(0)'" \
41
+ node "$RECONCILE" --bundle "$FIXTURE" --repo-root "$ROOT" 2>&1)"
42
+ exit_code=$?
43
+
44
+ echo "----- reconciler output -----"
45
+ echo "$out"
46
+ echo "-----------------------------"
47
+
48
+ if [[ $exit_code -eq 0 ]]; then
49
+ _pass "mixed-evidence bundle passes the real Trust Reconcile (exit 0) — the capability PR #264 lacked"
50
+ else
51
+ _fail "expected exit 0, got $exit_code"
52
+ fi
53
+
54
+ if echo "$out" | grep -q "RECONCILED: 'npm run check:content-boundary --'"; then
55
+ _pass "the test_output claim reconciled against its manifest command (fresh CI re-run)"
56
+ else
57
+ _fail "expected a RECONCILED line for the manifest-matched command"
58
+ fi
59
+
60
+ if echo "$out" | grep -q "ATTESTED (not independently verifiable at L0): 'c-session-local' (workflow.check.external) evidenceType=human_attestation"; then
61
+ _pass "the human_attestation claim was accepted as session-local, loudly marked ATTESTED (not flagged not-run)"
62
+ else
63
+ _fail "expected an ATTESTED (not independently verifiable at L0) line for the human_attestation claim"
64
+ fi
65
+
66
+ # WS8 iteration-4 (converged finding): the honest mixed bundle's ATTESTED claim must also be
67
+ # counted in the loud summary line, not just printed inline — proves the count is real, not
68
+ # just cosmetic per-claim decoration.
69
+ if echo "$out" | grep -q "1 attested claim(s) accepted without independent verification"; then
70
+ _pass "the attested-claim summary count line is present and correct (1)"
71
+ else
72
+ _fail "expected the '1 attested claim(s) accepted without independent verification' summary line"
73
+ fi
74
+
75
+ if echo "$out" | grep -q "WAIVED:"; then
76
+ _pass "the accepted_gap claim was printed on a distinct, loud WAIVED line"
77
+ else
78
+ _fail "expected a WAIVED line for the waived accepted_gap claim"
79
+ fi
80
+
81
+ # Guard: the manifest must have resolved from the live run-baseline.sh registry, not the
82
+ # legacy single-command fallback (proves the resolver is wired to the real registry).
83
+ if echo "$out" | grep -qE "manifest: [0-9]+ entries \(source: (package.json:trust-reconcile-manifest|evals/ci/run-baseline.sh)"; then
84
+ _pass "manifest resolved from the live run-baseline.sh registry (not a synthetic one)"
85
+ else
86
+ _fail "manifest did not resolve from the live registry: $(echo "$out" | grep -i manifest | head -1)"
87
+ fi
88
+
89
+ echo ""
90
+ if [[ $errors -eq 0 ]]; then
91
+ echo "test_trust_reconcile_mixed_bundle: all checks passed."
92
+ exit 0
93
+ else
94
+ echo "test_trust_reconcile_mixed_bundle: $errors check(s) failed."
95
+ exit 1
96
+ fi
@@ -0,0 +1,151 @@
1
+ #!/usr/bin/env bash
2
+ # test_trust_reconcile_negatives.sh — WS8 iteration-2 anti-gaming negative regressions.
3
+ #
4
+ # Every live exploit the reviewer/verifier reproduced against the WS8 reconciler is frozen
5
+ # here as a permanent negative fixture. Each asserts the REAL scripts/ci/trust-reconcile.js
6
+ # exits NON-ZERO and emits the SPECIFIC divergence string the fix introduced. If any fix is
7
+ # ever regressed, the corresponding exploit passes again and this eval (which runs in the
8
+ # required runtime-and-kit lane via antigaming-suite.sh) goes red.
9
+ #
10
+ # 1. no-label-bypass (finding 1) → not-run: a test_output claim with no
11
+ # manifest-matched execution.label is a divergence, never session-local.
12
+ # 2. skip-assumed-bypass (finding 2) → unwaived-assumed: 'assumed' alone is not a pass.
13
+ # 3. status-misassertion (finding 3) → status-misassertion: CI re-derives status; a
14
+ # self-reported status that does not match the bundle's own evidence is rejected.
15
+ # 4. waived-command-check (finding 4) → waiver-on-command-check: a command-backed
16
+ # (test_output) check cannot be waived.
17
+ # 5. ws3-old-style-bundle (AC6) → old all-test_output bundle FAILS the same way (exit 1,
18
+ # divergences) under the new reconciler as under the old one — no soundness regression.
19
+ # 6. fabricated-attestation (iteration-4, converged iteration-3 finding, both gates) → a
20
+ # fully self-consistent, hand-fabricated no-command 'security' claim+evidence+event
21
+ # triple (indistinguishable from a genuine attestation at the reconciler's own
22
+ # re-derivation layer) MUST still pass (exit 0 — blocking attestations at L0 would break
23
+ # every honest human-attestation use) BUT MUST be loudly, distinctly marked
24
+ # 'ATTESTED (not independently verifiable at L0)' plus the summary count line — never a
25
+ # quiet SESSION-LOCAL OK indistinguishable from a reconciled check. See ADR 0020 Residuals.
26
+ #
27
+ # Fresh-verify (Step 1) is a trivial pass so the proof is focused on the reconcile step; the
28
+ # manifest resolves from this repo's live run-baseline.sh registry (--repo-root "$ROOT").
29
+ # Deterministic, no model spend, self-cleaning.
30
+ # Usage: bash evals/integration/test_trust_reconcile_negatives.sh
31
+
32
+ set -uo pipefail
33
+
34
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
35
+ RECONCILE="$ROOT/scripts/ci/trust-reconcile.js"
36
+ FX="$ROOT/evals/fixtures/trust-reconcile-exploits"
37
+ WS3="$ROOT/evals/fixtures/trust-reconcile-ws3/ws3-bundle.json"
38
+
39
+ errors=0
40
+ _pass() { echo " PASS: $1"; }
41
+ _fail() { echo " FAIL: $1"; errors=$((errors + 1)); }
42
+
43
+ # run_case <label> <bundle> <needle>
44
+ # Asserts: reconciler exits non-zero AND stdout/stderr contains <needle>.
45
+ run_case() {
46
+ local label="$1" bundle="$2" needle="$3"
47
+ echo "=== $label ==="
48
+ if [[ ! -f "$bundle" ]]; then _fail "$label: fixture not found at $bundle"; return; fi
49
+ local out code
50
+ out="$(TRUST_RECONCILE_COMMANDS="node -e 'process.exit(0)'" \
51
+ node "$RECONCILE" --bundle "$bundle" --repo-root "$ROOT" 2>&1)"
52
+ code=$?
53
+ if [[ $code -ne 0 ]]; then
54
+ _pass "$label: reconciler exits non-zero ($code)"
55
+ else
56
+ _fail "$label: expected non-zero exit, got 0 — output: $out"
57
+ fi
58
+ if echo "$out" | grep -qF "$needle"; then
59
+ _pass "$label: emitted the expected divergence (\"$needle\")"
60
+ else
61
+ _fail "$label: expected divergence \"$needle\" not found — output: $out"
62
+ fi
63
+ }
64
+
65
+ # 1. Reviewer's no-label exploit → not-run (test_output must reconcile against the manifest).
66
+ run_case "no-label-bypass (finding 1)" "$FX/no-label-bypass.json" \
67
+ "no manifest-matched execution.label"
68
+
69
+ # 2. Verifier's skip->assumed exploit → unwaived-assumed.
70
+ run_case "skip-assumed-bypass (finding 2)" "$FX/skip-assumed-bypass.json" \
71
+ "[unwaived-assumed]"
72
+
73
+ # 3. Status-misassertion exploit → status re-derived CI-side; asserted != derived.
74
+ run_case "status-misassertion (finding 3)" "$FX/status-misassertion.json" \
75
+ "[status-misassertion]"
76
+
77
+ # 4. Waived command-backed check → waiver-on-command-check.
78
+ run_case "waived-command-check (finding 4)" "$FX/waived-command-check.json" \
79
+ "[waiver-on-command-check]"
80
+
81
+ # 5. AC6 backward-compat regression: the real ws3-kit-dependencies-namespacing/trust.bundle
82
+ # (an old-style all-test_output bundle whose commands are not manifest-matched) FAILS the
83
+ # same way under the new reconciler as under the old one — same FAIL verdict, divergences
84
+ # present, no silent pass introduced.
85
+ echo "=== ws3 old-style bundle (AC6 backward compat) ==="
86
+ if [[ ! -f "$WS3" ]]; then
87
+ _fail "ws3 fixture not found at $WS3"
88
+ else
89
+ ws3_out="$(TRUST_RECONCILE_COMMANDS="node -e 'process.exit(0)'" \
90
+ node "$RECONCILE" --bundle "$WS3" --repo-root "$ROOT" 2>&1)"
91
+ ws3_code=$?
92
+ if [[ $ws3_code -ne 0 ]]; then
93
+ _pass "ws3 old-style bundle FAILS (exit $ws3_code) — same verdict as the old reconciler"
94
+ else
95
+ _fail "ws3 old-style bundle expected non-zero exit, got 0 — output: $ws3_out"
96
+ fi
97
+ if echo "$ws3_out" | grep -qF "[not-run]"; then
98
+ _pass "ws3 old-style bundle emits a not-run divergence (its test_output commands are not manifest-matched)"
99
+ else
100
+ _fail "ws3 old-style bundle expected a not-run divergence — output: $ws3_out"
101
+ fi
102
+ if echo "$ws3_out" | grep -qF "trust divergence"; then
103
+ _pass "ws3 old-style bundle emits trust divergence(s)"
104
+ else
105
+ _fail "ws3 old-style bundle expected trust divergence(s) — output: $ws3_out"
106
+ fi
107
+ fi
108
+
109
+ # 6. Fabricated-attestation (iteration-4): passes (exit 0) but MUST carry the loud ATTESTED
110
+ # marker and the summary count line — NOT the old quiet SESSION-LOCAL OK. This is a
111
+ # visibility assertion, not a divergence assertion (unlike run_case above): a fabricated
112
+ # self-consistent attestation bundle is, by construction, indistinguishable from a genuine
113
+ # one at this layer (see ADR 0020 Residuals) — the fix is disclosure, not a block.
114
+ echo "=== fabricated-attestation (iteration-4, converged finding) ==="
115
+ FAB="$FX/fabricated-attestation.json"
116
+ if [[ ! -f "$FAB" ]]; then
117
+ _fail "fabricated-attestation fixture not found at $FAB"
118
+ else
119
+ fab_out="$(TRUST_RECONCILE_COMMANDS="node -e 'process.exit(0)'" \
120
+ node "$RECONCILE" --bundle "$FAB" --repo-root "$ROOT" 2>&1)"
121
+ fab_code=$?
122
+ if [[ $fab_code -eq 0 ]]; then
123
+ _pass "fabricated-attestation bundle passes (exit 0) — attestations are not blocked at L0"
124
+ else
125
+ _fail "fabricated-attestation bundle expected exit 0, got $fab_code — output: $fab_out"
126
+ fi
127
+ if echo "$fab_out" | grep -qF "ATTESTED (not independently verifiable at L0): 'c-fabricated-security' (workflow.check.security) evidenceType=attestation"; then
128
+ _pass "fabricated-attestation bundle emits the loud ATTESTED marker (not a quiet SESSION-LOCAL OK)"
129
+ else
130
+ _fail "expected the ATTESTED (not independently verifiable at L0) marker — output: $fab_out"
131
+ fi
132
+ if echo "$fab_out" | grep -qF "1 attested claim(s) accepted without independent verification"; then
133
+ _pass "fabricated-attestation bundle emits the attested-claim summary count line"
134
+ else
135
+ _fail "expected the attested-claim summary count line — output: $fab_out"
136
+ fi
137
+ if echo "$fab_out" | grep -qF "SESSION-LOCAL OK"; then
138
+ _fail "fabricated-attestation bundle must NOT emit the old quiet SESSION-LOCAL OK line"
139
+ else
140
+ _pass "fabricated-attestation bundle does not emit the old quiet SESSION-LOCAL OK line"
141
+ fi
142
+ fi
143
+
144
+ echo ""
145
+ if [[ $errors -eq 0 ]]; then
146
+ echo "test_trust_reconcile_negatives: all checks passed."
147
+ exit 0
148
+ else
149
+ echo "test_trust_reconcile_negatives: $errors check(s) failed."
150
+ exit 1
151
+ fi
@@ -20,16 +20,16 @@ echo ""
20
20
  global="$TMPDIR_EVAL/global"
21
21
  repo_a="$TMPDIR_EVAL/repo-a"
22
22
  repo_b="$TMPDIR_EVAL/repo-b"
23
- mkdir -p "$repo_a/.flow-agents/alpha" "$repo_b/.flow-agents/beta"
23
+ mkdir -p "$repo_a/.kontourai/flow-agents/alpha" "$repo_b/.kontourai/flow-agents/beta"
24
24
 
25
- cat > "$repo_a/.flow-agents/alpha/alpha--deliver.md" <<'MARKDOWN'
25
+ cat > "$repo_a/.kontourai/flow-agents/alpha/alpha--deliver.md" <<'MARKDOWN'
26
26
  # Deliver Alpha
27
27
 
28
28
  status: delivered
29
29
  type: deliver
30
30
  MARKDOWN
31
31
 
32
- cat > "$repo_b/.flow-agents/beta/beta--verify.md" <<'MARKDOWN'
32
+ cat > "$repo_b/.kontourai/flow-agents/beta/beta--verify.md" <<'MARKDOWN'
33
33
  # Verify Beta
34
34
 
35
35
  status: failed
@@ -94,8 +94,8 @@ fi
94
94
 
95
95
  discover_root="$TMPDIR_EVAL/discover-root"
96
96
  repo_c="$discover_root/gamma"
97
- mkdir -p "$repo_c/.flow-agents/gamma"
98
- cat > "$repo_c/.flow-agents/gamma/gamma--deliver.md" <<'MARKDOWN'
97
+ mkdir -p "$repo_c/.kontourai/flow-agents/gamma"
98
+ cat > "$repo_c/.kontourai/flow-agents/gamma/gamma--deliver.md" <<'MARKDOWN'
99
99
  # Deliver Gamma
100
100
 
101
101
  status: delivered