| Finding | Lane | Repair Command |
|---|---|---|
vendor_scrub: N match(es) |
vendor-scrub | grep -rn "<term>" . --include="*.rs" → rename |
receipt_guard: N failing |
receipts | node tools/receipt_guard.mjs --all → add missing sections |
cargo test failure |
fast | cargo test -p <crate> -- <test_name> --nocapture |
cargo deny advisory |
security | cargo deny list → update dep version |
| Playwright E2E failure | web-e2e | cd apps/web && npx playwright test --ui for interactive mode |
| README media drift | studio-sync | rtk bash ops/run-lane.sh studio-sync |
jankurai audit cap |
score | jankurai explain <HLT-XXX> → follow agent_fix |
Every lane writes structured output:
rtk bash ops/run-lane.sh fast→ exit 0 = all tests pass, stderr = failure detailsrtk bash ops/run-lane.sh vendor-scrub→target/jankurai/vendor-scrub.jsonl(machine-readable)rtk bash ops/run-lane.sh receipts→ exit 0 = 0 failing, lists each failing file on failurertk bash ops/run-lane.sh studio-sync→assets/readme/studio/badge/media plus README guarded blockjankurai audit→target/jankurai/repo-score.json(full score breakdown)jankurai audit --format json→ stdout JSON for programmatic consumption
Standard repair workflow for a failing CI run:
rtk bash scripts/ci-local.sh— reproduce locally- Check the failing lane output for specific file/line
- Fix the issue (rename, add section, etc.)
- Re-run the specific lane:
rtk bash ops/run-lane.sh <lane> - Once passing, run
rtk bash scripts/ci-local.shto confirm no regressions - Commit with a receipt in
.agents/receipts/<slice>/<timestamp>Z.md
All testing goes through rtk bash ops/run-lane.sh <lane>. See agent/proof-lanes.toml for
lane definitions and AGENTS.md for the full lane reference table.
Runs on every push via jankurai.yml CI and on every git push (pre-push hook).
The CI fast entrypoint verifies that the protected EI implementation paths are
encrypted before unlocking them. CI expects the shared symmetric developer key
in the ECHOFORGE_GIT_CRYPT_KEY_B64 secret:
git-crypt status -e detection/crypt_ip_impl/advanced_main_run_detectors.py \
detection/crypt_ip_impl/ei_evolution_trace.py
git-crypt unlock /tmp/echoforge-git-crypt.keyLocal developers should unlock once before running paper or advanced EI lanes:
rtk git-crypt unlock /path/to/echoforge-git-crypt.keyWhen the key is missing, the advanced runner and paper-evidence CLI return a
one-line git-crypt unlock warning rather than a Python traceback.
rtk bash ops/run-lane.sh fast
# Runs: cargo test --workspace --locked
# Output: test pass/fail counts, compiler warnings
# Artifacts: target/ (excluded from git)Pass signal: Exit 0, zero test failures Fail signal: Non-zero exit, output shows FAILED test names
Blocking lane -- failures prevent merge. Runs in strict-open.yml CI.
rtk bash ops/run-lane.sh security
# Runs: cargo deny check, cargo-cyclonedx, pip-licenses, secret scan
# Output: sbom/ directory, deny violations listPass signal: Exit 0, no vulnerabilities, no secrets found Fail signal: cargo deny prints violation with crate name and advisory ID
rtk bash ops/run-lane.sh vendor-scrub
# Runs: node tools/vendor_scrub.mjs
# Output: target/jankurai/vendor-scrub.md (Markdown report)
# target/jankurai/vendor-scrub.jsonl (JSONL for machine consumption)Pass signal: Exit 0, vendor_scrub: ... 0 match(es)
Fail signal: Exit 1, report lists file:line:term for each match
rtk bash ops/run-lane.sh receipts
# Runs: node tools/receipt_guard.mjs --all
# Output: pass/fail count, failing receipt paths with missing sectionsPass signal: Exit 0, receipt_guard: <N> receipt(s), 0 failing
Fail signal: Exit 1, lists each failing receipt and which H2 sections are missing
rtk bash ops/run-lane.sh web-e2e
# Runs: cd apps/web && npx playwright test
# Output: playwright-report/ with screenshots and traces on failure
# playwright-report/ux-qa-state.png (full-page UX QA screenshot)Pass signal: All tests passed
Fail signal: Playwright prints failing test names; traces in playwright-report/
Flow: browser gate after web-smoke; CI uploads web-e2e-artifacts from
apps/web/playwright-report/ and apps/web/test-results/.
rtk bash ops/run-lane.sh studio-sync
# Runs: score artifact validation/rendering, npm install, Playwright install,
# Rust Studio capture, README block writer
# Output: assets/readme/studio/jankurai-score.svg
# assets/readme/studio/studio-demo.gif
# assets/readme/studio/*.png
# assets/readme/studio/manifest.jsonPass signal: README hero/title/badge layout guard passes and media manifest
contains the GIF plus Command Center, Live Radar, and Monte Carlo screenshots.
Fail signal: Missing score artifact, broken README layout, missing media
asset, Playwright capture failure, or Rust Studio startup failure.
Flow: local regeneration runs score first. The post-merge
studio-readme-sync workflow sets STUDIO_SYNC_SCORE_SOURCE=artifact and uses
the jankurai-score artifact downloaded from the completed ci workflow run.
It pushes a bot commit to main only when README.md or
assets/readme/studio/ changed.
No-generated-output rule: only the README media assets under
assets/readme/studio/ are tracked for this lane. Do not stage
apps/web/dist/, apps/web/playwright-report/, apps/web/test-results/,
target/jankurai/, outputs/, downloaded score artifacts, or solver data.
rtk bash ops/run-lane.sh science-smoke
# Runs: Python pipeline smoke validation
# Output: outputs/ directory with generated artifactsKTH hardening is an opt-in local measured-anchor workflow. Raw KTH data stays
under ${ECHOFORGE_REAL_DATA_ROOT} and generated reports stay under
outputs/; neither should be committed.
- Build the KTH report:
rtk python3 -m detection.real_data.cli build-report --dataset-id kth-drone-bird-human-77ghz --run-id <run>. - Generate matched baseline and hardened training datasets with the same
seed. The hardened run passes
--real-anchor-priors outputs/real-data/kth-drone-bird-human-77ghz/<run>/calibration_coefficients.json. - Compare quantile-grid Wasserstein-1 and KS distances, overlap coefficient, q50 ratios, single-feature AUC leakage gates, shortcut-leakage gates, and clamp saturation.
- Accept only if family-specific hard-negative overlap improves on the KTH
holdout split and the hardened median
micro_doppler_peak_hz_proxyandmicro_doppler_bandwidth_hz_proxyare below their configured clamps. - Re-run the proof lane:
rtk python3 -m unittest discover -s detection/real_data/tests -p 'test_*.py',rtk python3 -m detection.real_data.cli validate-catalog,rtk python3 -m detection.real_data.cli guard-git, then the relevantjustlanes fromagent/test-map.json.
| Signal | Meaning | Repair |
|---|---|---|
FAILED in cargo test output |
Rust test failure | Check test name, read assertion message |
cargo deny advisory ID |
Known CVE in dependency | Update dep version or add exception in deny.toml |
vendor_scrub: N match(es) |
Banned term in code | Check target/jankurai/vendor-scrub.md, remove term |
receipt_guard: N failing |
Malformed receipts | Add required H2 sections to listed files |
Playwright expect(...).toBeVisible() failed |
UI element missing | Check component renders correct data-testid |
jankurai audit: caps=N |
Governance caps applied | Run jankurai explain <check-id> for remediation |
| Lane | Artifact Path | Format |
|---|---|---|
| fast | target/ |
cargo test output |
| vendor-scrub | target/jankurai/vendor-scrub.md |
Markdown |
| vendor-scrub | target/jankurai/vendor-scrub.jsonl |
JSONL |
| audit | target/jankurai/repo-score.json |
JSON |
| audit | target/jankurai/score-history.jsonl |
JSONL timeline |
| security | sbom/ |
CycloneDX JSON |
| web-e2e | apps/web/playwright-report/ |
HTML + traces |
| web-e2e | apps/web/playwright-report/ux-qa-state.png |
Full-page UX screenshot |
| studio-sync | assets/readme/studio/manifest.json |
Deterministic README media manifest |
| studio-sync | assets/readme/studio/ |
Tracked README GIF, PNGs, and score badge |
# View audit score trend
cat target/jankurai/score-history.jsonl | python3 -c \
"import sys,json; [print(l.get('timestamp','?'), l.get('score','?'), '/', l.get('raw','?')) for l in (json.loads(x) for x in sys.stdin)]"| Resource | Monthly cap | Stop condition | Kill switch |
|---|---|---|---|
| CI compute (GitHub Actions) | 2,000 min | Per-PR budget exceeded | Disable workflow in Settings → Actions |
| GPU smoke (ops/run-lane.sh gpu-smoke) | 0 min (CI skipped by default) | Never runs unless GPU_SMOKE=1 env set |
Unset GPU_SMOKE in repo secrets |
| Dependency audit (cargo deny) | 0 min (always fast) | Any advisory found | Fix advisory or add to deny.toml allow list |
| Secret scan (gitleaks) | ~30 s per run | Any detected secret | Fix and rotate the secret immediately |
Unbounded operations: There are no unbounded AI/LLM calls in CI. All proof lanes have timeout-minutes set.
Each error in CoreError (crates/echoforge-core/src/error.rs) emits a JSON-parseable line with purpose, repair_hint, and docs_url fields:
| Error Kind | purpose | repair_hint |
|---|---|---|
ValidationFailed |
Input failed schema/domain validation | Check field against schema; rerun just fast |
SchemaViolation |
Data does not conform to JSON schema | Run just contracts; check schema diff |
ArtifactNotFound |
Artifact ID missing from store | Verify via jankurai doctor .; check store path |
SerializationFailed |
JSON encode/decode error | Inspect detail field for serde error location |
InvalidConfiguration |
Config key invalid or missing | Review key/value pair; check env overrides |
Io |
Filesystem operation failed | Check path exists; verify disk space and permissions |
Errors are logged as structured JSON lines: {"error":"Kind","purpose":"...","repair_hint":"...","docs_url":"...","reason":"..."}.
All errors are rerunnable locally with the command listed in the finding's Rerun: field.
All CI lanes are bounded by timeout-minutes in GitHub Actions. No lane runs unbounded AI/LLM calls.
| Lane | Budget | Stop Condition | Kill-Switch |
|---|---|---|---|
fast |
30 min max | cargo test exit code ≠ 0 |
Cancel GitHub Actions run |
vendor-scrub |
15 min max | First banned-term match | Cancel GitHub Actions run |
receipts |
15 min max | First failing receipt | Cancel GitHub Actions run |
security |
30 min max | Any cargo deny advisory | Cancel GitHub Actions run |
web-smoke |
20 min max | First Vitest failure | Cancel GitHub Actions run |
web-e2e |
30 min max | First Playwright failure | Cancel GitHub Actions run |
studio-sync |
90 min max | First score/media/README sync failure | Cancel GitHub Actions run |
science-smoke |
30 min max | Any test failure | Cancel GitHub Actions run |
Local kill-switch: Ctrl-C on any just <lane> command. All lanes are idempotent — rerunnable without side effects.
Paid resource limits: No lane uses paid APIs (no LLM calls, no cloud inference). cargo deny and gitleaks are open-source tools with no per-run cost.
Observability repair receipts: All findings produce a Rerun: field pointing to a rerun command. The target/jankurai/repair-queue.jsonl file lists all pending repairs in machine-readable format. Each receipt entry includes the rerun command to replay the relevant lane.
| Resource | Quota | Threshold | Stop condition | Kill switch |
|---|---|---|---|---|
| GitHub Actions compute | 2,000 min/month | 80% (1,600 min) | Disable any non-critical job | Settings → Actions → Disable workflow |
| Cargo registry bandwidth | unlimited (cache-first) | N/A | Cache miss rate >50% | Pin actions/cache key |
| Secret scan (gitleaks) | 0 cost (OSS) | N/A | Any verified secret found | Rotate secret; git filter-repo to purge |
| Dependency audit (cargo-deny) | 0 cost (local) | N/A | Any unmaintained/vulnerable crate | Fix deny.toml; pin version |
| SBOM generation | 0 cost (local) | N/A | SBOM schema drift | Run just sbom and commit sbom/ |
Hard quota: Zero paid AI/LLM calls in any CI lane. Any lane that calls an external inference API must be gated behind an opt-in environment variable (AI_LANE=1) and documented in this table with an explicit per-run cost estimate.
Cost telemetry: The target/jankurai/score-history.jsonl file tracks audit run elapsed times. Run just score locally before push to catch regressions before CI.
All runtime errors emit structured JSON lines to stderr:
{"error": "ValidationFailed", "field": "manifest.schema_version", "reason": "unknown version 99", "rerun": "just fast"}Structured spans are emitted via the tracing crate for key entry points:
echoforge_core::artifact— artifact load/store operationsechoforge_radar::sim— synthesis pipeline (scene → episode)echoforge_dataset— dataset generation pipeline
Repair evidence: Each CI lane writes its output to target/jankurai/ so the next run can compare. The repair-queue.jsonl file is the authoritative list of open findings with their Rerun: commands.
Distributed traces link dataset pipeline spans using a campaign_request_id propagated as a request id through all child spans. The request id appears as a span field so collectors can filter by request id to reconstruct a full generation run.
Detection events include a correlation id field that links detector outputs back to their originating campaign batch. This correlation id is injected at scene-generation time and propagated through validation to enable end-to-end request tracing.