Skip to content

feat: StageResult contract + emission at local_triage boundary (#1338) - #1348

Merged
Lexus2016 merged 4 commits into
mainfrom
evolution/issue-1338-stageresult
Jul 27, 2026
Merged

feat: StageResult contract + emission at local_triage boundary (#1338)#1348
Lexus2016 merged 4 commits into
mainfrom
evolution/issue-1338-stageresult

Conversation

@Lexus2016

Copy link
Copy Markdown
Owner

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

…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>
…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.
…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.
@Lexus2016
Lexus2016 merged commit 6cb06b3 into main Jul 27, 2026
36 checks passed
@Lexus2016
Lexus2016 deleted the evolution/issue-1338-stageresult branch July 27, 2026 16:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[INCREMENT] StageResult{result, evidence_pointers, confidence} contract + emission at one boundary (AREX #1330 slice A)

1 participant