feat(st3): integration adapters — loop/integrations.py + LangGraph & Temporal recipes - #32
Conversation
…-clean, invariant-pinned
…e back the scorecard claim
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f4158953fb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| return ( | ||
| isinstance(gate.get("verdict"), str) | ||
| and isinstance(gate.get("false_completion"), bool) | ||
| and _valid_checks(gate.get("visible")) | ||
| and _valid_checks(gate.get("holdout")) |
There was a problem hiding this comment.
Recompute gate results before trusting Succeeded
When an adapter receives a malformed or tampered gate dict, _valid_gate only checks that verdict, false_completion, and non-empty check arrays exist; it does not require passed_visible/passed_holdout or re-derive them from the per-check evidence. As a result, a payload such as verdict: "Succeeded", false_completion: false, and a failed holdout check passes validation and to_terminal_state() returns Succeeded, after which emit.terminate will write a successful terminal. This violates the new adapter invariant for any caller that persists or forwards a corrupted gate result instead of the exact holdout_gate.decide() output; validate the flags/verdict against visible and holdout before allowing success.
Useful? React with 👍 / 👎.
Summary
PR-A of the v0.8.0 "composes the field" milestone — ST3: integration adapters. Spec:
docs/superpowers/specs/2026-07-08-v0.8.0-composes-the-field-design.md(normative mapping/precedence:docs/superpowers/specs/2026-06-30-st3-integration-adapters.md).Three deliverables:
loop/integrations.py— engine-neutral, pure-stdlib projection (EngineOutcome+to_terminal_state) from any engine's "the run ended" signal onto the 7 typed terminal states, fixed precedence safety → human → blocked → budget → spec-gap → gate verdict.Succeededis structurally unreachable without a greenholdout_gate.decideverdict + clean anticheat + a met criterion + evidence +reached_end;false_completionis copied from the gate, never synthesized; missing/invalid gate or anticheat input fails closed toFailedUnverifiable. 14 unit tests pin all of the above.examples/langgraph-emit/) — the certify node now routes gate → anticheat → adapter →loop.emit; the run scores clean underloop metrics(closes the recorded FCR-1.0 follow-up); sabotage path pins the false-completion invariant. Verified againstlanggraph1.2.8.examples/temporal-certify/) — certify-activity pattern (the certify activity is the workflow's only path to a returned result); cancellation →AbortedByHumanproven e2e on a real local Temporal dev server; retry exhaustion →FailedBlockedand timeout →FailedBudgetcovered at the mapper level; metrics-clean like its sibling. Verified againsttemporalio1.30.0.Acceptance criteria: spec §5 items 1–3 + 6.
Adjudicated deviation (documented carve-out)
Both recipes reset
<ws>/RUNLOG.mdto emit's own fresh header immediately afteropen_contract— a direct contract-file write, against the letter of the emit-only constraint. Root cause (confirmed independently by two reviewers): the scaffold seeds an unfilled{{ITERATION_OUTCOME}}placeholder thatloop metricsflags as an unrecognized outcome token, and the root fix lives intemplates//loop/scaffold.py/loop/emit.py— all outside PR-A's file discipline. The whole-branch review accepted the reset as an honest, contained carve-out (it strips a placeholder, never fabricates state; the header is byte-identical toemit.py's own). Recorded in the plan's Global Constraints; the root-fix affordance (e.g.emit.open_contract(seed_runlog=False)) will be filed as a PR-B contributor issue.For the human reviewer
e13adcf(rootCLAUDE.md) rode along on this branch (authored outside this run). The whole-branch review flags it as unfit for the public 0.8.0 cut as-is: the file says "do NOT commit CLAUDE.md" yet is committed; it embeds machine-local/mnt/c/...paths and local-marketplace notes; its "395 tests" figure is stale. No secrets, no gate impact — ST3 code is unaffected. Needs a decision before the PR-B release cut (drop vs. genericize).Test plan
python3 -B scripts/validate_frontmatter.py— 0 errorspython3 -B scripts/self_eval.py— 13/13 (100%)uv run --with pytest --with pyyaml --with jsonschema --with langgraph --with temporalio python -B -m pytest -q -p no:cacheprovider scripts— 391 passed / 9 skipped (baseline 372/10 + ST3 tests; recipe suites run for real)python3 -B -m py_compile loop/*.py scripts/*.py— cleanpython3 -B -m loop doctor examples/coverage-repair— okpython3 -B -m loop inspect examples/coverage-repair— 90 / strongrecipe-langgraph,recipe-temporal,action-dogfoodall green