@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,247 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# test_trust_reconcile_trailer_diagnostic.sh — Integration eval for scripts/ci/
|
|
3
|
+
# trust-reconcile.js's runtime-session commit-trailer diagnostic (issue #305, ADR 0022 §1).
|
|
4
|
+
#
|
|
5
|
+
# Proves the diagnostic added in findRuntimeSessionTrailers()/logRuntimeSessionTrailers()
|
|
6
|
+
# is audit-only:
|
|
7
|
+
# AC5 trailer-diagnostic-positive: a commit with a Claude-Session: trailer in the
|
|
8
|
+
# resolved range produces the exact line
|
|
9
|
+
# `[trust-reconcile] identified: runtime-session trailer 'Claude-Session' on <ref>`
|
|
10
|
+
# — the trailer KEY only, never the VALUE (session URL) — printed for the range's
|
|
11
|
+
# commit-with-trailer.
|
|
12
|
+
# AC6 trailer-diagnostic-negative: a commit range with no runtime-session trailer
|
|
13
|
+
# produces NO such diagnostic line, and the reconciler's exit code is IDENTICAL
|
|
14
|
+
# to the positive case (same canonical command, same bundle/DECLARED absence,
|
|
15
|
+
# differing only in trailer presence) — the diagnostic never changes the exit path.
|
|
16
|
+
# AC7 trailer-diagnostic-checkout-depth-verified: .github/workflows/trust-reconcile.yml
|
|
17
|
+
# already carries fetch-depth: 0 (no .yml edit needed for #305's depth ask).
|
|
18
|
+
# Base-ref-range vs narrower-fallback: both range-resolution paths
|
|
19
|
+
# (TRUST_RECONCILE_BASE_REF/GITHUB_BASE_REF resolvable vs unresolvable, falling back
|
|
20
|
+
# to just the head commit) are exercised directly against the exported
|
|
21
|
+
# findRuntimeSessionTrailers() helper (unit-style, no reconciler wrapper needed for
|
|
22
|
+
# this sub-case) as well as through the full reconciler CLI (integration-style).
|
|
23
|
+
#
|
|
24
|
+
# Eval-authoring hazards observed (per plan/goal constraints):
|
|
25
|
+
# - No self-recursive harness invocation: this eval shells out to trust-reconcile.js and
|
|
26
|
+
# to git only; it never invokes evals/run.sh or any other eval-suite entry point.
|
|
27
|
+
# - No legacy/deprecated-path literals: trailer fixture values are synthetic/generic
|
|
28
|
+
# (a https://claude.ai/code/session_test-fixture-only placeholder), never a copy of a
|
|
29
|
+
# real committed session URL or a legacy flat delivery/trust.bundle-style literal.
|
|
30
|
+
#
|
|
31
|
+
# Deterministic, no model spend, self-cleaning.
|
|
32
|
+
# Usage: bash evals/integration/test_trust_reconcile_trailer_diagnostic.sh
|
|
33
|
+
|
|
34
|
+
set -uo pipefail
|
|
35
|
+
|
|
36
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
37
|
+
RECONCILE="$ROOT/scripts/ci/trust-reconcile.js"
|
|
38
|
+
|
|
39
|
+
errors=0
|
|
40
|
+
TMP_DIR="$(mktemp -d)"
|
|
41
|
+
trap 'rm -rf "$TMP_DIR"' EXIT
|
|
42
|
+
pass() { echo " ✓ $1"; }
|
|
43
|
+
fail() { echo " ✗ $1"; errors=$((errors + 1)); }
|
|
44
|
+
|
|
45
|
+
echo "=== trust-reconcile.js runtime-session trailer diagnostic — integration eval ==="
|
|
46
|
+
|
|
47
|
+
# Synthetic-only trailer value — never a real/legacy committed session URL.
|
|
48
|
+
TRAILER_VALUE="https://claude.ai/code/session_test-fixture-only"
|
|
49
|
+
RECONCILE_CMD="node -e 'process.exit(0)'"
|
|
50
|
+
|
|
51
|
+
# ─── Fixture: a real scratch git repo with two commits (base, then head) ─────────
|
|
52
|
+
build_repo() {
|
|
53
|
+
local repo_dir="$1"
|
|
54
|
+
local with_trailer="$2" # "true" or "false"
|
|
55
|
+
mkdir -p "$repo_dir"
|
|
56
|
+
git init -q "$repo_dir"
|
|
57
|
+
git -C "$repo_dir" config user.email "eval@local"
|
|
58
|
+
git -C "$repo_dir" config user.name "eval"
|
|
59
|
+
echo "base" > "$repo_dir/f.txt"
|
|
60
|
+
git -C "$repo_dir" add -A
|
|
61
|
+
git -C "$repo_dir" commit -qm "base commit"
|
|
62
|
+
echo "change" >> "$repo_dir/f.txt"
|
|
63
|
+
git -C "$repo_dir" add -A
|
|
64
|
+
if [[ "$with_trailer" == "true" ]]; then
|
|
65
|
+
git -C "$repo_dir" commit -qm "$(printf 'feat: trailer test commit\n\nClaude-Session: %s\n' "$TRAILER_VALUE")"
|
|
66
|
+
else
|
|
67
|
+
git -C "$repo_dir" commit -qm "feat: no-trailer test commit"
|
|
68
|
+
fi
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
POS_REPO="$TMP_DIR/positive-repo"
|
|
72
|
+
NEG_REPO="$TMP_DIR/negative-repo"
|
|
73
|
+
build_repo "$POS_REPO" "true"
|
|
74
|
+
build_repo "$NEG_REPO" "false"
|
|
75
|
+
|
|
76
|
+
POS_BASE="$(git -C "$POS_REPO" rev-list --max-parents=0 HEAD)"
|
|
77
|
+
POS_HEAD="$(git -C "$POS_REPO" rev-parse HEAD)"
|
|
78
|
+
NEG_BASE="$(git -C "$NEG_REPO" rev-list --max-parents=0 HEAD)"
|
|
79
|
+
NEG_HEAD="$(git -C "$NEG_REPO" rev-parse HEAD)"
|
|
80
|
+
|
|
81
|
+
# A THIRD repo where the range-distinguishing case actually differs from POS_REPO/NEG_REPO:
|
|
82
|
+
# the trailer lives on a MIDDLE commit (between base and a later, trailer-free head commit)
|
|
83
|
+
# -- reachable ONLY via the ranged `git log <base>..<head>` walk, never via the narrower
|
|
84
|
+
# head-commit-only fallback. This is the genuine base-ref-range-vs-fallback distinguisher;
|
|
85
|
+
# POS_REPO/NEG_REPO above (trailer-or-not on the head commit itself) would pass under
|
|
86
|
+
# EITHER code path and do not by themselves prove the ranged branch is exercised.
|
|
87
|
+
RANGE_REPO="$TMP_DIR/range-only-repo"
|
|
88
|
+
mkdir -p "$RANGE_REPO"
|
|
89
|
+
git init -q "$RANGE_REPO"
|
|
90
|
+
git -C "$RANGE_REPO" config user.email "eval@local"
|
|
91
|
+
git -C "$RANGE_REPO" config user.name "eval"
|
|
92
|
+
echo "base" > "$RANGE_REPO/f.txt"
|
|
93
|
+
git -C "$RANGE_REPO" add -A
|
|
94
|
+
git -C "$RANGE_REPO" commit -qm "base commit"
|
|
95
|
+
RANGE_BASE="$(git -C "$RANGE_REPO" rev-parse HEAD)"
|
|
96
|
+
echo "middle" >> "$RANGE_REPO/f.txt"
|
|
97
|
+
git -C "$RANGE_REPO" add -A
|
|
98
|
+
git -C "$RANGE_REPO" commit -qm "$(printf 'feat: middle commit carries the trailer
|
|
99
|
+
|
|
100
|
+
Claude-Session: %s
|
|
101
|
+
' "$TRAILER_VALUE")"
|
|
102
|
+
echo "head" >> "$RANGE_REPO/f.txt"
|
|
103
|
+
git -C "$RANGE_REPO" add -A
|
|
104
|
+
git -C "$RANGE_REPO" commit -qm "feat: head commit itself has no trailer"
|
|
105
|
+
RANGE_HEAD="$(git -C "$RANGE_REPO" rev-parse HEAD)"
|
|
106
|
+
|
|
107
|
+
# --- AC5: positive case — exact diagnostic line, key only, no value leak --------
|
|
108
|
+
echo "--- AC5: positive — Claude-Session trailer present ---"
|
|
109
|
+
pos_out="$(TRUST_RECONCILE_BASE_REF="$POS_BASE" TRUST_RECONCILE_SHA="$POS_HEAD" TRUST_RECONCILE_REF="test-branch" \
|
|
110
|
+
TRUST_RECONCILE_COMMANDS="$RECONCILE_CMD" node "$RECONCILE" --repo-root "$POS_REPO" 2>&1)"
|
|
111
|
+
pos_code=$?
|
|
112
|
+
|
|
113
|
+
if echo "$pos_out" | grep -qF "[trust-reconcile] identified: runtime-session trailer 'Claude-Session' on test-branch"; then
|
|
114
|
+
pass "AC5: exact diagnostic line printed for the Claude-Session trailer"
|
|
115
|
+
else
|
|
116
|
+
fail "AC5: expected diagnostic line not found — output: $pos_out"
|
|
117
|
+
fi
|
|
118
|
+
|
|
119
|
+
if echo "$pos_out" | grep -qF "$TRAILER_VALUE"; then
|
|
120
|
+
fail "AC5: trailer VALUE ($TRAILER_VALUE) leaked into stdout — diagnostic must log the KEY only"
|
|
121
|
+
else
|
|
122
|
+
pass "AC5: trailer VALUE does not appear anywhere in stdout (key-only logging, per ADR 0022 §1's exact quoted format)"
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
# --- AC6: negative case — no trailer, no line, same canonical command/DECLARED state --
|
|
126
|
+
echo "--- AC6: negative — no runtime-session trailer present ---"
|
|
127
|
+
neg_out="$(TRUST_RECONCILE_BASE_REF="$NEG_BASE" TRUST_RECONCILE_SHA="$NEG_HEAD" TRUST_RECONCILE_REF="test-branch" \
|
|
128
|
+
TRUST_RECONCILE_COMMANDS="$RECONCILE_CMD" node "$RECONCILE" --repo-root "$NEG_REPO" 2>&1)"
|
|
129
|
+
neg_code=$?
|
|
130
|
+
|
|
131
|
+
if echo "$neg_out" | grep -q "identified: runtime-session trailer"; then
|
|
132
|
+
fail "AC6: an 'identified: runtime-session trailer' line was printed with no trailer present"
|
|
133
|
+
else
|
|
134
|
+
pass "AC6: no 'identified: runtime-session trailer' line printed (no trailer present)"
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
if [[ "$pos_code" == "$neg_code" ]]; then
|
|
138
|
+
pass "AC6: reconciler exit code is IDENTICAL between the trailer-present and no-trailer cases (both: $pos_code) — diagnostic never changes the exit path"
|
|
139
|
+
else
|
|
140
|
+
fail "AC6: reconciler exit code DIVERGED between trailer-present ($pos_code) and no-trailer ($neg_code) cases — the diagnostic must never affect the exit path"
|
|
141
|
+
fi
|
|
142
|
+
|
|
143
|
+
# --- Base-ref-range vs narrower-fallback, exercised directly on the exported helper --
|
|
144
|
+
# RANGE_REPO's trailer lives on a MIDDLE commit, absent from the head commit itself — this
|
|
145
|
+
# genuinely distinguishes the two code paths (see RANGE_REPO fixture comment above).
|
|
146
|
+
echo "--- base-ref-range vs narrower-fallback (direct helper exercise, genuinely distinguishing fixture) ---"
|
|
147
|
+
range_result="$(TRUST_RECONCILE_BASE_REF="$RANGE_BASE" node -e "
|
|
148
|
+
const { findRuntimeSessionTrailers } = require('$RECONCILE');
|
|
149
|
+
const found = findRuntimeSessionTrailers('$RANGE_REPO', { sha: '$RANGE_HEAD', ref: 'test-branch' });
|
|
150
|
+
console.log(JSON.stringify(found));
|
|
151
|
+
" 2>&1)"
|
|
152
|
+
if echo "$range_result" | grep -q '"trailerName":"Claude-Session"'; then
|
|
153
|
+
pass "base-ref-range path: findRuntimeSessionTrailers finds a trailer on a MIDDLE commit (base..head range) that is absent from the head commit itself, when TRUST_RECONCILE_BASE_REF resolves"
|
|
154
|
+
else
|
|
155
|
+
fail "base-ref-range path: findRuntimeSessionTrailers did not find the middle-commit trailer via the ranged walk — output: $range_result"
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
# Narrower fallback: no base ref env var set at all (helper's own internal base-ref
|
|
159
|
+
# resolution reads process.env directly, so unset both env vars for this call) — against
|
|
160
|
+
# the SAME range-only repo, this must NOT find the middle-commit trailer (it is invisible
|
|
161
|
+
# to a head-commit-only scan), proving the fallback is genuinely narrower, not just an
|
|
162
|
+
# equivalent restatement of the ranged path.
|
|
163
|
+
fallback_result="$(env -u TRUST_RECONCILE_BASE_REF -u GITHUB_BASE_REF node -e "
|
|
164
|
+
const { findRuntimeSessionTrailers } = require('$RECONCILE');
|
|
165
|
+
const found = findRuntimeSessionTrailers('$RANGE_REPO', { sha: '$RANGE_HEAD', ref: 'test-branch' });
|
|
166
|
+
console.log(JSON.stringify(found));
|
|
167
|
+
" 2>&1)"
|
|
168
|
+
if [[ "$fallback_result" == "[]" ]]; then
|
|
169
|
+
pass "narrower-fallback path: findRuntimeSessionTrailers does NOT find the middle-commit-only trailer when no base ref is resolvable (head-commit-only scan is genuinely narrower)"
|
|
170
|
+
else
|
|
171
|
+
fail "narrower-fallback path: expected an empty array (middle-commit trailer invisible to head-only scan), got: $fallback_result"
|
|
172
|
+
fi
|
|
173
|
+
|
|
174
|
+
# Narrower fallback, positive: against POS_REPO (trailer ON the head commit itself), the
|
|
175
|
+
# no-base-ref fallback still finds it — proving the fallback is not simply "always empty".
|
|
176
|
+
fallback_pos_result="$(env -u TRUST_RECONCILE_BASE_REF -u GITHUB_BASE_REF node -e "
|
|
177
|
+
const { findRuntimeSessionTrailers } = require('$RECONCILE');
|
|
178
|
+
const found = findRuntimeSessionTrailers('$POS_REPO', { sha: '$POS_HEAD', ref: 'test-branch' });
|
|
179
|
+
console.log(JSON.stringify(found));
|
|
180
|
+
" 2>&1)"
|
|
181
|
+
if echo "$fallback_pos_result" | grep -q '"trailerName":"Claude-Session"'; then
|
|
182
|
+
pass "narrower-fallback path: still finds a trailer that IS on the head commit itself (fallback scans the head commit, not nothing)"
|
|
183
|
+
else
|
|
184
|
+
fail "narrower-fallback path: did not find the head-commit trailer with no base ref set — output: $fallback_pos_result"
|
|
185
|
+
fi
|
|
186
|
+
|
|
187
|
+
# Narrower-fallback negative: no base ref, no trailer on the head commit itself (NEG_REPO).
|
|
188
|
+
fallback_neg_result="$(env -u TRUST_RECONCILE_BASE_REF -u GITHUB_BASE_REF node -e "
|
|
189
|
+
const { findRuntimeSessionTrailers } = require('$RECONCILE');
|
|
190
|
+
const found = findRuntimeSessionTrailers('$NEG_REPO', { sha: '$NEG_HEAD', ref: 'test-branch' });
|
|
191
|
+
console.log(JSON.stringify(found));
|
|
192
|
+
" 2>&1)"
|
|
193
|
+
if [[ "$fallback_neg_result" == "[]" ]]; then
|
|
194
|
+
pass "narrower-fallback path: findRuntimeSessionTrailers returns an empty array when the head commit itself has no trailer and no base ref is resolvable"
|
|
195
|
+
else
|
|
196
|
+
fail "narrower-fallback path: expected an empty array, got: $fallback_neg_result"
|
|
197
|
+
fi
|
|
198
|
+
|
|
199
|
+
# --- No-crash: unresolvable sha degrades to empty array, never throws -----------
|
|
200
|
+
degrade_result="$(node -e "
|
|
201
|
+
const { findRuntimeSessionTrailers } = require('$RECONCILE');
|
|
202
|
+
const found = findRuntimeSessionTrailers('$POS_REPO', { sha: '', ref: 'test-branch' });
|
|
203
|
+
console.log(JSON.stringify(found));
|
|
204
|
+
" 2>&1)"
|
|
205
|
+
if [[ "$degrade_result" == "[]" ]]; then
|
|
206
|
+
pass "empty sha degrades to an empty array (never throws, never crashes the caller)"
|
|
207
|
+
else
|
|
208
|
+
fail "empty sha did not degrade cleanly — got: $degrade_result"
|
|
209
|
+
fi
|
|
210
|
+
|
|
211
|
+
# --- AC7: checkout-depth already verified (no .yml edit needed) -----------------
|
|
212
|
+
echo "--- AC7: .github/workflows/trust-reconcile.yml already carries fetch-depth: 0 ---"
|
|
213
|
+
WORKFLOW_FILE="$ROOT/.github/workflows/trust-reconcile.yml"
|
|
214
|
+
if grep -n "fetch-depth: 0" "$WORKFLOW_FILE" >/dev/null 2>&1; then
|
|
215
|
+
pass "AC7: fetch-depth: 0 already present in trust-reconcile.yml (Addendum part 3) — no .yml change needed for #305's depth ask"
|
|
216
|
+
else
|
|
217
|
+
fail "AC7: fetch-depth: 0 not found in trust-reconcile.yml — expected it to already be present"
|
|
218
|
+
fi
|
|
219
|
+
|
|
220
|
+
if command -v python3 >/dev/null 2>&1 && python3 -c "import yaml" 2>/dev/null; then
|
|
221
|
+
if python3 - "$WORKFLOW_FILE" << 'PY' 2>/dev/null
|
|
222
|
+
import sys, yaml
|
|
223
|
+
try:
|
|
224
|
+
yaml.safe_load(open(sys.argv[1]).read())
|
|
225
|
+
sys.exit(0)
|
|
226
|
+
except yaml.YAMLError:
|
|
227
|
+
sys.exit(1)
|
|
228
|
+
PY
|
|
229
|
+
then
|
|
230
|
+
pass "AC7: trust-reconcile.yml parses as valid YAML (python3 yaml)"
|
|
231
|
+
else
|
|
232
|
+
fail "AC7: trust-reconcile.yml failed python3 yaml parse"
|
|
233
|
+
fi
|
|
234
|
+
else
|
|
235
|
+
grep -q "^name:" "$WORKFLOW_FILE" && grep -q "trust-reconcile" "$WORKFLOW_FILE" && \
|
|
236
|
+
pass "AC7: trust-reconcile.yml has expected structural fields (yaml parser unavailable, structural fallback)" || \
|
|
237
|
+
fail "AC7: trust-reconcile.yml missing expected structural fields"
|
|
238
|
+
fi
|
|
239
|
+
|
|
240
|
+
echo ""
|
|
241
|
+
if [[ "$errors" -eq 0 ]]; then
|
|
242
|
+
echo "PASS: trust-reconcile.js runtime-session trailer diagnostic (audit-only, key-only, exit-code-identical)"
|
|
243
|
+
exit 0
|
|
244
|
+
else
|
|
245
|
+
echo "FAIL: $errors check(s) failed"
|
|
246
|
+
exit 1
|
|
247
|
+
fi
|
|
@@ -73,6 +73,26 @@ else
|
|
|
73
73
|
_fail "multi-model parse returned empty"
|
|
74
74
|
fi
|
|
75
75
|
|
|
76
|
+
# --- 2b. remote/cache fallback: invalid cache or failed remote uses bundled -
|
|
77
|
+
price_cache_dir="$(mktemp -d)"
|
|
78
|
+
printf '%s' '<html>console auth gate</html>' > "$price_cache_dir/flow-agents-pricing-cache.json"
|
|
79
|
+
poisoned_cost=$(TMPDIR="$price_cache_dir" TELEMETRY_PRICING_FILE="" FLOW_AGENTS_PRICING_FILE="" TELEMETRY_PRICING_URL="http://127.0.0.1:1/api/telemetry/pricing" FLOW_AGENTS_PRICING_URL="" usage_parse_transcript "$tp" | jq '.estimated_cost_usd')
|
|
80
|
+
poisoned_ver=$(TMPDIR="$price_cache_dir" TELEMETRY_PRICING_FILE="" FLOW_AGENTS_PRICING_FILE="" TELEMETRY_PRICING_URL="http://127.0.0.1:1/api/telemetry/pricing" FLOW_AGENTS_PRICING_URL="" pricing_registry | jq -r '.current_version')
|
|
81
|
+
if [ "$poisoned_ver" = "2026-06-28" ] && [ "$(approx_eq "$poisoned_cost" 0.31)" = "true" ]; then
|
|
82
|
+
_pass "poisoned HTML pricing cache is ignored; bundled registry prices known models (cost=$poisoned_cost)"
|
|
83
|
+
else
|
|
84
|
+
_fail "poisoned cache fallback expected bundled version/cost 0.31 (version=$poisoned_ver cost=$poisoned_cost)"
|
|
85
|
+
fi
|
|
86
|
+
rm -f "$price_cache_dir/flow-agents-pricing-cache.json" 2>/dev/null
|
|
87
|
+
failed_remote_cost=$(TMPDIR="$price_cache_dir" TELEMETRY_PRICING_FILE="" FLOW_AGENTS_PRICING_FILE="" TELEMETRY_PRICING_URL="http://127.0.0.1:1/api/telemetry/pricing" FLOW_AGENTS_PRICING_URL="" usage_parse_transcript "$tp" | jq '.estimated_cost_usd')
|
|
88
|
+
failed_remote_ver=$(TMPDIR="$price_cache_dir" TELEMETRY_PRICING_FILE="" FLOW_AGENTS_PRICING_FILE="" TELEMETRY_PRICING_URL="http://127.0.0.1:1/api/telemetry/pricing" FLOW_AGENTS_PRICING_URL="" pricing_registry | jq -r '.current_version')
|
|
89
|
+
if [ "$failed_remote_ver" = "2026-06-28" ] && [ "$(approx_eq "$failed_remote_cost" 0.31)" = "true" ]; then
|
|
90
|
+
_pass "failed/401-style remote falls through to bundled registry with non-zero cost (cost=$failed_remote_cost)"
|
|
91
|
+
else
|
|
92
|
+
_fail "failed remote fallback expected bundled version/cost 0.31 (version=$failed_remote_ver cost=$failed_remote_cost)"
|
|
93
|
+
fi
|
|
94
|
+
rm -rf "$price_cache_dir" 2>/dev/null
|
|
95
|
+
|
|
76
96
|
# --- 3. empty / no-usage transcript ----------------------------------------
|
|
77
97
|
empty="$(mktemp)"; echo '{"type":"user","message":{"content":"hi"}}' > "$empty"
|
|
78
98
|
if usage_parse_transcript "$empty" >/dev/null 2>&1; then _fail "empty transcript should return non-zero"; else _pass "empty transcript → non-zero (null fallback)"; fi
|
|
@@ -94,6 +114,24 @@ old_cost=$(TELEMETRY_PRICING_FILE="$v2" usage_parse_transcript "$tp2" "old" | jq
|
|
|
94
114
|
{ [ "$(approx_eq "$new_cost" 25)" = "true" ] && [ "$(approx_eq "$old_cost" 1)" = "true" ]; } \
|
|
95
115
|
&& _pass "version selection (default=25 @new, override=1 @old)" || _fail "version selection (new=$new_cost old=$old_cost)"
|
|
96
116
|
|
|
117
|
+
# --- 5b. corrupt registry (present but unparseable) degrades to tokens-only -
|
|
118
|
+
# Regression for: a non-empty-but-malformed registry (truncated pricing.json,
|
|
119
|
+
# bad remote 200) must NOT crash the jq -n --argjson parse and discard tokens
|
|
120
|
+
# — it should degrade exactly like a missing registry (cost/version -> null).
|
|
121
|
+
corrupt="$(mktemp)"; printf '%s' '{not valid json' > "$corrupt"
|
|
122
|
+
corrupt_res="$(TELEMETRY_PRICING_FILE="$corrupt" usage_parse_transcript "$tp")"
|
|
123
|
+
if [ -n "$corrupt_res" ]; then
|
|
124
|
+
cit=$(echo "$corrupt_res" | jq '.input_tokens'); cot=$(echo "$corrupt_res" | jq '.output_tokens')
|
|
125
|
+
ccost=$(echo "$corrupt_res" | jq -r '.estimated_cost_usd'); cver=$(echo "$corrupt_res" | jq -r '.pricing_version')
|
|
126
|
+
cby=$(echo "$corrupt_res" | jq '.by_model|length')
|
|
127
|
+
{ [ "$cit" = "1000" ] && [ "$cot" = "2100" ] && [ "$ccost" = "null" ] && [ "$cver" = "null" ] && [ "$cby" -gt 0 ]; } \
|
|
128
|
+
&& _pass "corrupt registry: tokens/by_model survive, cost+version degrade to null" \
|
|
129
|
+
|| _fail "corrupt registry (in=$cit out=$cot cost=$ccost ver=$cver by_model_len=$cby)"
|
|
130
|
+
else
|
|
131
|
+
_fail "corrupt registry: usage_parse_transcript returned empty (tokens were discarded)"
|
|
132
|
+
fi
|
|
133
|
+
rm -f "$corrupt" 2>/dev/null
|
|
134
|
+
|
|
97
135
|
# --- 6. cross-runtime golden vectors ---------------------------------------
|
|
98
136
|
n=$(jq '.cases|length' "$GOLDEN")
|
|
99
137
|
for i in $(seq 0 $((n - 1))); do
|
|
@@ -112,6 +150,29 @@ for i in $(seq 0 $((n - 1))); do
|
|
|
112
150
|
rm -f "$gtp"
|
|
113
151
|
done
|
|
114
152
|
|
|
153
|
+
# --- 7. usage_model_from_transcript_usage() — runtime-agnostic model derivation
|
|
154
|
+
echo ""
|
|
155
|
+
echo "Model derivation tests"
|
|
156
|
+
|
|
157
|
+
single="$(mktemp)"; mk_line "claude-opus-4-8" 100 200 0 0 > "$single"
|
|
158
|
+
single_res="$(usage_parse_transcript "$single")"
|
|
159
|
+
single_model="$(usage_model_from_transcript_usage "$single_res")"
|
|
160
|
+
[ "$single_model" = "claude-opus-4-8" ] && _pass "single-model transcript resolves that model" || _fail "single-model transcript (got $single_model)"
|
|
161
|
+
|
|
162
|
+
multi="$(mktemp)"
|
|
163
|
+
{ mk_line "claude-opus-4-8" 1000 2000 0 500000; mk_line "claude-fable-5" 0 100 0 0; } > "$multi"
|
|
164
|
+
multi_res="$(usage_parse_transcript "$multi")"
|
|
165
|
+
multi_model="$(usage_model_from_transcript_usage "$multi_res")"
|
|
166
|
+
[ "$multi_model" = "claude-opus-4-8" ] && _pass "multi-model transcript resolves dominant-by-tokens model (opus over fable)" || _fail "multi-model dominant resolution (got $multi_model)"
|
|
167
|
+
|
|
168
|
+
empty_model="$(usage_model_from_transcript_usage "null")"
|
|
169
|
+
[ -z "$empty_model" ] && _pass "null transcript_usage resolves empty (falls through to usage_get_model)" || _fail "expected empty for null transcript_usage (got $empty_model)"
|
|
170
|
+
|
|
171
|
+
blank_model="$(usage_model_from_transcript_usage "")"
|
|
172
|
+
[ -z "$blank_model" ] && _pass "empty-string transcript_usage resolves empty (falls through to usage_get_model)" || _fail "expected empty for blank transcript_usage (got $blank_model)"
|
|
173
|
+
|
|
174
|
+
rm -f "$single" "$multi" 2>/dev/null
|
|
175
|
+
|
|
115
176
|
rm -f "$ov" "$bad" "$tp" "$empty" "$drift" "$dlog" "$tp2" "$v2" 2>/dev/null
|
|
116
177
|
|
|
117
178
|
echo ""
|