@kontourai/flow-agents 3.6.0 → 3.7.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 (86) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/build/src/builder-flow-run-adapter.d.ts +22 -2
  3. package/build/src/builder-flow-run-adapter.js +93 -28
  4. package/build/src/builder-flow-runtime.d.ts +8 -3
  5. package/build/src/builder-flow-runtime.js +308 -47
  6. package/build/src/cli/assignment-provider.d.ts +4 -7
  7. package/build/src/cli/assignment-provider.js +67 -13
  8. package/build/src/cli/builder-run.js +14 -18
  9. package/build/src/cli/workflow-sidecar.d.ts +28 -4
  10. package/build/src/cli/workflow-sidecar.js +801 -97
  11. package/build/src/cli/workflow.js +290 -42
  12. package/build/src/flow-kit/validate.d.ts +17 -0
  13. package/build/src/flow-kit/validate.js +340 -2
  14. package/build/src/index.js +5 -5
  15. package/build/src/lib/observed-command.d.ts +7 -0
  16. package/build/src/lib/observed-command.js +100 -0
  17. package/build/src/tools/generate-context-map.js +5 -3
  18. package/context/scripts/hooks/lib/kit-catalog.js +1 -1
  19. package/context/scripts/hooks/stop-goal-fit.js +78 -9
  20. package/docs/context-map.md +22 -20
  21. package/docs/developer-architecture.md +1 -1
  22. package/docs/public-workflow-cli.md +76 -7
  23. package/docs/skills-map.md +51 -27
  24. package/docs/spec/builder-flow-runtime.md +41 -40
  25. package/docs/workflow-usage-guide.md +109 -42
  26. package/evals/fixtures/hook-influence/cases.json +2 -2
  27. package/evals/integration/test_builder_entry_enforcement.sh +52 -41
  28. package/evals/integration/test_builder_step_producers.sh +297 -6
  29. package/evals/integration/test_bundle_install.sh +212 -63
  30. package/evals/integration/test_critique_supersession_roundtrip.sh +21 -8
  31. package/evals/integration/test_current_json_per_actor.sh +12 -0
  32. package/evals/integration/test_dual_emit_flow_step.sh +62 -43
  33. package/evals/integration/test_flowdef_session_activation.sh +145 -25
  34. package/evals/integration/test_flowdef_session_history_preservation.sh +23 -21
  35. package/evals/integration/test_gate_lockdown.sh +3 -5
  36. package/evals/integration/test_goal_fit_hook.sh +60 -2
  37. package/evals/integration/test_liveness_verdict.sh +14 -17
  38. package/evals/integration/test_phase_map_and_gate_claim.sh +63 -38
  39. package/evals/integration/test_public_workflow_cli.sh +325 -11
  40. package/evals/integration/test_pull_work_liveness_preflight.sh +22 -66
  41. package/evals/integration/test_sidecar_field_preservation.sh +36 -11
  42. package/evals/integration/test_workflow_sidecar_writer.sh +277 -44
  43. package/evals/integration/test_workflow_steering_hook.sh +15 -38
  44. package/evals/run.sh +2 -0
  45. package/evals/static/test_builder_skill_coherence.sh +247 -0
  46. package/evals/static/test_library_exports.sh +5 -2
  47. package/evals/static/test_workflow_skills.sh +13 -325
  48. package/kits/builder/flows/build.flow.json +22 -0
  49. package/kits/builder/flows/shape.flow.json +9 -9
  50. package/kits/builder/kit.json +70 -16
  51. package/kits/builder/skills/builder-shape/SKILL.md +75 -75
  52. package/kits/builder/skills/continue-work/SKILL.md +45 -106
  53. package/kits/builder/skills/deliver/SKILL.md +96 -442
  54. package/kits/builder/skills/design-probe/SKILL.md +40 -139
  55. package/kits/builder/skills/evidence-gate/SKILL.md +59 -201
  56. package/kits/builder/skills/execute-plan/SKILL.md +54 -125
  57. package/kits/builder/skills/fix-bug/SKILL.md +42 -132
  58. package/kits/builder/skills/gate-review/SKILL.md +60 -211
  59. package/kits/builder/skills/idea-to-backlog/SKILL.md +63 -244
  60. package/kits/builder/skills/learning-review/SKILL.md +63 -170
  61. package/kits/builder/skills/pickup-probe/SKILL.md +54 -111
  62. package/kits/builder/skills/plan-work/SKILL.md +51 -185
  63. package/kits/builder/skills/pull-work/SKILL.md +136 -485
  64. package/kits/builder/skills/release-readiness/SKILL.md +66 -107
  65. package/kits/builder/skills/review-work/SKILL.md +89 -176
  66. package/kits/builder/skills/tdd-workflow/SKILL.md +53 -147
  67. package/kits/builder/skills/verify-work/SKILL.md +101 -113
  68. package/package.json +2 -2
  69. package/scripts/hooks/lib/kit-catalog.js +1 -1
  70. package/scripts/hooks/stop-goal-fit.js +78 -9
  71. package/src/builder-flow-run-adapter.ts +118 -32
  72. package/src/builder-flow-runtime.ts +331 -61
  73. package/src/cli/assignment-provider-lock.test.mjs +83 -0
  74. package/src/cli/assignment-provider.ts +62 -13
  75. package/src/cli/builder-flow-run-adapter.test.mjs +4 -2
  76. package/src/cli/builder-flow-runtime.test.mjs +194 -8
  77. package/src/cli/builder-run.ts +3 -9
  78. package/src/cli/kit-metadata-security.test.mjs +232 -6
  79. package/src/cli/public-api.test.mjs +15 -0
  80. package/src/cli/workflow-sidecar-execution-proof.test.mjs +90 -0
  81. package/src/cli/workflow-sidecar.ts +724 -97
  82. package/src/cli/workflow.ts +277 -40
  83. package/src/flow-kit/validate.ts +320 -2
  84. package/src/index.ts +6 -5
  85. package/src/lib/observed-command.ts +96 -0
  86. package/src/tools/generate-context-map.ts +5 -3
@@ -1,159 +1,65 @@
1
1
  ---
2
2
  name: "tdd-workflow"
3
- description: "Test-driven development RED → GREEN → REFACTOR with git checkpoints. Wraps plan-work execute-plan review-work verify-work with test-first constraints and coverage gates."
3
+ description: "Test-first profile for builder.build. Requires observable RED, GREEN, and appropriate REFACTOR evidence through the standard build primitives."
4
4
  ---
5
5
 
6
6
  # TDD Workflow
7
7
 
8
- Test-driven development orchestrator. Wraps the standard plan → execute → verify chain with test-first constraints.
8
+ ## Role and Boundary
9
9
 
10
- ## When to Activate
10
+ **Role:** test-first `builder.build` profile.
11
11
 
12
- - User says "use TDD", "test-driven", "write tests first", "TDD"
13
- - User asks to build something and mentions test coverage requirements
12
+ Select this profile only when the user requests test-driven development or when
13
+ the selected Work Item explicitly requires a test-first approach. It constrains
14
+ the standard build primitives; it is not a separate flow and does not replace
15
+ `deliver` as the build entrypoint.
14
16
 
15
- ## Agents
16
-
17
- Same as deliver (inherited from primitives):
18
-
19
- | Agent | Used by |
20
- |---|---|
21
- | tool-planner | plan-work (with TDD constraints) |
22
- | tool-worker (x4) | execute-plan (tests first, then implementation) |
23
- | tool-code-reviewer | review-work |
24
- | tool-security-reviewer | review-work (conditional) |
25
- | tool-verifier | verify-work (with coverage check) |
26
- | tool-playwright | verify-work (if UI) |
17
+ The profile owns **no step-gate evidence**. The plan, execution, review, and
18
+ verification primitives own the artifacts and evidence for their respective
19
+ steps.
27
20
 
28
21
  ## Model Routing
29
22
 
30
- Delegates are spawned with an explicit model override resolved from
31
- `.datum/config.json` via `npx @kontourai/datum resolve <role> --json` see
32
- `context/contracts/execution-contract.md` § Delegation: Model Routing:
33
-
34
- | Delegate | Role |
35
- |---|---|
36
- | tool-worker | `delegate-mechanical` for fully-specified mechanical slices, `delegate-implementation` for precisely-planned implementation (RED/GREEN/REFACTOR), `delegate-design` when a slice needs design latitude |
37
- | tool-planner | `delegate-design` |
38
- | tool-code-reviewer / tool-security-reviewer | `delegate-implementation` by default, raised to the worker's tier when higher never below the tier of the checked work (Goodhart guard) |
39
- | tool-verifier / tool-playwright | `delegate-implementation` by default, raised to the worker's tier when higher — never below the tier of the checked work (Goodhart guard) |
40
-
41
- On a review/verify gate failure, re-dispatch the fix one tier higher and record
42
- the escalation (contract § Escalation on gate failure). Fallback: inherit the
43
- session model when datum/config is absent, noted in the artifact.
44
-
45
- ## Orchestrator Rule
46
-
47
- Same as deliver: you never touch source files. You coordinate the primitives with TDD-specific context.
48
-
49
- ## Workflow
50
-
51
- ### 1. Create session file
52
-
53
- Filename: `<branch>--tdd-<slug>.md`
54
- Set `status: planning`, `type: tdd`, `iteration: 0`
55
-
56
- ### 2. Plan (plan-work with TDD constraint)
57
-
58
- Invoke plan-work with additional constraint:
59
- ```
60
- Constraint: TEST-FIRST DEVELOPMENT
61
- - Plan MUST include test files as separate tasks in Wave 1
62
- - Each feature task must have a corresponding test task that precedes it
63
- - Test tasks specify: test file path, test cases to write, expected failures
64
- - Implementation tasks specify: which tests they make pass
65
- - Include a final "coverage check" task
66
- ```
67
-
68
- Present plan to user. Get approval.
69
-
70
- ### 3. Execute RED phase
71
-
72
- Invoke execute-plan for Wave 1 only (test tasks):
73
- - tool-worker writes test files
74
- - After Wave 1 completes, run the tests — they MUST fail (RED)
75
- - If tests pass (no RED state), the tests are wrong — flag to user
76
- - Git checkpoint: `test: add failing tests for <feature>`
77
-
78
- ### 4. Execute GREEN phase
79
-
80
- Invoke execute-plan for Wave 2 (implementation tasks):
81
- - tool-worker writes minimal code to make tests pass
82
- - After Wave 2 completes, run the tests — they MUST pass (GREEN)
83
- - If tests still fail, loop: re-invoke execute-plan with failure context
84
- - Git checkpoint: `feat: implement <feature> (tests passing)`
85
-
86
- ### 5. Execute REFACTOR phase
87
-
88
- Invoke execute-plan for Wave 3 (refactor tasks, if any):
89
- - tool-worker improves code quality while keeping tests green
90
- - After Wave 3, run tests again — must still pass
91
- - Git checkpoint: `refactor: clean up <feature>`
92
-
93
- ### 6. Review (review-work)
94
-
95
- Invoke `review-work` after GREEN/REFACTOR and before verification. Review findings must be fixed, accepted, deferred, or marked false positive before delivery.
96
-
97
- ### 7. Verify (verify-work with coverage gate)
98
-
99
- Invoke verify-work with additional context:
100
- ```
101
- Additional verification: Check test coverage.
102
- Run coverage command and verify >= 80% on changed files.
103
- Include coverage % in the verification report.
104
- If coverage < 80%, verdict is FAIL with coverage gap details.
105
- ```
106
-
107
- ### 8. Route on verdict
108
-
109
- Same as deliver:
110
- - **Clean review + all PASS + coverage >= 80%** → deliver
111
- - **Any FAIL or coverage < 80%** → loop (re-plan failing items)
112
- - **NOT_VERIFIED** → surface to user
113
-
114
- ### 9. Deliver
115
-
116
- Same as deliver, plus:
117
- - Report TDD cycle summary: RED → GREEN → REFACTOR with checkpoint SHAs
118
- - Report final coverage %
119
-
120
- ## Session File Format
121
-
122
- ```markdown
123
- # TDD: <Goal one-liner>
124
-
125
- branch: <branch>
126
- created: <date>
127
- status: planning | red | green | refactor | verifying | delivered
128
- type: tdd
129
- iteration: 0
130
- coverage_target: 80
131
-
132
- ## Plan
133
- (from plan-work)
134
-
135
- ## RED Phase
136
- - Tests written: <list>
137
- - All failing: YES/NO
138
- - Checkpoint: <SHA>
139
-
140
- ## GREEN Phase
141
- - Implementation: <list>
142
- - All passing: YES/NO
143
- - Checkpoint: <SHA>
144
-
145
- ## REFACTOR Phase
146
- - Changes: <list>
147
- - Tests still passing: YES/NO
148
- - Checkpoint: <SHA>
149
-
150
- ## Verification Report
151
- (from verify-work)
152
-
153
- ## History
154
- - iteration 1: RED ✓, GREEN ✓, REFACTOR ✓, coverage 85%
155
- ```
156
-
157
- `<branch>` is the branch recorded in `state.json`'s `branch` field (`ensure-session` derives `agent/<actor>/<slug>`; an explicit `--branch` flag overrides on a new session). `ensure-session` only records the name — creating and checking out the actual git branch/worktree remains this skill's responsibility.
158
-
159
- {context?}
23
+ Use `delegate-mechanical` for test and check bookkeeping, `delegate-design` for
24
+ acceptance and test design, and `delegate-implementation` for the red-green-
25
+ refactor implementation and its review. Resolve roles from `.datum/config.json`
26
+ under `context/contracts/execution-contract.md` and record fallbacks or
27
+ escalations.
28
+
29
+ ## Inputs and Provider Adapters
30
+
31
+ Use the selected Work Item's acceptance criteria, Repository adapter test
32
+ conventions and commands, and Change-adapter risk context. A remote issue or
33
+ pull request may supply these inputs, but no particular provider is required.
34
+
35
+ ## Profile Behavior
36
+
37
+ 1. Select `builder.build` through `deliver`, recording the `tdd-workflow`
38
+ profile in planning context.
39
+ 2. Have `plan-work` identify test scenarios before the implementation tasks,
40
+ including what behavior each test should demonstrate and why it should fail
41
+ against the pre-change behavior.
42
+ 3. Have `execute-plan` make the tests demonstrably fail for the intended
43
+ reason before implementation, then make them pass with the smallest adequate
44
+ change.
45
+ 4. Refactor only while the relevant tests remain passing. Use checkpoints when
46
+ the Repository adapter's practice calls for them; do not impose a commit
47
+ pattern.
48
+ 5. Have review and verification evaluate the test quality, changed behavior,
49
+ relevant regression coverage, and any project-defined coverage requirement.
50
+
51
+ Do not require an arbitrary numeric coverage percentage. Coverage targets come
52
+ from the Work Item, repository policy, or an explicit user decision.
53
+
54
+ ## Output Responsibility
55
+
56
+ This profile creates no independent artifact or evidence. Its output is the
57
+ test-first constraints and RED/GREEN/REFACTOR observations carried by the
58
+ standard primitive artifacts and final delivery report.
59
+
60
+ ## Standalone and No-Active-Run Behavior
61
+
62
+ `tdd-workflow` does not start or resume a run itself. With no active run,
63
+ route to `deliver` to select and start `builder.build` with this profile. With
64
+ an active run, apply it only when doing so is compatible with the current Work
65
+ Item and canonical next action; otherwise surface the conflict.
@@ -1,127 +1,115 @@
1
1
  ---
2
2
  name: "verify-work"
3
- description: "Verification primitive session file path to structured evidence verdict via tool-verifier + tool-playwright. Reads acceptance criteria from plan artifact."
3
+ description: "Report-only acceptance verification. Records command-backed Builder verification evidence in trust.bundle when bound to an active run."
4
4
  ---
5
5
 
6
- # Verify
6
+ # Verify Work
7
7
 
8
- Session file in, structured evidence verdict out. Delegates to tool-verifier and tool-playwright.
8
+ ## Role
9
9
 
10
- Verification is not critique. Run `review-work` first when the task needs maintainability, security, architecture, or standards review. Verification should start only after the required critique gate has been recorded or explicitly marked `not_verified`. `verify-work` records proof in `evidence.json`; `review-work` records critique through the critique artifact/sink, currently `critique.json` locally.
10
+ This is a Builder step skill.
11
11
 
12
- ## Agents
12
+ Verify Work proves acceptance criteria with reproducible evidence. It is
13
+ report-only: verifiers may inspect, test, and write evidence artifacts, but do
14
+ not patch source files or apply autofixes.
13
15
 
14
- | Agent | Role |
15
- |---|---|
16
- | tool-verifier | Code verification, acceptance criteria checking, structured verdicts |
17
- | tool-playwright | Visual verification, screenshots, accessibility checks |
16
+ Critique belongs to `review-work`; behavior proof belongs here.
17
+
18
+ ## Binding
19
+
20
+ | Context | Binding | Flow expectations |
21
+ | --- | --- | --- |
22
+ | Active Builder run | `builder.build` at `verify` | `acceptance-criteria` and `tests-evidence`; `policy-compliance` only when applicable. `review-work` separately produces `clean-critique`. |
23
+ | Standalone invocation | No Flow binding | No workflow mutation. |
24
+
25
+ For an active run, verify the binding first:
26
+
27
+ ```bash
28
+ flow-agents workflow status --session-dir <session-dir> --json
29
+ ```
30
+
31
+ Only a matching active `builder.build` run at `verify` may receive workflow
32
+ evidence. Otherwise, return the verification report and unresolved gaps without
33
+ calling `workflow evidence`.
18
34
 
19
35
  ## Model Routing
20
36
 
21
- Verify roles never resolve **below** the tier of the work they check (Goodhart
22
- guard): default `delegate-implementation`, raised to match or exceed the tier
23
- that produced the work under verification a verifier of `delegate-design` work
24
- resolves `delegate-design` or `orchestrator`, never a cheaper tier. Resolve the
25
- role from `.datum/config.json` (`npx @kontourai/datum resolve <role> --json`) and
26
- pass the model explicitly. See `context/contracts/execution-contract.md`
27
- § Delegation: Model Routing and § Goodhart guard. Fallback: inherit the session
28
- model when datum/config is absent, noted in the artifact.
29
-
30
- ## Orchestrator Rule
31
-
32
- You do not review source files. You delegate to tool-verifier and tool-playwright, then read the verdict artifact.
33
-
34
- ## Shared Contracts
35
-
36
- Follow:
37
- - `context/contracts/artifact-contract.md`
38
- - `context/contracts/verification-contract.md`
39
- - `context/contracts/planning-contract.md` for acceptance criteria and Definition Of Done
40
-
41
- This skill owns orchestration and routing. The verification contract owns phases, report-only behavior, verdict rules, report shape, Goal Fit checks, and `NOT_VERIFIED` handling.
42
-
43
- ## Read-Only Rule (STRICT)
44
-
45
- **Verifiers NEVER modify source code.** tool-verifier and tool-playwright are read-only reporters:
46
- - They may run commands (build, test, lint) but NEVER apply fixes
47
- - No format fixes, no lint auto-fixes, no "1 format fix applied"
48
- - No code patches, no "found and fixed" — report findings only
49
- - If a fix is needed, report it as a finding. The orchestrator routes it back to execute-plan.
50
-
51
- ## Input
52
-
53
- - **Session file path**: the session file in `.kontourai/flow-agents/<slug>/` (preferred)
54
- - The session file references the plan artifact (which has acceptance criteria) and execution progress (which has modified files)
55
- - If NO session file exists, delegate to tool-verifier directly (see Standalone Verification below)
56
-
57
- ## Standalone Verification (no session file)
58
-
59
- When invoked without a session file (e.g., user says "verify this project" or "run verification"):
60
-
61
- 1. Delegate to tool-verifier with:
62
- - The user's verification request
63
- - The current working directory
64
- - Modified files from `git diff --name-only` (if available)
65
- 2. Delegate to tool-playwright in parallel if UI changes are mentioned
66
- 3. Read the verdict and report to the user
67
-
68
- Skip session file lookup go straight to delegation.
69
-
70
- ## Workflow (with session file)
71
-
72
- 1. Read the session file to find the plan artifact path and modified files
73
- 2. Confirm the review-before-verify gate: the critique artifact/sink should show the required review pass, blocking findings, or an explicit `not_verified` gap. If the critique gate is missing for work that requires review, stop and route to `review-work` instead of treating verification as a substitute critique.
74
- 3. Set session file `status: verifying` and update `state.json` phase/status. Use `npm run workflow:sidecar -- advance-state <artifact-dir> --status verifying --phase verification --summary ... --next-action ...` when the repository provides it.
75
- 4. Delegate in parallel:
76
- ```
77
- tool-verifier:
78
- - Acceptance criteria from plan artifact
79
- - Acceptance criteria from acceptance.json when present
80
- - Definition Of Done and stop-short risks from plan artifact
81
- - Modified files from execution progress
82
- - Requirement to preserve each AC id and map it to command/test evidence plus structured source evidence refs when implementation behavior is claimed
83
- - Evidence ref schema: objects with `kind`, `url`, `file`, `line_start`, `line_end`, and `excerpt` where applicable; source refs require local file/line/excerpt and should use immutable GitHub blob permalinks pinned to a commit SHA when provider URLs are available
84
- - Build/test commands from AGENTS.md or plan
85
- - todo_file path for writing verdict artifact
86
- - Workflow artifact root path; append verifier progress with record-agent-event
87
-
88
- tool-playwright (if UI changes exist):
89
- - Pages/components to check
90
- - Expected visual state
91
- - Workflow artifact root path; append browser evidence or blockers with record-agent-event
92
- ```
93
- 5. Read the verdict artifact: `<session-basename>-review.md`
94
- 6. Update session file: paste verdict summary into `## Verification Report`
95
- 7. Write or update `evidence.json` with verification checks, top-level verdict, and `not_verified_gaps`
96
- - use `npm run workflow:sidecar -- record-evidence <artifact-dir> --verdict ... --check-json ...` when the repository provides it
97
- - `checks[].artifact_refs` must use structured evidence ref objects, not legacy strings
98
- - for multi-repo or cross-product work, preserve a coverage matrix in the
99
- evidence report or check summaries that lists each affected root and its
100
- build/test, dependency/security, provider/CI, and accepted-gap status
101
- - if external dependency audit or provider checks are blocked by approval,
102
- privacy, credentials, network, or missing change-provider state, record the
103
- affected roots as `not_verified` instead of collapsing the lane into a
104
- generic pass/fail
105
- 8. Update `acceptance.json` with criterion statuses and structured evidence refs
106
- - `criteria[].evidence_refs` must use structured evidence refs and map each AC id to command/test proof plus source refs for behavior claims
107
- - when source refs are missing for a behavior claim, mark the criterion `not_verified` or record an accepted gap instead of using broad prose-only evidence
108
- 9. Route on verdicts:
109
- - **All PASS** → set `status: verified`
110
- - **Any FAIL** → set `status: failed`, list failures
111
- - **Any NOT_VERIFIED** → set Markdown status `needs-decision`, set `state.json` status `needs_decision`, and surface to user
112
-
113
- ## Verification Contract
114
-
115
- tool-verifier writes the verdict artifact using `context/contracts/verification-contract.md`.
116
-
117
- You do not override verdicts. FAIL is FAIL until re-verified. `NOT_VERIFIED` items are surfaced to the user so they can decide whether to accept, fix, or skip. A technically green build is not enough for PASS when the `Definition Of Done` says the user still cannot run, understand, inspect, or act on the result.
37
+ Resolve `delegate-implementation` from `.datum/config.json` and follow
38
+ `context/contracts/execution-contract.md`. The Goodhart guard applies:
39
+ verification must never resolve below the reasoning tier of the checked work.
40
+ Record any fallback or escalation in the verification report.
41
+
42
+ ## Inputs
43
+
44
+ - Acceptance criteria, Definition Of Done, and stop-short risks.
45
+ - Changed-file scope from the session, plan, or `RepositoryAdapter`.
46
+ - Local checks and runtime evidence selected for the change.
47
+ - Relevant `CheckProvider` and `ChangeProvider` evidence when it exists.
48
+ - The `trust.bundle` critique slice when review is required; critique findings
49
+ remain separate from verification evidence.
50
+
51
+ ## Verification Work
52
+
53
+ 1. Re-check Goal Fit before testing: compare the delivered artifacts and actual
54
+ changed scope with the selected Work Item, Definition Of Done, acceptance
55
+ criteria, and stop-short risks. Missing requested behavior or unexplained
56
+ scope routes back even when the implementation plan was completed.
57
+ 2. Map each acceptance criterion to an observable check, source inspection, or
58
+ runtime observation. Delegate to `tool-verifier`; include `tool-playwright`
59
+ for browser-facing behavior.
60
+ 3. Run relevant build, type, lint, test, security, diff, browser, runtime, and
61
+ provider checks. `CheckProvider` evidence is provider-neutral; a provider
62
+ check is not assumed to exist for every repository.
63
+ 4. Record every criterion as `PASS`, `FAIL`, `NOT_VERIFIED`, or an explicitly
64
+ accepted gap. Missing, inaccessible, or inconclusive evidence is
65
+ `NOT_VERIFIED`, never `PASS`.
66
+ Reject prose-only claims and non-resolving references. Evidence references
67
+ must identify a command result, source location, provider record, runtime
68
+ observation, or artifact that a reviewer can inspect. A passing
69
+ `tests-evidence` claim needs every declared criterion exactly once, and every
70
+ passing criterion needs a `kind:"command"` reference whose command text
71
+ exactly matches one of the substantive `--command` values that ran
72
+ successfully. External-only attestations cannot satisfy it.
73
+ 5. Publish the relevant active-run expectation through the public CLI with one
74
+ or more exact commands that produced the test results. Repeat `--command`
75
+ when criteria require different checks, and include a matching top-level
76
+ `--evidence-ref-json` for every recorded command. A prose summary or an
77
+ artifact reference alone cannot satisfy `tests-evidence`:
78
+
79
+ ```bash
80
+ flow-agents workflow evidence --session-dir <session-dir> \
81
+ --expectation tests-evidence \
82
+ --status <pass|fail|not_verified> \
83
+ --command "npm test" \
84
+ --summary "The recorded test command supports the accepted behavior." \
85
+ --evidence-ref-json '{"kind":"command","excerpt":"npm test","summary":"Exact substantive project test command recorded for this verification result."}' \
86
+ --criterion-json '{"id":"<criterion-id>","status":"pass","evidence_refs":[{"kind":"command","excerpt":"npm test","summary":"Exact substantive project test command run for this criterion."}]}' \
87
+ --evidence-ref-json '{"kind":"artifact","file":"<session-dir>/<slug>--plan-work.md","summary":"Accepted criterion and planned verification mapping."}'
88
+ ```
89
+
90
+ When a policy check applies, publish `policy-compliance` in the same way. Do
91
+ not publish that optional expectation when no policy check applies.
118
92
 
119
93
  ## Output
120
94
 
121
- - Verdict artifact: `<session-basename>-review.md`
122
- - Session file updated with verification report and status
123
- - Structured sidecars updated: `state.json`, `acceptance.json`, and `evidence.json`
124
- - Acceptance evidence preserves AC ids and uses structured evidence refs; prose-only behavior claims are not clean verification evidence
125
- - Verdict follows `context/contracts/verification-contract.md`
126
-
127
- If `record-evidence` or artifact validation is unavailable or blocked, keep the verdict explicit and record the sidecar-write gap as `NOT_VERIFIED`. Do not convert verifier output into `PASS` without structured evidence when sidecars are required.
95
+ Record completed criteria as the required `acceptance-criteria` slice and the
96
+ verification result as the `tests-evidence` slice in `trust.bundle`.
97
+ It must preserve criterion identifiers and include a readable `Acceptance
98
+ Evidence` table in its summary or linked reviewable report:
99
+
100
+ | AC id | Status | Command/Test Evidence | Source Evidence | Gaps |
101
+ | --- | --- | --- | --- | --- |
102
+ | `<id>` | `PASS`, `FAIL`, or `NOT_VERIFIED` | Command, result, or observation | File, test, provider, or runtime reference | Missing or accepted evidence |
103
+
104
+ The result states the overall verification verdict and every unresolved gap.
105
+ For an active matching run, publish one `--criterion-json` object for every
106
+ accepted criterion, each with its own status and reviewable evidence refs, plus
107
+ a substantive literal `--command` for every distinct check that was run. Every
108
+ top-level and criterion command reference must exactly match one of those
109
+ commands. The public evidence calls
110
+ publish `acceptance-criteria`, `tests-evidence`, and applicable
111
+ `policy-compliance`; no retired
112
+ verification sidecar is a store. Never publish a placeholder, `true`,
113
+ `bash -c true`, or `node --version` as behavior evidence. In a packed or
114
+ temporary consumer repository, use a real project-local test/check/verify
115
+ script rather than a command that exists only in the Flow Agents source repo.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontourai/flow-agents",
3
- "version": "3.6.0",
3
+ "version": "3.7.0",
4
4
  "description": "Flow Agents — a Kontour product that applies Flow and Veritas discipline as a portable process layer inside the agent tools you already use: Claude Code, Codex, Kiro, opencode, pi, and GitHub Actions — with framework adapters (AWS Strands preview) on the same policy-engine contract.",
5
5
  "keywords": [
6
6
  "agents",
@@ -149,7 +149,7 @@
149
149
  "typescript": "^6.0.3"
150
150
  },
151
151
  "dependencies": {
152
- "@kontourai/flow": "^3.1.0"
152
+ "@kontourai/flow": "^3.1.4"
153
153
  },
154
154
  "optionalDependencies": {
155
155
  "@kontourai/surface": "^2.0.0",
@@ -137,7 +137,7 @@ function renderKitSteering(trigger) {
137
137
  else lines.push(`Activate \`${defaultSkill}\`.`);
138
138
  }
139
139
  if (targetFlowId) {
140
- lines.push(`Keep the session on \`${targetFlowId}\` and use \`npm run workflow:sidecar -- ensure-session --flow-id ${targetFlowId} ...\` when the repo provides the sidecar writer.`);
140
+ lines.push(`Keep the session on \`${targetFlowId}\`. Use the public \`flow-agents workflow\` interface only when it supports that Flow and its Work Item binding; otherwise report an unsupported-runtime blocker. Never call the package-internal writer from skill guidance.`);
141
141
  }
142
142
  if (requiredSequence.length) {
143
143
  lines.push(`Do not bypass ${requiredSequence.join(' -> ')} for matching work.`);
@@ -1759,6 +1759,37 @@ function hasSidecarPresence(artifactDir) {
1759
1759
  return fs.existsSync(path.join(artifactDir, 'state.json')) || fs.existsSync(path.join(artifactDir, 'trust.bundle'));
1760
1760
  }
1761
1761
 
1762
+ function canonicalFlowState(root, artifactDir) {
1763
+ if (!artifactDir) return { state: null, error: null };
1764
+ const slug = path.basename(artifactDir);
1765
+ if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug)) return { state: null, error: 'canonical Flow run slug is malformed' };
1766
+ const runDir = path.join(root, '.kontourai', 'flow', 'runs', slug);
1767
+ const components = [
1768
+ path.join(root, '.kontourai'),
1769
+ path.join(root, '.kontourai', 'flow'),
1770
+ path.join(root, '.kontourai', 'flow', 'runs'),
1771
+ runDir,
1772
+ ];
1773
+ try {
1774
+ for (const component of components) {
1775
+ const stat = fs.lstatSync(component);
1776
+ if (stat.isSymbolicLink() || !stat.isDirectory()) return { state: null, error: `canonical Flow run has an unsafe parent component: ${component}` };
1777
+ }
1778
+ const file = path.join(runDir, 'state.json');
1779
+ const stat = fs.lstatSync(file);
1780
+ if (stat.isSymbolicLink() || !stat.isFile()) return { state: null, error: 'canonical Flow state must be a non-symlink regular file' };
1781
+ const state = JSON.parse(fs.readFileSync(file, 'utf8'));
1782
+ if (!state || typeof state !== 'object' || Array.isArray(state)
1783
+ || typeof state.status !== 'string' || !state.status.trim()
1784
+ || typeof state.current_step !== 'string' || !state.current_step.trim()) {
1785
+ return { state: null, error: 'canonical Flow state is malformed' };
1786
+ }
1787
+ return { state, error: null };
1788
+ } catch (error) {
1789
+ return { state: null, error: `canonical Flow state is unavailable or malformed: ${safeOneLine(error && error.message || error, 120)}` };
1790
+ }
1791
+ }
1792
+
1762
1793
  // WS8 (AC10a): when current.json names a slug whose session directory does NOT exist,
1763
1794
  // return that slug so analyze() can log the staleness rather than silently falling back to
1764
1795
  // a global mtime scan that could resurface an abandoned/never-real session as active.
@@ -1871,7 +1902,7 @@ function missingBundleOrStateSignal(artifactDir, activeFlowStep) {
1871
1902
  //
1872
1903
  // Both are used in analyze() for blocking decisions AND in run() for the AC2
1873
1904
  // MAX_BLOCKS hard-block guard (preventing auto-release of hard blocks).
1874
- const HARD_BLOCK = /contradicts evidence\.json|caught false-completion|evidence verdict:|evidence check .+ status:|critique status|critique open|required sidecar is missing|command-log integrity check FAILED|gate misconfiguration:|exit-code-laundered|NOT_VERIFIED \(ambiguous\)/;
1905
+ const HARD_BLOCK = /contradicts evidence\.json|caught false-completion|evidence verdict:|evidence check .+ status:|critique status|critique open|required sidecar is missing|command-log integrity check FAILED|gate misconfiguration:|exit-code-laundered|NOT_VERIFIED \(ambiguous\)|canonical Flow (?:run remains active|state is unsafe or malformed)/;
1875
1906
  // FULL_BLOCK adds: workflow-state hygiene, surface-unavailable fail-closed, missing log.
1876
1907
  const FULL_BLOCK = /status:|Definition Of Done|Goal Fit|sidecar validation:|contradicts evidence\.json|workflow state|evidence verdict|evidence check|NOT_VERIFIED gap|critique status|critique open|next action|caught false-completion|NOT_VERIFIED —|command-log integrity check FAILED|gate misconfiguration:|surface unavailable —|expected capture log is missing|exit-code-laundered|malformed-evidence|NOT_VERIFIED \(ambiguous\)/;
1877
1908
 
@@ -1897,7 +1928,31 @@ async function analyze(root, now = Date.now()) {
1897
1928
  artifacts = artifacts.filter(a => a && hasSidecarPresence(path.dirname(a.file)));
1898
1929
  }
1899
1930
 
1900
- if (artifacts.length === 0) return { warnings: [], blocking: false, latestArtifactDir: null };
1931
+ const scopedCanonicalFlow = canonicalFlowState(root, scoped);
1932
+ const scopedState = scoped ? readJsonFile(path.join(scoped, 'state.json')) : null;
1933
+ const scopedProjectedActive = Boolean(scopedState && scopedState.flow_run && normalizedStatus(scopedState.flow_run.status) === 'active');
1934
+ if (scopedProjectedActive && scopedCanonicalFlow.error) {
1935
+ return {
1936
+ warnings: [`workflow state: canonical Flow state is unsafe or malformed for the active scoped session: ${scopedCanonicalFlow.error}. Resolve the canonical run before stopping.`],
1937
+ blocking: true,
1938
+ activeFlowRun: true,
1939
+ latestArtifactDir: scoped,
1940
+ gatePrefix: '[stop-gate]',
1941
+ };
1942
+ }
1943
+ if (artifacts.length === 0) {
1944
+ if (normalizedStatus(scopedCanonicalFlow.state?.status) === 'active') {
1945
+ const activeStep = safeOneLine(scopedCanonicalFlow.state.current_step || 'unknown', 80);
1946
+ return {
1947
+ warnings: [`workflow state: canonical Flow run remains active at step ${activeStep}; complete or explicitly cancel the run before stopping.`],
1948
+ blocking: true,
1949
+ activeFlowRun: true,
1950
+ latestArtifactDir: scoped,
1951
+ gatePrefix: '[stop-gate]',
1952
+ };
1953
+ }
1954
+ return { warnings: [], blocking: false, activeFlowRun: false, latestArtifactDir: null };
1955
+ }
1901
1956
 
1902
1957
  const latest = artifacts[0];
1903
1958
  const latestArtifactDir = path.dirname(latest.file);
@@ -1965,14 +2020,25 @@ async function analyze(root, now = Date.now()) {
1965
2020
  // Use module-scope HARD_BLOCK / FULL_BLOCK (defined above analyze()).
1966
2021
  // pre-execution/terminal tasks: only HARD_BLOCK signals cause a block.
1967
2022
  // execution-onward tasks: FULL_BLOCK signals cause a block.
1968
- const activeFlowRun = gateState && gateState.flow_run && normalizedStatus(gateState.flow_run.status) === 'active';
2023
+ const canonicalFlow = canonicalFlowState(root, latestArtifactDir);
2024
+ const activeProjectedFlow = gateState && gateState.flow_run && normalizedStatus(gateState.flow_run.status) === 'active';
2025
+ const unsafeActiveCanonical = Boolean(activeProjectedFlow && canonicalFlow.error);
2026
+ if (unsafeActiveCanonical) {
2027
+ warnings.push(`workflow state: canonical Flow state is unsafe or malformed for the active scoped session: ${canonicalFlow.error}. Resolve the canonical run before stopping.`);
2028
+ }
2029
+ const activeFlowRun = normalizedStatus(canonicalFlow.state?.status) === 'active'
2030
+ || (gateState && gateState.flow_run && normalizedStatus(gateState.flow_run.status) === 'active');
2031
+ if (activeFlowRun && !warnings.some(w => /canonical Flow run remains active/.test(w))) {
2032
+ const activeStep = safeOneLine(canonicalFlow.state?.current_step || gateState?.flow_run?.current_step || 'unknown', 80);
2033
+ warnings.push(`workflow state: canonical Flow run remains active at step ${activeStep}; complete or explicitly cancel the run before stopping.`);
2034
+ }
1969
2035
  const blockRe = ((preExecution && !activeFlowRun) || terminal) ? HARD_BLOCK : FULL_BLOCK;
1970
- const blocking = warnings.some(w => {
2036
+ const blocking = activeFlowRun || warnings.some(w => {
1971
2037
  // Capture cross-reference warn-mode notes never block (operator opted out).
1972
2038
  if (/\[backstop in warn mode — not blocking\]/.test(w)) return false;
1973
2039
  return blockRe.test(w);
1974
2040
  });
1975
- return { warnings, blocking, preExecution, gatePrefix: gateLabel(activeFlowStep), latestArtifactDir };
2041
+ return { warnings, blocking, activeFlowRun, preExecution, gatePrefix: gateLabel(activeFlowStep), latestArtifactDir };
1976
2042
  }
1977
2043
 
1978
2044
  /**
@@ -2220,8 +2286,9 @@ function releaseOnNonTerminalStop(root, artifactDir) {
2220
2286
 
2221
2287
  const state = readJsonFile(path.join(artifactDir, 'state.json'));
2222
2288
  if (!state) return; // AC5: no state.json — nothing to gate a release decision on.
2223
- if (state.flow_run && normalizedStatus(state.flow_run.status) === 'active') {
2224
- process.stderr.write(`[Hook] Goal Fit: stop-hook release skipped for active Flow run "${safeOneLine(state.flow_run.run_id || state.task_slug || 'unknown', 80)}"; continuation remains governed by Flow state.\n`);
2289
+ const canonicalFlow = canonicalFlowState(root, artifactDir);
2290
+ if (normalizedStatus(canonicalFlow.state?.status) === 'active' || (state.flow_run && normalizedStatus(state.flow_run.status) === 'active')) {
2291
+ process.stderr.write(`[Hook] Goal Fit: stop-hook release skipped for active Flow run "${safeOneLine(state.flow_run?.run_id || state.task_slug || path.basename(artifactDir), 80)}"; continuation remains governed by Flow state.\n`);
2225
2292
  return;
2226
2293
  }
2227
2294
 
@@ -2367,7 +2434,7 @@ async function run(rawInput) {
2367
2434
  // with runtime-constructed paths or by modifying the warning
2368
2435
  // text so the hash changes. The real anchor is external (signed checkpoints + human
2369
2436
  // review). This raises the cost of the burn-through-the-counter escape vector.
2370
- const isHardBlock = result.warnings.some(w => {
2437
+ const isHardBlock = result.activeFlowRun || result.warnings.some(w => {
2371
2438
  if (/\[backstop in warn mode — not blocking\]/.test(w)) return false;
2372
2439
  return HARD_BLOCK.test(w);
2373
2440
  });
@@ -2375,7 +2442,9 @@ async function run(rawInput) {
2375
2442
  // Do NOT clear the streak — keep accumulating so the same hard block stays visible.
2376
2443
  return {
2377
2444
  stdout: rawInput,
2378
- stderr: `${message}\n${gatePrefix} max-blocks reached but the block is a caught false-completion / integrity failure — not auto-releasing; requires a real fix or operator override.`,
2445
+ stderr: result.activeFlowRun
2446
+ ? `${message}\n${gatePrefix} max-blocks reached but canonical Flow remains active — not auto-releasing; complete or explicitly cancel the run.`
2447
+ : `${message}\n${gatePrefix} max-blocks reached but the block is a caught false-completion / integrity failure — not auto-releasing; requires a real fix or operator override.`,
2379
2448
  exitCode: 2,
2380
2449
  };
2381
2450
  }