@kontourai/flow-agents 3.3.0 → 3.4.1
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 +161 -0
- package/CHANGELOG.md +48 -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/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-sidecar.d.ts +93 -8
- package/build/src/cli/workflow-sidecar.js +1175 -158
- 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 +56 -3
- package/build/src/lib/flow-resolver.js +151 -11
- 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 +27 -1
- 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 +121 -21
- 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/decisions/embeddable-engine.md +152 -0
- package/docs/decisions/index.md +3 -1
- package/docs/decisions/trust-ledger-retention.md +88 -0
- package/docs/decisions/workflow-enforcement.md +31 -9
- package/docs/fixture-ownership.md +3 -0
- package/docs/implementing-trust-reconciliation.md +129 -0
- package/docs/index.md +19 -9
- package/docs/integrations/flow-agents-console.md +167 -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-usage-guide.md +10 -0
- package/evals/acceptance/prove-capture-teeth.sh +132 -0
- package/evals/ci/antigaming-suite.sh +1 -0
- package/evals/ci/run-baseline.sh +72 -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/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_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 +331 -1
- package/evals/integration/test_pull_work_board.sh +200 -0
- package/evals/integration/test_pull_work_provider.sh +1 -1
- 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_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 +30 -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_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 +29 -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/deliver/SKILL.md +42 -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 +21 -0
- package/kits/builder/skills/release-readiness/SKILL.md +12 -0
- package/kits/knowledge/kit.json +9 -0
- package/kits/veritas-governance/docs/README.md +35 -7
- package/kits/veritas-governance/fixtures/exemption-review/mixed-fresh-stale.DECLARED.json +14 -0
- package/kits/veritas-governance/kit.json +14 -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 +136 -0
- package/scripts/hooks/codex-hook-adapter.js +77 -2
- package/scripts/hooks/evidence-capture.js +38 -5
- 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 +121 -21
- 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/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/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 +101 -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-sidecar.ts +1150 -151
- 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 +153 -10
- 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 +26 -1
|
@@ -12,6 +12,34 @@
|
|
|
12
12
|
# 6. AC6 SHAPE-INVALID-REFUSED (#356): a shape-invalid trust.bundle (test_output claim
|
|
13
13
|
# naming a non-manifest command) is REFUSED by publishDelivery() -- non-zero exit, loud
|
|
14
14
|
# message, nothing copied to delivery/. Distinct from FAIL-SOFT (bundle absent).
|
|
15
|
+
# 7. AC1 HEAD-MISMATCH-REFUSED (#413 Facet A): a real git repo whose sealed
|
|
16
|
+
# trust.checkpoint.json commit_sha names commit A, but the repo's actual HEAD has been
|
|
17
|
+
# advanced to an unrelated orphan commit B (no ancestor relationship) -- publish-delivery
|
|
18
|
+
# REFUSES loudly (non-zero exit, RepoHeadMismatchError message), nothing copied to
|
|
19
|
+
# delivery/. The happy path (HEAD matches the sealed commit_sha) still publishes.
|
|
20
|
+
# 8. AC2 CROSS-SESSION-SEAL-SURVIVES (#413 Facet B): a fixture delivery/<other-slug>/ seal
|
|
21
|
+
# pre-exists before publishing a DIFFERENT slug -- the other slug's seal directory
|
|
22
|
+
# survives byte-identical; pruneSupersededSeals only ever touches its OWN keepSlug
|
|
23
|
+
# directory, never another session's.
|
|
24
|
+
# 9. FIX 4 SHALLOW-UNDETERMINABLE-WARNS-NOT-REFUSES (#413 iteration-2): a REAL shallow clone
|
|
25
|
+
# (git clone --depth 1) whose sealed trust.checkpoint.json commit_sha names a commit the
|
|
26
|
+
# shallow clone's object database does not have (so ancestry is UNDETERMINABLE, not
|
|
27
|
+
# positively confirmed absent) -- publish-delivery WARNS but still PUBLISHES (exit 0, bundle
|
|
28
|
+
# copied). Distinct from AC1 HEAD-MISMATCH-REFUSED above, which is a POSITIVELY-DETERMINABLE
|
|
29
|
+
# mismatch and correctly still hard-refuses.
|
|
30
|
+
# 10. NON-GIT-REPOROOT-WITH-SEALED-COMMIT-ALLOWS (#413 iteration-2 Fix 5, REVERTED in
|
|
31
|
+
# iteration-3): a sealed trust.checkpoint.json names a real commit_sha, but the resolved
|
|
32
|
+
# repoRoot is NOT a git working tree at all (a bare mkdir -p, no .git) -- publish-delivery
|
|
33
|
+
# still PUBLISHES (exit 0, bundle copied). This is a SUPPORTED flow (e.g. checkpoint-signing
|
|
34
|
+
# against a scratch/non-git dir -- see evals/integration/test_checkpoint_signing.sh TEST 2),
|
|
35
|
+
# not a mismatch signal: iteration-2's Fix 5 briefly hard-refused this case ("a sealed
|
|
36
|
+
# delivery implies the target should be a real git repo"), but that premise is false and
|
|
37
|
+
# regressed the supported scratch-dir flow, so it was reverted. Wrong-tree protection for a
|
|
38
|
+
# REAL git repoRoot still relies on the shape-check, verify-hold, and HEAD-vs-commit_sha
|
|
39
|
+
# ancestry gates (TEST 6/7/9 above), which correctly no-op (allow) here since there is no git
|
|
40
|
+
# HEAD to compare against. The pre-existing "no checkpoint / no commit_sha -> allow"
|
|
41
|
+
# no-opinion case (already covered by TEST 1/2/5/6 above, which use bare mkdir -p repos with
|
|
42
|
+
# no checkpoint at all) stays exactly the same allow behavior.
|
|
15
43
|
#
|
|
16
44
|
# Deterministic, no model spend, self-cleaning.
|
|
17
45
|
# Usage: bash evals/integration/test_publish_delivery.sh
|
|
@@ -116,6 +144,14 @@ AROOT1="$REPO1/.flow-agents"
|
|
|
116
144
|
SLUG1="pd-release-test"
|
|
117
145
|
SESSION_DIR1="$AROOT1/$SLUG1"
|
|
118
146
|
mkdir -p "$REPO1/kits"
|
|
147
|
+
printf '# marker\n' > "$REPO1/kits/.keep"
|
|
148
|
+
# REPO1 is a bare mkdir -p, not a real git working tree (#413 iteration-2 Fix 5 briefly required a
|
|
149
|
+
# real git repo here since it hard-refused a non-git repoRoot with a sealed commit_sha; Fix 5 was
|
|
150
|
+
# reverted in iteration-3 -- see checkpointHeadAncestry's doc comment -- so the bare-dir fixture is
|
|
151
|
+
# restored). record-release's sealTrustCheckpoint() calls resolveCommitSha(), which is deliberately
|
|
152
|
+
# AMBIENT (cwd-inheriting, never --repo-root-scoped) and fails (returns null) since $TMP itself is
|
|
153
|
+
# not inside any git working tree -- so no commit_sha is ever sealed here, and this test never
|
|
154
|
+
# touches the HEAD-vs-commit_sha ancestry gate at all (mismatchKind stays "none").
|
|
119
155
|
|
|
120
156
|
FIXTURE1="$TMP/fixture1.json"
|
|
121
157
|
write_bundle_to "$FIXTURE1" "node --version" "true"
|
|
@@ -128,7 +164,7 @@ setup_session "$AROOT1" "$SLUG1" "$FIXTURE1"
|
|
|
128
164
|
# into the manifest. Setting it here makes this fixture genuinely shape-valid (a
|
|
129
165
|
# manifest-matched command claim), matching what CI would actually accept for a repo whose
|
|
130
166
|
# canonical verify is "node --version" — not a preflight-specific carve-out.
|
|
131
|
-
rr_out1=$(TRUST_RECONCILE_COMMANDS="node --version" flow_agents_node "$WRITER" record-release "$SESSION_DIR1" \
|
|
167
|
+
rr_out1=$(cd "$REPO1" && TRUST_RECONCILE_COMMANDS="node --version" flow_agents_node "$WRITER" record-release "$SESSION_DIR1" \
|
|
132
168
|
--decision merge \
|
|
133
169
|
--gate-json '{"name":"merge","status":"pass","summary":"Ready."}' \
|
|
134
170
|
--summary "Release." --repo-root "$REPO1" \
|
|
@@ -339,6 +375,300 @@ else
|
|
|
339
375
|
_fail "AC6 SHAPE-INVALID-REFUSED: delivery/$SLUG6/trust.bundle was created despite invalid shape"
|
|
340
376
|
fi
|
|
341
377
|
|
|
378
|
+
# ==== TEST 7: AC1 HEAD-MISMATCH-REFUSED (#413 Facet A) ==============
|
|
379
|
+
# publishDelivery() now refuses loudly when the resolved repoRoot's HEAD is not an
|
|
380
|
+
# ancestor-or-equal of the session's sealed trust.checkpoint.json commit_sha -- a real git
|
|
381
|
+
# repo is required here (not a bare mkdir -p fixture) so `git rev-parse HEAD` genuinely
|
|
382
|
+
# resolves and the ancestor check has real commits to compare.
|
|
383
|
+
echo ""
|
|
384
|
+
echo "=== TEST 7: AC1 HEAD-MISMATCH-REFUSED ==="
|
|
385
|
+
|
|
386
|
+
REPO7="$TMP/repo7"
|
|
387
|
+
AROOT7="$REPO7/.flow-agents"
|
|
388
|
+
SLUG7="pd-head-mismatch-test"
|
|
389
|
+
SESSION_DIR7="$AROOT7/$SLUG7"
|
|
390
|
+
mkdir -p "$REPO7/kits"
|
|
391
|
+
printf '# marker\n' > "$REPO7/kits/.keep"
|
|
392
|
+
(cd "$REPO7" && git init -q && git config user.email "test@test.local" && git config user.name "test" && git add -A && git commit -q -m "commit A")
|
|
393
|
+
SHA_A="$(cd "$REPO7" && git rev-parse HEAD)"
|
|
394
|
+
|
|
395
|
+
FIXTURE7="$TMP/fixture7.json"
|
|
396
|
+
write_bundle_to "$FIXTURE7" "node --version" "true"
|
|
397
|
+
setup_session "$AROOT7" "$SLUG7" "$FIXTURE7"
|
|
398
|
+
# Seal a checkpoint naming commit A as the trusted commit_sha -- mirrors write_checkpoint_to's
|
|
399
|
+
# minimal, well-formed shape but targets the SESSION dir (where publishDelivery reads it from),
|
|
400
|
+
# not the delivery/ dir (write_checkpoint_to's existing target for the reconcile tests above).
|
|
401
|
+
printf '{"schema_version":"1.0","slug":"%s","work_item":null,"status":"delivered","phase":"release","sealed_at":"2026-06-27T00:00:00Z","commit_sha":"%s","checkpoint":{"asOf":"2026-06-27T00:00:00.000Z","statusByClaimId":{}}}' \
|
|
402
|
+
"$SLUG7" "$SHA_A" > "$SESSION_DIR7/trust.checkpoint.json"
|
|
403
|
+
|
|
404
|
+
# Advance repo7's HEAD to a genuinely UNRELATED orphan commit B -- no ancestor relationship
|
|
405
|
+
# with commit A at all.
|
|
406
|
+
(cd "$REPO7" && git checkout -q --orphan orphan-branch && git rm -rq --cached . >/dev/null 2>&1)
|
|
407
|
+
(cd "$REPO7" && mkdir -p kits && printf 'unrelated\n' > kits/unrelated.txt && git add -A && git commit -q -m "commit B (unrelated orphan)")
|
|
408
|
+
SHA_B="$(cd "$REPO7" && git rev-parse HEAD)"
|
|
409
|
+
|
|
410
|
+
if [[ "$SHA_A" != "$SHA_B" ]]; then
|
|
411
|
+
_pass "TEST 7 setup: commit A and commit B are genuinely distinct shas"
|
|
412
|
+
else
|
|
413
|
+
_fail "TEST 7 setup: commit A and commit B unexpectedly matched"
|
|
414
|
+
fi
|
|
415
|
+
|
|
416
|
+
mismatch_out=$(TRUST_RECONCILE_COMMANDS="node --version" flow_agents_node "$WRITER" publish-delivery "$SESSION_DIR7" --repo-root "$REPO7" 2>&1)
|
|
417
|
+
mismatch_exit=$?
|
|
418
|
+
|
|
419
|
+
if [[ $mismatch_exit -ne 0 ]]; then
|
|
420
|
+
_pass "AC1 HEAD-MISMATCH-REFUSED: publish-delivery exits non-zero when repoRoot HEAD does not match the sealed commit_sha"
|
|
421
|
+
else
|
|
422
|
+
_fail "AC1 HEAD-MISMATCH-REFUSED: expected non-zero exit, got 0 -- $mismatch_out"
|
|
423
|
+
fi
|
|
424
|
+
|
|
425
|
+
if echo "$mismatch_out" | grep -q "REFUSING to publish"; then
|
|
426
|
+
_pass "AC1 HEAD-MISMATCH-REFUSED: output names the refusal loudly (REFUSING to publish)"
|
|
427
|
+
else
|
|
428
|
+
_fail "AC1 HEAD-MISMATCH-REFUSED: expected a loud REFUSING to publish message, got: $mismatch_out"
|
|
429
|
+
fi
|
|
430
|
+
|
|
431
|
+
if echo "$mismatch_out" | grep -qF "$SHA_A" && echo "$mismatch_out" | grep -qF "$SHA_B"; then
|
|
432
|
+
_pass "AC1 HEAD-MISMATCH-REFUSED: refusal message names both the checkpoint commit_sha and the mismatched HEAD sha"
|
|
433
|
+
else
|
|
434
|
+
_fail "AC1 HEAD-MISMATCH-REFUSED: refusal message did not name both shas: $mismatch_out"
|
|
435
|
+
fi
|
|
436
|
+
|
|
437
|
+
DELIVERY_BUNDLE7="$REPO7/delivery/$SLUG7/trust.bundle"
|
|
438
|
+
if [[ ! -f "$DELIVERY_BUNDLE7" ]]; then
|
|
439
|
+
_pass "AC1 HEAD-MISMATCH-REFUSED: delivery/$SLUG7/trust.bundle NOT created on HEAD mismatch"
|
|
440
|
+
else
|
|
441
|
+
_fail "AC1 HEAD-MISMATCH-REFUSED: delivery/$SLUG7/trust.bundle was created despite the HEAD mismatch"
|
|
442
|
+
fi
|
|
443
|
+
|
|
444
|
+
# Happy path: seal a SECOND session's checkpoint against the repo's CURRENT (matching) HEAD --
|
|
445
|
+
# publish-delivery must still succeed. Proves the gate is scoped strictly to the mismatch case,
|
|
446
|
+
# never a spurious refusal.
|
|
447
|
+
SLUG7B="pd-head-match-test"
|
|
448
|
+
SESSION_DIR7B="$AROOT7/$SLUG7B"
|
|
449
|
+
FIXTURE7B="$TMP/fixture7b.json"
|
|
450
|
+
write_bundle_to "$FIXTURE7B" "node --version" "true"
|
|
451
|
+
setup_session "$AROOT7" "$SLUG7B" "$FIXTURE7B"
|
|
452
|
+
printf '{"schema_version":"1.0","slug":"%s","work_item":null,"status":"delivered","phase":"release","sealed_at":"2026-06-27T00:00:00Z","commit_sha":"%s","checkpoint":{"asOf":"2026-06-27T00:00:00.000Z","statusByClaimId":{}}}' "$SLUG7B" "$SHA_B" > "$SESSION_DIR7B/trust.checkpoint.json"
|
|
453
|
+
|
|
454
|
+
match_out=$(TRUST_RECONCILE_COMMANDS="node --version" flow_agents_node "$WRITER" publish-delivery "$SESSION_DIR7B" --repo-root "$REPO7" 2>&1)
|
|
455
|
+
match_exit=$?
|
|
456
|
+
|
|
457
|
+
if [[ $match_exit -eq 0 ]]; then
|
|
458
|
+
_pass "AC1 happy path: publish-delivery succeeds when repoRoot HEAD matches the sealed commit_sha"
|
|
459
|
+
else
|
|
460
|
+
_fail "AC1 happy path: publish-delivery unexpectedly failed on a matching HEAD/commit_sha: $match_out"
|
|
461
|
+
fi
|
|
462
|
+
if [[ -f "$REPO7/delivery/$SLUG7B/trust.bundle" ]]; then
|
|
463
|
+
_pass "AC1 happy path: delivery/$SLUG7B/trust.bundle created when HEAD matches commit_sha"
|
|
464
|
+
else
|
|
465
|
+
_fail "AC1 happy path: delivery/$SLUG7B/trust.bundle NOT created despite a matching HEAD/commit_sha"
|
|
466
|
+
fi
|
|
467
|
+
|
|
468
|
+
# ==== TEST 8: AC2 CROSS-SESSION-SEAL-SURVIVES (#413 Facet B) ========
|
|
469
|
+
# pruneSupersededSeals must never delete another session's delivery/<other-slug>/ directory --
|
|
470
|
+
# only its OWN keepSlug directory. Seed a fixture other-session seal BEFORE publishing a
|
|
471
|
+
# DIFFERENT slug, then assert the fixture survives byte-identical.
|
|
472
|
+
echo ""
|
|
473
|
+
echo "=== TEST 8: AC2 CROSS-SESSION-SEAL-SURVIVES ==="
|
|
474
|
+
|
|
475
|
+
REPO8="$TMP/repo8"
|
|
476
|
+
AROOT8="$REPO8/.flow-agents"
|
|
477
|
+
SLUG8="pd-cross-session-test"
|
|
478
|
+
SESSION_DIR8="$AROOT8/$SLUG8"
|
|
479
|
+
mkdir -p "$REPO8/kits"
|
|
480
|
+
|
|
481
|
+
OTHER_SLUG="pd-other-inflight-session"
|
|
482
|
+
OTHER_SEAL_DIR="$REPO8/delivery/$OTHER_SLUG"
|
|
483
|
+
mkdir -p "$OTHER_SEAL_DIR"
|
|
484
|
+
printf '{"marker":"other-session-trust-bundle","schemaVersion":5}' > "$OTHER_SEAL_DIR/trust.bundle"
|
|
485
|
+
printf '{"schema_version":"1.0","slug":"%s","work_item":null,"status":"delivered","phase":"release","sealed_at":"2026-06-27T00:00:00Z","commit_sha":"deadbeefdeadbeefdeadbeefdeadbeefdeadbeef","checkpoint":{"asOf":"2026-06-27T00:00:00.000Z","statusByClaimId":{}}}' > "$OTHER_SEAL_DIR/trust.checkpoint.json"
|
|
486
|
+
OTHER_BUNDLE_BEFORE="$(cat "$OTHER_SEAL_DIR/trust.bundle")"
|
|
487
|
+
OTHER_CHECKPOINT_BEFORE="$(cat "$OTHER_SEAL_DIR/trust.checkpoint.json")"
|
|
488
|
+
|
|
489
|
+
FIXTURE8="$TMP/fixture8.json"
|
|
490
|
+
write_bundle_to "$FIXTURE8" "node --version" "true"
|
|
491
|
+
setup_session "$AROOT8" "$SLUG8" "$FIXTURE8"
|
|
492
|
+
|
|
493
|
+
cross_out=$(TRUST_RECONCILE_COMMANDS="node --version" flow_agents_node "$WRITER" publish-delivery "$SESSION_DIR8" --repo-root "$REPO8" 2>&1)
|
|
494
|
+
cross_exit=$?
|
|
495
|
+
|
|
496
|
+
if [[ $cross_exit -eq 0 ]]; then
|
|
497
|
+
_pass "AC2 CROSS-SESSION-SEAL-SURVIVES: publish-delivery for $SLUG8 exits 0"
|
|
498
|
+
else
|
|
499
|
+
_fail "AC2 CROSS-SESSION-SEAL-SURVIVES: publish-delivery for $SLUG8 unexpectedly failed: $cross_out"
|
|
500
|
+
fi
|
|
501
|
+
|
|
502
|
+
if [[ -f "$REPO8/delivery/$SLUG8/trust.bundle" ]]; then
|
|
503
|
+
_pass "AC2 CROSS-SESSION-SEAL-SURVIVES: this session's OWN delivery/$SLUG8/trust.bundle was written"
|
|
504
|
+
else
|
|
505
|
+
_fail "AC2 CROSS-SESSION-SEAL-SURVIVES: delivery/$SLUG8/trust.bundle was not written"
|
|
506
|
+
fi
|
|
507
|
+
|
|
508
|
+
if [[ -d "$OTHER_SEAL_DIR" ]]; then
|
|
509
|
+
_pass "AC2 CROSS-SESSION-SEAL-SURVIVES: the OTHER session's delivery/$OTHER_SLUG/ directory SURVIVES"
|
|
510
|
+
else
|
|
511
|
+
_fail "AC2 CROSS-SESSION-SEAL-SURVIVES: the other session's delivery/$OTHER_SLUG/ directory was deleted -- cross-slug pruning regressed"
|
|
512
|
+
fi
|
|
513
|
+
|
|
514
|
+
if [[ -f "$OTHER_SEAL_DIR/trust.bundle" && "$(cat "$OTHER_SEAL_DIR/trust.bundle" 2>/dev/null)" == "$OTHER_BUNDLE_BEFORE" ]]; then
|
|
515
|
+
_pass "AC2 CROSS-SESSION-SEAL-SURVIVES: the other session's trust.bundle is byte-identical after this publish"
|
|
516
|
+
else
|
|
517
|
+
_fail "AC2 CROSS-SESSION-SEAL-SURVIVES: the other session's trust.bundle was mutated or removed"
|
|
518
|
+
fi
|
|
519
|
+
|
|
520
|
+
if [[ -f "$OTHER_SEAL_DIR/trust.checkpoint.json" && "$(cat "$OTHER_SEAL_DIR/trust.checkpoint.json" 2>/dev/null)" == "$OTHER_CHECKPOINT_BEFORE" ]]; then
|
|
521
|
+
_pass "AC2 CROSS-SESSION-SEAL-SURVIVES: the other session's trust.checkpoint.json is byte-identical after this publish"
|
|
522
|
+
else
|
|
523
|
+
_fail "AC2 CROSS-SESSION-SEAL-SURVIVES: the other session's trust.checkpoint.json was mutated or removed"
|
|
524
|
+
fi
|
|
525
|
+
|
|
526
|
+
# Mutation-test note (prune scoping): this eval passes ONLY because pruneSupersededSeals was
|
|
527
|
+
# scoped to keepSlug's own directory (#413 Facet B). Prior to that fix, this loop deleted ANY
|
|
528
|
+
# non-keepSlug directory under delivery/ that looked like a seal (contained trust.bundle or
|
|
529
|
+
# trust.checkpoint.json) -- exactly OTHER_SEAL_DIR's shape -- so this test would have failed
|
|
530
|
+
# the two directory/byte-identical checks above against the pre-fix implementation.
|
|
531
|
+
|
|
532
|
+
# ==== TEST 9: FIX 4 SHALLOW-UNDETERMINABLE-WARNS-NOT-REFUSES (#413 iteration-2) =====
|
|
533
|
+
# A REAL shallow clone (git clone --depth 1) whose sealed trust.checkpoint.json commit_sha names
|
|
534
|
+
# an OLDER commit the shallow clone's object database genuinely does not have -- `git merge-base
|
|
535
|
+
# --is-ancestor` cannot determine ancestry here (exit 128, not 0 or 1), which is the
|
|
536
|
+
# UNDETERMINABLE case Fix 4 must warn-and-allow, never hard-refuse. Distinct from TEST 7's
|
|
537
|
+
# POSITIVELY-DETERMINABLE orphan-commit mismatch, which correctly still hard-refuses.
|
|
538
|
+
echo ""
|
|
539
|
+
echo "=== TEST 9: FIX 4 SHALLOW-UNDETERMINABLE-WARNS-NOT-REFUSES ==="
|
|
540
|
+
|
|
541
|
+
SRC9="$TMP/src9"
|
|
542
|
+
mkdir -p "$SRC9/kits"
|
|
543
|
+
(cd "$SRC9" && git init -q && git config user.email "test@test.local" && git config user.name "test" \
|
|
544
|
+
&& printf 'a\n' > kits/.keep && git add -A && git commit -q -m "commit A (older, will be missing from the shallow clone)")
|
|
545
|
+
SHA9_A="$(cd "$SRC9" && git rev-parse HEAD)"
|
|
546
|
+
(cd "$SRC9" && printf 'b\n' > kits/b.txt && git add -A && git commit -q -m "commit B")
|
|
547
|
+
(cd "$SRC9" && printf 'c\n' > kits/c.txt && git add -A && git commit -q -m "commit C (HEAD, shallow clone's only commit)")
|
|
548
|
+
|
|
549
|
+
REPO9="$TMP/repo9"
|
|
550
|
+
if git clone -q --depth 1 --no-local "file://$SRC9" "$REPO9" >/dev/null 2>"$TMP/shallow-clone9.err"; then
|
|
551
|
+
_pass "TEST 9 setup: a real shallow clone (--depth 1) was created"
|
|
552
|
+
else
|
|
553
|
+
_fail "TEST 9 setup: shallow clone failed: $(cat "$TMP/shallow-clone9.err")"
|
|
554
|
+
fi
|
|
555
|
+
SHA9_HEAD="$(cd "$REPO9" && git rev-parse HEAD)"
|
|
556
|
+
|
|
557
|
+
# Confirm the shallow clone genuinely cannot determine ancestry for the older, missing commit --
|
|
558
|
+
# the exact precondition this test depends on.
|
|
559
|
+
if ! (cd "$REPO9" && git cat-file -e "$SHA9_A" 2>/dev/null); then
|
|
560
|
+
_pass "TEST 9 setup: the shallow clone's object database genuinely lacks commit A (the precondition for UNDETERMINABLE ancestry)"
|
|
561
|
+
else
|
|
562
|
+
_fail "TEST 9 setup: the shallow clone unexpectedly has commit A -- this fixture no longer exercises the undeterminable path"
|
|
563
|
+
fi
|
|
564
|
+
|
|
565
|
+
AROOT9="$REPO9/.flow-agents"
|
|
566
|
+
SLUG9="pd-shallow-undeterminable-test"
|
|
567
|
+
SESSION_DIR9="$AROOT9/$SLUG9"
|
|
568
|
+
mkdir -p "$REPO9/kits" # kits/ already exists from the clone, but keep parity with other tests' setup shape
|
|
569
|
+
|
|
570
|
+
FIXTURE9="$TMP/fixture9.json"
|
|
571
|
+
write_bundle_to "$FIXTURE9" "node --version" "true"
|
|
572
|
+
setup_session "$AROOT9" "$SLUG9" "$FIXTURE9"
|
|
573
|
+
# Seal a checkpoint naming the OLDER commit (A) the shallow clone does not have -- mirrors TEST
|
|
574
|
+
# 7's shape but targets a genuinely shallow repo.
|
|
575
|
+
printf '{"schema_version":"1.0","slug":"%s","work_item":null,"status":"delivered","phase":"release","sealed_at":"2026-06-27T00:00:00Z","commit_sha":"%s","checkpoint":{"asOf":"2026-06-27T00:00:00.000Z","statusByClaimId":{}}}' \
|
|
576
|
+
"$SLUG9" "$SHA9_A" > "$SESSION_DIR9/trust.checkpoint.json"
|
|
577
|
+
|
|
578
|
+
shallow_out=$(TRUST_RECONCILE_COMMANDS="node --version" flow_agents_node "$WRITER" publish-delivery "$SESSION_DIR9" --repo-root "$REPO9" 2>&1)
|
|
579
|
+
shallow_exit=$?
|
|
580
|
+
|
|
581
|
+
if [[ $shallow_exit -eq 0 ]]; then
|
|
582
|
+
_pass "FIX 4: publish-delivery from a shallow clone with an undeterminable checkpoint ancestry still exits 0 (warns, does not refuse)"
|
|
583
|
+
else
|
|
584
|
+
_fail "FIX 4: publish-delivery unexpectedly refused (non-zero exit) for the shallow/undeterminable case: $shallow_out"
|
|
585
|
+
fi
|
|
586
|
+
|
|
587
|
+
if echo "$shallow_out" | grep -qi "WARNING.*could not determine"; then
|
|
588
|
+
_pass "FIX 4: output contains a loud WARNING naming the undeterminable ancestry"
|
|
589
|
+
else
|
|
590
|
+
_fail "FIX 4: expected a loud WARNING for the undeterminable ancestry case, got: $shallow_out"
|
|
591
|
+
fi
|
|
592
|
+
|
|
593
|
+
if echo "$shallow_out" | grep -q "REFUSING to publish"; then
|
|
594
|
+
_fail "FIX 4: unexpectedly REFUSED the shallow/undeterminable case -- this must warn and allow, never hard-refuse"
|
|
595
|
+
else
|
|
596
|
+
_pass "FIX 4: no REFUSING to publish message -- the shallow/undeterminable case is correctly NOT treated as a hard refuse"
|
|
597
|
+
fi
|
|
598
|
+
|
|
599
|
+
if [[ -f "$REPO9/delivery/$SLUG9/trust.bundle" ]]; then
|
|
600
|
+
_pass "FIX 4: delivery/$SLUG9/trust.bundle WAS published despite the undeterminable ancestry (warn-and-allow, not refuse)"
|
|
601
|
+
else
|
|
602
|
+
_fail "FIX 4: delivery/$SLUG9/trust.bundle was NOT published -- the shallow/undeterminable case was incorrectly blocked"
|
|
603
|
+
fi
|
|
604
|
+
|
|
605
|
+
# Mutation-test note (Fix 4): this test passes ONLY because checkpointHeadAncestry's
|
|
606
|
+
# mismatchKind classification distinguishes "positive" (git merge-base --is-ancestor exits 1,
|
|
607
|
+
# a real answer) from "undeterminable-shallow" (exit 128 / spawn failure, e.g. this shallow
|
|
608
|
+
# clone's missing commit object). Prior to Fix 4, the collapsed isAncestorCommit() boolean
|
|
609
|
+
# treated shallow-missing exactly the same as a positively-confirmed non-ancestor, and this
|
|
610
|
+
# test would have failed the REFUSING/exit-0/bundle-published assertions above.
|
|
611
|
+
|
|
612
|
+
# ==== TEST 10: NON-GIT-REPOROOT-WITH-SEALED-COMMIT-ALLOWS (#413 iteration-2 Fix 5, reverted) ====
|
|
613
|
+
# repoRoot resolves to a real path, but it is NOT a git working tree at all (a bare mkdir -p,
|
|
614
|
+
# no .git anywhere) -- while the session's sealed trust.checkpoint.json names a real commit_sha.
|
|
615
|
+
# This is a SUPPORTED flow (scratch/checkpoint-signing dirs, see
|
|
616
|
+
# evals/integration/test_checkpoint_signing.sh TEST 2), so publish-delivery must still PUBLISH
|
|
617
|
+
# (exit 0, bundle copied) -- not the FIX 5 hard-refuse iteration-2 briefly added and iteration-3
|
|
618
|
+
# reverted. Distinct from the pre-existing "no checkpoint / no commit_sha -> allow" no-opinion
|
|
619
|
+
# case TEST 1/2/5/6 already cover with their own bare mkdir -p repos that have no checkpoint at
|
|
620
|
+
# all -- this test's REPO10 DOES have a sealed checkpoint with a real-looking commit_sha, and
|
|
621
|
+
# still allows.
|
|
622
|
+
echo ""
|
|
623
|
+
echo "=== TEST 10: NON-GIT-REPOROOT-WITH-SEALED-COMMIT-ALLOWS ==="
|
|
624
|
+
|
|
625
|
+
REPO10="$TMP/repo10"
|
|
626
|
+
AROOT10="$REPO10/.flow-agents"
|
|
627
|
+
SLUG10="pd-non-git-reporoot-test"
|
|
628
|
+
SESSION_DIR10="$AROOT10/$SLUG10"
|
|
629
|
+
mkdir -p "$REPO10/kits" # kits/ marker only -- deliberately NO git init anywhere under REPO10
|
|
630
|
+
|
|
631
|
+
FIXTURE10="$TMP/fixture10.json"
|
|
632
|
+
write_bundle_to "$FIXTURE10" "node --version" "true"
|
|
633
|
+
setup_session "$AROOT10" "$SLUG10" "$FIXTURE10"
|
|
634
|
+
# Seal a checkpoint naming a plausible-looking (but unverifiable, since there's no git repo here
|
|
635
|
+
# at all) commit_sha.
|
|
636
|
+
printf '{"schema_version":"1.0","slug":"%s","work_item":null,"status":"delivered","phase":"release","sealed_at":"2026-06-27T00:00:00Z","commit_sha":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","checkpoint":{"asOf":"2026-06-27T00:00:00.000Z","statusByClaimId":{}}}' \
|
|
637
|
+
> "$SESSION_DIR10/trust.checkpoint.json"
|
|
638
|
+
|
|
639
|
+
if [[ ! -d "$REPO10/.git" ]]; then
|
|
640
|
+
_pass "TEST 10 setup: REPO10 genuinely has no .git -- not a git working tree at all"
|
|
641
|
+
else
|
|
642
|
+
_fail "TEST 10 setup: REPO10 unexpectedly has a .git directory"
|
|
643
|
+
fi
|
|
644
|
+
|
|
645
|
+
nongit_out=$(TRUST_RECONCILE_COMMANDS="node --version" flow_agents_node "$WRITER" publish-delivery "$SESSION_DIR10" --repo-root "$REPO10" 2>&1)
|
|
646
|
+
nongit_exit=$?
|
|
647
|
+
|
|
648
|
+
if [[ $nongit_exit -eq 0 ]]; then
|
|
649
|
+
_pass "NON-GIT-REPOROOT-ALLOWS: publish-delivery exits 0 for a non-git repoRoot with a sealed commit_sha"
|
|
650
|
+
else
|
|
651
|
+
_fail "NON-GIT-REPOROOT-ALLOWS: expected exit 0 for a non-git repoRoot with a sealed commit_sha, got $nongit_exit -- $nongit_out"
|
|
652
|
+
fi
|
|
653
|
+
|
|
654
|
+
if ! echo "$nongit_out" | grep -q "REFUSING to publish"; then
|
|
655
|
+
_pass "NON-GIT-REPOROOT-ALLOWS: output does not contain a REFUSING to publish message"
|
|
656
|
+
else
|
|
657
|
+
_fail "NON-GIT-REPOROOT-ALLOWS: unexpected REFUSING to publish message, got: $nongit_out"
|
|
658
|
+
fi
|
|
659
|
+
|
|
660
|
+
if [[ -f "$REPO10/delivery/$SLUG10/trust.bundle" ]]; then
|
|
661
|
+
_pass "NON-GIT-REPOROOT-ALLOWS: delivery/$SLUG10/trust.bundle created for a non-git repoRoot with a sealed commit_sha"
|
|
662
|
+
else
|
|
663
|
+
_fail "NON-GIT-REPOROOT-ALLOWS: delivery/$SLUG10/trust.bundle NOT created despite the supported non-git-repoRoot flow"
|
|
664
|
+
fi
|
|
665
|
+
|
|
666
|
+
# Mutation-test note: this test passes only because checkpointHeadAncestry's non-git-repoRoot
|
|
667
|
+
# path resolves headSha to empty (git rev-parse HEAD fails outside a working tree) and returns
|
|
668
|
+
# mismatchKind:"none" (the same "no opinion, allow" result as the genuinely no-checkpoint case) --
|
|
669
|
+
# never the iteration-2 Fix 5 non-git-repo refuse arm, which this test's own removal proves is
|
|
670
|
+
# gone.
|
|
671
|
+
|
|
342
672
|
# ---- Summary ----
|
|
343
673
|
echo ""
|
|
344
674
|
echo "----------------------------------------------"
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
5
|
+
source "$ROOT/evals/lib/env.sh"
|
|
6
|
+
flow_agents_eval_bootstrap "$ROOT" || exit $?
|
|
7
|
+
SCRIPT="$ROOT/scripts/pull-work-provider.js"
|
|
8
|
+
TMPDIR_EVAL="$(mktemp -d)"
|
|
9
|
+
trap 'rm -rf "$TMPDIR_EVAL"' EXIT
|
|
10
|
+
|
|
11
|
+
errors=0
|
|
12
|
+
pass() { echo " ✓ $1"; }
|
|
13
|
+
fail() { echo " ✗ $1"; errors=$((errors + 1)); }
|
|
14
|
+
|
|
15
|
+
json_query() {
|
|
16
|
+
NO_COLOR=1 FORCE_COLOR=0 node -e 'const fs=require("fs"); let cur=JSON.parse(fs.readFileSync(process.argv[1],"utf8")); for (const part of process.argv[2].split(".")) cur=part==="length" ? cur.length : (Array.isArray(cur) ? cur[Number(part)] : cur[part]); console.log(cur);' "$1" "$2"
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
cat > "$TMPDIR_EVAL/settings.json" <<'JSON'
|
|
20
|
+
{
|
|
21
|
+
"schema_version": "1.0",
|
|
22
|
+
"projects": [
|
|
23
|
+
{
|
|
24
|
+
"project": { "repo": { "owner": "kontourai", "name": "flow-agents" } },
|
|
25
|
+
"work_item_provider": {
|
|
26
|
+
"role": "WorkItemProvider",
|
|
27
|
+
"kind": "github",
|
|
28
|
+
"repo": { "owner": "kontourai", "name": "flow-agents" },
|
|
29
|
+
"capabilities": ["issues", "labels"]
|
|
30
|
+
},
|
|
31
|
+
"board_provider": {
|
|
32
|
+
"role": "BoardProvider",
|
|
33
|
+
"kind": "github",
|
|
34
|
+
"repo": { "owner": "kontourai", "name": "flow-agents" },
|
|
35
|
+
"board": { "type": "github_project", "owner": "kontourai", "number": 1 },
|
|
36
|
+
"capabilities": ["projects_boards", "status_fields", "custom_fields"]
|
|
37
|
+
},
|
|
38
|
+
"selection": {
|
|
39
|
+
"filters": {
|
|
40
|
+
"issue_state": "open",
|
|
41
|
+
"include_labels": [],
|
|
42
|
+
"ready_statuses": ["ready"],
|
|
43
|
+
"exclude_statuses": ["in_progress", "blocked", "review", "verification", "done"]
|
|
44
|
+
},
|
|
45
|
+
"wip_policy": {
|
|
46
|
+
"prefer_finishing_active_work": true,
|
|
47
|
+
"active_statuses": ["in_progress", "review", "verification"],
|
|
48
|
+
"block_new_work_when_active_count_exceeds": 0
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
JSON
|
|
55
|
+
|
|
56
|
+
cat > "$TMPDIR_EVAL/items.json" <<'JSON'
|
|
57
|
+
{
|
|
58
|
+
"items": [
|
|
59
|
+
{
|
|
60
|
+
"id": "PVTI_1",
|
|
61
|
+
"position": 0,
|
|
62
|
+
"fieldValues": [
|
|
63
|
+
{ "field": { "name": "Status" }, "name": "Ready" },
|
|
64
|
+
{ "field": { "name": "Priority" }, "name": "P1" }
|
|
65
|
+
],
|
|
66
|
+
"content": {
|
|
67
|
+
"id": "I_7",
|
|
68
|
+
"number": 7,
|
|
69
|
+
"title": "P1 ready board item",
|
|
70
|
+
"body": "## Scope\nDo P1 work.\n\n## Acceptance criteria\nDone.",
|
|
71
|
+
"state": "OPEN",
|
|
72
|
+
"url": "https://github.com/kontourai/flow-agents/issues/7",
|
|
73
|
+
"repository": { "name": "flow-agents", "owner": { "login": "kontourai" } },
|
|
74
|
+
"labels": { "nodes": [{ "name": "builder" }] }
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"id": "PVTI_2",
|
|
79
|
+
"position": 1,
|
|
80
|
+
"status": "In Progress",
|
|
81
|
+
"priority": "P0",
|
|
82
|
+
"content": {
|
|
83
|
+
"id": "I_8",
|
|
84
|
+
"number": 8,
|
|
85
|
+
"title": "Active item excluded from ready queue",
|
|
86
|
+
"body": "## Scope\nAlready active.",
|
|
87
|
+
"state": "OPEN",
|
|
88
|
+
"url": "https://github.com/kontourai/flow-agents/issues/8",
|
|
89
|
+
"repository": { "name": "flow-agents", "owner": { "login": "kontourai" } },
|
|
90
|
+
"labels": []
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"id": "PVTI_3",
|
|
95
|
+
"position": 2,
|
|
96
|
+
"status": "ready",
|
|
97
|
+
"priority": "P0",
|
|
98
|
+
"content": {
|
|
99
|
+
"id": "I_5",
|
|
100
|
+
"number": 5,
|
|
101
|
+
"title": "P0 lower-case ready item",
|
|
102
|
+
"body": "## Scope\nDo P0 work.\n\n## Acceptance criteria\nDone.",
|
|
103
|
+
"state": "OPEN",
|
|
104
|
+
"url": "https://github.com/kontourai/flow-agents/issues/5",
|
|
105
|
+
"repository": { "name": "flow-agents", "owner": { "login": "kontourai" } },
|
|
106
|
+
"labels": []
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"id": "PVTI_4",
|
|
111
|
+
"position": 3,
|
|
112
|
+
"status": "Ready",
|
|
113
|
+
"priority": "P2",
|
|
114
|
+
"content": {
|
|
115
|
+
"id": "I_9",
|
|
116
|
+
"number": 9,
|
|
117
|
+
"title": "P2 ready board item",
|
|
118
|
+
"body": "## Scope\nDo P2 work.\n\n## Acceptance criteria\nDone.",
|
|
119
|
+
"state": "OPEN",
|
|
120
|
+
"url": "https://github.com/kontourai/flow-agents/issues/9",
|
|
121
|
+
"repository": { "name": "flow-agents", "owner": { "login": "kontourai" } },
|
|
122
|
+
"labels": []
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
],
|
|
126
|
+
"open_issues": [
|
|
127
|
+
{
|
|
128
|
+
"id": "I_5",
|
|
129
|
+
"number": 5,
|
|
130
|
+
"title": "P0 lower-case ready item",
|
|
131
|
+
"state": "OPEN",
|
|
132
|
+
"url": "https://github.com/kontourai/flow-agents/issues/5",
|
|
133
|
+
"labels": []
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"id": "I_11",
|
|
137
|
+
"number": 11,
|
|
138
|
+
"title": "Open issue missing from board",
|
|
139
|
+
"state": "OPEN",
|
|
140
|
+
"url": "https://github.com/kontourai/flow-agents/issues/11",
|
|
141
|
+
"labels": [{ "name": "intake" }]
|
|
142
|
+
}
|
|
143
|
+
]
|
|
144
|
+
}
|
|
145
|
+
JSON
|
|
146
|
+
|
|
147
|
+
cat > "$TMPDIR_EVAL/zero-ready.json" <<'JSON'
|
|
148
|
+
{
|
|
149
|
+
"items": [
|
|
150
|
+
{
|
|
151
|
+
"id": "PVTI_10",
|
|
152
|
+
"position": 0,
|
|
153
|
+
"status": "Blocked",
|
|
154
|
+
"priority": "P0",
|
|
155
|
+
"content": {
|
|
156
|
+
"id": "I_10",
|
|
157
|
+
"number": 10,
|
|
158
|
+
"title": "Blocked board item",
|
|
159
|
+
"state": "OPEN",
|
|
160
|
+
"url": "https://github.com/kontourai/flow-agents/issues/10",
|
|
161
|
+
"labels": []
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
],
|
|
165
|
+
"open_issues": []
|
|
166
|
+
}
|
|
167
|
+
JSON
|
|
168
|
+
|
|
169
|
+
echo "=== Pull Work Board Ready Queue ==="
|
|
170
|
+
|
|
171
|
+
node "$SCRIPT" \
|
|
172
|
+
--settings-json "$TMPDIR_EVAL/settings.json" \
|
|
173
|
+
--items-json "$TMPDIR_EVAL/items.json" \
|
|
174
|
+
> "$TMPDIR_EVAL/board.json"
|
|
175
|
+
status=$?
|
|
176
|
+
[[ "$status" -eq 0 ]] && pass "board reader exits successfully" || fail "board reader exits successfully"
|
|
177
|
+
|
|
178
|
+
[[ "$(json_query "$TMPDIR_EVAL/board.json" "ready_queue.length")" == "3" ]] && pass "filters only ready board items" || fail "filters only ready board items"
|
|
179
|
+
[[ "$(json_query "$TMPDIR_EVAL/board.json" "ready_queue.0.id")" == "github:kontourai/flow-agents#5" ]] && pass "orders P0 before P1 and preserves board position tiebreak" || fail "orders P0 before P1 and preserves board position tiebreak"
|
|
180
|
+
[[ "$(json_query "$TMPDIR_EVAL/board.json" "ready_queue.1.id")" == "github:kontourai/flow-agents#7" ]] && pass "orders P1 before P2" || fail "orders P1 before P2"
|
|
181
|
+
[[ "$(json_query "$TMPDIR_EVAL/board.json" "ready_queue.2.id")" == "github:kontourai/flow-agents#9" ]] && pass "keeps P2 ready after higher priorities" || fail "keeps P2 ready after higher priorities"
|
|
182
|
+
[[ "$(json_query "$TMPDIR_EVAL/board.json" "ready_queue.0.status")" == "ready" ]] && pass "matches ready status case-insensitively" || fail "matches ready status case-insensitively"
|
|
183
|
+
[[ "$(json_query "$TMPDIR_EVAL/board.json" "ready_queue.0.board_membership.priority")" == "P0" ]] && pass "preserves board priority on candidate" || fail "preserves board priority on candidate"
|
|
184
|
+
[[ "$(json_query "$TMPDIR_EVAL/board.json" "intake_gaps.length")" == "1" ]] && pass "detects open WorkItemProvider issues absent from board" || fail "detects open WorkItemProvider issues absent from board"
|
|
185
|
+
[[ "$(json_query "$TMPDIR_EVAL/board.json" "intake_gaps.0.id")" == "github:kontourai/flow-agents#11" ]] && pass "reports missing issue as intake gap" || fail "reports missing issue as intake gap"
|
|
186
|
+
|
|
187
|
+
node "$SCRIPT" \
|
|
188
|
+
--settings-json "$TMPDIR_EVAL/settings.json" \
|
|
189
|
+
--items-json "$TMPDIR_EVAL/zero-ready.json" \
|
|
190
|
+
> "$TMPDIR_EVAL/zero-ready-output.json"
|
|
191
|
+
[[ "$(json_query "$TMPDIR_EVAL/zero-ready-output.json" "ready_queue.length")" == "0" ]] && pass "zero-ready fixture has empty ready queue" || fail "zero-ready fixture has empty ready queue"
|
|
192
|
+
[[ "$(json_query "$TMPDIR_EVAL/zero-ready-output.json" "warnings.0.code")" == "zero_ready_items" ]] && pass "zero ready emits loud warning" || fail "zero ready emits loud warning"
|
|
193
|
+
|
|
194
|
+
if [[ "$errors" -eq 0 ]]; then
|
|
195
|
+
echo "Pull work board checks passed"
|
|
196
|
+
else
|
|
197
|
+
echo "Pull work board checks failed: $errors"
|
|
198
|
+
fi
|
|
199
|
+
|
|
200
|
+
exit "$errors"
|
|
@@ -13,7 +13,7 @@ pass() { echo " ✓ $1"; }
|
|
|
13
13
|
fail() { echo " ✗ $1"; errors=$((errors + 1)); }
|
|
14
14
|
|
|
15
15
|
json_query() {
|
|
16
|
-
node -e 'const fs=require("fs"); let cur=JSON.parse(fs.readFileSync(process.argv[1],"utf8")); for (const part of process.argv[2].split(".")) cur=part==="length" ? cur.length : (Array.isArray(cur) ? cur[Number(part)] : cur[part]); console.log(cur);' "$1" "$2"
|
|
16
|
+
NO_COLOR=1 FORCE_COLOR=0 node -e 'const fs=require("fs"); let cur=JSON.parse(fs.readFileSync(process.argv[1],"utf8")); for (const part of process.argv[2].split(".")) cur=part==="length" ? cur.length : (Array.isArray(cur) ? cur[Number(part)] : cur[part]); console.log(cur);' "$1" "$2"
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
echo "=== Pull Work Provider Normalization ==="
|