@kontourai/flow-agents 2.3.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.
- package/.github/CODEOWNERS +8 -0
- package/.github/workflows/ci.yml +32 -0
- package/AGENTS.md +4 -4
- package/CHANGELOG.md +39 -0
- package/CONTEXT.md +14 -0
- package/README.md +9 -3
- package/agents/dev.json +1 -1
- package/agents/tool-code-reviewer.json +1 -1
- package/agents/tool-planner.json +3 -3
- package/agents/tool-verifier.json +3 -3
- package/build/src/cli/console-learning-projection.js +3 -2
- package/build/src/cli/init.js +104 -21
- package/build/src/cli/kit.js +37 -6
- package/build/src/cli/pull-work-provider.js +1 -1
- package/build/src/cli/usage-feedback.js +3 -3
- package/build/src/cli/validate-hook-influence.js +1 -0
- package/build/src/cli/validate-workflow-artifacts.js +22 -6
- package/build/src/cli/workflow-artifact-cleanup-audit.js +36 -2
- package/build/src/cli/workflow-sidecar.d.ts +14 -7
- package/build/src/cli/workflow-sidecar.js +792 -69
- package/build/src/flow-kit/validate.d.ts +23 -0
- package/build/src/flow-kit/validate.js +67 -1
- package/build/src/index.d.ts +1 -1
- package/build/src/index.js +1 -1
- package/build/src/lib/flow-resolver.d.ts +6 -4
- package/build/src/lib/flow-resolver.js +125 -58
- package/build/src/lib/local-artifact-root.d.ts +14 -2
- package/build/src/lib/local-artifact-root.js +22 -5
- package/build/src/lib/workflow-learning-projection.js +2 -2
- package/build/src/runtime-adapters.d.ts +12 -0
- package/build/src/runtime-adapters.js +56 -16
- package/build/src/tools/build-universal-bundles.js +49 -16
- package/build/src/tools/generate-context-map.js +10 -8
- package/build/src/tools/validate-source-tree.js +23 -1
- package/console.telemetry.json +22 -0
- package/context/contracts/artifact-contract.md +38 -7
- package/context/contracts/builder-kit-workflow-state-contract.md +3 -2
- package/context/contracts/decision-registry-contract.md +263 -0
- package/context/contracts/delivery-contract.md +1 -1
- package/context/contracts/planning-contract.md +2 -1
- package/context/contracts/review-contract.md +5 -3
- package/context/contracts/verification-contract.md +9 -1
- package/context/contracts/work-item-contract.md +1 -1
- package/context/deferred/parallelization.md +1 -1
- package/context/gate-awareness.md +4 -4
- package/context/scripts/git-status.sh +2 -2
- package/context/scripts/hooks/config-protection.js +502 -2
- package/context/scripts/hooks/lib/config-protection-remedies.js +69 -0
- package/context/scripts/hooks/run-hook.js +14 -1
- package/context/scripts/hooks/stop-goal-fit.js +1140 -99
- package/context/scripts/hooks/workflow-steering.js +212 -6
- package/docs/adr/0007-flow-skill-kit-tool-boundary.md +2 -0
- package/docs/adr/0015-flow-flow-agents-boundary-reconciliation.md +35 -0
- package/docs/adr/0019-kit-dependency-ownership.md +62 -0
- package/docs/adr/0020-trust-reconcile-manifest-and-claim-classification.md +290 -0
- package/docs/adr/0021-assignment-leases-and-stale-claim-takeover.md +221 -0
- package/docs/adr/0022-fail-closed-delivery-reconciliation-with-governed-exemptions.md +283 -0
- package/docs/agent-system-guidebook.md +3 -3
- package/docs/agent-usage-feedback-loop.md +6 -6
- package/docs/context-map.md +9 -7
- package/docs/decisions/decision-records.md +57 -0
- package/docs/decisions/index.md +14 -0
- package/docs/decisions/promotion-gate.md +52 -0
- package/docs/developer-architecture.md +1 -1
- package/docs/fixture-ownership.md +3 -0
- package/docs/flow-kit-repository-contract.md +5 -5
- package/docs/getting-started.md +12 -2
- package/docs/integrations/harness-install.md +2 -1
- package/docs/kit-authoring-guide.md +64 -5
- package/docs/knowledge-kit.md +5 -1
- package/docs/learnings/2026-07-improvement-program.md +203 -0
- package/docs/migrations.md +6 -5
- package/docs/north-star.md +2 -2
- package/docs/operating-layers.md +4 -3
- package/docs/repository-structure.md +5 -5
- package/docs/skills-map.md +8 -8
- package/docs/spec/runtime-hook-surface.md +19 -15
- package/docs/spikes/graph-provider-2026-07.md +155 -0
- package/docs/standards-register.md +7 -7
- package/docs/trust-anchor-adoption.md +105 -4
- package/docs/work-item-adapters.md +1 -1
- package/docs/workflow-artifact-lifecycle.md +72 -9
- package/docs/workflow-eval-strategy.md +3 -3
- package/docs/workflow-shared-contracts.md +1 -1
- package/docs/workflow-usage-guide.md +254 -21
- package/evals/acceptance/DEMO-false-completion.md +20 -11
- package/evals/acceptance/prove-capture-teeth-declared.sh +15 -15
- package/evals/acceptance/prove-capture-teeth.sh +11 -11
- package/evals/acceptance/test_kiro_harness.sh +1 -1
- package/evals/ci/antigaming-suite.sh +5 -0
- package/evals/ci/run-baseline.sh +65 -1
- package/evals/fixtures/flow-kit-repository/invalid-bad-dependency/flows/review.flow.json +26 -0
- package/evals/fixtures/flow-kit-repository/invalid-bad-dependency/kit.json +13 -0
- package/evals/fixtures/flow-kit-repository/valid-with-dependency/flows/review.flow.json +26 -0
- package/evals/fixtures/flow-kit-repository/valid-with-dependency/kit.json +13 -0
- package/evals/fixtures/hook-influence/cases.json +32 -0
- package/evals/fixtures/pull-work-provider/github-issues.json +6 -6
- package/evals/fixtures/trust-reconcile-exploits/fabricated-attestation.json +59 -0
- package/evals/fixtures/trust-reconcile-exploits/no-label-bypass.json +36 -0
- package/evals/fixtures/trust-reconcile-exploits/skip-assumed-bypass.json +59 -0
- package/evals/fixtures/trust-reconcile-exploits/status-misassertion.json +48 -0
- package/evals/fixtures/trust-reconcile-exploits/waived-command-check.json +44 -0
- package/evals/fixtures/trust-reconcile-mixed-bundle/mixed-bundle.json +159 -0
- package/evals/fixtures/trust-reconcile-ws3/ws3-bundle.json +920 -0
- package/evals/integration/test_actor_identity.sh +254 -0
- package/evals/integration/test_builder_step_producers.sh +33 -23
- package/evals/integration/test_bundle_install.sh +22 -16
- package/evals/integration/test_bundle_lifecycle.sh +11 -11
- package/evals/integration/test_captured_fail_reconciliation.sh +50 -50
- package/evals/integration/test_checkpoint_signing.sh +43 -0
- package/evals/integration/test_claim_lookup.sh +4 -4
- package/evals/integration/test_codex_hook_resolution.sh +114 -0
- package/evals/integration/test_command_log_concurrency.sh +8 -8
- package/evals/integration/test_command_log_fork_classification.sh +3 -3
- package/evals/integration/test_command_log_integrity.sh +16 -16
- package/evals/integration/test_console_learning_projection.sh +1 -1
- package/evals/integration/test_dual_emit_flow_step.sh +145 -0
- package/evals/integration/test_enforcer_expects_driven.sh +12 -12
- package/evals/integration/test_evidence_capture_hook.sh +14 -13
- package/evals/integration/test_fixture_retirement_audit.sh +2 -2
- package/evals/integration/test_flow_agents_statusline.sh +2 -2
- package/evals/integration/test_flow_kit_install_git.sh +52 -0
- package/evals/integration/test_flow_kit_repository.sh +2 -0
- package/evals/integration/test_flowdef_session_activation.sh +6 -6
- package/evals/integration/test_flowdef_union_floor_regression.sh +429 -0
- package/evals/integration/test_gate_bypass_chain.sh +52 -40
- package/evals/integration/test_gate_lockdown.sh +97 -73
- package/evals/integration/test_gate_review_inquiry_records.sh +3 -3
- package/evals/integration/test_goal_fit_escape_hatch.sh +10 -10
- package/evals/integration/test_goal_fit_ghost_session.sh +104 -0
- package/evals/integration/test_goal_fit_hook.sh +32 -32
- package/evals/integration/test_goal_fit_rederive.sh +9 -9
- package/evals/integration/test_hook_category_behaviors.sh +103 -0
- package/evals/integration/test_hook_influence_cases.sh +1 -0
- package/evals/integration/test_install_merge.sh +262 -1
- package/evals/integration/test_kit_identity_trust.sh +6 -6
- package/evals/integration/test_liveness_conflict_injection.sh +587 -0
- package/evals/integration/test_liveness_heartbeat.sh +677 -0
- package/evals/integration/test_liveness_verdict.sh +394 -0
- package/evals/integration/test_local_flow_kit_install.sh +15 -0
- package/evals/integration/test_phase_map_and_gate_claim.sh +63 -11
- package/evals/integration/test_promote_gate.sh +178 -0
- package/evals/integration/test_publish_delivery.sh +2 -2
- package/evals/integration/test_pull_work_liveness_preflight.sh +386 -0
- package/evals/integration/test_pull_work_provider.sh +2 -2
- package/evals/integration/test_reconcile_soundness.sh +4 -4
- package/evals/integration/test_resolvefirststep_security.sh +22 -0
- package/evals/integration/test_runtime_adapter_activation.sh +87 -18
- package/evals/integration/test_session_resume_roundtrip.sh +147 -0
- package/evals/integration/test_sidecar_field_preservation.sh +249 -0
- package/evals/integration/test_trust_reconcile.sh +2 -2
- package/evals/integration/test_trust_reconcile_manifest.sh +79 -0
- package/evals/integration/test_trust_reconcile_mixed_bundle.sh +96 -0
- package/evals/integration/test_trust_reconcile_negatives.sh +151 -0
- package/evals/integration/test_usage_feedback_global.sh +5 -5
- package/evals/integration/test_validate_artifacts_portability.sh +60 -0
- package/evals/integration/test_verify_cli.sh +2 -2
- package/evals/integration/test_veritas_governance_kit.sh +117 -0
- package/evals/integration/test_workflow_artifact_cleanup_audit.sh +26 -1
- package/evals/integration/test_workflow_artifacts.sh +33 -0
- package/evals/integration/test_workflow_sidecar_writer.sh +723 -74
- package/evals/integration/test_workflow_steering_hook.sh +175 -5
- package/evals/lib/codex-provider.sh +1 -1
- package/evals/lib/node.sh +19 -1
- package/evals/run.sh +22 -0
- package/evals/static/test_decisions.sh +150 -0
- package/evals/static/test_flowdef_codeowners_coverage.sh +56 -0
- package/evals/static/test_package.sh +19 -10
- package/evals/static/test_universal_bundles.sh +48 -3
- package/evals/static/test_workflow_skills.sh +41 -8
- package/kits/builder/flows/build.flow.json +3 -74
- package/kits/builder/flows/publish-learn.flow.json +90 -0
- package/kits/builder/kit.json +11 -0
- package/kits/builder/skills/builder-shape/SKILL.md +1 -1
- package/kits/builder/skills/deliver/SKILL.md +13 -11
- package/kits/builder/skills/design-probe/SKILL.md +4 -4
- package/kits/builder/skills/evidence-gate/SKILL.md +26 -1
- package/kits/builder/skills/execute-plan/SKILL.md +2 -2
- package/kits/builder/skills/fix-bug/SKILL.md +2 -0
- package/kits/builder/skills/gate-review/SKILL.md +6 -6
- package/kits/builder/skills/idea-to-backlog/SKILL.md +1 -1
- package/kits/builder/skills/learning-review/SKILL.md +7 -7
- package/kits/builder/skills/pickup-probe/SKILL.md +5 -4
- package/kits/builder/skills/plan-work/SKILL.md +27 -5
- package/kits/builder/skills/pull-work/SKILL.md +80 -5
- package/kits/builder/skills/release-readiness/SKILL.md +4 -4
- package/kits/builder/skills/review-work/SKILL.md +24 -1
- package/kits/builder/skills/tdd-workflow/SKILL.md +2 -0
- package/kits/builder/skills/verify-work/SKILL.md +8 -1
- package/kits/catalog.json +6 -0
- package/kits/veritas-governance/adapter/readiness-to-trust-bundle.mjs +178 -0
- package/kits/veritas-governance/docs/README.md +75 -0
- package/kits/veritas-governance/fixtures/readiness/not-ready.readiness-report.json +4645 -0
- package/kits/veritas-governance/fixtures/readiness/ready.readiness-report.json +4403 -0
- package/kits/veritas-governance/flows/readiness-check.flow.json +35 -0
- package/kits/veritas-governance/kit.json +16 -0
- package/package.json +8 -4
- package/packaging/README.md +2 -2
- package/packaging/conformance/fixtures/config-protection--allow-read-state-json.json +20 -0
- package/packaging/conformance/fixtures/config-protection--block-write-state-json.json +20 -0
- package/packaging/conformance/fixtures/stop-goal-fit--block-bundle-disputed-claim.json +1 -1
- package/packaging/conformance/fixtures/stop-goal-fit--block-capture-contradicts-claimed-pass.json +1 -1
- package/packaging/manifest.json +9 -10
- package/schemas/decision-record.schema.json +109 -0
- package/schemas/workflow-evidence.schema.json +1 -1
- package/schemas/workflow-state.schema.json +5 -0
- package/scripts/README.md +8 -3
- package/scripts/check-content-boundary.cjs +1 -1
- package/scripts/check-decisions.cjs +356 -0
- package/scripts/ci/derive-claim-status.mjs +74 -0
- package/scripts/ci/trust-reconcile.js +436 -79
- package/scripts/git-status.sh +2 -2
- package/scripts/hooks/claude-telemetry-hook.js +37 -3
- package/scripts/hooks/codex-telemetry-hook.js +36 -2
- package/scripts/hooks/config-protection.js +102 -30
- package/scripts/hooks/evidence-capture.js +3 -3
- package/scripts/hooks/lib/actor-identity.js +368 -0
- package/scripts/hooks/lib/config-protection-remedies.js +69 -0
- package/scripts/hooks/lib/liveness-heartbeat.js +361 -0
- package/scripts/hooks/lib/liveness-policy.js +127 -0
- package/scripts/hooks/lib/liveness-read.js +105 -12
- package/scripts/hooks/lib/liveness-write.js +46 -0
- package/scripts/hooks/lib/local-artifact-paths.js +12 -6
- package/scripts/hooks/opencode-telemetry-hook.js +27 -1
- package/scripts/hooks/pi-telemetry-hook.js +27 -1
- package/scripts/hooks/stop-goal-fit.js +157 -26
- package/scripts/hooks/workflow-steering.js +77 -3
- package/scripts/install-codex-home.sh +138 -38
- package/scripts/statusline/flow-agents-statusline.js +2 -2
- package/src/cli/console-learning-projection.ts +3 -2
- package/src/cli/init.ts +101 -21
- package/src/cli/kit.ts +37 -6
- package/src/cli/public-api.test.mjs +58 -6
- package/src/cli/pull-work-provider.ts +1 -1
- package/src/cli/trust-bundle-policy-order.test.mjs +87 -0
- package/src/cli/usage-feedback.ts +3 -3
- package/src/cli/validate-hook-influence.ts +1 -0
- package/src/cli/validate-workflow-artifacts.ts +22 -6
- package/src/cli/veritas-readiness-adapter.test.mjs +267 -0
- package/src/cli/workflow-artifact-cleanup-audit.ts +35 -2
- package/src/cli/workflow-sidecar.ts +795 -71
- package/src/flow-kit/validate.ts +74 -1
- package/src/index.ts +6 -2
- package/src/lib/flow-resolver.ts +123 -55
- package/src/lib/local-artifact-root.ts +24 -5
- package/src/lib/workflow-learning-projection.ts +2 -2
- package/src/runtime-adapters.ts +61 -15
- package/src/tools/build-universal-bundles.ts +49 -16
- package/src/tools/generate-context-map.ts +10 -8
- package/src/tools/validate-source-tree.ts +23 -1
|
@@ -16,7 +16,7 @@ ideas -> Builder Kit shape / idea-to-backlog -> work items -> pull-work -> picku
|
|
|
16
16
|
|
|
17
17
|
You can do this in one conversation, but the gates should stay explicit. Do not let shaping, planning, implementation, and release confidence blur into one continuous task.
|
|
18
18
|
|
|
19
|
-
Workflow artifacts follow a closeout lifecycle. Local runtime artifacts live under `.flow-agents/<slug>/` and stay uncommitted. When a branch needs reviewable in-progress planning, promote durable behavior, decisions, evidence, and usage notes into long-lived docs, source, schemas, or provider records before merge.
|
|
19
|
+
Workflow artifacts follow a closeout lifecycle. Local runtime artifacts live under `.kontourai/flow-agents/<slug>/` and stay uncommitted. When a branch needs reviewable in-progress planning, promote durable behavior, decisions, evidence, and usage notes into long-lived docs, source, schemas, or provider records before merge.
|
|
20
20
|
|
|
21
21
|
For local artifact queue hygiene, run the read-only cleanup audit:
|
|
22
22
|
|
|
@@ -56,7 +56,7 @@ Expected behavior:
|
|
|
56
56
|
Expected artifact:
|
|
57
57
|
|
|
58
58
|
```text
|
|
59
|
-
.flow-agents/<slug>/<slug>--idea-to-backlog.md
|
|
59
|
+
.kontourai/flow-agents/<slug>/<slug>--idea-to-backlog.md
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
The artifact should include `source_ideas`, `idea_inventory`, `slice_candidates`, `bundle_justification`, `dependency_map`, `phase`, `decisions`, `opportunity_briefs`, `shaped_work`, `risk_release_notes`, `backlog_links`, `parked_or_rejected`, `open_questions`, `next_gate`, and the Builder Kit Flow Definition link. Use this phase to decide what deserves backlog space. Provider-backed work items should be executable or near-executable work, not a dumping ground for every idea. GitHub issues are the first adapter example.
|
|
@@ -109,7 +109,7 @@ Expected behavior:
|
|
|
109
109
|
Expected artifact:
|
|
110
110
|
|
|
111
111
|
```text
|
|
112
|
-
.flow-agents/<slug>/<slug>--pull-work.md
|
|
112
|
+
.kontourai/flow-agents/<slug>/<slug>--pull-work.md
|
|
113
113
|
```
|
|
114
114
|
|
|
115
115
|
When a repository has backlog provider settings, `pull-work` should use those settings without requiring the user to name the board. In Flow Agents, `npm run effective-backlog-settings -- --repo-path . --json` resolves `kontourai/flow-agents` to GitHub Project `kontourai/1`, so a prompt like `use pull-work` is enough for the configured provider path.
|
|
@@ -136,7 +136,7 @@ Your WIP can block starting new work. Other people's WIP should block only when
|
|
|
136
136
|
|
|
137
137
|
After `pull-work` passes the pickup gate in the Builder Kit build flow, use the Builder Kit pickup Probe before planning. The Flow Definition step is named `design-probe`, and the build path is `pull-work -> design-probe -> plan`. The generic `design-probe` skill owns one-question-at-a-time design alignment; the `pickup-probe` skill is the Builder Kit work-item/docs/provider-grounded specialization used at that step.
|
|
138
138
|
|
|
139
|
-
The pickup Probe must record goal fit and scope, blockers and dependencies, dependency freshness, acceptance criteria quality, provider state, risk, stop-short risks, planning readiness, decisions, unresolved questions, accepted gaps, sandbox/worktree mode, expected modified files, and conflict risks. Record those in `.flow-agents/<slug>/<slug>--pull-work.md` or the plan handoff artifact before `plan-work` begins.
|
|
139
|
+
The pickup Probe must record goal fit and scope, blockers and dependencies, dependency freshness, acceptance criteria quality, provider state, risk, stop-short risks, planning readiness, decisions, unresolved questions, accepted gaps, sandbox/worktree mode, expected modified files, and conflict risks. Record those in `.kontourai/flow-agents/<slug>/<slug>--pull-work.md` or the plan handoff artifact before `plan-work` begins.
|
|
140
140
|
|
|
141
141
|
When the selected work item includes `planned_base_ref` and `planned_base_sha`, compare that base with current `main` before planning. If relevant files, contracts, docs, schemas, or dependency states changed since the work was shaped, classify the drift as `no_material_drift`, `scope_drift`, `dependency_drift`, `contract_drift`, or `conflict_risk`. Ask for alignment before planning when drift changes scope, acceptance criteria, dependency assumptions, or execution risk.
|
|
142
142
|
|
|
@@ -184,7 +184,7 @@ Then use `plan-work`.
|
|
|
184
184
|
Example prompt:
|
|
185
185
|
|
|
186
186
|
```text
|
|
187
|
-
Use plan-work for the selected work item in .flow-agents/<slug>/<slug>--pull-work.md. Produce an execution plan with acceptance criteria, file ownership, test strategy, and parallelization opportunities. Do not implement yet.
|
|
187
|
+
Use plan-work for the selected work item in .kontourai/flow-agents/<slug>/<slug>--pull-work.md. Produce an execution plan with acceptance criteria, file ownership, test strategy, and parallelization opportunities. Do not implement yet.
|
|
188
188
|
```
|
|
189
189
|
|
|
190
190
|
Then use `execute-plan` only after the plan is accepted.
|
|
@@ -200,7 +200,7 @@ When `pull-work` chooses a worktree, record `worktree_lifecycle`: path, branch,
|
|
|
200
200
|
Example prompt:
|
|
201
201
|
|
|
202
202
|
```text
|
|
203
|
-
Use execute-plan for .flow-agents/<slug>/<slug>--plan.md. Prefer isolated worktrees for parallel or risky work. Execute the plan and keep progress in the session artifact.
|
|
203
|
+
Use execute-plan for .kontourai/flow-agents/<slug>/<slug>--plan.md. Prefer isolated worktrees for parallel or risky work. Execute the plan and keep progress in the session artifact.
|
|
204
204
|
```
|
|
205
205
|
|
|
206
206
|
## 5. Review, Then Verify
|
|
@@ -212,7 +212,7 @@ Review checks quality, security triggers, architecture fit, project standards, r
|
|
|
212
212
|
Example prompt:
|
|
213
213
|
|
|
214
214
|
```text
|
|
215
|
-
Use review-work for .flow-agents/<slug>/<slug>--deliver.md. Run code review, security review if triggered, and standards/architecture critique. Record findings in critique.json. Do not fix code.
|
|
215
|
+
Use review-work for .kontourai/flow-agents/<slug>/<slug>--deliver.md. Run code review, security review if triggered, and standards/architecture critique. Record findings in critique.json. Do not fix code.
|
|
216
216
|
```
|
|
217
217
|
|
|
218
218
|
Then use `verify-work` for implementation verification. Verification is evidence: it asks what proves the accepted behavior works.
|
|
@@ -222,7 +222,7 @@ Verification runs build/type/lint/test/security/browser/runtime checks as releva
|
|
|
222
222
|
Example prompt:
|
|
223
223
|
|
|
224
224
|
```text
|
|
225
|
-
Use verify-work for .flow-agents/<slug>/<slug>--deliver.md. Map every acceptance criterion to evidence and record PASS, FAIL, or NOT_VERIFIED.
|
|
225
|
+
Use verify-work for .kontourai/flow-agents/<slug>/<slug>--deliver.md. Map every acceptance criterion to evidence and record PASS, FAIL, or NOT_VERIFIED.
|
|
226
226
|
```
|
|
227
227
|
|
|
228
228
|
## 6. Build Trust With Evidence Gate
|
|
@@ -253,7 +253,7 @@ Pickup Probe may update durable docs only when the decision is no longer a trans
|
|
|
253
253
|
|
|
254
254
|
## 7. Check Goal Fit Before Stopping
|
|
255
255
|
|
|
256
|
-
Goal Fit is the local stop condition before a final answer. The working artifact in `.flow-agents/<slug>/` should answer:
|
|
256
|
+
Goal Fit is the local stop condition before a final answer. The working artifact in `.kontourai/flow-agents/<slug>/` should answer:
|
|
257
257
|
|
|
258
258
|
- What did the user originally ask for?
|
|
259
259
|
- Can the user run, understand, inspect, or act on the result now?
|
|
@@ -272,7 +272,7 @@ npm run workflow:sidecar -- ensure-session \
|
|
|
272
272
|
--summary "<summary>" \
|
|
273
273
|
--criterion "<acceptance criterion>"
|
|
274
274
|
|
|
275
|
-
npm run workflow:sidecar -- init-plan .flow-agents/<slug>/<slug>--deliver.md \
|
|
275
|
+
npm run workflow:sidecar -- init-plan .kontourai/flow-agents/<slug>/<slug>--deliver.md \
|
|
276
276
|
--source-request "<request>" \
|
|
277
277
|
--summary "<summary>" \
|
|
278
278
|
--next-action "<next step>"
|
|
@@ -306,10 +306,113 @@ Rules:
|
|
|
306
306
|
- Issue-backed sessions should prefer `--work-item` over hand-supplied `--task-slug` so that
|
|
307
307
|
liveness subjectId alignment is automatic.
|
|
308
308
|
|
|
309
|
+
#### Branch convention
|
|
310
|
+
|
|
311
|
+
`ensure-session` derives a routing branch name for every newly created session and records it
|
|
312
|
+
in `state.json.branch`, seeds it into the session Markdown's `branch:` line, and mirrors it into
|
|
313
|
+
`current.json.branch` for the currently active session. The derived format is:
|
|
314
|
+
|
|
315
|
+
```
|
|
316
|
+
agent/<actor>/<slug>
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
`<actor>` comes from the same actor resolver used by liveness tracking
|
|
320
|
+
(`scripts/hooks/lib/actor-identity.js`'s `resolveActor`), and `<slug>` is the session's task slug
|
|
321
|
+
(or the deterministic `--work-item` slug described above).
|
|
322
|
+
|
|
323
|
+
Neither the resolved actor string nor an arbitrary `--task-slug` is guaranteed to be a valid git
|
|
324
|
+
ref component, so `ensure-session` runs both through an incremental `sanitizeBranchSegment` pass
|
|
325
|
+
before joining them into `agent/<actor>/<slug>`:
|
|
326
|
+
|
|
327
|
+
1. Replace any `:` with `-` (the actor resolver's own `:` delimiter is not a legal ref character).
|
|
328
|
+
2. Re-run the actor resolver's own charset restriction (`[A-Za-z0-9_.-]`, 64-char cap).
|
|
329
|
+
3. Collapse repeated `..` sequences to a single `-` (git forbids two consecutive dots in a ref
|
|
330
|
+
component).
|
|
331
|
+
4. Strip a leading `.` (git forbids a component starting with `.`).
|
|
332
|
+
5. Strip a trailing `.` (fix-plan iteration 1, F1 — git forbids a component ending in `.`; the
|
|
333
|
+
prior pass only handled a run of 2+ trailing dots via the `..`-collapse step above and missed
|
|
334
|
+
the single-trailing-dot case, e.g. a `--task-slug` of `my-fix.`). This runs *before* the next
|
|
335
|
+
step so a `.lock` suffix hidden behind trailing dots (e.g. `foo.lock.`) is exposed and still
|
|
336
|
+
rewritten rather than left dangling.
|
|
337
|
+
6. Rewrite a trailing `.lock` to `-lock` (git forbids a component ending in `.lock`).
|
|
338
|
+
7. If the FINAL result after the above steps is empty, OR is exactly the literal string
|
|
339
|
+
`unknown`, fall back to `unknown-<hash>` where `<hash>` is the first 6 hex characters of
|
|
340
|
+
`sha256(<raw input before step 1>)` (fix-plan iteration 1 F4, tightened by iteration 2 F4').
|
|
341
|
+
The hash is deterministic (same raw input always derives the same fallback, preserving the
|
|
342
|
+
"never re-derive an existing session's branch" guarantee below) but makes two *different*
|
|
343
|
+
raw inputs that both land on the fallback derive distinct branches instead of silently
|
|
344
|
+
colliding on the bare literal `unknown`. This covers three distinct ways a raw input can land
|
|
345
|
+
on the fallback, all disambiguated identically with **no exceptions**: an all-garbage input
|
|
346
|
+
(e.g. `--task-slug "???"`) whose charset filter in step 2 collapses it to nothing; a near-miss
|
|
347
|
+
input like `"unknown."` or `".unknown"` that step 4/5's leading/trailing-dot stripping
|
|
348
|
+
collapses down to the literal `unknown`; and a raw input that genuinely *is* the literal
|
|
349
|
+
string `unknown` verbatim. Iteration 1 exempted that last case (a literal `"unknown"` input
|
|
350
|
+
was left undisambiguated); iteration 2 (F4') removed that carve-out because it let a literal
|
|
351
|
+
`--actor unknown` collide, undisambiguated, with a near-miss input like `"unknown."` that
|
|
352
|
+
collapses to the same segment — every input that reaches the fallback token is now
|
|
353
|
+
disambiguated uniformly.
|
|
354
|
+
|
|
355
|
+
As of fix-plan iteration 1 (re-verified against the sanitizer above, see F1 in
|
|
356
|
+
`.kontourai/flow-agents/kontourai-flow-agents-289/kontourai-flow-agents-289--fix-plan-iteration-1.md`),
|
|
357
|
+
this pass empirically closes every concrete git-check-ref-format(1) failure mode reachable
|
|
358
|
+
through it: `sanitizeSegment`'s own `[A-Za-z0-9_.-]` charset restriction (step 2) already strips
|
|
359
|
+
every character git-check-ref-format forbids elsewhere in a ref component — `@`, `{`/`}` (so
|
|
360
|
+
`@{` cannot survive), `/` (so a derived segment can never end with `/`, contain `//`, or itself
|
|
361
|
+
be a bare `@`), whitespace, and other control characters — so none of those were ever actually
|
|
362
|
+
reachable in a *derived* segment even before this iteration; only the single-trailing-dot case
|
|
363
|
+
(step 5, above) was a real, reachable gap, and it is now closed. There is no longer a known
|
|
364
|
+
accepted gap for the derived path. This is still not a from-scratch reimplementation of
|
|
365
|
+
`git-check-ref-format(1)` (e.g. it has not been exhaustively fuzzed against every future git
|
|
366
|
+
version's rule set) — but it is not a partial/best-effort pass either.
|
|
367
|
+
|
|
368
|
+
- Pass `--branch <value>` to `ensure-session` to record an explicit value verbatim instead of the
|
|
369
|
+
derived name. The override only applies while creating a brand-new session.
|
|
370
|
+
- Unlike the derived path, an explicit `--branch` is **not** sanitized — it is caller intent and
|
|
371
|
+
may legitimately contain `/` (to nest under an existing convention), so `ensure-session`
|
|
372
|
+
strictly *validates* it instead and dies with a remediation message, before writing any session
|
|
373
|
+
artifact. Validation runs in two passes:
|
|
374
|
+
1. Whole-string lexical checks (fix-plan iteration 1, F2) — the value must not:
|
|
375
|
+
- contain a control character, newline, or space;
|
|
376
|
+
- start or end with `/`, or contain `//`;
|
|
377
|
+
- start with `.`, or contain a `..` sequence;
|
|
378
|
+
- end with `.` or `.lock`; or
|
|
379
|
+
- contain any character outside `[A-Za-z0-9_./-]`.
|
|
380
|
+
2. Per-`/`-component lexical checks (fix-plan iteration 2, F2') — the whole-string checks above
|
|
381
|
+
only examine the very start/end of the full value, so a charset-legal value can still smuggle
|
|
382
|
+
an invalid path component past them (e.g. `-lead`, `a/.b`, `foo.lock/bar`, `a/./b`). Every
|
|
383
|
+
`/`-delimited component must not be empty, must not be exactly `.`, must not start with `.`
|
|
384
|
+
or `-` (applied uniformly to every component, not just the first — intentionally stricter
|
|
385
|
+
than git strictly requires, which is fine for a caller-facing override flag), and must not
|
|
386
|
+
end with `.` or `.lock`.
|
|
387
|
+
3. Belt-and-braces (fix-plan iteration 2, F2'): once both lexical passes above succeed, the real
|
|
388
|
+
`git check-ref-format --branch <value>` binary is invoked (argv-array, no shell, 5-second
|
|
389
|
+
timeout) as the final authority. It can only ever *reject* a value the lexical checks already
|
|
390
|
+
let through — never re-legalize one they rejected — so it closes any residual gap between this
|
|
391
|
+
hand-rolled lexical pass and git's actual ref-name rules. When git cannot be spawned at all
|
|
392
|
+
(not installed) or does not complete within the timeout, this step is skipped silently and the
|
|
393
|
+
lexical checks above remain the sole authority.
|
|
394
|
+
|
|
395
|
+
A value that passes all of the above is recorded exactly as given (no trimming, no
|
|
396
|
+
sanitization).
|
|
397
|
+
- `ensure-session` only records the branch **name** — in `state.json`, the session Markdown, and
|
|
398
|
+
`current.json`. It does not run `git checkout -b` or `git worktree add`; creating and checking
|
|
399
|
+
out the actual branch/worktree remains the calling skill's responsibility (see
|
|
400
|
+
[ADR 0021](adr/0021-assignment-leases-and-stale-claim-takeover.md) §3).
|
|
401
|
+
- Resuming an existing session directory never re-derives or overwrites its already-recorded
|
|
402
|
+
`branch` — the session Markdown's existing `branch:` line always wins, regardless of which
|
|
403
|
+
actor next calls `ensure-session` against that slug. This is what makes takeover continuity
|
|
404
|
+
("resume the incumbent's branch, never a parallel one") true by construction; see
|
|
405
|
+
[ADR 0021](adr/0021-assignment-leases-and-stale-claim-takeover.md) §5.
|
|
406
|
+
- `branch` is an optional field in `workflow-state.schema.json` for migration honesty: legacy
|
|
407
|
+
`state.json` files that predate this convention have no `branch` key and still validate.
|
|
408
|
+
`workflow:validate-artifacts` prints a non-blocking `WARN` line to stderr (not a hard failure)
|
|
409
|
+
when a `state.json` has no `branch` field, naming the gap without breaking legacy
|
|
410
|
+
sessions/fixtures.
|
|
411
|
+
|
|
309
412
|
Reviewer Markdown artifacts can be imported into `critique.json`:
|
|
310
413
|
|
|
311
414
|
```bash
|
|
312
|
-
npm run workflow:sidecar -- import-critique .flow-agents/<slug> .flow-agents/<slug>/<slug>--review.md
|
|
415
|
+
npm run workflow:sidecar -- import-critique .kontourai/flow-agents/<slug> .kontourai/flow-agents/<slug>/<slug>--review.md
|
|
313
416
|
```
|
|
314
417
|
|
|
315
418
|
Core workflow skills should use these writer commands when available. If a writer command or validation is unavailable or blocked, the artifact should record the exact sidecar gap as `NOT_VERIFIED` rather than silently falling back to an unstructured pass.
|
|
@@ -381,17 +484,17 @@ Use release-readiness for this evidence-gate PASS. Decide whether to MERGE, RELE
|
|
|
381
484
|
|
|
382
485
|
## 10. Promote Final Acceptance Docs
|
|
383
486
|
|
|
384
|
-
`.flow-agents/<slug>/` is local runtime/session state by default in the Flow Agents source tree. Exported agent bundles may map the runtime root to a distribution-specific path through their bundle instructions. Treat local workflow roots as working memory for a delivery. After provider checks pass and the work is merged or otherwise accepted, promote the useful parts into durable documentation, provider comments/descriptions, release notes, or archive records.
|
|
487
|
+
`.kontourai/flow-agents/<slug>/` is local runtime/session state by default in the Flow Agents source tree. Exported agent bundles may map the runtime root to a distribution-specific path through their bundle instructions. Treat local workflow roots as working memory for a delivery. After provider checks pass and the work is merged or otherwise accepted, promote the useful parts into durable documentation, provider comments/descriptions, release notes, or archive records.
|
|
385
488
|
|
|
386
489
|
Use the helper:
|
|
387
490
|
|
|
388
491
|
```bash
|
|
389
|
-
npm run promote-workflow-artifact -- .flow-agents/<slug>/<slug>--deliver.md
|
|
492
|
+
npm run promote-workflow-artifact -- .kontourai/flow-agents/<slug>/<slug>--deliver.md
|
|
390
493
|
```
|
|
391
494
|
|
|
392
495
|
Expected behavior:
|
|
393
496
|
|
|
394
|
-
- copy the source artifact into `.flow-agents/<slug>/archive/<date>/`
|
|
497
|
+
- copy the source artifact into `.kontourai/flow-agents/<slug>/archive/<date>/`
|
|
395
498
|
- create or update a durable doc under `docs/delivery/`
|
|
396
499
|
- include the plan, evidence, Goal Fit, and Final Acceptance sections when present
|
|
397
500
|
- link the durable doc back to the archived artifact so future readers can inspect why and how the feature was built
|
|
@@ -430,7 +533,7 @@ flow-agents console-learning-projection --artifact-root .flow-agents --kontour-r
|
|
|
430
533
|
|
|
431
534
|
Those flags are the defaults. The command writes `.kontour/projections/flow-agents-learning/<scope-kind>-<scope-id>.json`. Generated learnings are inert, non-authoritative Console read models with `family: "workflow"` and `nonAuthority: true`. `learning.json` remains the Flow Agents-owned source data; the command does not mutate it, execute routing or prevention, create provider issues, implement Source/Sink storage, add UI, or model domain-learning. The producer performs minimal projection source-shape checks for required fields; full `learning.json` JSON Schema validation remains covered by `npm run workflow:validate-artifacts`. When a sibling Console checkout is available, `inspectLocalKontour` may inspect the generated projection, but Flow Agents local tests validate the committed projection shape.
|
|
432
535
|
|
|
433
|
-
For local-only users, `.flow-agents/<slug>/` is the recent recovery cache and queue dashboard. Retain active blockers and unresolved learning. Prune or archive routine successful runtime artifacts after 14-30 days once provider records, durable docs, or knowledge notes contain the useful history. Keep security, migration, release, or provider-governance evidence longer when auditability matters, usually 30-90 days unless a project policy says otherwise.
|
|
536
|
+
For local-only users, `.kontourai/flow-agents/<slug>/` is the recent recovery cache and queue dashboard. Retain active blockers and unresolved learning. Prune or archive routine successful runtime artifacts after 14-30 days once provider records, durable docs, or knowledge notes contain the useful history. Keep security, migration, release, or provider-governance evidence longer when auditability matters, usually 30-90 days unless a project policy says otherwise.
|
|
434
537
|
|
|
435
538
|
## Quick Prompt Templates
|
|
436
539
|
|
|
@@ -455,7 +558,7 @@ Use evidence-gate. Map acceptance criteria to evidence, inspect CI and scope int
|
|
|
455
558
|
Check local goal fit:
|
|
456
559
|
|
|
457
560
|
```text
|
|
458
|
-
Before final answer, update the Goal Fit Gate in the current `.flow-agents/<slug>/` delivery artifact. Keep working on unchecked items unless I explicitly accept them.
|
|
561
|
+
Before final answer, update the Goal Fit Gate in the current `.kontourai/flow-agents/<slug>/` delivery artifact. Keep working on unchecked items unless I explicitly accept them.
|
|
459
562
|
```
|
|
460
563
|
|
|
461
564
|
Release decision:
|
|
@@ -484,7 +587,7 @@ The `RESUME:` block supplements the existing `STATE:` line and contains:
|
|
|
484
587
|
- **Next step** — the first `handoff.json next_steps` entry.
|
|
485
588
|
- **Blockers** — any recorded blockers from `handoff.json`, or "none".
|
|
486
589
|
- **Trust** — `Trust: N verified / M disputed / T total` from reading `trust.bundle`. Each disputed or unknown claim is listed with its id and a copy-pasteable remedy command: `npm run workflow:sidecar -- claim <id> <dir>`.
|
|
487
|
-
- **Liveness advisory** (when applicable) — `[LIVENESS WARNING: another agent appears live on this work: actor <X>, last seen <T>]` when the shared liveness stream (`.flow-agents/liveness/events.jsonl`, ADR 0012) contains a fresh claim or heartbeat from a different actor for the same slug. This is advisory only — the hook exits 0 regardless.
|
|
590
|
+
- **Liveness advisory** (when applicable) — `[LIVENESS WARNING: another agent appears live on this work: actor <X>, last seen <T>]` when the shared liveness stream (`.kontourai/flow-agents/liveness/events.jsonl`, ADR 0012) contains a fresh claim or heartbeat from a different actor for the same slug. This is advisory only — the hook exits 0 regardless. The block also always includes an `ACTOR: <actor> (<source>)` line — the same runtime-agnostic actor identity this session resolves for itself (see "Actor identity and liveness writes" below), so a resuming agent can see at a glance which identity its own liveness claims/heartbeats will be filed under.
|
|
488
591
|
- **Route hint** — `To continue: resume this work. Or run pull-work to assess WIP and start new/parallel work.` — always routes the resume-vs-parallel decision through `pull-work` rather than auto-taking it.
|
|
489
592
|
|
|
490
593
|
The `RESUME:` block appears on `SessionStart` only. `UserPromptSubmit` and `PostToolUse`
|
|
@@ -493,16 +596,24 @@ behavior is unchanged.
|
|
|
493
596
|
All reads are fail-open: a missing `handoff.json`, `trust.bundle`, or liveness stream
|
|
494
597
|
degrades gracefully — the section is omitted or shows "no data", and the hook never throws.
|
|
495
598
|
|
|
496
|
-
The
|
|
497
|
-
|
|
498
|
-
|
|
599
|
+
The `RESUME:` advisory read above is read-only (ADR 0012); liveness *writes* happen
|
|
600
|
+
elsewhere in the lifecycle and already exist today: `init-plan` claims the active slug and
|
|
601
|
+
`advance-state` heartbeats/releases it. As of #288, `FLOW_AGENTS_LIVENESS` defaults **on** —
|
|
602
|
+
presence is ambient by default. Set it to `off`/`0`/`false`/`no`/`disabled`
|
|
603
|
+
(case-insensitive) to opt back out. Claim TTL defaults to `1800` seconds and is
|
|
604
|
+
configurable via `FLOW_AGENTS_LIVENESS_TTL_SECONDS`; per ADR 0012 §4, tuning this value is
|
|
605
|
+
itself the operational risk — too tight manufactures false reclaims, so treat liveness as
|
|
606
|
+
advisory and double-check against real branch/PR state before tightening it. A throttled
|
|
607
|
+
tool-activity heartbeat also rides ordinary tool use (see "Tool-activity heartbeat"
|
|
608
|
+
below), so a long-running wave never goes stale on TTL alone just because it hasn't hit a
|
|
609
|
+
phase transition. The session-level event log (Layer 2) is still deferred.
|
|
499
610
|
|
|
500
611
|
### Shared liveness helper
|
|
501
612
|
|
|
502
613
|
The freshness logic is centralised in `scripts/hooks/lib/liveness-read.js` (pure CJS,
|
|
503
614
|
zero dependencies). It exports:
|
|
504
615
|
|
|
505
|
-
- `readLivenessEvents(streamPath)` — reads a `.flow-agents/liveness/events.jsonl` file
|
|
616
|
+
- `readLivenessEvents(streamPath)` — reads a `.kontourai/flow-agents/liveness/events.jsonl` file
|
|
506
617
|
line-by-line, JSON-parses each, and tolerates malformed lines.
|
|
507
618
|
- `freshHolders(events, slug, selfActor, nowMs)` — returns actors (excluding `selfActor`)
|
|
508
619
|
who hold a within-TTL claim or heartbeat on `subjectId === slug`.
|
|
@@ -510,3 +621,125 @@ zero dependencies). It exports:
|
|
|
510
621
|
Both the hook (`scripts/hooks/workflow-steering.js`) and the compiled CLI
|
|
511
622
|
(`build/src/cli/workflow-sidecar.js`) consume this helper so the TTL/freshness logic lives
|
|
512
623
|
in one place.
|
|
624
|
+
|
|
625
|
+
### Tool-activity heartbeat
|
|
626
|
+
|
|
627
|
+
`scripts/hooks/lib/liveness-heartbeat.js` (pure CJS, zero dependencies — same sharing pattern
|
|
628
|
+
as `liveness-read.js` and `actor-identity.js`) exports `maybeEmitHeartbeat({ cwd, env, now })`.
|
|
629
|
+
All four telemetry hook wrappers (`scripts/hooks/{claude,codex,opencode,pi}-telemetry-hook.js`)
|
|
630
|
+
call it whenever the current invocation's canonical event resolves to `postToolUse`. Per
|
|
631
|
+
[`docs/spec/runtime-hook-surface.md`](spec/runtime-hook-surface.md) row 280, `PostToolUseFailure`
|
|
632
|
+
is a **Claude Code-only** additional native event mapped onto canonical `postToolUse` — Codex,
|
|
633
|
+
Kiro, opencode, and pi each map only their own single native `postToolUse`-equivalent event
|
|
634
|
+
(`PostToolUse`, `PostToolUse`, `tool.execute.after`, `tool_result` respectively); no other
|
|
635
|
+
runtime has a distinct "failure" variant. The heartbeat call runs independently of the existing
|
|
636
|
+
`telemetry.sh` spawn. On each call it:
|
|
637
|
+
|
|
638
|
+
1. Checks `isLivenessEnabled()` — no-ops (`disabled`) if `FLOW_AGENTS_LIVENESS` is off.
|
|
639
|
+
2. Reads `current.json`'s `active_slug` and resolves the actor (`actor-identity.js`) — no-ops
|
|
640
|
+
if there is no active slug or the actor cannot be resolved. These two checks run *before*
|
|
641
|
+
actor resolution specifically so a repo with liveness disabled, or with no active session,
|
|
642
|
+
never pays the actor resolver's process-ancestry `ps` spawn cost.
|
|
643
|
+
3. Reads a **bounded tail** (the last 64KB, newline-aligned so a partial line at the truncation
|
|
644
|
+
boundary is dropped) of the `liveness/events.jsonl` stream, filtered for that
|
|
645
|
+
`(subjectId, actor)` pair. Because the stream is append-only, this bounded read is exact for
|
|
646
|
+
any pair whose most recent event lies within that window — which, in steady state, is always
|
|
647
|
+
true within one throttle period. Only if the pair has **zero** matching events anywhere in
|
|
648
|
+
the tail (the rare case of the first heartbeat after a claim old enough to have scrolled out
|
|
649
|
+
of the last 64KB) does it fall back to one full read of the stream. No-ops if there is no
|
|
650
|
+
prior `claim` event from this actor for this subject, or if the actor's most recent event for
|
|
651
|
+
the subject is a `release`.
|
|
652
|
+
4. Throttles: only appends a new `heartbeat` event once at least
|
|
653
|
+
`FLOW_AGENTS_LIVENESS_HEARTBEAT_THROTTLE_SECONDS` (default `60`) seconds have elapsed since
|
|
654
|
+
that actor's last recorded event for the subject.
|
|
655
|
+
|
|
656
|
+
The throttle window is derived from the actor-scoped stream tail itself — there is
|
|
657
|
+
deliberately no separate, mutable "last heartbeat" state file. Per ADR 0021 §3 (which lists
|
|
658
|
+
"advance-state + tool activity" heartbeats as one of the cross-cutting liveness touchpoints,
|
|
659
|
+
riding existing writes rather than a bespoke timer), a shared state file keyed on anything
|
|
660
|
+
less specific than the actor would reintroduce the same last-writer-wins race that ADR 0021
|
|
661
|
+
is designed to close. Each actor only ever contends with its own prior writes, so there is no
|
|
662
|
+
cross-session race to guard against.
|
|
663
|
+
|
|
664
|
+
`maybeEmitHeartbeat` is fail-open, matching the #287 actor-identity convention below: any
|
|
665
|
+
error is caught, a diagnostic is written to stderr, and the call returns without throwing — it
|
|
666
|
+
never blocks the tool call, never alters a wrapper's stdout/success-output shape, and never
|
|
667
|
+
changes a wrapper's exit code. It also does not read or depend on `TELEMETRY_ENABLED` —
|
|
668
|
+
disabling telemetry does not disable liveness heartbeats, and vice versa; the two are
|
|
669
|
+
independent, sibling concerns.
|
|
670
|
+
|
|
671
|
+
### Overlap detection and correction
|
|
672
|
+
|
|
673
|
+
Two composable mechanisms (#320) tighten the gap ADR 0012 §4 names — a false-stale
|
|
674
|
+
double-hold is *detected*, not *prevented*, and liveness stays advisory, never a lock: a
|
|
675
|
+
deterministic **tiebreaker CLI** (`liveness verdict`) that lets a losing session
|
|
676
|
+
self-correct within the same `pull-work` pass, and a **mid-turn conflict injection** that
|
|
677
|
+
surfaces another actor's fresh claim on a session's own held subject inside its own
|
|
678
|
+
tool-call context, on the runtimes whose hook contract supports it. Neither mechanism
|
|
679
|
+
mutates GitHub/provider state or introduces a new state file (ADR 0012 §5); each closes
|
|
680
|
+
one of the cross-cutting liveness touchpoints ADR 0021 §3 lists, without implementing
|
|
681
|
+
that ADR's still-Draft takeover/supersede or publish-gate slices.
|
|
682
|
+
|
|
683
|
+
The table below documents the full selection/mid-flight/publish latency budget — where a
|
|
684
|
+
double-hold can occur, what detects it, what corrects it, and the typical latency before
|
|
685
|
+
correction happens:
|
|
686
|
+
|
|
687
|
+
| Window | What can go wrong | Detector | Corrector | Typical latency |
|
|
688
|
+
| --- | --- | --- | --- | --- |
|
|
689
|
+
| **Selection** | Two sessions both select and claim the same subject in the same narrow read-then-write window (#166). | `pull-work`'s preflight (`### 1a. Liveness Selection Preflight`) plus its post-claim re-check (`### Post-Claim Conflict Re-check`), both reading `liveness status`. | `liveness verdict` computes the deterministic winner; the losing session runs `liveness release` and returns to `### 3. Select Work` to reselect in the same pass (#320). | One `pull-work` pass — seconds. |
|
|
690
|
+
| **Mid-flight** | After selection, another actor claims the same subject while this session is mid-execution, before its next natural checkpoint. | The tool-activity heartbeat's bounded tail read (#288), extended to also run the conflict check on the same in-memory buffer, zero added I/O (#320). | Claude Code and Codex: mid-turn hook feedback (`hookSpecificOutput.additionalContext`) surfaced on the very next tool call. opencode and pi: a stderr diagnostic only today (their generated plugin/extension does not consume telemetry-wrapper stdout — a disclosed gap, tracked in #333, not closed by this issue); all four runtimes still fall back to the pre-existing next-turn `workflow-steering.js` `[LIVENESS WARNING: ...]` digest. | Claude Code/Codex: next tool call. opencode/pi: next `SessionStart` or a manual check, plus the stderr diagnostic at the time of the conflicting tool call. |
|
|
691
|
+
| **Publish** | Two sessions both believe they hold exclusive claim at the moment of publish (merge/release). | Not yet implemented. | Not yet implemented — the `verify-hold` publish gate (ADR 0021 §3, tracked as #293). | Would be blocking, at publish time. |
|
|
692
|
+
|
|
693
|
+
The Publish row is **not implemented by this issue** — it is named here so the table is
|
|
694
|
+
read as an honest latency-budget map, not mistaken for a claim that overlap detection is
|
|
695
|
+
fully closed end-to-end. See [ADR 0012](adr/0012-agent-coordination-as-liveness-claims.md)
|
|
696
|
+
§4 and [ADR 0021](adr/0021-assignment-leases-and-stale-claim-takeover.md) §3 for the
|
|
697
|
+
underlying design rationale.
|
|
698
|
+
|
|
699
|
+
### Actor identity and liveness writes
|
|
700
|
+
|
|
701
|
+
Liveness claims/heartbeats/releases are attributed to a runtime-agnostic **actor struct**
|
|
702
|
+
`{runtime, session_id, host, human?}`, serialized (via `serializeActor()` in the shared
|
|
703
|
+
`scripts/hooks/lib/actor-identity.js` resolver — same sharing pattern as `liveness-read.js`
|
|
704
|
+
above) into a single string safe for the existing `${subjectId}::${actor}` grouping key. The
|
|
705
|
+
serialized actor string embeds this machine's `os.hostname()` — so `liveness/events.jsonl` (and
|
|
706
|
+
therefore `.kontourai/flow-agents/` as a whole) can indirectly reveal hostnames of every host
|
|
707
|
+
that has claimed work in this repo; `.kontourai/` must stay gitignored (it already is, by
|
|
708
|
+
default) and must never be force-added (`git add -f`) or bundled into a shareable support
|
|
709
|
+
bundle without first reviewing it for this kind of incidental host-identifying information. Both
|
|
710
|
+
`workflow-sidecar`'s `liveness` command and `workflow-steering.js`'s SessionStart advisory
|
|
711
|
+
consume the same `resolveActor()` function, so a session's own claim/heartbeat events are
|
|
712
|
+
never mistaken for "another agent."
|
|
713
|
+
|
|
714
|
+
`resolveActor()` derives the actor automatically, with zero required configuration, via a
|
|
715
|
+
priority chain:
|
|
716
|
+
|
|
717
|
+
1. An explicit `FLOW_AGENTS_ACTOR` env override, if set (and not the literal `"local"`,
|
|
718
|
+
case-insensitive) — always wins.
|
|
719
|
+
2. A runtime-native session-id env var already ambient in the current process's own
|
|
720
|
+
environment — confirmed for Claude Code (`CLAUDE_CODE_SESSION_ID`); the equivalent var for
|
|
721
|
+
Codex/opencode/pi is unverified as of this writing.
|
|
722
|
+
3. A process-ancestry fallback (the resolver's parent PID plus that parent process's exact
|
|
723
|
+
start timestamp, hashed into a short opaque token) — needs no runtime cooperation, is
|
|
724
|
+
stable across repeated invocations within one session, and is distinct across concurrent
|
|
725
|
+
sessions on one host. This is the correctness backstop for runtimes whose native
|
|
726
|
+
session-id env var is not yet confirmed.
|
|
727
|
+
|
|
728
|
+
**Liveness writes fail loud.** `liveness claim`, `liveness heartbeat`, and `liveness release`
|
|
729
|
+
exit nonzero with remediation text whenever the resolved actor is empty or the literal
|
|
730
|
+
`"local"` (case-insensitive) — they never silently fall back to the old shared `"local"`
|
|
731
|
+
default. Fix: pass `--actor <id>` explicitly, set `FLOW_AGENTS_ACTOR=<id>`, or run inside a
|
|
732
|
+
supported runtime so the derivation chain above can resolve a real identity.
|
|
733
|
+
|
|
734
|
+
**Liveness reads stay backward-compatible.** `liveness status` and `freshHolders()` (in
|
|
735
|
+
`liveness-read.js`) continue to parse, group, and label pre-existing events whose `actor`
|
|
736
|
+
field is the literal string `"local"` without error or behavior change — only *new* writes
|
|
737
|
+
are rejected, not historical data.
|
|
738
|
+
|
|
739
|
+
This actor struct is the same shape referenced by
|
|
740
|
+
[ADR 0012](adr/0012-agent-coordination-as-liveness-claims.md) and by
|
|
741
|
+
[ADR 0021](adr/0021-assignment-leases-and-stale-claim-takeover.md) §2 (`AssignmentProvider`)
|
|
742
|
+
as the forward-looking identity model for durable assignment. ADR 0021 is still Draft, and its
|
|
743
|
+
other slices (`AssignmentProvider`, the janitor, takeover/supersede, the verify-hold publish
|
|
744
|
+
gate) are **not** implemented by this change — only the actor struct and derivation chain
|
|
745
|
+
described here.
|
|
@@ -39,16 +39,23 @@ variance is the problem. You cannot ship "the model will probably catch it."
|
|
|
39
39
|
### With Flow Agents (block mode, shipped default) — refused, deterministically
|
|
40
40
|
|
|
41
41
|
The Stop is blocked and the agent receives this exact, evidence-grounded refusal
|
|
42
|
-
(`stop-goal-fit` hook, captured verbatim
|
|
42
|
+
(`stop-goal-fit` hook, captured verbatim from the same seeded `add-auth` fixture run
|
|
43
|
+
directly through `scripts/hooks/stop-goal-fit.js` with `FLOW_AGENTS_GOAL_FIT_MODE=block`):
|
|
43
44
|
```
|
|
44
|
-
[
|
|
45
|
-
- add-auth--deliver.md
|
|
46
|
-
- add-auth
|
|
47
|
-
- add-auth
|
|
48
|
-
|
|
45
|
+
[stop-gate] Goal Fit warning:
|
|
46
|
+
- .kontourai/flow-agents/add-auth/add-auth--deliver.md is still status:executing (0m old). Do not final-answer as complete unless the next step is explicit.
|
|
47
|
+
- .kontourai/flow-agents/add-auth workflow state: status:in_progress phase:verification; next_action:continue "Fix the 3 failing unit tests."
|
|
48
|
+
- .kontourai/flow-agents/add-auth next action: Fix the 3 failing unit tests.
|
|
49
|
+
- .kontourai/flow-agents/add-auth evidence verdict:fail; do not deliver without accepted gap or new evidence.
|
|
50
|
+
→ fix the failing check, or record it as an accepted gap with justification in the session artifact
|
|
51
|
+
- .kontourai/flow-agents/add-auth evidence check unit-tests status:fail: 3 unit tests are still failing
|
|
52
|
+
→ fix the failing check, or record it as an accepted gap with justification in the session artifact
|
|
53
|
+
[stop-gate] Stop blocked — 5 evidence gap(s) (block 1; after 3 identical blocks I stop blocking and hand this to you)
|
|
49
54
|
```
|
|
50
55
|
This is not model judgment — it is a hook reading the evidence file. It fires the same
|
|
51
|
-
way every time, on every model. (Block exit 2 → the runtime's Stop is denied.
|
|
56
|
+
way every time, on every model. (Block exit 2 → the runtime's Stop is denied. The
|
|
57
|
+
`[stop-gate]` prefix becomes `[<flowId>/<gateId>]`, e.g. `[builder.build/verify-gate]`,
|
|
58
|
+
when the session has an active FlowDefinition gate; see `loadActiveFlowStep`.)
|
|
52
59
|
|
|
53
60
|
---
|
|
54
61
|
|
|
@@ -115,11 +122,13 @@ the model can't talk its way around.
|
|
|
115
122
|
|
|
116
123
|
## How each arm was run
|
|
117
124
|
|
|
118
|
-
- **Codex live**: use the dedicated installer, which flattens the config to the home
|
|
119
|
-
and copies your real auth from `~/.codex
|
|
125
|
+
- **Codex live**: use the dedicated installer, which flattens the config to the Codex home
|
|
126
|
+
root and copies your real auth from `~/.codex`. By default it targets `CODEX_HOME`, or
|
|
127
|
+
`~/.codex` when `CODEX_HOME` is unset; pass a positional path only for an explicit
|
|
128
|
+
isolated or test install:
|
|
120
129
|
```bash
|
|
121
|
-
bash scripts/install-codex-home.sh
|
|
122
|
-
|
|
130
|
+
bash scripts/install-codex-home.sh
|
|
131
|
+
codex exec --dangerously-bypass-hook-trust -C <project> "<prompt>"
|
|
123
132
|
```
|
|
124
133
|
Verified live: from a bare `continue`, Codex re-grounded and created `RESUMED.txt`.
|
|
125
134
|
- **Claude live**: `dist/claude-code/install.sh <workspace>` then `claude -p` from the
|
|
@@ -37,11 +37,11 @@ trap cleanup EXIT
|
|
|
37
37
|
# ─── helper: seed a minimal delivered workflow artifact ───────────────────────
|
|
38
38
|
seed_repo() { # $1=dir $2=slug
|
|
39
39
|
local p="$1" slug="$2"
|
|
40
|
-
mkdir -p "$p/.flow-agents/$slug"
|
|
40
|
+
mkdir -p "$p/.kontourai/flow-agents/$slug"
|
|
41
41
|
printf '# Repo\n' > "$p/AGENTS.md"
|
|
42
42
|
printf '%s' "{\"schema_version\":\"1.0\",\"task_slug\":\"$slug\",\"status\":\"delivered\",\"phase\":\"done\",\"updated_at\":\"2026-06-27T00:00:00Z\",\"next_action\":{\"status\":\"done\",\"summary\":\"done\"}}" \
|
|
43
|
-
> "$p/.flow-agents/$slug/state.json"
|
|
44
|
-
cat > "$p/.flow-agents/$slug/$slug--deliver.md" << MD
|
|
43
|
+
> "$p/.kontourai/flow-agents/$slug/state.json"
|
|
44
|
+
cat > "$p/.kontourai/flow-agents/$slug/$slug--deliver.md" << MD
|
|
45
45
|
# $slug
|
|
46
46
|
|
|
47
47
|
branch: main
|
|
@@ -65,7 +65,7 @@ write_declared_bundle() { # $1=bundle-path
|
|
|
65
65
|
python3 - "$1" << 'PY'
|
|
66
66
|
import json, sys
|
|
67
67
|
bundle = {
|
|
68
|
-
"schemaVersion":
|
|
68
|
+
"schemaVersion": 5,
|
|
69
69
|
"source": "flow-agents/workflow-sidecar",
|
|
70
70
|
"claims": [{
|
|
71
71
|
"id": "c1",
|
|
@@ -138,13 +138,13 @@ seed_repo "$T1" "declared-false"
|
|
|
138
138
|
|
|
139
139
|
# current.json: active FlowDefinition
|
|
140
140
|
printf '%s' '{"artifact_dir":"declared-false","active_flow_id":"builder.build","active_step_id":"verify"}' \
|
|
141
|
-
> "$T1/.flow-agents/current.json"
|
|
141
|
+
> "$T1/.kontourai/flow-agents/current.json"
|
|
142
142
|
|
|
143
|
-
write_declared_bundle "$T1/.flow-agents/declared-false/trust.bundle"
|
|
143
|
+
write_declared_bundle "$T1/.kontourai/flow-agents/declared-false/trust.bundle"
|
|
144
144
|
|
|
145
145
|
# command-log: npm test recorded as FAIL — the independent truth source says FAILED
|
|
146
146
|
printf '%s\n' '{"command":"npm test","observedResult":"fail","exitCode":1,"capturedAt":"2026-06-27T00:00:00Z","source":"postToolUse-capture"}' \
|
|
147
|
-
> "$T1/.flow-agents/declared-false/command-log.jsonl"
|
|
147
|
+
> "$T1/.kontourai/flow-agents/declared-false/command-log.jsonl"
|
|
148
148
|
|
|
149
149
|
set +e
|
|
150
150
|
t1_out="$(FLOW_AGENTS_GOAL_FIT_MODE=block \
|
|
@@ -186,13 +186,13 @@ T2="$TMP/t2"
|
|
|
186
186
|
seed_repo "$T2" "declared-pass"
|
|
187
187
|
|
|
188
188
|
printf '%s' '{"artifact_dir":"declared-pass","active_flow_id":"builder.build","active_step_id":"verify"}' \
|
|
189
|
-
> "$T2/.flow-agents/current.json"
|
|
189
|
+
> "$T2/.kontourai/flow-agents/current.json"
|
|
190
190
|
|
|
191
191
|
# Reuse same bundle (trusts pass) but command-log confirms pass
|
|
192
|
-
python3 - "$T2/.flow-agents/declared-pass/trust.bundle" << 'PY'
|
|
192
|
+
python3 - "$T2/.kontourai/flow-agents/declared-pass/trust.bundle" << 'PY'
|
|
193
193
|
import json, sys
|
|
194
194
|
bundle = {
|
|
195
|
-
"schemaVersion":
|
|
195
|
+
"schemaVersion": 5,
|
|
196
196
|
"source": "flow-agents/workflow-sidecar",
|
|
197
197
|
"claims": [{
|
|
198
198
|
"id": "c2",
|
|
@@ -229,7 +229,7 @@ PY
|
|
|
229
229
|
|
|
230
230
|
# command-log: npm test recorded as PASS — confirming evidence
|
|
231
231
|
printf '%s\n' '{"command":"npm test","observedResult":"pass","exitCode":0,"capturedAt":"2026-06-27T00:00:00Z","source":"postToolUse-capture"}' \
|
|
232
|
-
> "$T2/.flow-agents/declared-pass/command-log.jsonl"
|
|
232
|
+
> "$T2/.kontourai/flow-agents/declared-pass/command-log.jsonl"
|
|
233
233
|
|
|
234
234
|
set +e
|
|
235
235
|
t2_out="$(FLOW_AGENTS_GOAL_FIT_MODE=block \
|
|
@@ -260,12 +260,12 @@ seed_repo "$T3" "wf-false"
|
|
|
260
260
|
|
|
261
261
|
# No current.json active flow → loadActiveFlowStep returns null → workflow.* fallback
|
|
262
262
|
printf '%s' '{"artifact_dir":"wf-false"}' \
|
|
263
|
-
> "$T3/.flow-agents/current.json"
|
|
263
|
+
> "$T3/.kontourai/flow-agents/current.json"
|
|
264
264
|
|
|
265
|
-
python3 - "$T3/.flow-agents/wf-false/trust.bundle" << 'PY'
|
|
265
|
+
python3 - "$T3/.kontourai/flow-agents/wf-false/trust.bundle" << 'PY'
|
|
266
266
|
import json, sys
|
|
267
267
|
bundle = {
|
|
268
|
-
"schemaVersion":
|
|
268
|
+
"schemaVersion": 5,
|
|
269
269
|
"source": "flow-agents/workflow-sidecar",
|
|
270
270
|
"claims": [{
|
|
271
271
|
"id": "c3",
|
|
@@ -302,7 +302,7 @@ PY
|
|
|
302
302
|
|
|
303
303
|
# command-log: npm test recorded as FAIL
|
|
304
304
|
printf '%s\n' '{"command":"npm test","observedResult":"fail","exitCode":1,"capturedAt":"2026-06-27T00:00:00Z","source":"postToolUse-capture"}' \
|
|
305
|
-
> "$T3/.flow-agents/wf-false/command-log.jsonl"
|
|
305
|
+
> "$T3/.kontourai/flow-agents/wf-false/command-log.jsonl"
|
|
306
306
|
|
|
307
307
|
set +e
|
|
308
308
|
t3_out="$(FLOW_AGENTS_GOAL_FIT_MODE=block \
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# claimed-pass command, and that a matching capture log lets Stop through.
|
|
7
7
|
#
|
|
8
8
|
# Mirrors prove-teeth.sh: installs each bundle and runs the installed hook commands
|
|
9
|
-
# with seeded .flow-agents state, exactly as the runtime would on PostToolUse / Stop.
|
|
9
|
+
# with seeded .kontourai/flow-agents state, exactly as the runtime would on PostToolUse / Stop.
|
|
10
10
|
#
|
|
11
11
|
# Usage: bash evals/acceptance/prove-capture-teeth.sh
|
|
12
12
|
set -uo pipefail
|
|
@@ -34,12 +34,12 @@ PY
|
|
|
34
34
|
# Seed: model CLAIMS the command passed (evidence.json) but the deterministic
|
|
35
35
|
# capture log recorded it as FAIL — a false-completion the gate must catch.
|
|
36
36
|
seed_capture_false_pass(){ # $1 project dir
|
|
37
|
-
local p="$1"; mkdir -p "$p/.flow-agents/cap-false"
|
|
37
|
+
local p="$1"; mkdir -p "$p/.kontourai/flow-agents/cap-false"
|
|
38
38
|
[ -f "$p/AGENTS.md" ] || printf '# Repo\n' > "$p/AGENTS.md"
|
|
39
|
-
printf '%s' '{"schema_version":"1.0","task_slug":"cap-false","status":"delivered","phase":"done","updated_at":"2026-06-23T00:00:00Z","next_action":{"status":"done","summary":"done"}}' > "$p/.flow-agents/cap-false/state.json"
|
|
40
|
-
printf '%s' '{"schema_version":"1.0","task_slug":"cap-false","verdict":"pass","checks":[{"id":"unit-tests","kind":"command","status":"pass","command":"npm test","summary":"tests passed"}]}' > "$p/.flow-agents/cap-false/evidence.json"
|
|
41
|
-
printf '%s\n' '{"command":"npm test","observedResult":"fail","exitCode":1,"capturedAt":"2026-06-23T00:00:00Z","source":"postToolUse-capture"}' > "$p/.flow-agents/cap-false/command-log.jsonl"
|
|
42
|
-
cat > "$p/.flow-agents/cap-false/cap-false--deliver.md" <<'MD'
|
|
39
|
+
printf '%s' '{"schema_version":"1.0","task_slug":"cap-false","status":"delivered","phase":"done","updated_at":"2026-06-23T00:00:00Z","next_action":{"status":"done","summary":"done"}}' > "$p/.kontourai/flow-agents/cap-false/state.json"
|
|
40
|
+
printf '%s' '{"schema_version":"1.0","task_slug":"cap-false","verdict":"pass","checks":[{"id":"unit-tests","kind":"command","status":"pass","command":"npm test","summary":"tests passed"}]}' > "$p/.kontourai/flow-agents/cap-false/evidence.json"
|
|
41
|
+
printf '%s\n' '{"command":"npm test","observedResult":"fail","exitCode":1,"capturedAt":"2026-06-23T00:00:00Z","source":"postToolUse-capture"}' > "$p/.kontourai/flow-agents/cap-false/command-log.jsonl"
|
|
42
|
+
cat > "$p/.kontourai/flow-agents/cap-false/cap-false--deliver.md" <<'MD'
|
|
43
43
|
# Cap False
|
|
44
44
|
|
|
45
45
|
branch: main
|
|
@@ -76,15 +76,15 @@ run_bundle(){ # $1 label, $2 install.sh, $3 settings-json-rel, $4 home-env-name
|
|
|
76
76
|
|
|
77
77
|
# The capture hook deterministically records a real command result through the
|
|
78
78
|
# installed adapter path.
|
|
79
|
-
mkdir -p "$proj/.flow-agents/live-cap"
|
|
79
|
+
mkdir -p "$proj/.kontourai/flow-agents/live-cap"
|
|
80
80
|
[ -f "$proj/AGENTS.md" ] || printf '# Repo\n' > "$proj/AGENTS.md"
|
|
81
|
-
printf '%s' '{"schema_version":"1.0","task_slug":"live-cap","status":"in_progress","phase":"verification","updated_at":"2026-06-23T00:00:00Z"}' > "$proj/.flow-agents/live-cap/state.json"
|
|
81
|
+
printf '%s' '{"schema_version":"1.0","task_slug":"live-cap","status":"in_progress","phase":"verification","updated_at":"2026-06-23T00:00:00Z"}' > "$proj/.kontourai/flow-agents/live-cap/state.json"
|
|
82
82
|
printf '{"hook_event_name":"PostToolUse","tool_name":"Bash","cwd":"%s","tool_input":{"command":"npm run lint"},"error":"command failed"}' "$proj" \
|
|
83
83
|
| env "$homevar=$home" CLAUDE_PROJECT_DIR="$home" bash -c "$capcmd" >/dev/null 2>&1 || true
|
|
84
|
-
if rg -q '"command":"npm run lint","observedResult":"fail"' "$proj/.flow-agents/live-cap/command-log.jsonl" 2>/dev/null; then
|
|
84
|
+
if rg -q '"command":"npm run lint","observedResult":"fail"' "$proj/.kontourai/flow-agents/live-cap/command-log.jsonl" 2>/dev/null; then
|
|
85
85
|
_p "$label capture hook records a real FAIL to command-log.jsonl through the installed adapter"
|
|
86
86
|
else
|
|
87
|
-
_f "$label capture hook did not record the command result: $(cat "$proj/.flow-agents/live-cap/command-log.jsonl" 2>/dev/null)"
|
|
87
|
+
_f "$label capture hook did not record the command result: $(cat "$proj/.kontourai/flow-agents/live-cap/command-log.jsonl" 2>/dev/null)"
|
|
88
88
|
fi
|
|
89
89
|
|
|
90
90
|
# --- Teeth: claims-pass-but-log-shows-fail → Stop is BLOCKED ---
|
|
@@ -95,7 +95,7 @@ run_bundle(){ # $1 label, $2 install.sh, $3 settings-json-rel, $4 home-env-name
|
|
|
95
95
|
echo "$blk" | is_block && _p "$label BLOCKS a claimed-pass command that the capture log recorded as FAIL" || _f "$label did NOT block the captured false-completion: $blk"
|
|
96
96
|
|
|
97
97
|
# control: a matching capture log (pass) lets Stop through on the capture axis.
|
|
98
|
-
printf '%s\n' '{"command":"npm test","observedResult":"pass","exitCode":0,"capturedAt":"2026-06-23T00:00:00Z","source":"postToolUse-capture"}' > "$proj/.flow-agents/cap-false/command-log.jsonl"
|
|
98
|
+
printf '%s\n' '{"command":"npm test","observedResult":"pass","exitCode":0,"capturedAt":"2026-06-23T00:00:00Z","source":"postToolUse-capture"}' > "$proj/.kontourai/flow-agents/cap-false/command-log.jsonl"
|
|
99
99
|
local okblk; okblk="$(printf '{"hook_event_name":"Stop","cwd":"%s"}' "$proj" | env "$homevar=$home" CLAUDE_PROJECT_DIR="$home" FLOW_AGENTS_GOAL_FIT_BACKSTOP=skip bash -c "$stopcmd" 2>&1)"
|
|
100
100
|
if echo "$okblk" | grep -q 'caught false-completion'; then
|
|
101
101
|
_f "$label control: a confirming capture log should not raise a false-completion"
|
|
@@ -113,7 +113,7 @@ MARKDOWN
|
|
|
113
113
|
stop_output="$(cd "$TMP_WORK" && FLOW_AGENTS_GOAL_FIT_STRICT=true kiro-cli chat --agent dev --no-interactive "Reply with READY only." 2>&1 || true)"
|
|
114
114
|
stop_clean="$(printf '%s' "$stop_output" | strip_ansi)"
|
|
115
115
|
if echo "$stop_clean" | grep -q 'stop "node .*stop:goal-fit stop-goal-fit.js standard,strict" failed with exit code: 2' \
|
|
116
|
-
&& echo "$stop_clean" | grep -q '\[
|
|
116
|
+
&& echo "$stop_clean" | grep -q '\[stop-gate\] Goal Fit warning:' \
|
|
117
117
|
&& echo "$stop_clean" | grep -q 'live-stop--deliver.md is still status:executing'; then
|
|
118
118
|
_pass "strict Goal Fit stop hook surfaces live Kiro stop gate"
|
|
119
119
|
else
|