@kontourai/flow-agents 3.2.0 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/add-to-project.yml +15 -0
- package/.github/workflows/ci.yml +173 -0
- package/CHANGELOG.md +54 -0
- package/CONTEXT.md +5 -1
- package/README.md +19 -8
- package/build/src/builder-flow-run-adapter.d.ts +80 -0
- package/build/src/builder-flow-run-adapter.js +241 -0
- package/build/src/builder-flow-runtime.d.ts +16 -0
- package/build/src/builder-flow-runtime.js +290 -0
- package/build/src/cli/assignment-provider.js +10 -1
- package/build/src/cli/builder-run.d.ts +1 -0
- package/build/src/cli/builder-run.js +27 -0
- package/build/src/cli/effective-backlog-settings.js +70 -2
- package/build/src/cli/init.d.ts +34 -0
- package/build/src/cli/init.js +341 -61
- package/build/src/cli/kit.js +55 -12
- package/build/src/cli/pull-work-provider.js +346 -5
- package/build/src/cli/skill-drift-check.d.ts +1 -0
- package/build/src/cli/skill-drift-check.js +165 -0
- package/build/src/cli/telemetry-doctor.d.ts +37 -0
- package/build/src/cli/telemetry-doctor.js +53 -6
- package/build/src/cli/validate-hook-influence.js +37 -7
- package/build/src/cli/workflow-artifact-cleanup-audit.js +418 -11
- package/build/src/cli/workflow-sidecar.d.ts +310 -1
- package/build/src/cli/workflow-sidecar.js +1914 -126
- package/build/src/cli.js +5 -0
- package/build/src/flow-kit/validate.d.ts +54 -34
- package/build/src/flow-kit/validate.js +237 -26
- package/build/src/index.d.ts +2 -0
- package/build/src/index.js +1 -0
- package/build/src/lib/console-connect-options.d.ts +97 -0
- package/build/src/lib/console-connect-options.js +199 -0
- package/build/src/lib/console-telemetry-validate.d.ts +49 -0
- package/build/src/lib/console-telemetry-validate.js +91 -0
- package/build/src/lib/flow-resolver.d.ts +54 -1
- package/build/src/lib/flow-resolver.js +112 -5
- package/build/src/lib/fs.d.ts +17 -0
- package/build/src/lib/fs.js +172 -0
- package/build/src/lib/local-artifact-root.d.ts +44 -1
- package/build/src/lib/local-artifact-root.js +131 -3
- package/build/src/runtime-adapters.d.ts +39 -3
- package/build/src/runtime-adapters.js +77 -31
- package/build/src/tools/build-universal-bundles.js +40 -2
- package/build/src/tools/codex-agent-routing.d.ts +2 -0
- package/build/src/tools/codex-agent-routing.js +49 -0
- package/build/src/tools/generate-context-map.js +1 -0
- package/build/src/tools/validate-source-tree.js +30 -3
- package/context/contracts/artifact-contract.md +16 -2
- package/context/scripts/hooks/lib/kit-catalog.js +235 -0
- package/context/scripts/hooks/lib/runnable-command.js +177 -0
- package/context/scripts/hooks/stop-goal-fit.js +278 -48
- package/context/scripts/hooks/workflow-steering.js +194 -22
- package/context/scripts/package.json +3 -0
- package/context/scripts/telemetry/install-console-config.sh +25 -4
- package/context/scripts/telemetry/lib/config.sh +102 -12
- package/context/scripts/telemetry/lib/pricing.sh +50 -0
- package/context/scripts/telemetry/lib/session.sh +3 -0
- package/context/scripts/telemetry/lib/transport.sh +87 -0
- package/context/scripts/telemetry/lib/usage.sh +205 -4
- package/context/scripts/telemetry/telemetry.conf +6 -0
- package/context/scripts/telemetry/telemetry.sh +48 -0
- package/context/settings/workspace-backlog-provider-settings.example.json +48 -0
- package/docs/agent-usage-feedback-loop.md +35 -0
- package/docs/architecture-engine-and-kits.md +110 -0
- package/docs/context-map.md +2 -0
- package/docs/coordination-guide.md +370 -0
- package/docs/decisions/agent-coordination.md +26 -9
- package/docs/decisions/embeddable-engine.md +152 -0
- package/docs/decisions/index.md +5 -3
- package/docs/decisions/trust-ledger-retention.md +88 -0
- package/docs/decisions/trust-reconcile.md +42 -9
- package/docs/decisions/workflow-enforcement.md +31 -9
- package/docs/fixture-ownership.md +6 -2
- package/docs/implementing-trust-reconciliation.md +129 -0
- package/docs/index.md +23 -9
- package/docs/integrations/flow-agents-console.md +275 -0
- package/docs/integrations/index.md +4 -0
- package/docs/kit-authoring-guide.md +52 -21
- package/docs/spec/builder-flow-runtime.md +80 -0
- package/docs/spec/runtime-hook-surface.md +45 -1
- package/docs/specs/economics-record-contract.md +270 -0
- package/docs/specs/harness-capability-matrix.md +74 -0
- package/docs/specs/learning-review-proposals-contract.md +340 -0
- package/docs/specs/routing-efficiency-review.md +59 -0
- package/docs/verifiable-trust.md +74 -25
- package/docs/workflow-artifact-lifecycle.md +38 -1
- package/docs/workflow-usage-guide.md +10 -0
- package/evals/acceptance/prove-capture-teeth.sh +132 -0
- package/evals/ci/antigaming-suite.sh +2 -0
- package/evals/ci/run-baseline.sh +78 -4
- package/evals/fixtures/economics/acceptance.json +12 -0
- package/evals/fixtures/economics/agents/tool-worker-1/events.jsonl +2 -0
- package/evals/fixtures/economics/agents/tool-worker-2/events.jsonl +2 -0
- package/evals/fixtures/economics/agents/tool-worker-3/events.jsonl +2 -0
- package/evals/fixtures/economics/agents/tool-worker-4/events.jsonl +1 -0
- package/evals/fixtures/economics/agents/tool-worker-5/events.jsonl +2 -0
- package/evals/fixtures/economics/critique.json +22 -0
- package/evals/fixtures/economics/expected-record.json +71 -0
- package/evals/fixtures/economics/session-usage-event.json +1 -0
- package/evals/fixtures/economics/state.json +11 -0
- package/evals/fixtures/economics/transcript.jsonl +3 -0
- package/evals/fixtures/hook-influence/cases.json +7 -7
- package/evals/fixtures/learning-review-proposals/balanced/economics.jsonl +6 -0
- package/evals/fixtures/learning-review-proposals/effect-follow-up/economics.jsonl +5 -0
- package/evals/fixtures/learning-review-proposals/effect-follow-up/sessions/task-lr-ef-1/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/effect-follow-up/sessions/task-lr-ef-2/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/effect-follow-up/sessions/task-lr-ef-3/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/effect-follow-up/sessions/task-lr-ef-4/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/effect-follow-up/sessions/task-lr-ef-5/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/economics.jsonl +6 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/expected-aggregates.json +30 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/expected-aggregates.md +66 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-1/gate-review.inquiries.json +26 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-1/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-2/gate-review.inquiries.json +26 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-2/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-3/gate-review.inquiries.json +26 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-3/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-4/gate-review.inquiries.json +26 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-4/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-5/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/pattern-present/sessions/task-lr-pp-6/trust.bundle +21 -0
- package/evals/fixtures/learning-review-proposals/repeat-window/economics.jsonl +6 -0
- package/evals/fixtures/learning-review-proposals/under-threshold/economics.jsonl +3 -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/fixtures/telemetry/usage-transcript-sample.jsonl +4 -0
- package/evals/fixtures/trust-reconcile-exploits/mcp-degrade.json +42 -0
- package/evals/integration/test_builder_entry_enforcement.sh +241 -0
- package/evals/integration/test_builder_step_producers.sh +18 -10
- package/evals/integration/test_bundle_install.sh +172 -0
- package/evals/integration/test_checkpoint_signing.sh +10 -2
- package/evals/integration/test_ci_actor_identity.sh +221 -0
- package/evals/integration/test_console_tenant_isolation.sh +167 -0
- package/evals/integration/test_critique_supersession_roundtrip.sh +4 -1
- package/evals/integration/test_dual_emit_flow_step.sh +10 -4
- package/evals/integration/test_economics_record.sh +674 -0
- package/evals/integration/test_effective_backlog_settings.sh +1 -1
- package/evals/integration/test_evidence_capture_hook.sh +17 -2
- package/evals/integration/test_exemption_usage_review.sh +198 -0
- package/evals/integration/test_fixture_retirement_audit.sh +2 -2
- package/evals/integration/test_flow_kit_install_git.sh +83 -0
- package/evals/integration/test_flowdef_session_activation.sh +0 -1
- package/evals/integration/test_flowdef_session_history_preservation.sh +13 -3
- package/evals/integration/test_gate_lockdown.sh +7 -0
- package/evals/integration/test_gate_review_inquiry_records.sh +9 -1
- package/evals/integration/test_goal_fit_hook.sh +2031 -0
- package/evals/integration/test_hook_category_behaviors.sh +8 -1
- package/evals/integration/test_hook_influence_cases.sh +25 -1
- package/evals/integration/test_install_merge.sh +227 -2
- package/evals/integration/test_kit_conformance_levels.sh +6 -6
- package/evals/integration/test_learning_review_proposals.sh +329 -0
- package/evals/integration/test_liveness_conflict_injection.sh +26 -22
- package/evals/integration/test_liveness_console_relay.sh +166 -0
- package/evals/integration/test_liveness_heartbeat.sh +17 -17
- package/evals/integration/test_liveness_worktree_root.sh +575 -0
- package/evals/integration/test_phase_map_and_gate_claim.sh +6 -1
- package/evals/integration/test_publish_delivery.sh +389 -2
- package/evals/integration/test_pull_work_board.sh +200 -0
- package/evals/integration/test_pull_work_provider.sh +1 -1
- package/evals/integration/test_reconcile_preflight.sh +304 -0
- package/evals/integration/test_record_check.sh +378 -0
- package/evals/integration/test_routing_efficiency.sh +71 -0
- package/evals/integration/test_runtime_adapter_activation.sh +28 -0
- package/evals/integration/test_session_resume_roundtrip.sh +16 -19
- package/evals/integration/test_skill_drift_check.sh +870 -0
- package/evals/integration/test_takeover_protocol.sh +340 -0
- package/evals/integration/test_telemetry.sh +445 -0
- package/evals/integration/test_telemetry_doctor.sh +66 -0
- package/evals/integration/test_telemetry_usage_pipeline.sh +228 -0
- package/evals/integration/test_trust_reconcile_negatives.sh +121 -13
- package/evals/integration/test_trust_reconcile_trailer_diagnostic.sh +247 -0
- package/evals/integration/test_usage_cost.sh +61 -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/integration/test_workflow_sidecar_writer.sh +1395 -0
- package/evals/integration/test_workflow_steering_hook.sh +157 -16
- package/evals/integration/test_workspace_settings.sh +176 -0
- package/evals/lib/env.sh +26 -0
- package/evals/lib/node.sh +8 -0
- package/evals/run.sh +37 -0
- package/evals/static/test_ci_integration_coverage.sh +115 -0
- package/evals/static/test_declared_scope_forms_documented.sh +114 -0
- package/evals/static/test_universal_bundles.sh +34 -0
- package/evals/static/test_validate_source_kit_asset_scope.sh +259 -0
- package/evals/static/test_workflow_skills.sh +1 -1
- package/kits/builder/flows/build.flow.json +9 -18
- package/kits/builder/flows/publish-learn.flow.json +5 -1
- package/kits/builder/kit.json +120 -0
- package/kits/builder/skills/continue-work/SKILL.md +2 -0
- package/kits/builder/skills/deliver/SKILL.md +115 -0
- package/kits/builder/skills/evidence-gate/SKILL.md +12 -0
- package/kits/builder/skills/execute-plan/SKILL.md +9 -0
- package/kits/builder/skills/learning-review/SKILL.md +51 -0
- package/kits/builder/skills/plan-work/SKILL.md +17 -20
- package/kits/builder/skills/pull-work/SKILL.md +33 -2
- package/kits/builder/skills/release-readiness/SKILL.md +12 -0
- package/kits/knowledge/kit.json +9 -0
- package/kits/veritas-governance/docs/README.md +113 -7
- 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/fixtures/exemption-review/mixed-fresh-stale.DECLARED.json +14 -0
- package/kits/veritas-governance/flows/exemption-issuance.flow.json +35 -0
- package/kits/veritas-governance/kit.json +19 -0
- package/kits/veritas-governance/skills/exemption-usage-review/SKILL.md +128 -0
- package/kits/veritas-governance/skills/exemption-usage-review/review-exemptions.mjs +231 -0
- package/package.json +2 -2
- package/packaging/manifest.json +29 -0
- package/schemas/backlog-provider-settings.schema.json +13 -0
- package/schemas/workflow-state.schema.json +44 -0
- package/scripts/README.md +4 -0
- package/scripts/check-content-boundary.cjs +8 -1
- package/scripts/ci/trust-reconcile.js +214 -253
- package/scripts/hooks/codex-hook-adapter.js +77 -2
- package/scripts/hooks/evidence-capture.js +38 -5
- package/scripts/hooks/lib/actor-identity.js +82 -0
- package/scripts/hooks/lib/codex-exit-code.js +316 -0
- package/scripts/hooks/lib/kit-catalog.js +235 -0
- package/scripts/hooks/lib/liveness-write.js +28 -1
- package/scripts/hooks/lib/local-artifact-paths.js +97 -1
- package/scripts/hooks/lib/runnable-command.js +177 -0
- package/scripts/hooks/lib/skill-drift.js +350 -0
- package/scripts/hooks/stop-goal-fit.js +278 -48
- package/scripts/hooks/workflow-steering.js +194 -22
- package/scripts/install-codex-home.sh +97 -47
- package/scripts/install-merge.js +72 -14
- package/scripts/install-owned-files.js +178 -0
- package/scripts/lib/reconcile-shape.js +381 -0
- package/scripts/liveness/relay.sh +84 -0
- package/scripts/telemetry/economics-record.schema.json +145 -0
- package/scripts/telemetry/economics-record.sh +331 -0
- package/scripts/telemetry/install-console-config.sh +25 -4
- package/scripts/telemetry/learning-review-decide.sh +124 -0
- package/scripts/telemetry/learning-review-proposals.schema.json +161 -0
- package/scripts/telemetry/learning-review-proposals.sh +484 -0
- package/scripts/telemetry/lib/config.sh +102 -12
- package/scripts/telemetry/lib/pricing.sh +14 -6
- package/scripts/telemetry/lib/session.sh +3 -0
- package/scripts/telemetry/lib/transport.sh +133 -15
- package/scripts/telemetry/lib/usage.sh +121 -28
- package/scripts/telemetry/routing-efficiency.sh +0 -0
- package/scripts/telemetry/telemetry.conf +6 -0
- package/scripts/telemetry/telemetry.sh +48 -0
- package/src/builder-flow-run-adapter.ts +357 -0
- package/src/builder-flow-runtime.ts +348 -0
- package/src/cli/assignment-provider.ts +12 -1
- package/src/cli/builder-flow-run-adapter.test.mjs +495 -0
- package/src/cli/builder-flow-runtime.test.mjs +213 -0
- package/src/cli/builder-run.ts +28 -0
- package/src/cli/codex-agent-routing.test.mjs +44 -0
- package/src/cli/codex-exit-code.test.mjs +207 -0
- package/src/cli/console-connect-options.test.mjs +329 -0
- package/src/cli/console-telemetry-validate.test.mjs +157 -0
- package/src/cli/effective-backlog-settings.ts +68 -2
- package/src/cli/flow-resolver-composition.test.mjs +72 -0
- package/src/cli/init.test.mjs +161 -0
- package/src/cli/init.ts +407 -62
- package/src/cli/kit-metadata-security.test.mjs +443 -0
- package/src/cli/kit.ts +50 -12
- package/src/cli/pull-work-provider.ts +377 -3
- package/src/cli/sidecar-pure-helpers.test.mjs +64 -0
- package/src/cli/skill-drift-check.ts +196 -0
- package/src/cli/telemetry-doctor.test.mjs +53 -0
- package/src/cli/telemetry-doctor.ts +50 -7
- package/src/cli/validate-hook-influence.ts +37 -6
- package/src/cli/workflow-artifact-cleanup-audit.ts +483 -10
- package/src/cli/workflow-sidecar.ts +1980 -119
- package/src/cli.ts +5 -0
- package/src/flow-kit/validate.ts +277 -38
- package/src/index.ts +19 -0
- package/src/lib/console-connect-options.ts +261 -0
- package/src/lib/console-telemetry-validate.ts +88 -0
- package/src/lib/flow-resolver.ts +117 -4
- package/src/lib/fs.ts +160 -0
- package/src/lib/local-artifact-root.ts +129 -3
- package/src/runtime-adapters.ts +113 -33
- package/src/tools/build-universal-bundles.ts +36 -2
- package/src/tools/codex-agent-routing.ts +48 -0
- package/src/tools/generate-context-map.ts +1 -0
- package/src/tools/validate-source-tree.ts +29 -3
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# `kontour.console.economics` — per-run economics record contract (v0.1)
|
|
2
|
+
|
|
3
|
+
**Status:** ratified (flow-agents #349). **Kind:** `kontour.console.economics`. **Version:** `0.1`.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Every kit-driven run emits exactly one **per-run economics record** — cost, time,
|
|
8
|
+
iterations, and defects caught — so that "flow kits save money and produce more accurate
|
|
9
|
+
results" is a **measurable, falsifiable** claim backed by data. This record is the
|
|
10
|
+
measurement substrate for the Kit-economics telemetry initiative (I32–I35): it is
|
|
11
|
+
consumed by the baseline harness (#350), the small-model headline (#409), and the console
|
|
12
|
+
value view (console #117).
|
|
13
|
+
|
|
14
|
+
## Architecture (console ADR 0003)
|
|
15
|
+
|
|
16
|
+
- **Call 1 — additive kind on one pipe.** `kontour.console.economics` is a new *versioned
|
|
17
|
+
record KIND* that rides the single authenticated ingress (`ApiSink`, `POST /records`)
|
|
18
|
+
alongside `kontour.console.event`, `.projection`, and `.liveness`. It is **never** a new
|
|
19
|
+
endpoint or a new auth path.
|
|
20
|
+
- **Call 2 — tenant is bound from the verified principal.** The `ApiSink` stamps the
|
|
21
|
+
authoritative tenant from the request principal. The emitter MAY carry `tenant_id`
|
|
22
|
+
(from `CONSOLE_TENANT_ID`) for **self-description only**; the emitter is never the source
|
|
23
|
+
of truth for tenancy.
|
|
24
|
+
- **Call 3 — immutable fact, rollups are projections.** This record is an **immutable
|
|
25
|
+
per-run fact**. The console-side economics rollups and the value view are **rebuildable
|
|
26
|
+
projections** over the stream of these records. flow-agents emits facts, never a rollup;
|
|
27
|
+
this emitter computes **no cross-run aggregate**.
|
|
28
|
+
- **Call 6 — local-first, best-effort.** The record is **always** written to the local log
|
|
29
|
+
channel first; the console POST is a **detached, fail-open** fire that can never block or
|
|
30
|
+
fail a run. Every failure path is a quiet `exit 0`.
|
|
31
|
+
|
|
32
|
+
## Record shape
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"schema": "kontour.console.economics",
|
|
37
|
+
"version": "0.1",
|
|
38
|
+
"run_id": "string",
|
|
39
|
+
"at": "epoch-millis string",
|
|
40
|
+
"task_slug": "string|null",
|
|
41
|
+
"model": "string",
|
|
42
|
+
"pricing_version": "string|null",
|
|
43
|
+
|
|
44
|
+
"cost": {
|
|
45
|
+
"input_tokens": 0,
|
|
46
|
+
"output_tokens": 0,
|
|
47
|
+
"cache_creation_input_tokens": 0,
|
|
48
|
+
"cache_read_input_tokens": 0,
|
|
49
|
+
"estimated_cost_usd": 0.0,
|
|
50
|
+
"by_model": []
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
"time": {
|
|
54
|
+
"wall_clock_s": 0,
|
|
55
|
+
"human_wait_s": 0
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
"phases": [
|
|
59
|
+
{ "phase": "plan|execute|review|verify|unattributed",
|
|
60
|
+
"input_tokens": 0, "output_tokens": 0,
|
|
61
|
+
"cache_creation_input_tokens": 0, "cache_read_input_tokens": 0,
|
|
62
|
+
"estimated_cost_usd": 0.0, "wall_clock_s": 0 }
|
|
63
|
+
],
|
|
64
|
+
|
|
65
|
+
"iterations": {
|
|
66
|
+
"count": 1,
|
|
67
|
+
"route_backs": 0
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
"defects": {
|
|
71
|
+
"gate_fires": 0,
|
|
72
|
+
"findings_by_severity": { "critical": 0, "high": 0, "medium": 0, "low": 0 },
|
|
73
|
+
"caught_false_completions": 0,
|
|
74
|
+
"verification_verdict": "PASS|FAIL|NOT_VERIFIED"
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
"tenant_id": "string|null"
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Field sources
|
|
82
|
+
|
|
83
|
+
Every field derives from a named telemetry event, usage field, or sidecar file. The emitter
|
|
84
|
+
**never re-estimates tokens** — ground truth is the transcript's `.message.usage` blocks,
|
|
85
|
+
already parsed by `usage_parse_transcript` (scripts/telemetry/lib/usage.sh) and carried on
|
|
86
|
+
the `session.usage` event.
|
|
87
|
+
|
|
88
|
+
| Field | Type | Source |
|
|
89
|
+
| --- | --- | --- |
|
|
90
|
+
| `schema` | literal | `"kontour.console.economics"` |
|
|
91
|
+
| `version` | literal | `"0.1"` |
|
|
92
|
+
| `run_id` | string | `session.usage .session_id` |
|
|
93
|
+
| `at` | epoch-millis string | `session.usage .timestamp` (session end) |
|
|
94
|
+
| `task_slug` | string\|null | `state.json .task_slug` |
|
|
95
|
+
| `model` | string | `session.usage .usage.model` |
|
|
96
|
+
| `pricing_version` | string\|null | `session.usage .usage.pricing_version` (from `pricing.json` `current_version`) |
|
|
97
|
+
| `cost.input_tokens` | int | `session.usage .usage.input_tokens` (transcript ground truth) |
|
|
98
|
+
| `cost.output_tokens` | int | `session.usage .usage.output_tokens` |
|
|
99
|
+
| `cost.cache_creation_input_tokens` | int | `session.usage .usage.cache_creation_input_tokens` |
|
|
100
|
+
| `cost.cache_read_input_tokens` | int | `session.usage .usage.cache_read_input_tokens` |
|
|
101
|
+
| `cost.estimated_cost_usd` | number | `session.usage .usage.estimated_cost_usd` (derived; recomputable console-side from `pricing_version`) |
|
|
102
|
+
| `cost.by_model` | array | `session.usage .usage.by_model`, verbatim |
|
|
103
|
+
| `time.wall_clock_s` | int | `session.usage .usage.duration_s` |
|
|
104
|
+
| `time.human_wait_s` | int | elapsed time blocked on a human decision (slice-1: `0` if uninstrumented; **never omit the key**) |
|
|
105
|
+
| `phases[]` | array | per-phase attribution — see the phase-sum invariant below |
|
|
106
|
+
| `iterations.count` | int | deliver-loop passes (plan→execute→review→verify); slice-1 default `1` |
|
|
107
|
+
| `iterations.route_backs` | int | verify FAIL → re-plan/re-execute loops; slice-1 default `0` |
|
|
108
|
+
| `defects.gate_fires` | int | count of gate fires in the run |
|
|
109
|
+
| `defects.findings_by_severity` | object | grouped from `critique.json .critiques[].findings[]` on `.severity` (missing → `low`) |
|
|
110
|
+
| `defects.caught_false_completions` | int | claimed-pass ACs contradicted by trusted-backstop re-runs (DISTINCT counter) |
|
|
111
|
+
| `defects.verification_verdict` | enum | final verify-work verdict from the sidecar (`PASS`\|`FAIL`\|`NOT_VERIFIED`) |
|
|
112
|
+
| `delegations[]` | array | per-sub-agent delegation facts + derived outcome (#415) — see below; `[]` when `--agents-dir` is absent |
|
|
113
|
+
| `signals` | object | harness-capability declaration — what telemetry this runtime exposed (see below + `harness-capability-matrix.md`) |
|
|
114
|
+
| `tenant_id` | string\|null | self-description only; the `ApiSink` stamps the authoritative tenant (ADR 0003 call 2) |
|
|
115
|
+
|
|
116
|
+
## `delegations[]` — per-sub-agent routing facts + outcome (#415)
|
|
117
|
+
|
|
118
|
+
When the emitter is given `--agents-dir <slug>/agents`, it assembles one entry per delegated
|
|
119
|
+
sub-agent, joined from each `<slug>/agents/<agent-id>/events.jsonl`:
|
|
120
|
+
|
|
121
|
+
| Field | Type | Source |
|
|
122
|
+
| --- | --- | --- |
|
|
123
|
+
| `agent_id` | string\|null | the sub-agent id (join key) |
|
|
124
|
+
| `role` | string | routing role recorded on the delegation event (`delegate-mechanical`\|`delegate-implementation`\|`delegate-design`\|…) |
|
|
125
|
+
| `resolved_model` | string | the model that role resolved to (`.datum/config.json`), e.g. `claude-haiku-4-5@anthropic` |
|
|
126
|
+
| `summary` | string\|null | the delegation/escalation event's free-text summary (stands in for a structured task_type) |
|
|
127
|
+
| `escalated_from` | string | present only when the sub-agent escalated: the lower tier it was promoted from |
|
|
128
|
+
| `dispatch_count` | int | how many times the orchestrator (re)dispatched this agent_id (delegation + escalation events); `>1` = re-prompted |
|
|
129
|
+
| `outcome` | enum | `accepted`\|`rework`\|`diverged`\|`failed`\|`unavailable` — derived (see below) |
|
|
130
|
+
|
|
131
|
+
**Assembly rule:** all events for an `agent_id` are grouped; role/model come from the **latest**
|
|
132
|
+
`delegation`/`escalation` event (an escalation supersedes and carries `escalated_from`). Any read/parse
|
|
133
|
+
failure degrades to `[]` — never fatal (local-first, best-effort).
|
|
134
|
+
|
|
135
|
+
**Outcome — derived only from ORCHESTRATOR-OBSERVABLE signals, never fabricated.** The orchestrator
|
|
136
|
+
knows what it dispatched, how often it re-dispatched, and how it corrected — so outcome holds **without
|
|
137
|
+
peeking inside the sub-agent** (which most harnesses forbid — see `harness-capability-matrix.md`):
|
|
138
|
+
|
|
139
|
+
- `diverged` — an explicit supersession marker (`kind:"supersession"` or `status:"diverged"`) exists.
|
|
140
|
+
- `rework` — an escalation happened **or** the orchestrator re-dispatched the agent (`dispatch_count > 1`).
|
|
141
|
+
- `failed` — the latest terminal verdict event (`kind` `evidence`/`verdict`) is a FAIL.
|
|
142
|
+
- `accepted` — the latest terminal verdict is a PASS (and no escalation / re-dispatch / supersession).
|
|
143
|
+
- `unavailable` — no terminal verdict was recorded on this harness. **Not assumed `accepted`** — absence
|
|
144
|
+
of a verdict is not evidence of success.
|
|
145
|
+
|
|
146
|
+
**Per-delegation COST is still not carried here.** Token usage is *sub-agent-internal* and no runtime
|
|
147
|
+
isolates it today (`signals.per_delegation_tokens = false`), so a per-delegation cost split would be
|
|
148
|
+
fabrication. Cost per `(role, model)` is a **console projection** — join `delegations[]` (role→model)
|
|
149
|
+
against `cost.by_model` (1:1 with roles under the current `.datum/config.json`), labeled model-granularity.
|
|
150
|
+
|
|
151
|
+
## `signals` — harness-capability declaration
|
|
152
|
+
|
|
153
|
+
Declares what telemetry the emitting runtime actually exposed, so a consumer distinguishes a real zero
|
|
154
|
+
from a harness-blind gap (full doctrine + per-runtime matrix in `harness-capability-matrix.md`):
|
|
155
|
+
|
|
156
|
+
| Field | Meaning |
|
|
157
|
+
| --- | --- |
|
|
158
|
+
| `runtime` | the runtime that produced the record (`claude-code`, `kiro-cli`, …), from `session.usage .agent.runtime` |
|
|
159
|
+
| `per_delegation_tokens` | `true` iff the runtime isolates per-sub-agent tokens. `false` everywhere today → per-delegation cost unavailable |
|
|
160
|
+
| `per_delegation_outcome` | outcome-signal coverage this run: `full`\|`partial`\|`none`\|`n/a` |
|
|
161
|
+
|
|
162
|
+
Consumers MUST read `signals` before rendering a delegation metric: if the needed signal is unavailable,
|
|
163
|
+
show "not measurable on this harness," never a misleading number.
|
|
164
|
+
|
|
165
|
+
## R7 Goodhart guard (structural, hard requirement)
|
|
166
|
+
|
|
167
|
+
`cost` and `defects` are **co-required** in the JSON Schema
|
|
168
|
+
(`"required": ["schema","version","run_id","cost","time","iterations","defects"]`). A record
|
|
169
|
+
with `cost` but no `defects` block is **schema-invalid**. This is structural: **no consumer
|
|
170
|
+
can render "cheaper" without also rendering "and here is what it caught / missed."** Cost is
|
|
171
|
+
only meaningful paired with the defect signal it traded against — the Goodhart pair.
|
|
172
|
+
|
|
173
|
+
## Phase-sum invariant
|
|
174
|
+
|
|
175
|
+
The sum over `phases[].input_tokens` (and each other token / cost / wall field) MUST equal
|
|
176
|
+
the corresponding top-level `cost` / `time` total. When no phase context exists in
|
|
177
|
+
`state.json`, **all** amounts land in a single `{"phase":"unattributed", ...}` entry — never
|
|
178
|
+
silently dropped or misattributed. The eval asserts this invariant for both the
|
|
179
|
+
phase-known and phase-unknown fixtures.
|
|
180
|
+
|
|
181
|
+
## Version semantics
|
|
182
|
+
|
|
183
|
+
`version` is the record-shape version, independent of `pricing_version` (which versions the
|
|
184
|
+
cost derivation). A shape change bumps `version`; a pricing change bumps `pricing_version`.
|
|
185
|
+
Because the record stream is immutable and tenant-stamped, shape evolution is a
|
|
186
|
+
**re-projection** console-side, not a migration of authority.
|
|
187
|
+
|
|
188
|
+
## Emission (local-first, best-effort)
|
|
189
|
+
|
|
190
|
+
1. The record is assembled with a **single `jq -c` filter** so every untrusted field
|
|
191
|
+
(`task_slug`, model names, finding text) is `\u`-escaped — JSON is never string-built.
|
|
192
|
+
2. The record is written to the local economics log
|
|
193
|
+
(`${TELEMETRY_ECONOMICS_LOG_FILE:-${TELEMETRY_DATA_DIR}/economics.jsonl}`) **first** — the
|
|
194
|
+
fixed, non-doubled path (#469; `TELEMETRY_DATA_DIR` is already the fully-qualified
|
|
195
|
+
`.../.kontourai/telemetry` data dir, so only `economics.jsonl` is appended to it, never a
|
|
196
|
+
second `.kontourai/telemetry/...` suffix on top).
|
|
197
|
+
3. Only then is the record best-effort POSTed to `<console>/records` via the shared
|
|
198
|
+
`console_post_json` transport core — detached, fail-open, and gated on
|
|
199
|
+
`FLOW_AGENTS_CONSOLE_ECONOMICS_RELAY` and only when a console endpoint is configured.
|
|
200
|
+
4. Every failure path is `exit 0`. The emitter only writes/relays a fact — it never mutates
|
|
201
|
+
a kit, gate, or claim (render-don't-execute).
|
|
202
|
+
5. **Unattributed/no-signal suppression** (economics-relay-unattributed-suppression): the local
|
|
203
|
+
write in step 2 is unconditional, but the console POST in step 3 is additionally suppressed —
|
|
204
|
+
the run's fact still lands in the local `economics.jsonl`, it just never reaches the console —
|
|
205
|
+
when the assembled record carries **none** of the following:
|
|
206
|
+
|
|
207
|
+
```
|
|
208
|
+
suppress_relay =
|
|
209
|
+
(task_slug is null/empty/"unattributed")
|
|
210
|
+
AND (cost.estimated_cost_usd == 0)
|
|
211
|
+
AND (no token volume — cost.input_tokens + cost.output_tokens
|
|
212
|
+
+ cost.cache_creation_input_tokens + cost.cache_read_input_tokens == 0)
|
|
213
|
+
AND (defects.gate_fires == 0)
|
|
214
|
+
AND (defects.caught_false_completions == 0)
|
|
215
|
+
AND (sum of defects.findings_by_severity.* == 0)
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Any one of real task attribution, real cost, real token volume, or a real defect/gate signal
|
|
219
|
+
is enough to still relay the record unchanged. The token-volume leg exists because cost
|
|
220
|
+
legitimately degrades to `0` on an unpriced/new model (see `scripts/telemetry/lib/usage.sh`'s
|
|
221
|
+
contract) while the transcript-ground-truth token counts remain a real signal — without this
|
|
222
|
+
leg, a real, unattributed, unpriced-model run with genuine token volume would be
|
|
223
|
+
indistinguishable from a truly-empty run and would be wrongly suppressed, dropping real ROI
|
|
224
|
+
data.
|
|
225
|
+
|
|
226
|
+
This guard exists because `telemetry.sh` invokes the emitter on every `session.usage` Stop
|
|
227
|
+
event once usage tracking is on, regardless of whether the run had an active Builder task —
|
|
228
|
+
with no `active_slug`, `task_slug` resolves to `null` (assembled as `state.task_slug // null`;
|
|
229
|
+
it is never the literal string `"unattributed"` as *data* — that literal is only how the
|
|
230
|
+
console *renders* a `null`/empty `task_slug` in its ROI view) and every `defects.*` field sits
|
|
231
|
+
at its zero default, so without this guard every no-task, no-signal run relayed a `null`
|
|
232
|
+
task_slug, `$0`-cost, zero-token, zero-defect record that diluted the console
|
|
233
|
+
`/api/economics` ROI view's `firstPassRate` and cost aggregates. The `!= "unattributed"` leg
|
|
234
|
+
in the predicate is harmless defense-in-depth (in case an upstream caller ever passes that
|
|
235
|
+
literal string), not a claim that the emitter itself produces it. `delegations[]`/`signals.*`
|
|
236
|
+
are deliberately excluded from the predicate — `--agents-dir` is only ever passed alongside
|
|
237
|
+
`--state`, so `delegations` is already `[]` whenever the other terms are at their zero
|
|
238
|
+
defaults.
|
|
239
|
+
|
|
240
|
+
**The guard itself fails OPEN toward relaying.** The suppress path only fires when jq
|
|
241
|
+
successfully evaluates the predicate above to an explicit `false` (a genuinely-empty record);
|
|
242
|
+
a jq/read failure (non-zero exit, or any output other than the literal `false`) falls through
|
|
243
|
+
and the record RELAYS unchanged — dropping a real record is worse than an extra empty one
|
|
244
|
+
reaching the console, so a guard failure never silently swallows real data. Set
|
|
245
|
+
`TELEMETRY_ECONOMICS_DEBUG=1` to log a one-line `economics-record: suppressing console relay
|
|
246
|
+
(...)` diagnostic to stderr whenever the guard actually suppresses a POST.
|
|
247
|
+
|
|
248
|
+
### Enabling the relay (config-driven, opt-out — #469)
|
|
249
|
+
|
|
250
|
+
The console relay is **on by default once a Console telemetry sink is configured** — it is no
|
|
251
|
+
longer env-var-only. `scripts/telemetry/lib/config.sh` resolves
|
|
252
|
+
`FLOW_AGENTS_CONSOLE_ECONOMICS_RELAY` as follows:
|
|
253
|
+
|
|
254
|
+
- An explicit `console_economics_relay` key in a trusted conf (`.kontourai/telemetry-console.conf`
|
|
255
|
+
or `~/.flow-agents/telemetry-console.conf` — mode `600`, owned by the current user; see the
|
|
256
|
+
telemetry-mirror trust gate in `docs/agent-usage-feedback-loop.md`) always wins: truthy
|
|
257
|
+
(`1`/`true`/`yes`/`on`) forces the relay on, falsey (`0`/`false`/`no`/`off`) forces it off.
|
|
258
|
+
- Otherwise, once `console_telemetry_url` / `console_telemetry_endpoint_url` resolves (from that
|
|
259
|
+
same trusted conf, or a directly-set env var), the relay **defaults on**.
|
|
260
|
+
- A caller-pre-set `FLOW_AGENTS_CONSOLE_ECONOMICS_RELAY` environment variable is left untouched
|
|
261
|
+
and takes priority over the default-on rule (but not over an explicit conf key).
|
|
262
|
+
- The optional `console_economics_endpoint_url` conf key (or the
|
|
263
|
+
`FLOW_AGENTS_CONSOLE_ECONOMICS_ENDPOINT_URL` env var) overrides the derived `<console>/records`
|
|
264
|
+
endpoint when it must differ from the telemetry sink's origin.
|
|
265
|
+
- To opt out without hand-editing the conf, pass `--no-economics-relay` to
|
|
266
|
+
`install-console-config.sh`, which writes `console_economics_relay=0`.
|
|
267
|
+
|
|
268
|
+
The raw `FLOW_AGENTS_CONSOLE_ECONOMICS_RELAY` / `FLOW_AGENTS_CONSOLE_ECONOMICS_ENDPOINT_URL` env
|
|
269
|
+
vars are still honored directly, for one-off invocations or CI where writing a conf file isn't
|
|
270
|
+
worth it — but the conf keys above are the normal path for an installed setup.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Harness-capability matrix
|
|
2
|
+
|
|
3
|
+
**The signals a feature can rely on depend on which runtime/harness the kit is hooked into. State the
|
|
4
|
+
coverage; never assume it, never fabricate the gap.**
|
|
5
|
+
|
|
6
|
+
This is a cross-cutting contract: any feature whose data comes from telemetry (economics, delegation
|
|
7
|
+
efficiency, liveness, learning) must declare which signals it needs, which *class* each falls in, and
|
|
8
|
+
how it degrades when the current runtime does not expose one. A missing signal is rendered as
|
|
9
|
+
**unavailable**, distinct from a real zero — so a consumer never reads "harness-blind" as "measured 0."
|
|
10
|
+
|
|
11
|
+
## The load-bearing distinction: orchestrator-observable vs sub-agent-internal
|
|
12
|
+
|
|
13
|
+
Not all "we can't see inside the sub-agent" gaps are equal. Two classes:
|
|
14
|
+
|
|
15
|
+
- **Orchestrator-observable** — what our hooks see the *main agent* (the orchestrator) do. The
|
|
16
|
+
orchestrator knows the prompt it dispatched, how many times it re-dispatched/re-prompted the same
|
|
17
|
+
sub-agent, its own iteration/route-back count, and when it superseded or corrected a result. Our
|
|
18
|
+
telemetry observes the orchestrator directly, so **these hold on any runtime that runs our hooks —
|
|
19
|
+
no sub-agent introspection required.** This is where per-delegation *outcome* comes from.
|
|
20
|
+
- **Sub-agent-internal** — signals that live inside the sub-agent's own turn: its token usage, its
|
|
21
|
+
internal reasoning, a verdict it computed but never surfaced to the orchestrator. Capturing these
|
|
22
|
+
requires the harness to expose per-sub-agent instrumentation. **Most harnesses do not today**, so
|
|
23
|
+
features that need them (e.g. per-delegation *cost*) must declare the signal unavailable and fall
|
|
24
|
+
back to a coarser, honest proxy.
|
|
25
|
+
|
|
26
|
+
The practical upshot for #415: we can attribute **outcome** (accepted / rework / diverged / failed) from
|
|
27
|
+
orchestrator-observable behavior even though we cannot attribute **cost** per delegation — because
|
|
28
|
+
tokens are sub-agent-internal and outcome is not.
|
|
29
|
+
|
|
30
|
+
## The `signals` block
|
|
31
|
+
|
|
32
|
+
Every `kontour.console.economics` record carries a `signals` object declaring what the emitting runtime
|
|
33
|
+
exposed:
|
|
34
|
+
|
|
35
|
+
| Field | Class | Meaning |
|
|
36
|
+
| --- | --- | --- |
|
|
37
|
+
| `runtime` | — | the runtime that produced the record (`claude-code`, `kiro-cli`, `codex`, …) |
|
|
38
|
+
| `per_delegation_tokens` | sub-agent-internal | `true` iff the runtime isolates per-sub-agent token usage. **`false` on every runtime today** → per-delegation cost is unavailable; the console attributes cost at `(role, model)` granularity via `cost.by_model` instead. |
|
|
39
|
+
| `per_delegation_outcome` | orchestrator-observable | coverage of the outcome signal on this run: `full` (every delegation resolved to a real outcome), `partial` (some), `none` (delegations exist but none had a verdict/escalation/re-dispatch), `n/a` (no delegations observed). |
|
|
40
|
+
|
|
41
|
+
Consumers (console panels, `learning-review`) MUST read `signals` before rendering a metric: if the
|
|
42
|
+
signal a metric needs is unavailable, show "not measurable on this harness," not a misleading number.
|
|
43
|
+
|
|
44
|
+
## Per-runtime coverage (current, honest snapshot)
|
|
45
|
+
|
|
46
|
+
`✓` exposed · `partial` best-effort/orchestrator-derived · `✗` not exposed. Update this table as
|
|
47
|
+
runtimes add instrumentation — it is the single source of truth the `signals` values are stamped from.
|
|
48
|
+
|
|
49
|
+
| Signal | Class | claude-code | kiro-cli | codex | raw-model runner |
|
|
50
|
+
| --- | --- | --- | --- | --- | --- |
|
|
51
|
+
| whole-run tokens/cost (`by_model`) | run-level | ✓ | ✓ | ✓ | partial |
|
|
52
|
+
| delegation dispatch (role/model) | orchestrator-observable | ✓ | ✓ | partial | ✗ |
|
|
53
|
+
| re-dispatch / re-prompt count | orchestrator-observable | ✓ | ✓ | partial | ✗ |
|
|
54
|
+
| escalation (tier bump) | orchestrator-observable | ✓ | ✓ | partial | ✗ |
|
|
55
|
+
| supersession / correction | orchestrator-observable | partial | partial | ✗ | ✗ |
|
|
56
|
+
| per-sub-agent terminal verdict | mixed | partial | partial | ✗ | ✗ |
|
|
57
|
+
| per-sub-agent tokens/cost | sub-agent-internal | ✗ | ✗ | ✗ | ✗ |
|
|
58
|
+
|
|
59
|
+
"partial" for verdicts/supersession reflects that these depend on the workflow actually recording an
|
|
60
|
+
`evidence`/`verdict`/`supersession` event for the agent — capturable, but not guaranteed every run.
|
|
61
|
+
That is exactly why `outcome` degrades to `unavailable` rather than `accepted` when the event is absent.
|
|
62
|
+
|
|
63
|
+
## The doctrine (applies to any telemetry-dependent feature)
|
|
64
|
+
|
|
65
|
+
1. **Classify each signal** as run-level, orchestrator-observable, or sub-agent-internal. Prefer
|
|
66
|
+
orchestrator-observable derivations — they are the most portable across harnesses.
|
|
67
|
+
2. **Declare coverage in-band** (a `signals`-style block) so a consumer can distinguish real-zero from
|
|
68
|
+
harness-blind at read time.
|
|
69
|
+
3. **Degrade to an explicit `unavailable`**, never to a fabricated value. A cost you cannot attribute
|
|
70
|
+
is not `$0`; an outcome you cannot observe is not `accepted`.
|
|
71
|
+
4. **Fall back to the coarsest honest proxy** when the fine signal is missing (per-delegation cost →
|
|
72
|
+
`(role, model)` via `by_model`), and label the proxy as such.
|
|
73
|
+
5. **Keep this matrix current.** When a harness starts exposing a signal, flip the cell and the
|
|
74
|
+
`signals` stamp follows — the feature "lights up" without a schema change.
|