Resolves #13985
Golden Path now fails loud when the synthesizer does not prove a handoff write: golden-path records a failed task outcome with reasonCode: golden-path-handoff-write-unverified unless wroteHandoff: true is returned. The Active PR Cycle renderer is centralized, emits a freshness expiry for live PR snapshots, and replaces stale PR blocks with an explicit degraded section when GitHub PR fetch fails instead of preserving old lifecycle data.
Evidence: L2 focused unit/static/config lint is complete. Residual: L3 live post-merge validation should confirm the next orchestrator Golden Path run updates resources/content/sandman_handoff.md and no longer leaves stale PR lifecycle state behind a completed task marker.
Deltas from ticket
- Added
goldenPathActivePrStateFreshnessMs / NEO_GOLDEN_PATH_ACTIVE_PR_STATE_FRESHNESS_MS with a 60 minute default for Active PR Cycle State freshness.
- Kept repo-enrichment failure local to the handoff output: fetch failures render degraded PR state but do not block the rest of the Golden Path write.
- Added scheduler-level write-proof enforcement so a silent/undefined synthesizer return can no longer mark
golden-path complete.
Config Template Change
Changed key:
goldenPathActivePrStateFreshnessMs / NEO_GOLDEN_PATH_ACTIVE_PR_STATE_FRESHNESS_MS
Local config follow-up:
- No manual value is required; the default is active.
- After merge, run the config overlay update script so gitignored local
config.mjs files understand the new shape.
- Restart the orchestrator after pulling
dev; running daemons need the new code and config leaf loaded.
Test Evidence
node --check ai/services/graph/GoldenPathSynthesizer.mjs
node --check ai/daemons/orchestrator/scheduling/pipeline.mjs
node --check test/playwright/unit/ai/services/graph/GoldenPathSynthesizer.spec.mjs
node --check test/playwright/unit/ai/daemons/orchestrator/scheduling/pipeline.spec.mjs
node --check test/playwright/unit/ai/daemons/orchestrator/Orchestrator.spec.mjs
npm run test-unit -- test/playwright/unit/ai/daemons/orchestrator/scheduling/pipeline.spec.mjs -> 17 passed
npm run test-unit -- test/playwright/unit/ai/daemons/orchestrator/Orchestrator.spec.mjs -> 56 passed
npm run test-unit -- test/playwright/unit/ai/services/graph/GoldenPathSynthesizer.spec.mjs -> 36 passed
- Exact-head self-review spot checks: pipeline missing-handoff proof 1/1, Active PR Cycle State 2/2, full
Orchestrator.spec.mjs 56/56.
npm run ai:lint-config-template-ssot -> passed
npm run agent-preflight -- ai/daemons/orchestrator/scheduling/pipeline.mjs ai/mcp/server/memory-core/config.template.mjs ai/services/graph/GoldenPathSynthesizer.mjs test/playwright/unit/ai/daemons/orchestrator/Orchestrator.spec.mjs test/playwright/unit/ai/daemons/orchestrator/scheduling/pipeline.spec.mjs test/playwright/unit/ai/services/graph/GoldenPathSynthesizer.spec.mjs -> passed
git diff --check -> passed
Post-Merge Validation
Commits
816d146f0d - fix(ai): fail loud on stale handoff PR state (#13985)
Authored by Euclid (GPT-5, Codex Desktop). Session 019ef378-527d-7393-bc74-ec3a1d3f2ddf.
Resolves #13985
Golden Path now fails loud when the synthesizer does not prove a handoff write:
golden-pathrecords a failed task outcome withreasonCode: golden-path-handoff-write-unverifiedunlesswroteHandoff: trueis returned. The Active PR Cycle renderer is centralized, emits a freshness expiry for live PR snapshots, and replaces stale PR blocks with an explicit degraded section when GitHub PR fetch fails instead of preserving old lifecycle data.Evidence: L2 focused unit/static/config lint is complete. Residual: L3 live post-merge validation should confirm the next orchestrator Golden Path run updates
resources/content/sandman_handoff.mdand no longer leaves stale PR lifecycle state behind a completed task marker.Deltas from ticket
goldenPathActivePrStateFreshnessMs/NEO_GOLDEN_PATH_ACTIVE_PR_STATE_FRESHNESS_MSwith a 60 minute default forActive PR Cycle Statefreshness.golden-pathcomplete.Config Template Change
Changed key:
goldenPathActivePrStateFreshnessMs/NEO_GOLDEN_PATH_ACTIVE_PR_STATE_FRESHNESS_MSLocal config follow-up:
config.mjsfiles understand the new shape.dev; running daemons need the new code and config leaf loaded.Test Evidence
node --check ai/services/graph/GoldenPathSynthesizer.mjsnode --check ai/daemons/orchestrator/scheduling/pipeline.mjsnode --check test/playwright/unit/ai/services/graph/GoldenPathSynthesizer.spec.mjsnode --check test/playwright/unit/ai/daemons/orchestrator/scheduling/pipeline.spec.mjsnode --check test/playwright/unit/ai/daemons/orchestrator/Orchestrator.spec.mjsnpm run test-unit -- test/playwright/unit/ai/daemons/orchestrator/scheduling/pipeline.spec.mjs-> 17 passednpm run test-unit -- test/playwright/unit/ai/daemons/orchestrator/Orchestrator.spec.mjs-> 56 passednpm run test-unit -- test/playwright/unit/ai/services/graph/GoldenPathSynthesizer.spec.mjs-> 36 passedOrchestrator.spec.mjs56/56.npm run ai:lint-config-template-ssot-> passednpm run agent-preflight -- ai/daemons/orchestrator/scheduling/pipeline.mjs ai/mcp/server/memory-core/config.template.mjs ai/services/graph/GoldenPathSynthesizer.mjs test/playwright/unit/ai/daemons/orchestrator/Orchestrator.spec.mjs test/playwright/unit/ai/daemons/orchestrator/scheduling/pipeline.spec.mjs test/playwright/unit/ai/services/graph/GoldenPathSynthesizer.spec.mjs-> passedgit diff --check-> passedPost-Merge Validation
dev, runnode ./ai/scripts/setup/initServerConfigs.mjs --migrate-config, then restart the orchestrator.resources/content/sandman_handoff.mdwith anActive PR Cycle Statefreshness expiry or degraded PR-state marker.golden-pathtask state is not marked completed unless the synthesizer reportswroteHandoff: true.Commits
816d146f0d-fix(ai): fail loud on stale handoff PR state (#13985)Authored by Euclid (GPT-5, Codex Desktop). Session 019ef378-527d-7393-bc74-ec3a1d3f2ddf.