@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,228 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# test_telemetry_usage_pipeline.sh — Layer 2: hermetic Stop-hook usage pipeline
|
|
3
|
+
#
|
|
4
|
+
# Proves the full telemetry.sh Stop path (add_stop_data_and_emit_usage) yields
|
|
5
|
+
# a session.usage event with real tokens, a concrete (non-"unknown") model,
|
|
6
|
+
# and a non-null estimated_cost_usd when a runtime transcript is supplied —
|
|
7
|
+
# and that tokens still survive (with estimated_cost_usd null) when the
|
|
8
|
+
# pricing registry is forced unavailable. Also guards the kiro-cli
|
|
9
|
+
# non-regression case: with no transcript, model still resolves via the
|
|
10
|
+
# existing usage_get_model() kiro lookup (unaffected by this fix).
|
|
11
|
+
#
|
|
12
|
+
# Uses the same TELEMETRY_DIR resolution convention as test_telemetry.sh
|
|
13
|
+
# (prefers context/scripts/telemetry when present) so this exercises the same
|
|
14
|
+
# copy CI actually runs, while explicitly pointing TELEMETRY_PRICING_FILE at
|
|
15
|
+
# the canonical bundled registry so pricing resolves regardless of which copy
|
|
16
|
+
# is under test (context/scripts/telemetry ships no bundled pricing.json).
|
|
17
|
+
set -uo pipefail
|
|
18
|
+
|
|
19
|
+
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
20
|
+
if [[ -d "$ROOT_DIR/context/scripts/telemetry" ]]; then
|
|
21
|
+
TELEMETRY_DIR="$ROOT_DIR/context/scripts/telemetry"
|
|
22
|
+
else
|
|
23
|
+
TELEMETRY_DIR="$HOME/.flow-agents/context/scripts/telemetry"
|
|
24
|
+
fi
|
|
25
|
+
TELEMETRY_SH="${TELEMETRY_DIR}/telemetry.sh"
|
|
26
|
+
PRICING_FILE="$ROOT_DIR/scripts/telemetry/pricing.json"
|
|
27
|
+
FIXTURE_TRANSCRIPT="$ROOT_DIR/evals/fixtures/telemetry/usage-transcript-sample.jsonl"
|
|
28
|
+
|
|
29
|
+
TMPDIR_EVAL=$(mktemp -d /tmp/eval-telemetry-usage-pipeline.XXXXXX)
|
|
30
|
+
TMPLOG="${TMPDIR_EVAL}/test-output.jsonl"
|
|
31
|
+
FAKE_HOME="${TMPDIR_EVAL}/home"
|
|
32
|
+
mkdir -p "$FAKE_HOME" "$TMPDIR_EVAL/sessions"
|
|
33
|
+
|
|
34
|
+
pass=0; fail=0
|
|
35
|
+
_pass() { echo " ✓ $1"; pass=$((pass + 1)); }
|
|
36
|
+
_fail() { echo " ✗ $1"; fail=$((fail + 1)); }
|
|
37
|
+
|
|
38
|
+
echo "=== Layer 2: Telemetry Usage Pipeline (hermetic fixture) ==="
|
|
39
|
+
echo ""
|
|
40
|
+
|
|
41
|
+
if [[ ! -f "$TELEMETRY_SH" ]]; then
|
|
42
|
+
_fail "telemetry.sh not found at $TELEMETRY_SH"
|
|
43
|
+
echo "Cannot continue without telemetry script"
|
|
44
|
+
rm -rf "$TMPDIR_EVAL"
|
|
45
|
+
exit 1
|
|
46
|
+
fi
|
|
47
|
+
if [[ ! -f "$FIXTURE_TRANSCRIPT" ]]; then
|
|
48
|
+
_fail "fixture transcript not found at $FIXTURE_TRANSCRIPT"
|
|
49
|
+
rm -rf "$TMPDIR_EVAL"
|
|
50
|
+
exit 1
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# Wait for a new line to land in TMPLOG (telemetry.sh's Stop path emits
|
|
54
|
+
# asynchronously even in foreground mode's background-adjacent callers).
|
|
55
|
+
_wait_for_line() {
|
|
56
|
+
local before_lines="$1" i=0 current_lines
|
|
57
|
+
while [[ $i -lt 50 ]]; do
|
|
58
|
+
current_lines=$(wc -l < "$TMPLOG" 2>/dev/null | tr -d ' ')
|
|
59
|
+
[[ "${current_lines:-0}" -gt "$before_lines" ]] && break
|
|
60
|
+
sleep 0.1; i=$((i + 1))
|
|
61
|
+
done
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
_wait_for_file_line() {
|
|
65
|
+
local file="$1" i=0 current_lines
|
|
66
|
+
while [[ $i -lt 50 ]]; do
|
|
67
|
+
current_lines=$(wc -l < "$file" 2>/dev/null | tr -d ' ')
|
|
68
|
+
[[ "${current_lines:-0}" -gt 0 ]] && break
|
|
69
|
+
sleep 0.1; i=$((i + 1))
|
|
70
|
+
done
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
# Run a real Stop event against a freshly-established session (agentSpawn
|
|
74
|
+
# first, matching real usage — Claude Code always sends SessionStart before
|
|
75
|
+
# Stop). Returns the emitted session.usage event (jq-compact, one line).
|
|
76
|
+
_run_stop() {
|
|
77
|
+
local input="$1"; shift
|
|
78
|
+
local extra_env_count="$#"
|
|
79
|
+
local extra_env=("$@")
|
|
80
|
+
local common_env=(
|
|
81
|
+
HOME="$FAKE_HOME"
|
|
82
|
+
TELEMETRY_ENABLED=true
|
|
83
|
+
TELEMETRY_CHANNELS=full
|
|
84
|
+
TELEMETRY_CHANNEL_FULL_LOG_FILE="$TMPLOG"
|
|
85
|
+
FLOW_AGENTS_TELEMETRY_FOREGROUND=true
|
|
86
|
+
TELEMETRY_CONFIG_FILE="$TMPDIR_EVAL/telemetry.conf"
|
|
87
|
+
TELEMETRY_DATA_DIR="$TMPDIR_EVAL"
|
|
88
|
+
TELEMETRY_SESSION_DIR="$TMPDIR_EVAL/sessions"
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
local before_lines
|
|
92
|
+
touch "$TMPLOG"
|
|
93
|
+
before_lines=$(wc -l < "$TMPLOG" | tr -d ' ')
|
|
94
|
+
echo '{"cwd":"/tmp"}' | env "${common_env[@]}" bash "$TELEMETRY_SH" agentSpawn dev >/dev/null 2>&1
|
|
95
|
+
_wait_for_line "$before_lines"
|
|
96
|
+
|
|
97
|
+
before_lines=$(wc -l < "$TMPLOG" | tr -d ' ')
|
|
98
|
+
if [[ "$extra_env_count" -gt 0 ]]; then
|
|
99
|
+
echo "$input" | env "${common_env[@]}" TELEMETRY_USAGE_TRACKING=true "${extra_env[@]}" \
|
|
100
|
+
bash "$TELEMETRY_SH" Stop dev 2>/dev/null
|
|
101
|
+
else
|
|
102
|
+
echo "$input" | env "${common_env[@]}" TELEMETRY_USAGE_TRACKING=true \
|
|
103
|
+
bash "$TELEMETRY_SH" Stop dev 2>/dev/null
|
|
104
|
+
fi
|
|
105
|
+
_wait_for_line "$before_lines"
|
|
106
|
+
|
|
107
|
+
tail -n +"$((before_lines + 1))" "$TMPLOG" 2>/dev/null | jq -c 'select(.event_type=="session.usage")' | tail -1
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
# --- 1. With transcript + pricing available: real tokens, cost, concrete model
|
|
111
|
+
echo "--- Fixture transcript, pricing available ---"
|
|
112
|
+
input1=$(jq -nc --arg tp "$FIXTURE_TRANSCRIPT" '{session_id:"pipeline-1",transcript_path:$tp,hook_event_name:"Stop"}')
|
|
113
|
+
out1=$(_run_stop "$input1" TELEMETRY_PRICING_FILE="$PRICING_FILE")
|
|
114
|
+
|
|
115
|
+
if [[ -n "$out1" ]]; then
|
|
116
|
+
model=$(echo "$out1" | jq -r '.usage.model')
|
|
117
|
+
it=$(echo "$out1" | jq -r '.usage.input_tokens')
|
|
118
|
+
ot=$(echo "$out1" | jq -r '.usage.output_tokens')
|
|
119
|
+
cost=$(echo "$out1" | jq -r '.usage.estimated_cost_usd')
|
|
120
|
+
by_model_len=$(echo "$out1" | jq -r '.usage.by_model | length')
|
|
121
|
+
|
|
122
|
+
[[ "$model" != "unknown" && "$model" != "null" && -n "$model" ]] && _pass "model is concrete (got: $model)" || _fail "model should not be unknown (got: $model)"
|
|
123
|
+
[[ "$model" == "claude-opus-4-8" ]] && _pass "model is the dominant-by-tokens model (claude-opus-4-8)" || _fail "expected dominant model claude-opus-4-8, got $model"
|
|
124
|
+
[[ "$it" != "null" && "$it" -gt 0 ]] && _pass "input_tokens is real and non-null (got: $it)" || _fail "input_tokens should be non-null/positive (got: $it)"
|
|
125
|
+
[[ "$ot" != "null" && "$ot" -gt 0 ]] && _pass "output_tokens is real and non-null (got: $ot)" || _fail "output_tokens should be non-null/positive (got: $ot)"
|
|
126
|
+
cost_positive=$(echo "$out1" | jq -r '(.usage.estimated_cost_usd // 0) > 0')
|
|
127
|
+
[[ "$cost" != "null" && "$cost_positive" == "true" ]] && _pass "estimated_cost_usd is real and non-null (got: $cost)" || _fail "estimated_cost_usd should be non-null/positive (got: $cost)"
|
|
128
|
+
[[ "$by_model_len" == "2" ]] && _pass "by_model has 2 entries" || _fail "expected 2 by_model entries, got $by_model_len"
|
|
129
|
+
else
|
|
130
|
+
_fail "no session.usage event emitted for fixture transcript"
|
|
131
|
+
fi
|
|
132
|
+
|
|
133
|
+
# --- 1b. Economics attribution: canonical current pointer beats stale legacy
|
|
134
|
+
echo ""
|
|
135
|
+
echo "--- Economics attribution uses canonical current pointer ---"
|
|
136
|
+
ATTR_CWD="${TMPDIR_EVAL}/workspace"
|
|
137
|
+
CANON_SLUG="canonical-task"
|
|
138
|
+
LEGACY_SLUG="legacy-task"
|
|
139
|
+
ECON_LOG="${TMPDIR_EVAL}/economics.jsonl"
|
|
140
|
+
mkdir -p "$ATTR_CWD/.kontourai/flow-agents/$CANON_SLUG" "$ATTR_CWD/.flow-agents/$LEGACY_SLUG"
|
|
141
|
+
: > "$ECON_LOG"
|
|
142
|
+
printf '%s\n' "{\"active_slug\":\"$CANON_SLUG\"}" > "$ATTR_CWD/.kontourai/flow-agents/current.json"
|
|
143
|
+
printf '%s\n' "{\"active_slug\":\"$LEGACY_SLUG\"}" > "$ATTR_CWD/.flow-agents/current.json"
|
|
144
|
+
printf '%s\n' '{"schema_version":"1.0","task_slug":"canonical-task","phase":"execution","verification_verdict":"PASS"}' > "$ATTR_CWD/.kontourai/flow-agents/$CANON_SLUG/state.json"
|
|
145
|
+
printf '%s\n' '{"schema_version":"1.0","task_slug":"legacy-task","phase":"execution","verification_verdict":"PASS"}' > "$ATTR_CWD/.flow-agents/$LEGACY_SLUG/state.json"
|
|
146
|
+
input_attr=$(jq -nc --arg tp "$FIXTURE_TRANSCRIPT" --arg cwd "$ATTR_CWD" '{session_id:"pipeline-attribution",transcript_path:$tp,hook_event_name:"Stop",cwd:$cwd}')
|
|
147
|
+
TELEMETRY_SH_SAVED="$TELEMETRY_SH"
|
|
148
|
+
TELEMETRY_SH="$ROOT_DIR/scripts/telemetry/telemetry.sh"
|
|
149
|
+
out_attr=$(_run_stop "$input_attr" TELEMETRY_PRICING_FILE="$PRICING_FILE" TELEMETRY_ECONOMICS_LOG_FILE="$ECON_LOG")
|
|
150
|
+
TELEMETRY_SH="$TELEMETRY_SH_SAVED"
|
|
151
|
+
_wait_for_file_line "$ECON_LOG"
|
|
152
|
+
|
|
153
|
+
if [[ -n "$out_attr" && -s "$ECON_LOG" ]]; then
|
|
154
|
+
attr_task=$(tail -1 "$ECON_LOG" | jq -r '.task_slug')
|
|
155
|
+
attr_phase=$(tail -1 "$ECON_LOG" | jq -r '.phases[0].phase')
|
|
156
|
+
[[ "$attr_task" == "$CANON_SLUG" ]] && _pass "economics record task_slug comes from canonical .kontourai current pointer" || _fail "expected canonical task_slug '$CANON_SLUG', got '$attr_task'"
|
|
157
|
+
[[ "$attr_phase" == "execution" ]] && _pass "economics record phase comes from canonical state.json" || _fail "expected canonical phase execution, got '$attr_phase'"
|
|
158
|
+
else
|
|
159
|
+
_fail "economics attribution record was not emitted for canonical-current test"
|
|
160
|
+
fi
|
|
161
|
+
|
|
162
|
+
# --- 2. Pricing forced unavailable: tokens survive, cost is null ------------
|
|
163
|
+
echo ""
|
|
164
|
+
echo "--- Fixture transcript, pricing forced unavailable ---"
|
|
165
|
+
input2=$(jq -nc --arg tp "$FIXTURE_TRANSCRIPT" '{session_id:"pipeline-2",transcript_path:$tp,hook_event_name:"Stop"}')
|
|
166
|
+
out2=$(_run_stop "$input2" TELEMETRY_PRICING_FILE=/nonexistent/pricing.json TELEMETRY_PRICING_URL="" FLOW_AGENTS_PRICING_FILE="" FLOW_AGENTS_PRICING_URL="")
|
|
167
|
+
|
|
168
|
+
if [[ -n "$out2" ]]; then
|
|
169
|
+
it2=$(echo "$out2" | jq -r '.usage.input_tokens')
|
|
170
|
+
ot2=$(echo "$out2" | jq -r '.usage.output_tokens')
|
|
171
|
+
cost2=$(echo "$out2" | jq -r '.usage.estimated_cost_usd')
|
|
172
|
+
pv2=$(echo "$out2" | jq -r '.usage.pricing_version')
|
|
173
|
+
model2=$(echo "$out2" | jq -r '.usage.model')
|
|
174
|
+
|
|
175
|
+
[[ "$it2" != "null" && "$it2" -gt 0 ]] && _pass "tokens survive when pricing unavailable (input_tokens=$it2)" || _fail "tokens should survive when pricing unavailable (got input_tokens=$it2)"
|
|
176
|
+
[[ "$ot2" != "null" && "$ot2" -gt 0 ]] && _pass "output_tokens survive when pricing unavailable (got: $ot2)" || _fail "output_tokens should survive when pricing unavailable (got: $ot2)"
|
|
177
|
+
[[ "$cost2" == "null" ]] && _pass "estimated_cost_usd is null when pricing unavailable (cost degrades, tokens don't)" || _fail "estimated_cost_usd should be null when pricing unavailable (got: $cost2)"
|
|
178
|
+
[[ "$pv2" == "null" ]] && _pass "pricing_version is null when pricing unavailable" || _fail "pricing_version should be null when pricing unavailable (got: $pv2)"
|
|
179
|
+
[[ "$model2" == "claude-opus-4-8" ]] && _pass "model still resolves from transcript when pricing unavailable" || _fail "expected model claude-opus-4-8, got $model2"
|
|
180
|
+
else
|
|
181
|
+
_fail "no session.usage event emitted when pricing forced unavailable"
|
|
182
|
+
fi
|
|
183
|
+
|
|
184
|
+
# --- 3. No transcript (kiro-cli style): model still resolves via kiro fallback, no regression
|
|
185
|
+
echo ""
|
|
186
|
+
echo "--- No transcript (kiro-cli non-regression) ---"
|
|
187
|
+
input3='{"session_id":"pipeline-3","hook_event_name":"Stop"}'
|
|
188
|
+
out3=$(_run_stop "$input3")
|
|
189
|
+
|
|
190
|
+
if [[ -n "$out3" ]]; then
|
|
191
|
+
model3=$(echo "$out3" | jq -r '.usage.model')
|
|
192
|
+
it3=$(echo "$out3" | jq -r '.usage.input_tokens')
|
|
193
|
+
by_model3=$(echo "$out3" | jq -r '.usage.by_model')
|
|
194
|
+
|
|
195
|
+
# FAKE_HOME has no ~/.kiro/agents spec, so usage_get_model's kiro lookup
|
|
196
|
+
# falls through to "unknown" — this is the pre-existing, unfixed kiro path
|
|
197
|
+
# and must be untouched by the transcript-model override (transcript_usage
|
|
198
|
+
# is null here, so model is never overridden).
|
|
199
|
+
[[ "$model3" == "unknown" ]] && _pass "no-transcript path still resolves via usage_get_model kiro fallback (unknown, no regression)" || _fail "expected kiro fallback 'unknown' with no transcript, got $model3"
|
|
200
|
+
[[ "$it3" == "null" ]] && _pass "input_tokens is null with no transcript (expected)" || _fail "expected null input_tokens with no transcript, got $it3"
|
|
201
|
+
[[ "$by_model3" == "null" ]] && _pass "by_model is null with no transcript (expected)" || _fail "expected null by_model with no transcript, got $by_model3"
|
|
202
|
+
else
|
|
203
|
+
_fail "no session.usage event emitted for no-transcript case"
|
|
204
|
+
fi
|
|
205
|
+
|
|
206
|
+
# --- 4. Empty transcript + TELEMETRY_USAGE_DEBUG=1: debug reason is emitted -
|
|
207
|
+
echo ""
|
|
208
|
+
echo "--- Empty transcript, TELEMETRY_USAGE_DEBUG=1 (debug path) ---"
|
|
209
|
+
EMPTY_TRANSCRIPT="${TMPDIR_EVAL}/empty-transcript.jsonl"
|
|
210
|
+
: > "$EMPTY_TRANSCRIPT"
|
|
211
|
+
DEBUG_DRIFT_LOG="${TMPDIR_EVAL}/debug-drift.log"
|
|
212
|
+
input4=$(jq -nc --arg tp "$EMPTY_TRANSCRIPT" '{session_id:"pipeline-4",transcript_path:$tp,hook_event_name:"Stop"}')
|
|
213
|
+
out4=$(_run_stop "$input4" TELEMETRY_USAGE_DEBUG=1 TELEMETRY_DRIFT_LOG="$DEBUG_DRIFT_LOG")
|
|
214
|
+
|
|
215
|
+
if grep -q '\[telemetry\] usage_parse_transcript:' "$DEBUG_DRIFT_LOG" 2>/dev/null; then
|
|
216
|
+
_pass "debug reason line emitted for empty-transcript no-usage scenario"
|
|
217
|
+
else
|
|
218
|
+
_fail "expected a usage_parse_transcript debug reason line in $DEBUG_DRIFT_LOG"
|
|
219
|
+
fi
|
|
220
|
+
|
|
221
|
+
model4=$(echo "$out4" | jq -r '.usage.model // "unknown"' 2>/dev/null)
|
|
222
|
+
[[ -z "$out4" || "$model4" == "unknown" ]] && _pass "empty-transcript path emits no real usage (no regression)" || _fail "expected no/unknown usage for empty transcript, got model=$model4"
|
|
223
|
+
|
|
224
|
+
rm -rf "$TMPDIR_EVAL"
|
|
225
|
+
|
|
226
|
+
echo ""
|
|
227
|
+
echo "Telemetry usage pipeline: $pass passed, $fail failed"
|
|
228
|
+
[ "$fail" -eq 0 ]
|
|
@@ -9,21 +9,23 @@
|
|
|
9
9
|
#
|
|
10
10
|
# 1. no-label-bypass (finding 1) → not-run: a test_output claim with no
|
|
11
11
|
# manifest-matched execution.label is a divergence, never session-local.
|
|
12
|
-
# 2.
|
|
13
|
-
#
|
|
12
|
+
# 2. mcp-degrade (issue 492) → not-run: an MCP-shaped execution.label is not a
|
|
13
|
+
# manifest command and can never be RECONCILED as a CI-verified command check.
|
|
14
|
+
# 3. skip-assumed-bypass (finding 2) → unwaived-assumed: 'assumed' alone is not a pass.
|
|
15
|
+
# 4. status-misassertion (finding 3) → status-misassertion: CI re-derives status; a
|
|
14
16
|
# self-reported status that does not match the bundle's own evidence is rejected.
|
|
15
|
-
#
|
|
17
|
+
# 5. waived-command-check (finding 4) → waiver-on-command-check: a command-backed
|
|
16
18
|
# (test_output) check cannot be waived.
|
|
17
|
-
#
|
|
19
|
+
# 6. ws3-old-style-bundle (AC6) → old all-test_output bundle FAILS the same way (exit 1,
|
|
18
20
|
# divergences) under the new reconciler as under the old one — no soundness regression.
|
|
19
|
-
#
|
|
21
|
+
# 7. fabricated-attestation (iteration-4, converged iteration-3 finding, both gates) → a
|
|
20
22
|
# fully self-consistent, hand-fabricated no-command 'security' claim+evidence+event
|
|
21
23
|
# triple (indistinguishable from a genuine attestation at the reconciler's own
|
|
22
24
|
# re-derivation layer) MUST still pass (exit 0 — blocking attestations at L0 would break
|
|
23
25
|
# every honest human-attestation use) BUT MUST be loudly, distinctly marked
|
|
24
26
|
# 'ATTESTED (not independently verifiable at L0)' plus the summary count line — never a
|
|
25
27
|
# quiet SESSION-LOCAL OK indistinguishable from a reconciled check. See ADR 0020 Residuals.
|
|
26
|
-
#
|
|
28
|
+
# 8. delivery/DECLARED marker regressions (ADR 0022 §1/§2, section 7 below) — bundle-absent
|
|
27
29
|
# fail-closed default, malformed/empty-array/missing-field diagnostics, and all four
|
|
28
30
|
# matchesScope() forms (ref:, commit: single + range, author:, branch-prefix:) including
|
|
29
31
|
# positive AND near-miss coverage, plus the compound (space-separated AND) scope form a
|
|
@@ -40,6 +42,7 @@
|
|
|
40
42
|
set -uo pipefail
|
|
41
43
|
|
|
42
44
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
45
|
+
source "$ROOT/evals/lib/node.sh"
|
|
43
46
|
RECONCILE="$ROOT/scripts/ci/trust-reconcile.js"
|
|
44
47
|
FX="$ROOT/evals/fixtures/trust-reconcile-exploits"
|
|
45
48
|
WS3="$ROOT/evals/fixtures/trust-reconcile-ws3/ws3-bundle.json"
|
|
@@ -48,10 +51,12 @@ errors=0
|
|
|
48
51
|
_pass() { echo " PASS: $1"; }
|
|
49
52
|
_fail() { echo " FAIL: $1"; errors=$((errors + 1)); }
|
|
50
53
|
|
|
51
|
-
# run_case <label> <bundle> <needle>
|
|
52
|
-
# Asserts: reconciler exits non-zero
|
|
54
|
+
# run_case <label> <bundle> <needle> [forbidden]
|
|
55
|
+
# Asserts: reconciler exits non-zero, stdout/stderr contains <needle>, and optionally does
|
|
56
|
+
# NOT contain <forbidden>.
|
|
53
57
|
run_case() {
|
|
54
58
|
local label="$1" bundle="$2" needle="$3"
|
|
59
|
+
local forbidden="${4:-}"
|
|
55
60
|
echo "=== $label ==="
|
|
56
61
|
if [[ ! -f "$bundle" ]]; then _fail "$label: fixture not found at $bundle"; return; fi
|
|
57
62
|
local out code
|
|
@@ -68,25 +73,38 @@ run_case() {
|
|
|
68
73
|
else
|
|
69
74
|
_fail "$label: expected divergence \"$needle\" not found — output: $out"
|
|
70
75
|
fi
|
|
76
|
+
if [[ -n "$forbidden" ]]; then
|
|
77
|
+
if echo "$out" | grep -qF "$forbidden"; then
|
|
78
|
+
_fail "$label: must NOT emit \"$forbidden\" — output: $out"
|
|
79
|
+
else
|
|
80
|
+
_pass "$label: does not emit \"$forbidden\""
|
|
81
|
+
fi
|
|
82
|
+
fi
|
|
71
83
|
}
|
|
72
84
|
|
|
73
85
|
# 1. Reviewer's no-label exploit → not-run (test_output must reconcile against the manifest).
|
|
74
86
|
run_case "no-label-bypass (finding 1)" "$FX/no-label-bypass.json" \
|
|
75
87
|
"no manifest-matched execution.label"
|
|
76
88
|
|
|
77
|
-
# 2.
|
|
89
|
+
# 2. Issue #492: MCP-shaped self-reported pass → not-run (not manifest-matched), never
|
|
90
|
+
# RECONCILED as a CI-verified command check.
|
|
91
|
+
run_case "mcp-degrade (issue 492)" "$FX/mcp-degrade.json" \
|
|
92
|
+
"command is not in the reconcile manifest" \
|
|
93
|
+
"RECONCILED"
|
|
94
|
+
|
|
95
|
+
# 3. Verifier's skip->assumed exploit → unwaived-assumed.
|
|
78
96
|
run_case "skip-assumed-bypass (finding 2)" "$FX/skip-assumed-bypass.json" \
|
|
79
97
|
"[unwaived-assumed]"
|
|
80
98
|
|
|
81
|
-
#
|
|
99
|
+
# 4. Status-misassertion exploit → status re-derived CI-side; asserted != derived.
|
|
82
100
|
run_case "status-misassertion (finding 3)" "$FX/status-misassertion.json" \
|
|
83
101
|
"[status-misassertion]"
|
|
84
102
|
|
|
85
|
-
#
|
|
103
|
+
# 5. Waived command-backed check → waiver-on-command-check.
|
|
86
104
|
run_case "waived-command-check (finding 4)" "$FX/waived-command-check.json" \
|
|
87
105
|
"[waiver-on-command-check]"
|
|
88
106
|
|
|
89
|
-
#
|
|
107
|
+
# 6. AC6 backward-compat regression: the real ws3-kit-dependencies-namespacing/trust.bundle
|
|
90
108
|
# (an old-style all-test_output bundle whose commands are not manifest-matched) FAILS the
|
|
91
109
|
# same way under the new reconciler as under the old one — same FAIL verdict, divergences
|
|
92
110
|
# present, no silent pass introduced.
|
|
@@ -114,7 +132,7 @@ else
|
|
|
114
132
|
fi
|
|
115
133
|
fi
|
|
116
134
|
|
|
117
|
-
#
|
|
135
|
+
# 7. Fabricated-attestation (iteration-4): passes (exit 0) but MUST carry the loud ATTESTED
|
|
118
136
|
# marker and the summary count line — NOT the old quiet SESSION-LOCAL OK. This is a
|
|
119
137
|
# visibility assertion, not a divergence assertion (unlike run_case above): a fabricated
|
|
120
138
|
# self-consistent attestation bundle is, by construction, indistinguishable from a genuine
|
|
@@ -919,6 +937,96 @@ else
|
|
|
919
937
|
_fail "prefer-newest: expected 'owning, newest wins' in the selection line -- output: $out8d"
|
|
920
938
|
fi
|
|
921
939
|
|
|
940
|
+
# 9. [iteration-1 F1 CRITICAL regression guard] CI trust-reconcile.js MUST stay fail-closed
|
|
941
|
+
# when scripts/ci/derive-claim-status.mjs is unavailable (Surface unresolvable, spawn
|
|
942
|
+
# failure, malformed bundle, etc.) -- deriveClaimStatuses() returns null in that case, and
|
|
943
|
+
# BEFORE #356's extraction the inline session-local loop turned every session-local
|
|
944
|
+
# pass-asserting claim into a `status-underivable` divergence (hard FAIL). The extraction's
|
|
945
|
+
# shared sessionLocalShapeIssues() briefly made that a caller-controlled `onUnderivable` mode
|
|
946
|
+
# (see reconcile-shape.js) -- this section proves CI still defaults/forces the safe 'fail'
|
|
947
|
+
# mode, and (paired) that the LOCAL reconcile-preflight intentionally diverges into the
|
|
948
|
+
# 'reduce' mode on the exact same bundle. Without the fix, case 9a below FAILS (exits 0
|
|
949
|
+
# instead of 1) -- this is the single regression eval that let the CRITICAL through
|
|
950
|
+
# code-review-356 iteration 0.
|
|
951
|
+
echo ""
|
|
952
|
+
echo "=== 9. derive-claim-status.mjs unavailable: CI fail-closed vs local-preflight reduced-coverage (iteration-1 F1) ==="
|
|
953
|
+
|
|
954
|
+
DERIVE_HELPER="$ROOT/scripts/ci/derive-claim-status.mjs"
|
|
955
|
+
DERIVE_HELPER_HIDDEN="$DERIVE_HELPER.hidden-by-test-9"
|
|
956
|
+
|
|
957
|
+
# hide_derive_helper / restore_derive_helper: rename the real ESM helper out of the way so
|
|
958
|
+
# scripts/ci/trust-reconcile.js's deriveClaimStatuses() -- which does fs.existsSync(helper)
|
|
959
|
+
# before ever spawning it -- returns null exactly as it would if Surface could not resolve.
|
|
960
|
+
# Always restored via trap, including on a hard failure of this script.
|
|
961
|
+
hide_derive_helper() {
|
|
962
|
+
if [[ -f "$DERIVE_HELPER" ]]; then
|
|
963
|
+
mv "$DERIVE_HELPER" "$DERIVE_HELPER_HIDDEN"
|
|
964
|
+
fi
|
|
965
|
+
}
|
|
966
|
+
restore_derive_helper() {
|
|
967
|
+
if [[ -f "$DERIVE_HELPER_HIDDEN" ]]; then
|
|
968
|
+
mv "$DERIVE_HELPER_HIDDEN" "$DERIVE_HELPER"
|
|
969
|
+
fi
|
|
970
|
+
}
|
|
971
|
+
trap 'cleanup_declared; rm -rf "$PERSESSION_TMPROOT"; restore_derive_helper' EXIT
|
|
972
|
+
|
|
973
|
+
# A one-claim, session-local, pass-asserting bundle (reuses the finding-3 exploit fixture --
|
|
974
|
+
# a human_attestation-backed claim asserting status "verified"; any session-local
|
|
975
|
+
# pass-asserting claim exercises this path since the whole derivedStatus map is null, not a
|
|
976
|
+
# single claim's lookup).
|
|
977
|
+
CASE9_BUNDLE="$FX/status-misassertion.json"
|
|
978
|
+
|
|
979
|
+
hide_derive_helper
|
|
980
|
+
|
|
981
|
+
# 9a. CI (real scripts/ci/trust-reconcile.js): derive-claim-status.mjs unavailable -> MUST
|
|
982
|
+
# still exit non-zero (status-underivable, fail-closed) -- the pre-#356 guarantee.
|
|
983
|
+
out9a="$(TRUST_RECONCILE_COMMANDS="node -e 'process.exit(0)'" \
|
|
984
|
+
node "$RECONCILE" --bundle "$CASE9_BUNDLE" --repo-root "$ROOT" 2>&1)"
|
|
985
|
+
code9a=$?
|
|
986
|
+
if [[ $code9a -ne 0 ]]; then
|
|
987
|
+
_pass "derive-unavailable-ci: reconciler exits non-zero ($code9a) -- fail-closed preserved when re-derivation is unavailable"
|
|
988
|
+
else
|
|
989
|
+
_fail "derive-unavailable-ci: expected non-zero exit (fail-closed), got 0 -- output: $out9a"
|
|
990
|
+
fi
|
|
991
|
+
if echo "$out9a" | grep -qF "[status-underivable]"; then
|
|
992
|
+
_pass "derive-unavailable-ci: emitted the status-underivable divergence"
|
|
993
|
+
else
|
|
994
|
+
_fail "derive-unavailable-ci: expected a [status-underivable] divergence -- output: $out9a"
|
|
995
|
+
fi
|
|
996
|
+
if echo "$out9a" | grep -qF "refusing to trust a self-reported status (fail-closed)"; then
|
|
997
|
+
_pass "derive-unavailable-ci: emitted the verbatim fail-closed message"
|
|
998
|
+
else
|
|
999
|
+
_fail "derive-unavailable-ci: expected the verbatim fail-closed message -- output: $out9a"
|
|
1000
|
+
fi
|
|
1001
|
+
|
|
1002
|
+
# 9b. Paired proof the modes diverge intentionally: the LOCAL reconcile-preflight, on the
|
|
1003
|
+
# SAME bundle with the SAME helper hidden, DEGRADES -- it does not hard-fail on the
|
|
1004
|
+
# underivable-status dimension (it opts into reduce mode explicitly; see
|
|
1005
|
+
# src/cli/workflow-sidecar.ts's runReconcilePreflight).
|
|
1006
|
+
# Nested under a subdirectory (not the raw mktemp -d path) -- mktemp -d's own
|
|
1007
|
+
# "tmp.XXXXXXXXXX" basename contains a dot that path.extname()/artifactDirFrom() would
|
|
1008
|
+
# misparse as a file extension, incorrectly stripping the directory segment.
|
|
1009
|
+
CASE9_TMPROOT="$(mktemp -d)"
|
|
1010
|
+
CASE9_SESSION="$CASE9_TMPROOT/session"
|
|
1011
|
+
mkdir -p "$CASE9_SESSION"
|
|
1012
|
+
cp "$CASE9_BUNDLE" "$CASE9_SESSION/trust.bundle"
|
|
1013
|
+
out9b="$(flow_agents_node workflow-sidecar reconcile-preflight "$CASE9_SESSION" --repo-root "$ROOT" 2>&1)"
|
|
1014
|
+
code9b=$?
|
|
1015
|
+
rm -rf "$CASE9_TMPROOT"
|
|
1016
|
+
if [[ $code9b -eq 0 ]]; then
|
|
1017
|
+
_pass "derive-unavailable-local-preflight: reconcile-preflight exits 0 (reduced-coverage degrade, not a hard fail) -- proves the CI/local modes diverge intentionally"
|
|
1018
|
+
else
|
|
1019
|
+
_fail "derive-unavailable-local-preflight: expected exit 0 (reduced-coverage degrade), got $code9b -- output: $out9b"
|
|
1020
|
+
fi
|
|
1021
|
+
if echo "$out9b" | grep -qF "status-underivable"; then
|
|
1022
|
+
_fail "derive-unavailable-local-preflight: must NOT emit status-underivable in reduced-coverage mode -- output: $out9b"
|
|
1023
|
+
else
|
|
1024
|
+
_pass "derive-unavailable-local-preflight: does not emit status-underivable (reduced-coverage checks only)"
|
|
1025
|
+
fi
|
|
1026
|
+
|
|
1027
|
+
restore_derive_helper
|
|
1028
|
+
|
|
1029
|
+
|
|
922
1030
|
echo ""
|
|
923
1031
|
if [[ $errors -eq 0 ]]; then
|
|
924
1032
|
echo "test_trust_reconcile_negatives: all checks passed."
|