@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.
- package/CHANGELOG.md +7 -0
- package/build/src/builder-flow-run-adapter.d.ts +22 -2
- package/build/src/builder-flow-run-adapter.js +93 -28
- package/build/src/builder-flow-runtime.d.ts +8 -3
- package/build/src/builder-flow-runtime.js +308 -47
- package/build/src/cli/assignment-provider.d.ts +4 -7
- package/build/src/cli/assignment-provider.js +67 -13
- package/build/src/cli/builder-run.js +14 -18
- package/build/src/cli/workflow-sidecar.d.ts +28 -4
- package/build/src/cli/workflow-sidecar.js +801 -97
- package/build/src/cli/workflow.js +290 -42
- package/build/src/flow-kit/validate.d.ts +17 -0
- package/build/src/flow-kit/validate.js +340 -2
- package/build/src/index.js +5 -5
- package/build/src/lib/observed-command.d.ts +7 -0
- package/build/src/lib/observed-command.js +100 -0
- package/build/src/tools/generate-context-map.js +5 -3
- package/context/scripts/hooks/lib/kit-catalog.js +1 -1
- package/context/scripts/hooks/stop-goal-fit.js +78 -9
- package/docs/context-map.md +22 -20
- package/docs/developer-architecture.md +1 -1
- package/docs/public-workflow-cli.md +76 -7
- package/docs/skills-map.md +51 -27
- package/docs/spec/builder-flow-runtime.md +41 -40
- package/docs/workflow-usage-guide.md +109 -42
- package/evals/fixtures/hook-influence/cases.json +2 -2
- package/evals/integration/test_builder_entry_enforcement.sh +52 -41
- package/evals/integration/test_builder_step_producers.sh +297 -6
- package/evals/integration/test_bundle_install.sh +212 -63
- package/evals/integration/test_critique_supersession_roundtrip.sh +21 -8
- package/evals/integration/test_current_json_per_actor.sh +12 -0
- package/evals/integration/test_dual_emit_flow_step.sh +62 -43
- package/evals/integration/test_flowdef_session_activation.sh +145 -25
- package/evals/integration/test_flowdef_session_history_preservation.sh +23 -21
- package/evals/integration/test_gate_lockdown.sh +3 -5
- package/evals/integration/test_goal_fit_hook.sh +60 -2
- package/evals/integration/test_liveness_verdict.sh +14 -17
- package/evals/integration/test_phase_map_and_gate_claim.sh +63 -38
- package/evals/integration/test_public_workflow_cli.sh +325 -11
- package/evals/integration/test_pull_work_liveness_preflight.sh +22 -66
- package/evals/integration/test_sidecar_field_preservation.sh +36 -11
- package/evals/integration/test_workflow_sidecar_writer.sh +277 -44
- package/evals/integration/test_workflow_steering_hook.sh +15 -38
- package/evals/run.sh +2 -0
- package/evals/static/test_builder_skill_coherence.sh +247 -0
- package/evals/static/test_library_exports.sh +5 -2
- package/evals/static/test_workflow_skills.sh +13 -325
- package/kits/builder/flows/build.flow.json +22 -0
- package/kits/builder/flows/shape.flow.json +9 -9
- package/kits/builder/kit.json +70 -16
- package/kits/builder/skills/builder-shape/SKILL.md +75 -75
- package/kits/builder/skills/continue-work/SKILL.md +45 -106
- package/kits/builder/skills/deliver/SKILL.md +96 -442
- package/kits/builder/skills/design-probe/SKILL.md +40 -139
- package/kits/builder/skills/evidence-gate/SKILL.md +59 -201
- package/kits/builder/skills/execute-plan/SKILL.md +54 -125
- package/kits/builder/skills/fix-bug/SKILL.md +42 -132
- package/kits/builder/skills/gate-review/SKILL.md +60 -211
- package/kits/builder/skills/idea-to-backlog/SKILL.md +63 -244
- package/kits/builder/skills/learning-review/SKILL.md +63 -170
- package/kits/builder/skills/pickup-probe/SKILL.md +54 -111
- package/kits/builder/skills/plan-work/SKILL.md +51 -185
- package/kits/builder/skills/pull-work/SKILL.md +136 -485
- package/kits/builder/skills/release-readiness/SKILL.md +66 -107
- package/kits/builder/skills/review-work/SKILL.md +89 -176
- package/kits/builder/skills/tdd-workflow/SKILL.md +53 -147
- package/kits/builder/skills/verify-work/SKILL.md +101 -113
- package/package.json +2 -2
- package/scripts/hooks/lib/kit-catalog.js +1 -1
- package/scripts/hooks/stop-goal-fit.js +78 -9
- package/src/builder-flow-run-adapter.ts +118 -32
- package/src/builder-flow-runtime.ts +331 -61
- package/src/cli/assignment-provider-lock.test.mjs +83 -0
- package/src/cli/assignment-provider.ts +62 -13
- package/src/cli/builder-flow-run-adapter.test.mjs +4 -2
- package/src/cli/builder-flow-runtime.test.mjs +194 -8
- package/src/cli/builder-run.ts +3 -9
- package/src/cli/kit-metadata-security.test.mjs +232 -6
- package/src/cli/public-api.test.mjs +15 -0
- package/src/cli/workflow-sidecar-execution-proof.test.mjs +90 -0
- package/src/cli/workflow-sidecar.ts +724 -97
- package/src/cli/workflow.ts +277 -40
- package/src/flow-kit/validate.ts +320 -2
- package/src/index.ts +6 -5
- package/src/lib/observed-command.ts +96 -0
- package/src/tools/generate-context-map.ts +5 -3
|
@@ -1,159 +1,65 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "tdd-workflow"
|
|
3
|
-
description: "Test-
|
|
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
|
-
|
|
8
|
+
## Role and Boundary
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
**Role:** test-first `builder.build` profile.
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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: "
|
|
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
|
-
|
|
8
|
+
## Role
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
This is a Builder step skill.
|
|
11
11
|
|
|
12
|
-
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
-
|
|
38
|
-
|
|
39
|
-
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
2224
|
-
|
|
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:
|
|
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
|
}
|