feat: StageResult contract + emission at local_triage boundary (#1338) - #1348
Merged
Conversation
…mission at local_triage boundary (#1338) Slice A of AREX confidence-gated loop (#1330): - Define StageResult dataclass in evolution/lib/stage_result.py - Emit StageResult at the local_triage stage boundary in evolution_local_triage.py - Add comprehensive tests for serialisation roundtrip and wrap factory Closes #1338 Co-Authored-By: Hermes Evolution <evolution@hermes.ai>
This was referenced Jul 27, 2026
This was referenced Jul 27, 2026
…bsent The new StageResult emission imported evolution.lib.stage_result at module level. evolution_local_triage.py runs standalone — the access gate copies just this one file into a working directory — so the import raised ImportError there and the script died before writing its analysis file. Six contracts in test_evolution_analysis_gate.py assert that file is written on every path, including the fail-closed one, and all six broke. Same lesson as #1304/#1314 in the harvest cron, and the same remedy: guard the import, keep the required output unconditional. The StageResult tuple is additive telemetry (#1338 slice A), so it is skipped when the package is not importable rather than taking the triage output down with it. 30 passing across test_evolution_analysis_gate.py, test_stage_result.py and test_evolution_local_triage.py; ruff clean.
4 tasks
…envelope The real cause of the six failing analysis-gate contracts, found after the import guard in the previous commit only masked it locally. run_local_triage built a StageResult wrapping `output`, then stored that envelope back inside `output`. output["stage_result"]["result"] therefore pointed at output itself, and json.dumps raised "Circular reference detected" when writing the analysis file. The gate runs the script as `python3 ... || true`, so the exception was swallowed and the only symptom was a missing analysis/YYYY-MM-DD.json — "expected exactly one analysis file, found []" in all six tests. It reproduced only when the evolution package was importable. Running the script directly puts scripts/ on sys.path, not the repo root, so the import failed and the whole block was skipped; CI installs the package, so it executed there. `PYTHONPATH=. pytest tests/scripts/test_evolution_analysis_gate.py` reproduces it locally. The envelope now carries evidence_pointers/confidence/stage/timestamp and drops `result` — it is attached to the document it describes, so restating it was both cyclic and a duplicate serialization of the whole payload. Adds test_output_is_json_serializable_with_stage_result, which asserts the output round-trips through json.dumps — the gate's `|| true` hides this class of failure, so it needs asserting directly rather than via the file's absence. 31 passing across test_evolution_local_triage.py, test_evolution_analysis_gate.py and test_stage_result.py, with and without PYTHONPATH; ruff clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Slice A of AREX confidence-gated loop (#1330). Defines StageResult{result, evidence_pointers, confidence} dataclass and emits it at the local_triage boundary. Tests: 11 passed. Closes #1338