@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
|
@@ -77,6 +77,263 @@ echo "--- captured real-veritas-output fixtures ---"
|
|
|
77
77
|
gate_case "$KIT/fixtures/readiness/ready.readiness-report.json" "positive" 0
|
|
78
78
|
gate_case "$KIT/fixtures/readiness/not-ready.readiness-report.json" "negative" 1
|
|
79
79
|
|
|
80
|
+
# --- exemption-issuance flow: registration/K0 validity ---------------------------
|
|
81
|
+
EXEMPTION_FLOWDEF="$KIT/flows/exemption-issuance.flow.json"
|
|
82
|
+
if node -e "const f=require('$EXEMPTION_FLOWDEF'); if(f.id!=='veritas-governance.exemption-issuance') process.exit(1);" 2>/dev/null; then
|
|
83
|
+
pass "exemption-issuance flow file has id veritas-governance.exemption-issuance"
|
|
84
|
+
else
|
|
85
|
+
fail "exemption-issuance flow file missing or has unexpected id"
|
|
86
|
+
fi
|
|
87
|
+
if rg -q '"id": *"veritas-governance\.exemption-issuance"' "$KIT/kit.json" && rg -q '"path": *"flows/exemption-issuance\.flow\.json"' "$KIT/kit.json"; then
|
|
88
|
+
pass "exemption-issuance flow is registered in kit.json flows[]"
|
|
89
|
+
else
|
|
90
|
+
fail "exemption-issuance flow is NOT registered in kit.json flows[]"
|
|
91
|
+
fi
|
|
92
|
+
# Re-run the whole-kit container validation (already covers the new flow file too, since
|
|
93
|
+
# `flow kit validate` walks every flows[] entry) — a second explicit assertion, scoped to
|
|
94
|
+
# this flow's own gate shape, per AC2.
|
|
95
|
+
if node -e "
|
|
96
|
+
const f=require('$EXEMPTION_FLOWDEF');
|
|
97
|
+
const g=Object.values(f.gates)[0];
|
|
98
|
+
const bc=g.expects[0].bundle_claim;
|
|
99
|
+
if (g.expects[0].kind!=='trust.bundle') process.exit(1);
|
|
100
|
+
if (bc.claimType!=='no-agent-delivery-exemption-approval') process.exit(1);
|
|
101
|
+
if (bc.subjectType!=='delivery-scope') process.exit(1);
|
|
102
|
+
if (JSON.stringify(bc.accepted_statuses)!=='[\"verified\"]') process.exit(1);
|
|
103
|
+
" 2>/dev/null; then
|
|
104
|
+
pass "exemption-issuance gate expects[] kind is trust.bundle and pins claimType/subjectType/accepted_statuses exactly"
|
|
105
|
+
else
|
|
106
|
+
fail "exemption-issuance gate expects[] shape does not match the pinned claim selector"
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
# --- exemption-issuance flow: positive/negative gate cases (AC3) -----------------
|
|
110
|
+
# gate_case() above is readiness-check-specific (drives the readiness adapter + fixed gate
|
|
111
|
+
# id gate-check-gate). The exemption-issuance flow has no adapter (issue's Files list does
|
|
112
|
+
# not add one — the approval bundle is hand-authored/fixture-authored) and a different gate
|
|
113
|
+
# id, so it gets its own small helper.
|
|
114
|
+
# $1 bundle fixture path, $2 label, $3 expected exit (0=pass, 1=block)
|
|
115
|
+
exemption_gate_case() {
|
|
116
|
+
local bundle="$1" label="$2" expect="$3"
|
|
117
|
+
local work="$TMP_DIR/$label"; mkdir -p "$work"; ( cd "$work" && node "$FLOW_CLI" init >/dev/null 2>&1 )
|
|
118
|
+
( cd "$work" && node "$FLOW_CLI" start "$EXEMPTION_FLOWDEF" --run-id "$label" >/dev/null 2>&1 )
|
|
119
|
+
( cd "$work" && node "$FLOW_CLI" attach-evidence "$label" --gate human-approval-gate --file "$bundle" --bundle >"$work/attach.out" 2>&1 )
|
|
120
|
+
if ! rg -q 'kind: trust.bundle' "$work/attach.out"; then
|
|
121
|
+
fail "[$label] evidence did not attach as kind: trust.bundle"; sed -n '1,20p' "$work/attach.out"; return
|
|
122
|
+
fi
|
|
123
|
+
( cd "$work" && node "$FLOW_CLI" evaluate "$label" --gate human-approval-gate --exit-code >"$work/eval.out" 2>&1 )
|
|
124
|
+
local got=$?
|
|
125
|
+
if [[ "$got" == "$expect" ]]; then
|
|
126
|
+
pass "[$label] exemption-issuance gate evaluate exit $got as expected ($(rg -o '^(pass|block|route-back) human-approval-gate.*' "$work/eval.out" | head -1))"
|
|
127
|
+
else
|
|
128
|
+
fail "[$label] exemption-issuance gate evaluate exit $got, expected $expect"; sed -n '1,20p' "$work/eval.out"
|
|
129
|
+
fi
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
echo "--- exemption-issuance: gate blocks without a verified approval, passes with one ---"
|
|
133
|
+
exemption_gate_case "$KIT/fixtures/exemption/approved.trust-bundle.json" "exemption-positive" 0
|
|
134
|
+
exemption_gate_case "$KIT/fixtures/exemption/not-approved.trust-bundle.json" "exemption-negative" 1
|
|
135
|
+
|
|
136
|
+
# --- exemption-issuance: issue-step DECLARED append semantics (AC4) --------------
|
|
137
|
+
# Seed a scratch delivery/DECLARED with main's real 2-entry array (inlined here, not read
|
|
138
|
+
# live from the repo, so this eval is not coupled to that file's future contents), then
|
|
139
|
+
# simulate the issue step's write: append a third, well-formed entry. Assert append, not
|
|
140
|
+
# clobber: length 3, and the first two entries byte-identical pre/post.
|
|
141
|
+
echo "--- exemption-issuance: issue step appends to delivery/DECLARED, does not clobber ---"
|
|
142
|
+
DECLARED_WORK="$TMP_DIR/declared-append"
|
|
143
|
+
mkdir -p "$DECLARED_WORK/delivery"
|
|
144
|
+
SEEDED_DECLARED='[
|
|
145
|
+
{
|
|
146
|
+
"scope": "author:dependabot[bot]",
|
|
147
|
+
"reason": "dependabot dependency-update PRs; no agent delivery involved",
|
|
148
|
+
"approved_by": "brian.anderson1222 (AC8 option-a decision, ADR 0022 approval 2026-07-02)",
|
|
149
|
+
"declared_at": "2026-07-03T16:27:21Z"
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"scope": "author:github-actions[bot] branch-prefix:release-please--",
|
|
153
|
+
"reason": "release-please automation PR; no agent delivery involved",
|
|
154
|
+
"approved_by": "brian.anderson1222 (AC8 option-a decision, ADR 0022 approval 2026-07-02)",
|
|
155
|
+
"declared_at": "2026-07-03T16:27:21Z"
|
|
156
|
+
}
|
|
157
|
+
]'
|
|
158
|
+
printf '%s' "$SEEDED_DECLARED" > "$DECLARED_WORK/delivery/DECLARED.seed"
|
|
159
|
+
|
|
160
|
+
NEW_ENTRY_SCOPE="author:exemption-eval-bot[bot]"
|
|
161
|
+
NEW_ENTRY_ACTOR="exemption-eval-bot[bot]"
|
|
162
|
+
NEW_ENTRY_REASON="exemption-issuance eval: no-agent-delivery exemption for a test bot scope"
|
|
163
|
+
NEW_ENTRY_APPROVED_BY="eval-fixture-approver (exemption-issuance flow)"
|
|
164
|
+
NEW_ENTRY_DECLARED_AT="2026-07-01T00:00:00Z"
|
|
165
|
+
|
|
166
|
+
# Simulate the issue step: read-modify-write (parse the existing array, append one entry).
|
|
167
|
+
node -e "
|
|
168
|
+
const fs = require('fs');
|
|
169
|
+
const seedPath = '$DECLARED_WORK/delivery/DECLARED.seed';
|
|
170
|
+
const outPath = '$DECLARED_WORK/delivery/DECLARED';
|
|
171
|
+
const existing = JSON.parse(fs.readFileSync(seedPath, 'utf8'));
|
|
172
|
+
const appended = existing.concat([{
|
|
173
|
+
scope: '$NEW_ENTRY_SCOPE',
|
|
174
|
+
reason: '$NEW_ENTRY_REASON',
|
|
175
|
+
approved_by: '$NEW_ENTRY_APPROVED_BY',
|
|
176
|
+
declared_at: '$NEW_ENTRY_DECLARED_AT'
|
|
177
|
+
}]);
|
|
178
|
+
fs.writeFileSync(outPath, JSON.stringify(appended, null, 2) + '\n');
|
|
179
|
+
"
|
|
180
|
+
|
|
181
|
+
if node -e "
|
|
182
|
+
const fs = require('fs');
|
|
183
|
+
const seeded = JSON.parse(fs.readFileSync('$DECLARED_WORK/delivery/DECLARED.seed', 'utf8'));
|
|
184
|
+
const appended = JSON.parse(fs.readFileSync('$DECLARED_WORK/delivery/DECLARED', 'utf8'));
|
|
185
|
+
if (!Array.isArray(appended) || appended.length !== 3) process.exit(1);
|
|
186
|
+
if (JSON.stringify(appended[0]) !== JSON.stringify(seeded[0])) process.exit(1);
|
|
187
|
+
if (JSON.stringify(appended[1]) !== JSON.stringify(seeded[1])) process.exit(1);
|
|
188
|
+
"; then
|
|
189
|
+
pass "issue-step append: 3 entries present, first two byte-identical to the seeded 2-entry array (append, not clobber)"
|
|
190
|
+
else
|
|
191
|
+
fail "issue-step append: entry count or pre-existing entries diverged from the seeded array"
|
|
192
|
+
fi
|
|
193
|
+
|
|
194
|
+
if node -e "
|
|
195
|
+
const fs = require('fs');
|
|
196
|
+
const appended = JSON.parse(fs.readFileSync('$DECLARED_WORK/delivery/DECLARED', 'utf8'));
|
|
197
|
+
const entry = appended[2];
|
|
198
|
+
const required = ['scope', 'reason', 'approved_by', 'declared_at'];
|
|
199
|
+
for (const f of required) {
|
|
200
|
+
if (typeof entry[f] !== 'string' || entry[f].trim() === '') process.exit(1);
|
|
201
|
+
}
|
|
202
|
+
"; then
|
|
203
|
+
pass "issue-step append: appended entry is well-formed (scope/reason/approved_by/declared_at all present, non-empty)"
|
|
204
|
+
else
|
|
205
|
+
fail "issue-step append: appended entry is missing/empty a required field"
|
|
206
|
+
fi
|
|
207
|
+
|
|
208
|
+
# --- exemption-issuance: REAL trust-reconcile.js reads the appended marker (AC5) -
|
|
209
|
+
# Reuse test_trust_reconcile_negatives.sh section 7's write_declared/env-override pattern:
|
|
210
|
+
# TRUST_RECONCILE_COMMANDS is a trivial pass so Step 1 always succeeds; TRUST_RECONCILE_ACTOR
|
|
211
|
+
# is set to match the appended entry's author: scope exactly (the bare actor name, without
|
|
212
|
+
# the "author:" prefix, matching matchesScope()'s author: condition contract).
|
|
213
|
+
echo "--- exemption-issuance: REAL trust-reconcile.js reads the appended marker as well-formed and in-scope ---"
|
|
214
|
+
RECONCILE="$ROOT/scripts/ci/trust-reconcile.js"
|
|
215
|
+
RECONCILE_CMD="node -e 'process.exit(0)'"
|
|
216
|
+
|
|
217
|
+
reconcile_out="$(TRUST_RECONCILE_ACTOR="$NEW_ENTRY_ACTOR" TRUST_RECONCILE_COMMANDS="$RECONCILE_CMD" \
|
|
218
|
+
node "$RECONCILE" --repo-root "$DECLARED_WORK" 2>&1)"
|
|
219
|
+
reconcile_code=$?
|
|
220
|
+
if [[ "$reconcile_code" -eq 0 ]]; then
|
|
221
|
+
pass "trust-reconcile.js exits 0 against the appended 3-entry delivery/DECLARED (in-scope match)"
|
|
222
|
+
else
|
|
223
|
+
fail "trust-reconcile.js expected exit 0, got $reconcile_code — output: $reconcile_out"
|
|
224
|
+
fi
|
|
225
|
+
if echo "$reconcile_out" | grep -qF "DECLARED (no-agent-delivery): $NEW_ENTRY_SCOPE — $NEW_ENTRY_REASON (approved by $NEW_ENTRY_APPROVED_BY, declared $NEW_ENTRY_DECLARED_AT)"; then
|
|
226
|
+
pass "trust-reconcile.js emits the exact DECLARED (no-agent-delivery) line for the appended entry"
|
|
227
|
+
else
|
|
228
|
+
fail "trust-reconcile.js did not emit the expected DECLARED (no-agent-delivery) line — output: $reconcile_out"
|
|
229
|
+
fi
|
|
230
|
+
|
|
231
|
+
# --- exemption-issuance: negative — malformed/out-of-scope append still fails closed (AC6) --
|
|
232
|
+
# This case's DECLARED file has the two pre-existing WELL-FORMED entries (dependabot,
|
|
233
|
+
# release-please) plus a malformed appended (third) entry (missing approved_by). The
|
|
234
|
+
# malformed entry is excluded from parseDeclaredMarker()'s wellFormed[] bucket entirely (its
|
|
235
|
+
# "missing required field(s)" line is only a non-fatal stderr warning, logged so one bad
|
|
236
|
+
# entry cannot silently mask a good one -- see resolveDeclaredExemption()); scope-matching
|
|
237
|
+
# then proceeds against the two remaining well-formed entries, neither of which matches this
|
|
238
|
+
# case's TRUST_RECONCILE_ACTOR context, so the FATAL diagnostic that actually fires is the
|
|
239
|
+
# scope-mismatch path, not the missing-field path. This proves: a malformed appended entry
|
|
240
|
+
# is ignored as an entry (does not itself exempt Step 2), and with no other in-scope
|
|
241
|
+
# well-formed entry present, the reconciler still fails closed overall.
|
|
242
|
+
echo "--- exemption-issuance: malformed appended entry is ignored; no in-scope entry remains -> fails closed ---"
|
|
243
|
+
DECLARED_NEG_WORK="$TMP_DIR/declared-append-negative"
|
|
244
|
+
mkdir -p "$DECLARED_NEG_WORK/delivery"
|
|
245
|
+
# Same seed, but the appended (third) entry is missing approved_by — malformed.
|
|
246
|
+
SEEDED_DECLARED_JSON="$SEEDED_DECLARED" NEW_ENTRY_SCOPE="$NEW_ENTRY_SCOPE" NEW_ENTRY_REASON="$NEW_ENTRY_REASON" NEW_ENTRY_DECLARED_AT="$NEW_ENTRY_DECLARED_AT" OUT_PATH="$DECLARED_NEG_WORK/delivery/DECLARED" node -e "
|
|
247
|
+
const fs = require('fs');
|
|
248
|
+
const existing = JSON.parse(process.env.SEEDED_DECLARED_JSON);
|
|
249
|
+
const appended = existing.concat([{
|
|
250
|
+
scope: process.env.NEW_ENTRY_SCOPE,
|
|
251
|
+
reason: process.env.NEW_ENTRY_REASON,
|
|
252
|
+
declared_at: process.env.NEW_ENTRY_DECLARED_AT
|
|
253
|
+
}]);
|
|
254
|
+
fs.writeFileSync(process.env.OUT_PATH, JSON.stringify(appended, null, 2) + '\n');
|
|
255
|
+
"
|
|
256
|
+
neg_out="$(TRUST_RECONCILE_ACTOR="$NEW_ENTRY_ACTOR" TRUST_RECONCILE_COMMANDS="$RECONCILE_CMD" \
|
|
257
|
+
node "$RECONCILE" --repo-root "$DECLARED_NEG_WORK" 2>&1)"
|
|
258
|
+
neg_code=$?
|
|
259
|
+
if [[ "$neg_code" -ne 0 ]]; then
|
|
260
|
+
pass "trust-reconcile.js fails closed ($neg_code): malformed appended entry ignored, no in-scope well-formed entry remains"
|
|
261
|
+
else
|
|
262
|
+
fail "trust-reconcile.js expected non-zero exit on a malformed appended entry, got 0 — output: $neg_out"
|
|
263
|
+
fi
|
|
264
|
+
if echo "$neg_out" | grep -qF "[bundle-required-no-declared-marker] delivery/DECLARED marker present but out of scope for this change"; then
|
|
265
|
+
pass "trust-reconcile.js's FATAL diagnostic is the out-of-scope path (the malformed entry itself never satisfies the gate)"
|
|
266
|
+
else
|
|
267
|
+
fail "trust-reconcile.js did not emit the expected out-of-scope FATAL diagnostic — output: $neg_out"
|
|
268
|
+
fi
|
|
269
|
+
|
|
270
|
+
# Companion variant (true missing-field proof): a DECLARED file whose ONLY entry is the
|
|
271
|
+
# malformed one (no other well-formed entry to fall through to) — here the FATAL diagnostic
|
|
272
|
+
# IS the malformed/missing-field path itself, naming approved_by, per the merged reconciler's
|
|
273
|
+
# exact string (resolveDeclaredExemption(), wellFormed.length === 0 branch).
|
|
274
|
+
echo "--- exemption-issuance: DECLARED file with ONLY a malformed entry -> the missing-field diagnostic itself is fatal ---"
|
|
275
|
+
DECLARED_ONLY_MALFORMED_WORK="$TMP_DIR/declared-only-malformed"
|
|
276
|
+
mkdir -p "$DECLARED_ONLY_MALFORMED_WORK/delivery"
|
|
277
|
+
NEW_ENTRY_SCOPE="$NEW_ENTRY_SCOPE" NEW_ENTRY_REASON="$NEW_ENTRY_REASON" NEW_ENTRY_DECLARED_AT="$NEW_ENTRY_DECLARED_AT" OUT_PATH="$DECLARED_ONLY_MALFORMED_WORK/delivery/DECLARED" node -e "
|
|
278
|
+
const fs = require('fs');
|
|
279
|
+
const onlyEntry = [{
|
|
280
|
+
scope: process.env.NEW_ENTRY_SCOPE,
|
|
281
|
+
reason: process.env.NEW_ENTRY_REASON,
|
|
282
|
+
declared_at: process.env.NEW_ENTRY_DECLARED_AT
|
|
283
|
+
}];
|
|
284
|
+
fs.writeFileSync(process.env.OUT_PATH, JSON.stringify(onlyEntry, null, 2) + '\n');
|
|
285
|
+
"
|
|
286
|
+
only_malformed_out="$(TRUST_RECONCILE_ACTOR="$NEW_ENTRY_ACTOR" TRUST_RECONCILE_COMMANDS="$RECONCILE_CMD" \
|
|
287
|
+
node "$RECONCILE" --repo-root "$DECLARED_ONLY_MALFORMED_WORK" 2>&1)"
|
|
288
|
+
only_malformed_code=$?
|
|
289
|
+
if [[ "$only_malformed_code" -ne 0 ]]; then
|
|
290
|
+
pass "trust-reconcile.js fails closed ($only_malformed_code) when DECLARED's only entry is malformed"
|
|
291
|
+
else
|
|
292
|
+
fail "trust-reconcile.js expected non-zero exit when DECLARED's only entry is malformed, got 0 — output: $only_malformed_out"
|
|
293
|
+
fi
|
|
294
|
+
if echo "$only_malformed_out" | grep -qF "[bundle-required-no-declared-marker] delivery/DECLARED marker is malformed: missing required field(s) [approved_by]"; then
|
|
295
|
+
pass "trust-reconcile.js's FATAL diagnostic IS the missing-field path, naming approved_by (true missing-field proof)"
|
|
296
|
+
else
|
|
297
|
+
fail "trust-reconcile.js did not emit the expected FATAL missing-field diagnostic naming approved_by — output: $only_malformed_out"
|
|
298
|
+
fi
|
|
299
|
+
|
|
300
|
+
# Second negative variant: well-formed but out-of-scope append (resolved context does not
|
|
301
|
+
# match the new entry's scope) — proves scope-mismatch also fails closed, not just malformed
|
|
302
|
+
# fields.
|
|
303
|
+
DECLARED_NEG_SCOPE_WORK="$TMP_DIR/declared-append-out-of-scope"
|
|
304
|
+
mkdir -p "$DECLARED_NEG_SCOPE_WORK/delivery"
|
|
305
|
+
SEEDED_DECLARED_JSON="$SEEDED_DECLARED" NEW_ENTRY_SCOPE="$NEW_ENTRY_SCOPE" NEW_ENTRY_REASON="$NEW_ENTRY_REASON" NEW_ENTRY_APPROVED_BY="$NEW_ENTRY_APPROVED_BY" NEW_ENTRY_DECLARED_AT="$NEW_ENTRY_DECLARED_AT" OUT_PATH="$DECLARED_NEG_SCOPE_WORK/delivery/DECLARED" node -e "
|
|
306
|
+
const fs = require('fs');
|
|
307
|
+
const existing = JSON.parse(process.env.SEEDED_DECLARED_JSON);
|
|
308
|
+
const appended = existing.concat([{
|
|
309
|
+
scope: process.env.NEW_ENTRY_SCOPE,
|
|
310
|
+
reason: process.env.NEW_ENTRY_REASON,
|
|
311
|
+
approved_by: process.env.NEW_ENTRY_APPROVED_BY,
|
|
312
|
+
declared_at: process.env.NEW_ENTRY_DECLARED_AT
|
|
313
|
+
}]);
|
|
314
|
+
fs.writeFileSync(process.env.OUT_PATH, JSON.stringify(appended, null, 2) + '\n');
|
|
315
|
+
"
|
|
316
|
+
neg_scope_out="$(TRUST_RECONCILE_ACTOR="not-the-right-actor[bot]" TRUST_RECONCILE_COMMANDS="$RECONCILE_CMD" \
|
|
317
|
+
node "$RECONCILE" --repo-root "$DECLARED_NEG_SCOPE_WORK" 2>&1)"
|
|
318
|
+
neg_scope_code=$?
|
|
319
|
+
if [[ "$neg_scope_code" -ne 0 ]]; then
|
|
320
|
+
pass "trust-reconcile.js fails closed ($neg_scope_code) when the resolved context does not match the appended entry's scope"
|
|
321
|
+
else
|
|
322
|
+
fail "trust-reconcile.js expected non-zero exit for an out-of-scope append, got 0 — output: $neg_scope_out"
|
|
323
|
+
fi
|
|
324
|
+
if echo "$neg_scope_out" | grep -qF "out of scope" || echo "$neg_scope_out" | grep -qF "bundle-required-no-declared-marker"; then
|
|
325
|
+
pass "trust-reconcile.js emits 'out of scope' or 'bundle-required-no-declared-marker' for the out-of-scope append"
|
|
326
|
+
else
|
|
327
|
+
fail "trust-reconcile.js did not emit the expected out-of-scope diagnostic — output: $neg_scope_out"
|
|
328
|
+
fi
|
|
329
|
+
|
|
330
|
+
# --- exemption-issuance: no-fork check, specific to this task's new assets (AC8) -
|
|
331
|
+
if grep -rn "veritas-governance" "$ROOT/scripts/ci/trust-reconcile.js" >/dev/null 2>&1; then
|
|
332
|
+
fail "scripts/ci/trust-reconcile.js references kits/veritas-governance (no-fork/layering violated)"
|
|
333
|
+
else
|
|
334
|
+
pass "no-fork: scripts/ci/trust-reconcile.js has zero references to veritas-governance (anchor stays kit-agnostic)"
|
|
335
|
+
fi
|
|
336
|
+
|
|
80
337
|
# --- Optional live Veritas leg --------------------------------------------------
|
|
81
338
|
VBIN="${VERITAS_BIN:-veritas}"
|
|
82
339
|
if command -v "$VBIN" >/dev/null 2>&1 && [[ -n "${VERITAS_GOVERNED_REPO:-}" && -d "${VERITAS_GOVERNED_REPO:-}/.veritas" ]]; then
|