@kontourai/flow-agents 3.2.0 → 3.3.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/workflows/ci.yml +12 -0
- package/CHANGELOG.md +13 -0
- package/build/src/cli/assignment-provider.js +10 -1
- package/build/src/cli/workflow-artifact-cleanup-audit.js +418 -11
- package/build/src/cli/workflow-sidecar.d.ts +224 -0
- package/build/src/cli/workflow-sidecar.js +775 -4
- package/build/src/tools/validate-source-tree.js +3 -2
- package/context/contracts/artifact-contract.md +16 -2
- package/context/scripts/hooks/workflow-steering.js +73 -1
- package/docs/coordination-guide.md +370 -0
- package/docs/decisions/agent-coordination.md +26 -9
- package/docs/decisions/index.md +2 -2
- package/docs/decisions/trust-reconcile.md +42 -9
- package/docs/fixture-ownership.md +3 -2
- package/docs/index.md +4 -0
- package/docs/integrations/flow-agents-console.md +108 -0
- package/docs/integrations/index.md +4 -0
- package/docs/workflow-artifact-lifecycle.md +38 -1
- package/evals/ci/antigaming-suite.sh +1 -0
- package/evals/ci/run-baseline.sh +6 -0
- package/evals/fixtures/reconcile-preflight/disputed-critique-unsuperseded.json +48 -0
- package/evals/fixtures/reconcile-preflight/standalone-disputed-session-local.json +59 -0
- package/evals/integration/test_checkpoint_signing.sh +10 -2
- package/evals/integration/test_ci_actor_identity.sh +221 -0
- package/evals/integration/test_fixture_retirement_audit.sh +2 -2
- package/evals/integration/test_publish_delivery.sh +59 -2
- package/evals/integration/test_reconcile_preflight.sh +304 -0
- package/evals/integration/test_takeover_protocol.sh +340 -0
- package/evals/integration/test_trust_reconcile_negatives.sh +91 -0
- package/evals/integration/test_verify_hold.sh +910 -0
- package/evals/integration/test_veritas_governance_kit.sh +257 -0
- package/evals/integration/test_workflow_artifact_cleanup_audit.sh +575 -3
- package/evals/run.sh +8 -0
- package/kits/builder/skills/continue-work/SKILL.md +2 -0
- package/kits/builder/skills/deliver/SKILL.md +73 -0
- package/kits/builder/skills/pull-work/SKILL.md +12 -2
- package/kits/veritas-governance/docs/README.md +81 -3
- package/kits/veritas-governance/fixtures/exemption/approved.trust-bundle.json +74 -0
- package/kits/veritas-governance/fixtures/exemption/not-approved.trust-bundle.json +74 -0
- package/kits/veritas-governance/flows/exemption-issuance.flow.json +35 -0
- package/kits/veritas-governance/kit.json +5 -0
- package/package.json +1 -1
- package/scripts/ci/trust-reconcile.js +78 -253
- package/scripts/hooks/lib/actor-identity.js +82 -0
- package/scripts/hooks/workflow-steering.js +73 -1
- package/scripts/lib/reconcile-shape.js +381 -0
- package/src/cli/assignment-provider.ts +12 -1
- package/src/cli/workflow-artifact-cleanup-audit.ts +483 -10
- package/src/cli/workflow-sidecar.ts +866 -4
- package/src/tools/validate-source-tree.ts +3 -2
|
@@ -1,20 +1,53 @@
|
|
|
1
1
|
---
|
|
2
|
-
status:
|
|
2
|
+
status: current
|
|
3
3
|
subject: Trust-reconcile and delivery reconciliation
|
|
4
|
-
decided: 2026-07-
|
|
4
|
+
decided: 2026-07-04
|
|
5
5
|
evidence:
|
|
6
6
|
- kind: adr
|
|
7
7
|
ref: docs/adr/0020-trust-reconcile-manifest-and-claim-classification.md
|
|
8
8
|
- kind: adr
|
|
9
9
|
ref: docs/adr/0022-fail-closed-delivery-reconciliation-with-governed-exemptions.md
|
|
10
|
+
- kind: doc
|
|
11
|
+
ref: docs/coordination-guide.md
|
|
10
12
|
---
|
|
11
13
|
# Trust-reconcile and delivery reconciliation
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
(`
|
|
16
|
-
|
|
15
|
+
**Decision.** Delivery is **fail-closed with governed exemptions**. `publishDelivery()` passes a
|
|
16
|
+
bundle through three distinct, type-discriminated tiers — fail-soft (absent bundle tolerated) →
|
|
17
|
+
shape gate (`InvalidBundleShapeError`, #356) → hold gate (`NotFreshHolderError`, #293) — and CI's
|
|
18
|
+
reconcile is fail-closed by default (`onUnderivable: 'fail'`). A local `reconcile-preflight`
|
|
19
|
+
mirrors CI's shape check via the *shared* `scripts/lib/reconcile-shape.js` so the two cannot
|
|
20
|
+
drift. Concurrent deliveries are isolated by **per-session paths** (`delivery/<slug>/`, #379), and
|
|
21
|
+
a checkpoint's `commit_sha` must be an ancestor of HEAD (seal-at-parent) so a stale bundle can't be
|
|
22
|
+
replayed onto a moved branch. See the [coordination guide](../coordination-guide.md#how-delivery-itself-is-made-tamper-resistant).
|
|
17
23
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
**Rationale.** The default must be safe: an underivable status fails the run rather than passing
|
|
25
|
+
it, and a hard block on the shared publish path is applied only on high-confidence signals so it
|
|
26
|
+
never false-blocks legitimate work. The frozen ADRs ([0020](../adr/0020-trust-reconcile-manifest-and-claim-classification.md),
|
|
27
|
+
[0022](../adr/0022-fail-closed-delivery-reconciliation-with-governed-exemptions.md)) hold the
|
|
28
|
+
immutable rationale.
|
|
29
|
+
|
|
30
|
+
## Implementation note (#356, iteration 1)
|
|
31
|
+
|
|
32
|
+
A local, pre-push `reconcile-preflight` now exists (`workflow-sidecar reconcile-preflight
|
|
33
|
+
<artifact-dir>`), reusing — never forking — the shape-classification logic CI's
|
|
34
|
+
`scripts/ci/trust-reconcile.js` enforces via the shared `scripts/lib/reconcile-shape.js`
|
|
35
|
+
module. `publishDelivery()` is itself fail-closed on shape-invalidity: it calls the same
|
|
36
|
+
preflight before copying anything into `delivery/`, and refuses to publish a bundle that
|
|
37
|
+
fails the shape check.
|
|
38
|
+
|
|
39
|
+
The reduced-coverage degradation (trusting a session-local claim's self-reported status when
|
|
40
|
+
CI-side re-derivation is unavailable) is a **LOCAL-preflight-only** opt-in
|
|
41
|
+
(`sessionLocalShapeIssues(..., { onUnderivable: 'reduce' })`). CI's `trust-reconcile.js`
|
|
42
|
+
always calls the shared function with `{ onUnderivable: 'fail' }` (also the function's
|
|
43
|
+
default when no mode is given) and remains fail-closed: when status re-derivation is
|
|
44
|
+
unavailable, every session-local pass-asserting claim becomes a `status-underivable`
|
|
45
|
+
divergence and the run fails, exactly as before the shape logic was extracted.
|
|
46
|
+
|
|
47
|
+
## Implementation note (#379, per-session delivery paths)
|
|
48
|
+
|
|
49
|
+
Concurrent deliveries no longer contend on a shared `delivery/trust.bundle`. Each session writes
|
|
50
|
+
its bundle under `delivery/<slug>/`; CI selects prefer-newest. Publishing must **restore sibling
|
|
51
|
+
`delivery/<slug>/` directories** from `origin/main` before committing — after a soft-reset,
|
|
52
|
+
`git add -A` would otherwise stage the deletion of other sessions' delivery dirs that the branch
|
|
53
|
+
predates. This is the standard step in the publish sequence documented in the coordination guide.
|
|
@@ -22,9 +22,10 @@ run `npm run validate:source --` and `npm run fixture:retirement-audit --`.
|
|
|
22
22
|
| `evals/fixtures/hook-influence` | hook influence behavioral cases | `evals/integration/test_hook_influence_cases.sh`, `evals/static/test_workflow_skills.sh`, `scripts/validate-hook-influence-cases.js` | Keep while hook influence cases define agent guidance behavior. |
|
|
23
23
|
| `evals/fixtures/pull-work-provider` | work item provider normalization fixtures | `evals/integration/test_pull_work_provider.sh` | Keep while provider normalization preserves blockers, artifact refs, board membership, and freshness metadata. |
|
|
24
24
|
| `evals/fixtures/pull-work-wip-shepherding` | WIP shepherding state fixtures | `evals/static/test_workflow_skills.sh` | Keep while pull-work documents personal versus global WIP behavior. |
|
|
25
|
+
| `evals/fixtures/reconcile-preflight` | #356 reconcile-preflight shape fixtures not already covered by trust-reconcile-exploits (un-superseded disputed critique, standalone disputed session-local claim) | `evals/integration/test_reconcile_preflight.sh` | Keep while the local `reconcile-preflight` subcommand (#356) is proven against the two shapes trust-reconcile-exploits does not already fixture (un-superseded disputed critique, standalone disputed session-local claim); the other four shapes reuse trust-reconcile-exploits/trust-reconcile-mixed-bundle directly rather than forking near-duplicates. |
|
|
25
26
|
| `evals/fixtures/surface-trust` | Surface trust evidence fixtures | `evals/integration/test_workflow_sidecar_writer.sh` | Keep while sidecar writer maps Surface trust evidence into workflow records. |
|
|
26
|
-
| `evals/fixtures/trust-reconcile-exploits` | WS8 trust-reconcile anti-gaming exploit fixtures (frozen negative regressions) | `evals/integration/test_trust_reconcile_negatives.sh` | Keep while trust-reconcile.js enforces the WS8 iteration-2 soundness properties (no-label test_output, unwaived-assumed, status-misassertion, waiver-on-command); each fixture is a permanent negative regression. |
|
|
27
|
-
| `evals/fixtures/trust-reconcile-mixed-bundle` | WS8 trust-reconcile mixed-evidence end-to-end proof fixture | `evals/integration/test_trust_reconcile_mixed_bundle.sh` | Keep while the trust-reconcile manifest/classification/waiver contract (ADR 0020) is enforced; proves a mixed test_output + session-local + waived bundle passes the CI anchor. |
|
|
27
|
+
| `evals/fixtures/trust-reconcile-exploits` | WS8 trust-reconcile anti-gaming exploit fixtures (frozen negative regressions); also reused by the #356 local reconcile-preflight eval (same shapes, no forked copies) | `evals/integration/test_trust_reconcile_negatives.sh`, `evals/integration/test_reconcile_preflight.sh` | Keep while trust-reconcile.js enforces the WS8 iteration-2 soundness properties (no-label test_output, unwaived-assumed, status-misassertion, waiver-on-command); each fixture is a permanent negative regression. |
|
|
28
|
+
| `evals/fixtures/trust-reconcile-mixed-bundle` | WS8 trust-reconcile mixed-evidence end-to-end proof fixture; also reused by the #356 reconcile-preflight eval as its CLEAN-BUNDLE (AC4) case | `evals/integration/test_trust_reconcile_mixed_bundle.sh`, `evals/integration/test_reconcile_preflight.sh` | Keep while the trust-reconcile manifest/classification/waiver contract (ADR 0020) is enforced; proves a mixed test_output + session-local + waived bundle passes the CI anchor. |
|
|
28
29
|
| `evals/fixtures/trust-reconcile-ws3` | WS8 AC6 backward-compat fixture: real ws3-kit-dependencies-namespacing old-style bundle | `evals/integration/test_trust_reconcile_negatives.sh` | Keep while backward compatibility with pre-classification (all-test_output) bundles is asserted; proves an old-style bundle still FAILS the same way (no silent pass). |
|
|
29
30
|
| `evals/fixtures/usage-feedback` | usage feedback import/outcome fixtures | `evals/integration/test_usage_feedback_import.sh`, `evals/integration/test_usage_feedback_outcomes.sh`, `evals/integration/test_usage_feedback_report.sh` | Keep while usage feedback import, outcome, and report flows accept JSONL fixture input. |
|
|
30
31
|
| `evals/fixtures/veritas-governance-adapter` | Veritas governance adapter fixtures | `evals/integration/test_veritas_governance_adapter.sh` | Keep while the Veritas adapter supports pass, unconfigured, and secret-failure governance paths. |
|
package/docs/index.md
CHANGED
|
@@ -118,6 +118,10 @@ Use fix-bug. Reproduce the problem, diagnose root cause, implement the fix, and
|
|
|
118
118
|
<strong>System Guidebook</strong>
|
|
119
119
|
<span>The plain-language map of how Flow Agents is assembled and how it should feel to use.</span>
|
|
120
120
|
</a>
|
|
121
|
+
<a class="doc-card" href="coordination-guide.html">
|
|
122
|
+
<strong>Parallel-Session Coordination</strong>
|
|
123
|
+
<span>Run many sessions against one repo without collisions: the two-stream model (liveness + assignment), the four guard points, the one hard publish fence, and how delivery defends itself.</span>
|
|
124
|
+
</a>
|
|
121
125
|
<a class="doc-card" href="skills-map.html">
|
|
122
126
|
<strong>Workflow Map</strong>
|
|
123
127
|
<span>See the core skills, gates, artifacts, and route-back behavior.</span>
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Flow Agents × Kontour Console
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Flow Agents × Kontour Console
|
|
6
|
+
|
|
7
|
+
Flow Agents' [coordination substrate](../coordination-guide.md) is **local-first and complete on a
|
|
8
|
+
single machine** — the local liveness stream plus the GitHub `AssignmentProvider` give you full
|
|
9
|
+
parallel-session safety with no server. The **Kontour Console** (`console.kontourai.io`) is the
|
|
10
|
+
**optional fleet tier** layered on top: it never becomes the authority for coordination; it *relays,
|
|
11
|
+
projects, and eventually arbitrates* across machines and teammates.
|
|
12
|
+
|
|
13
|
+
> This is the design boundary, stated plainly: **single-machine parallelism is fully unlocked
|
|
14
|
+
> locally, for free.** Multi-machine fleets, cross-teammate visibility, human oversight, history, and
|
|
15
|
+
> team-level insight are what the hosted tier adds — and sells. See [ADR 0021 §7](../adr/0021-assignment-leases-and-stale-claim-takeover.md)
|
|
16
|
+
> for the ratifying decision.
|
|
17
|
+
|
|
18
|
+
**Tracking:** flow-agents epic [#394](https://github.com/kontourai/flow-agents/issues/394) · console
|
|
19
|
+
epic [#123](https://github.com/kontourai/console/issues/123). This doc is the in-repo narrative; the
|
|
20
|
+
issues carry live slice status.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## What the Console already is
|
|
25
|
+
|
|
26
|
+
The Console is a Node/TypeScript monorepo (`console-core` / `console-server` / `console-ui`), backed
|
|
27
|
+
by Postgres (Neon), deployed on Render, running the dogfood instance at `console.kontourai.io`. It
|
|
28
|
+
already ingests and projects agent telemetry:
|
|
29
|
+
|
|
30
|
+
- **Ingest** — `POST /records` accepts telemetry records; auth via `Bearer` / `X-Console-API-Token`
|
|
31
|
+
plus `X-Console-Tenant-Id` (tokens configured through `CONSOLE_AUTH_TOKENS_JSON`).
|
|
32
|
+
- **Projection** — `GET /state` returns an `OperatingState` projection; **SSE** streams live updates.
|
|
33
|
+
- **Economics** — per-session cost/usage views (console #117) and an org-scoped registry (#118).
|
|
34
|
+
|
|
35
|
+
Its multi-tenancy today is **strong at the infrastructure layer** (Postgres primary keys per tenant,
|
|
36
|
+
per-tenant hubs and SSE fan-out) but **weak at the schema layer**: records don't self-identify their
|
|
37
|
+
tenant — tenancy is carried by the request header, not the record body. Closing that gap is part of
|
|
38
|
+
this epic (see *Tenant hardening* below).
|
|
39
|
+
|
|
40
|
+
## The design invariant: relay, never authority
|
|
41
|
+
|
|
42
|
+
Two rules keep the Console from compromising the local-first guarantee:
|
|
43
|
+
|
|
44
|
+
1. **Heartbeats are never written to a provider.** They mirror to the Console relay (the one vantage
|
|
45
|
+
with global heartbeat visibility) but never to GitHub — rate-limit abuse for no benefit. At most a
|
|
46
|
+
claim comment refreshes on phase transitions, doubling as board-level progress.
|
|
47
|
+
2. **The advisory stream stays advisory.** The Console projects the same liveness/assignment signals
|
|
48
|
+
the local substrate computes; in Phase 1 it adds *visibility*, not new authority. Only in Phase 2,
|
|
49
|
+
opt-in, does a Console-backed `AssignmentProvider` make assignment authoritative across machines —
|
|
50
|
+
and even then it implements the exact same contract the GitHub/local providers do.
|
|
51
|
+
|
|
52
|
+
## The phased plan (one epic, two phases)
|
|
53
|
+
|
|
54
|
+
### Phase 1 — read-only fleet insight (the relay)
|
|
55
|
+
|
|
56
|
+
Turn per-repo coordination into a team-wide view, without changing where authority lives.
|
|
57
|
+
|
|
58
|
+
| Slice | Repo | What it does |
|
|
59
|
+
| --- | --- | --- |
|
|
60
|
+
| **ApiSink** ([console #73]) | console | The ingest substrate the relay rides on — the prerequisite. |
|
|
61
|
+
| **Liveness relay** (flow-agents [#295]) | flow-agents | An optional sink: sessions mirror `claim`/`heartbeat`/`release` events to the Console, reusing its idempotent ingest + tenant auth + SSE. Off by default; strictly additive. |
|
|
62
|
+
| **Fleet projection** | console | Active actors, `held`/`reclaimable` subjects, and per-session cost, projected per tenant — the fleet view. |
|
|
63
|
+
| **In-hub janitor** | console | The [coordination janitor](../coordination-guide.md#10-takeover-protocol-forthcoming--294) run centrally: the Console is the one vantage with global heartbeat visibility, so stale-claim reaping for a *fleet* is its natural first cross-machine duty. (Decision: the janitor lives **in the console hub**, not per-client.) |
|
|
64
|
+
|
|
65
|
+
Phase 1 delivers the "see everyone's active sessions, and your own usage in team context" outcome —
|
|
66
|
+
project/team insight views alongside individual ones — while coordination authority stays exactly
|
|
67
|
+
where it is today (local + GitHub).
|
|
68
|
+
|
|
69
|
+
### Phase 2 — authoritative fleet coordination
|
|
70
|
+
|
|
71
|
+
Opt-in, for teams that want cross-machine assignment arbitration:
|
|
72
|
+
|
|
73
|
+
- **Console `AssignmentProvider`** — a third implementation of the [assignment-provider contract](https://github.com/kontourai/flow-agents/blob/main/context/contracts/assignment-provider-contract.md),
|
|
74
|
+
making assignment authoritative across machines (not just within one repo's GitHub board). Same
|
|
75
|
+
`claim`/`release`/`supersede`/`status`/`list` operations; same effective-state join. This is also
|
|
76
|
+
what lets [verify-hold](../coordination-guide.md#8-guard-point-3--the-verify-hold-publish-gate-the-one-hard-fence)
|
|
77
|
+
enforce against a *fleet-wide* holder, not just a local one.
|
|
78
|
+
- **Tenant hardening** (console #98–#100) — close the schema-level gap: put an **explicit `tenant_id`
|
|
79
|
+
on records** (decision) so tenancy is self-describing in the body, not only in the request header,
|
|
80
|
+
hardening the phased auth model end-to-end.
|
|
81
|
+
- **Native init step** — `flow-agents init` gains a first-class, optional Console-integration step:
|
|
82
|
+
configure the relay sink, tenant, and (Phase 2) the Console provider at install time, so joining a
|
|
83
|
+
fleet is a setup choice rather than manual wiring.
|
|
84
|
+
|
|
85
|
+
## How CI fits (paired with #398)
|
|
86
|
+
|
|
87
|
+
The [CI-runtime actor identity tier (#398)](https://github.com/kontourai/flow-agents/issues/398) makes
|
|
88
|
+
CI sessions carry a **stable identity** (e.g. `github-actions:<run-id>` plus `GITHUB_ACTOR`/repo/SHA).
|
|
89
|
+
That has two payoffs here: the [verify-hold gate](../coordination-guide.md#1-the-actor-model--who-am-i)
|
|
90
|
+
upgrades from *advisory* to *enforcing* in CI, and CI becomes an **attributable participant** in the
|
|
91
|
+
fleet — its records land in the same Console projections, so team/project/individual insight views
|
|
92
|
+
include automated work, not just interactive sessions. #398 is the keystone that makes the Console
|
|
93
|
+
fleet view whole.
|
|
94
|
+
|
|
95
|
+
## Dogfooding
|
|
96
|
+
|
|
97
|
+
`console.kontourai.io` runs from the `console` repo; the deployment lives in `console-deploy` (the
|
|
98
|
+
dogfood instance). Flow Agents development itself is intended to run against it — the fleet view of our
|
|
99
|
+
own parallel Builder sessions is both the first real test and the first sales demo of the tier.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Status
|
|
104
|
+
|
|
105
|
+
Designed and ratified ([ADR 0021 §7](../adr/0021-assignment-leases-and-stale-claim-takeover.md)); the
|
|
106
|
+
local substrate it builds on is complete (see the [coordination guide](../coordination-guide.md)). Phase
|
|
107
|
+
1 begins with console #73 (ApiSink) → flow-agents #295 (relay). This is forward-looking: no Console
|
|
108
|
+
integration ships in the coordination substrate itself — it is strictly the optional tier above it.
|
|
@@ -49,6 +49,10 @@ The <a href="../spec/runtime-hook-surface.html">Runtime Hook Surface spec</a> de
|
|
|
49
49
|
<strong>Knowledge Kit Live Example</strong>
|
|
50
50
|
<span>End-to-end proof of the Knowledge Kit ingest + compile flows against a real Strands agent (OllamaModel / qwen3:1.7b). No API key required. Includes acceptance test with telemetry and provenance assertions.</span>
|
|
51
51
|
</a>
|
|
52
|
+
<a class="doc-card" href="flow-agents-console.html">
|
|
53
|
+
<strong>Flow Agents × Console</strong>
|
|
54
|
+
<span>The optional fleet tier over the local coordination substrate: a liveness relay, team/project insight views, an in-hub janitor, and (Phase 2) a Console-backed AssignmentProvider. Local-first stands; the Console never becomes the authority.</span>
|
|
55
|
+
</a>
|
|
52
56
|
</div>
|
|
53
57
|
|
|
54
58
|
---
|
|
@@ -19,10 +19,47 @@ npm run workflow-artifact-cleanup-audit -- --artifact-root .flow-agents --json
|
|
|
19
19
|
|
|
20
20
|
The default root for local runtime artifacts is `.kontourai/flow-agents`. `.flow-agents` may hold explicit durable Flow Agents config/install state, but it is not a runtime fallback. Move old local sessions with the migration script instead of relying on automatic fallback reads.
|
|
21
21
|
|
|
22
|
-
The command scans immediate workflow directories, skips non-workflow lanes such as `archive/`, and reports active WIP separately from cleanup candidates, terminal done records, active learning follow-ups, and invalid sidecars.
|
|
22
|
+
The command scans immediate workflow directories, skips non-workflow lanes such as `archive/`, and reports active WIP separately from cleanup candidates, terminal done records, active learning follow-ups, and invalid sidecars.
|
|
23
23
|
|
|
24
24
|
Use the Current-State Semantics and Local Retention Policy sections below to interpret each bucket. In particular, learning records with `learning.status: followup_required` or any `routing[].status: open` remain active learning follow-ups until every route is completed, opened elsewhere, deferred with a trigger, accepted, or rejected.
|
|
25
25
|
|
|
26
|
+
## Apply Mode
|
|
27
|
+
|
|
28
|
+
Dry-run classification is the default and remains a zero-side-effect, read-only pass. Pass `--apply` to actually archive-move the sessions the classifier already puts in `cleanup_candidate` (and aged `terminal_done` sessions past the retention window) out of the active listing:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Dry-run (unchanged; still the default with no flags)
|
|
32
|
+
npm run workflow-artifact-cleanup-audit -- --artifact-root .kontourai/flow-agents
|
|
33
|
+
|
|
34
|
+
# Archive-move cleanup_candidate / aged terminal_done sessions
|
|
35
|
+
npm run workflow-artifact-cleanup-audit -- --artifact-root .kontourai/flow-agents --apply
|
|
36
|
+
|
|
37
|
+
# Also archive-move lifecycle-ambiguous and genuinely-stub invalid sessions (second gate)
|
|
38
|
+
npm run workflow-artifact-cleanup-audit -- --artifact-root .kontourai/flow-agents --apply --apply-ambiguous
|
|
39
|
+
|
|
40
|
+
# Custom retention window and destination
|
|
41
|
+
npm run workflow-artifact-cleanup-audit -- --artifact-root .kontourai/flow-agents \
|
|
42
|
+
--apply --freshness-window-hours 72 --archive-root /path/to/archive
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Two-gate model.** `--apply` alone only ever moves `cleanup_candidate` sessions and aged `terminal_done` sessions (the same buckets the manual Session Archival Policy procedure in `context/contracts/artifact-contract.md` already selects by hand) — it never touches anything the classifier calls `active_wip`, `active_learning_followup`, or `invalid`. A session the classifier marks `invalid` with an "unrecognized lifecycle shape" reason (a delivered/accepted session whose shape doesn't fit a known terminal pattern, but is otherwise a real, substantive record) is reported separately as **ambiguous** and is moved only when `--apply-ambiguous` is *also* passed — this is a deliberate second opt-in, not a default, because confirming that kind of straggler is genuinely done (e.g. its referenced PR actually merged) is a human/flow judgment call this tool does not make for you (see `--confirm` below).
|
|
46
|
+
|
|
47
|
+
**Safety rails.** Regardless of flags, `--apply`/`--apply-ambiguous` never touch:
|
|
48
|
+
|
|
49
|
+
1. **Active work** — `active_wip` and `active_learning_followup` sessions are hard-excluded; no flag combination overrides this.
|
|
50
|
+
2. **A session someone else is holding** — if the local liveness stream shows a fresh claim on a session's slug (any actor, not just the current one), that session is skipped and reported as blocked by a held liveness claim, even if the classifier would otherwise archive it.
|
|
51
|
+
3. **Anything too recent** — a session newer than the freshness window (`--freshness-window-hours`, default 48) is never moved, using `state.json`'s `updated_at` as the primary signal; directory modification time is used only as a fallback when `state.json` is missing or unparsable, never preferred over `updated_at` when it is present (bulk worktree operations can reset file mtimes without touching the actual session content, so mtime alone is not a trustworthy freshness signal).
|
|
52
|
+
4. **Infrastructure directories** — per-agent claim/assignment tracking, the runtime adapter's generated output, the skills catalog, and similar structural directories are recognized by their own shape (they carry their own top-level pointer/lock files, i.e. they are themselves a workflow-sidecar-managed root, not a session) and are never treated as sessions to begin with, so a nested runtime tree with real sub-sessions of its own is never flattened into a single misclassified entry or partially swept.
|
|
53
|
+
5. **Substantive sessions with a schema nit** — an `invalid` session that actually has real `state.json` plus `learning.json` and/or `trust.bundle` content is always report-only, even under `--apply --apply-ambiguous`; only a genuinely empty/stub `invalid` directory (no state at all, or state with no sidecar content) is ever eligible for the ambiguous-archive path.
|
|
54
|
+
|
|
55
|
+
**Never delete.** Every move is an archive-move (rename, or copy-then-verify-then-remove-source when a plain rename can't cross filesystems) — the tool has no delete capability of any kind, in any mode.
|
|
56
|
+
|
|
57
|
+
**Where things land.** `--apply` moves matching sessions to `<archive-root>/<date>-<runid>/<slug>/`, where `--archive-root` defaults to a sibling `.kontourai/flow-agents-archive/` next to the artifact root. This is a deliberately *different* destination from the manual, in-tree `<artifact-root>/archive/<slug>/` convention the Session Archival Policy section of `context/contracts/artifact-contract.md` documents for hand-driven moves: giving every automated `--apply` invocation its own dated, run-scoped directory means two same-day runs never collide, and it keeps the artifact root's own scan set immutable while a run is in progress. A human archiving a session by hand may still use the in-tree `archive/<slug>/` path from that section; the two destinations serve the same retirement intent through different (manual vs. automated) procedures — this mode automates the `cleanup_candidate`/aged-`terminal_done` selection that section already specifies, it does not replace the manual path for everything else.
|
|
58
|
+
|
|
59
|
+
**Manifest.** Any `--apply` run that moves at least one session writes `MANIFEST.md` into that run's archive directory, listing each moved session's slug, classification, last-updated timestamp, and the classifier's own reason text. A run that moves nothing writes no manifest and creates no new archive directory. `--confirm <slug>=<evidence>` (repeatable) lets the invoking human or flow record, verbatim, evidence they already independently gathered (for example, that a straggler's referenced PR is confirmed merged) into that slug's manifest row — a slug moved without a matching `--confirm` entry shows `"none recorded"` rather than a fabricated value. This tool makes no network or `gh` calls itself; it only records evidence it is told.
|
|
60
|
+
|
|
61
|
+
This is the same procedure a 2026-07-05 live triage sweep of this repo's own `.kontourai/flow-agents/` tree ran by hand before `--apply` existed (see that sweep's own `MANIFEST.md` for the real cases — stale stubs, aged cleanup candidates, confirmed-merged-PR stragglers, and the infrastructure/schema-nit exclusions above) — the sweep's findings are what shaped the safety rails above; `--apply` automates exactly that already-proven procedure.
|
|
62
|
+
|
|
26
63
|
## Artifact Lanes
|
|
27
64
|
|
|
28
65
|
Use one local non-durable lane under `.kontourai/flow-agents/`:
|
|
@@ -35,6 +35,7 @@ TESTS=(
|
|
|
35
35
|
"evals/integration/test_trust_reconcile_manifest.sh"
|
|
36
36
|
"evals/integration/test_trust_reconcile_mixed_bundle.sh"
|
|
37
37
|
"evals/integration/test_trust_reconcile_negatives.sh"
|
|
38
|
+
"evals/integration/test_reconcile_preflight.sh"
|
|
38
39
|
"evals/integration/test_goal_fit_ghost_session.sh"
|
|
39
40
|
)
|
|
40
41
|
|
package/evals/ci/run-baseline.sh
CHANGED
|
@@ -22,11 +22,14 @@ CHECKS=(
|
|
|
22
22
|
"Workflow sidecar writer integration|bash evals/integration/test_workflow_sidecar_writer.sh"
|
|
23
23
|
"Sidecar field preservation integration|bash evals/integration/test_sidecar_field_preservation.sh"
|
|
24
24
|
"Actor identity resolver integration|bash evals/integration/test_actor_identity.sh"
|
|
25
|
+
"CI-runtime actor identity integration|bash evals/integration/test_ci_actor_identity.sh"
|
|
25
26
|
"Assignment provider local-file integration|bash evals/integration/test_assignment_provider_local_file.sh"
|
|
26
27
|
"Assignment provider github integration|bash evals/integration/test_assignment_provider_github.sh"
|
|
27
28
|
"Stop hook release-with-handoff integration|bash evals/integration/test_stop_hook_release.sh"
|
|
28
29
|
"Pull work assignment join integration|bash evals/integration/test_pull_work_assignment_join.sh"
|
|
29
30
|
"Ensure-session ownership guard integration|bash evals/integration/test_ensure_session_ownership_guard.sh"
|
|
31
|
+
"Verify-hold gate integration|bash evals/integration/test_verify_hold.sh"
|
|
32
|
+
"Takeover protocol integration|bash evals/integration/test_takeover_protocol.sh"
|
|
30
33
|
"Current.json per-actor integration|bash evals/integration/test_current_json_per_actor.sh"
|
|
31
34
|
"Goal Fit hook integration|bash evals/integration/test_goal_fit_hook.sh"
|
|
32
35
|
"Hook category behavior integration|bash evals/integration/test_hook_category_behaviors.sh"
|
|
@@ -78,11 +81,14 @@ LANE_WORKFLOW_CONTRACTS=(
|
|
|
78
81
|
"Workflow sidecar writer integration"
|
|
79
82
|
"Sidecar field preservation integration"
|
|
80
83
|
"Actor identity resolver integration"
|
|
84
|
+
"CI-runtime actor identity integration"
|
|
81
85
|
"Assignment provider local-file integration"
|
|
82
86
|
"Assignment provider github integration"
|
|
83
87
|
"Stop hook release-with-handoff integration"
|
|
84
88
|
"Pull work assignment join integration"
|
|
85
89
|
"Ensure-session ownership guard integration"
|
|
90
|
+
"Verify-hold gate integration"
|
|
91
|
+
"Takeover protocol integration"
|
|
86
92
|
"Current.json per-actor integration"
|
|
87
93
|
)
|
|
88
94
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 5,
|
|
3
|
+
"source": "reconcile-preflight-fixture:disputed-critique-unsuperseded",
|
|
4
|
+
"note": "#356 shape 3: an un-superseded workflow.critique.review claim with a 'fail' verdict derives status 'disputed' — session-local-failed divergence (a disputed critique always blocks reconcile unless a later same-reviewer pass superseded it via metadata.superseded_by).",
|
|
5
|
+
"claims": [
|
|
6
|
+
{
|
|
7
|
+
"id": "c-disputed-critique",
|
|
8
|
+
"claimType": "workflow.critique.review",
|
|
9
|
+
"value": "fail",
|
|
10
|
+
"status": "disputed",
|
|
11
|
+
"subjectId": "reconcile-preflight-fixture/review-1",
|
|
12
|
+
"facet": "flow-agents.workflow",
|
|
13
|
+
"subjectType": "workflow-critique",
|
|
14
|
+
"fieldOrBehavior": "Found a critical security issue in the auth handler.",
|
|
15
|
+
"createdAt": "2026-07-04T00:00:00Z",
|
|
16
|
+
"updatedAt": "2026-07-04T00:00:00Z",
|
|
17
|
+
"impactLevel": "medium",
|
|
18
|
+
"verificationPolicyId": "policy:workflow.critique.review",
|
|
19
|
+
"metadata": { "origin": "critique", "reviewer": "tool-code-reviewer", "reviewed_at": "2026-07-04T00:00:00Z" }
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"evidence": [],
|
|
23
|
+
"policies": [
|
|
24
|
+
{
|
|
25
|
+
"id": "policy:workflow.critique.review",
|
|
26
|
+
"claimType": "workflow.critique.review",
|
|
27
|
+
"requiredEvidence": [],
|
|
28
|
+
"acceptanceCriteria": ["A verified verification event must support a workflow.critique.review claim."],
|
|
29
|
+
"reviewAuthority": "system",
|
|
30
|
+
"validityRule": { "kind": "manual" },
|
|
31
|
+
"stalenessTriggers": [],
|
|
32
|
+
"conflictRules": [],
|
|
33
|
+
"impactLevel": "medium"
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"events": [
|
|
37
|
+
{
|
|
38
|
+
"id": "evt-disputed-critique",
|
|
39
|
+
"claimId": "c-disputed-critique",
|
|
40
|
+
"status": "disputed",
|
|
41
|
+
"actor": "flow-agents/workflow-sidecar",
|
|
42
|
+
"method": "validation",
|
|
43
|
+
"evidenceIds": [],
|
|
44
|
+
"createdAt": "2026-07-04T00:00:00Z",
|
|
45
|
+
"verifiedAt": "2026-07-04T00:00:00Z"
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 5,
|
|
3
|
+
"source": "reconcile-preflight-fixture:standalone-disputed-session-local",
|
|
4
|
+
"note": "#356 shape 4 (the #292/#384 variant): a NON-critique session-local claim (workflow.check.external, human_attestation-backed) with a re-derived status of 'disputed' and no waiver. Distinct from shape 3 (an un-superseded disputed CRITIQUE) only in claimType/subject — both land on the same session-local-failed divergence, proving a disjoint pre-existing failure can never be smuggled in as a standalone claim; the fix hint directs the agent to document it as prose in a waived non-command summary instead.",
|
|
5
|
+
"claims": [
|
|
6
|
+
{
|
|
7
|
+
"id": "c-standalone-disputed",
|
|
8
|
+
"claimType": "workflow.check.external",
|
|
9
|
+
"value": "fail",
|
|
10
|
+
"status": "disputed",
|
|
11
|
+
"subjectId": "reconcile-preflight-fixture/pre-existing-flaky-integration",
|
|
12
|
+
"facet": "flow-agents.workflow",
|
|
13
|
+
"subjectType": "workflow-check",
|
|
14
|
+
"fieldOrBehavior": "pre-existing integration test failure unrelated to this change",
|
|
15
|
+
"createdAt": "2026-07-04T00:00:00Z",
|
|
16
|
+
"updatedAt": "2026-07-04T00:00:00Z",
|
|
17
|
+
"impactLevel": "high",
|
|
18
|
+
"verificationPolicyId": "policy:workflow.check.external:human_attestation"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"evidence": [
|
|
22
|
+
{
|
|
23
|
+
"id": "ev-standalone-disputed",
|
|
24
|
+
"claimId": "c-standalone-disputed",
|
|
25
|
+
"evidenceType": "human_attestation",
|
|
26
|
+
"method": "attestation",
|
|
27
|
+
"sourceRef": "reconcile-preflight-fixture/evidence.json",
|
|
28
|
+
"excerptOrSummary": "pre-existing integration test failure, unrelated to this change, observed but not fixed",
|
|
29
|
+
"observedAt": "2026-07-04T00:00:00Z",
|
|
30
|
+
"collectedBy": "flow-agents/workflow-sidecar",
|
|
31
|
+
"passing": false
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
"policies": [
|
|
35
|
+
{
|
|
36
|
+
"id": "policy:workflow.check.external:human_attestation",
|
|
37
|
+
"claimType": "workflow.check.external",
|
|
38
|
+
"requiredEvidence": ["human_attestation"],
|
|
39
|
+
"acceptanceCriteria": ["A verified verification event must support a workflow.check.external claim."],
|
|
40
|
+
"reviewAuthority": "system",
|
|
41
|
+
"validityRule": { "kind": "manual" },
|
|
42
|
+
"stalenessTriggers": [],
|
|
43
|
+
"conflictRules": [],
|
|
44
|
+
"impactLevel": "high"
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
"events": [
|
|
48
|
+
{
|
|
49
|
+
"id": "evt-standalone-disputed",
|
|
50
|
+
"claimId": "c-standalone-disputed",
|
|
51
|
+
"status": "disputed",
|
|
52
|
+
"actor": "flow-agents/workflow-sidecar",
|
|
53
|
+
"method": "attestation",
|
|
54
|
+
"evidenceIds": ["ev-standalone-disputed"],
|
|
55
|
+
"createdAt": "2026-07-04T00:00:00Z",
|
|
56
|
+
"verifiedAt": "2026-07-04T00:00:00Z"
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}
|
|
@@ -278,14 +278,22 @@ flow_agents_node "$WRITER" init-plan "$SESSION_DIR2/${SLUG2}--deliver.md" \
|
|
|
278
278
|
--source-request "Test" --summary "Test" \
|
|
279
279
|
--timestamp "2026-06-26T11:01:00Z" >/dev/null 2>&1
|
|
280
280
|
|
|
281
|
+
# #356: the check-json below carries a real "command" so its test_output evidence
|
|
282
|
+
# has a manifest-matchable execution.label (evidence.execution.label) -- otherwise the new
|
|
283
|
+
# reconcile-preflight gate inside publishDelivery() (#356 Wave 3, AC6) correctly refuses to
|
|
284
|
+
# publish a "kind":"build" claim with test_output evidence but no captured command (a
|
|
285
|
+
# genuinely shape-invalid claim CI's own trust-reconcile.js would ALSO reject -- this is not
|
|
286
|
+
# a preflight-specific false positive, see reconcile-shape.js's finding-1 hardening).
|
|
287
|
+
# TRUST_RECONCILE_COMMANDS makes "node --version" resolve via resolveManifest's legacy
|
|
288
|
+
# fallback tier, matching what a real repo configured with that canonical verify would do.
|
|
281
289
|
flow_agents_node "$WRITER" record-evidence "$SESSION_DIR2" \
|
|
282
290
|
--verdict pass \
|
|
283
|
-
--check-json '{"id":"build","kind":"build","status":"pass","summary":"build passed"}' \
|
|
291
|
+
--check-json '{"id":"build","kind":"build","status":"pass","summary":"build passed","command":"node --version"}' \
|
|
284
292
|
--timestamp "2026-06-26T11:02:00Z" >/dev/null 2>&1
|
|
285
293
|
|
|
286
294
|
# advance-state to delivered: this is the other code path that seals the checkpoint
|
|
287
295
|
SEAL_EXIT=0
|
|
288
|
-
flow_agents_node "$WRITER" advance-state "$SESSION_DIR2" \
|
|
296
|
+
TRUST_RECONCILE_COMMANDS="node --version" flow_agents_node "$WRITER" advance-state "$SESSION_DIR2" \
|
|
289
297
|
--status delivered \
|
|
290
298
|
--phase release \
|
|
291
299
|
--summary "Delivered." \
|