Summary
Four LangGraph capabilities are not wrapped by the governed kernel: retry_policy, cache_policy, durability, and subgraphs. .inner reaches them, but the execution entry points there fail closed — driving a compiled graph through raw LangGraph raises MissingRunContextError rather than silently running with no budget and no trace. So .inner is an inspection escape hatch, not a way to run the graph, and these four features are currently unreachable from a governed run.
Why this matters
Every one of these interacts with a guarantee this kernel makes. A retry that the runtime does not know about is spend the budget never metered and an attempt the trace never recorded. A cache hit is a node that appears to have executed for free. Making a feature available without quietly voiding the audit trail is exactly the graph engineering problem this repo exists to solve — which is why these were left out rather than passed through.
Where in the code
grapharc/runtime/graph.py — add_node, compile, the _wrap node wrappers, _enter / _leave
grapharc/runtime/graph.py — CompiledGraphARC, and the fail-closed .inner entry points
grapharc/runtime/budget.py — the meter and deadline_guard, which any retry must respect
grapharc/observe/trace.py — the event shape; note attempt already exists for resume
grapharc/observe/replay.py — _build_executions keys on (node, step, attempt)
Confirm none are wrapped:
grep -n "retry_policy\|cache_policy\|durability" grapharc/runtime/graph.py # no hits
What to change
Take one of these per PR — do not attempt all four at once. Each needs its semantics settled first:
retry_policy — the hardest and most valuable.
- Every attempt must appear on the trace, and
(node, step, attempt) must stay unique or replay will merge two attempts into one execution.
- Tokens spent by a failed attempt are real spend and must be metered; a retry must not reset the budget.
- A retry must not extend a
max_seconds deadline. The guard's exit-time check must still refuse a node that overran across attempts.
- Interaction with the existing resume
attempt counter must be defined, not discovered.
cache_policy
- A cache hit is not an execution. Decide what the trace says: a distinct phase, or an
end event flagged as cached? metrics.nodes_executed counts end events, so this choice changes reported numbers.
- A cached result must still pass the write-permission allowlist and state type validation — the cache must not become a way to smuggle a value past the declared write channel.
durability
- Interacts with the checkpointer, which is LangGraph's, and with trace continuity, which is GraphARC's. Define what a durability level promises about the trace.
Subgraphs
- The largest design question: a subgraph has its own state schema, its own writes, and potentially its own budget. Does it get its own meter that charges back to the parent, as the governed loop's rounds do? How do its nodes appear in
replay — nested, or flattened with a path?
How to verify
uv run pytest -q
uv run ruff check .
Whichever you take, the gate is a failure test, matching this repo's convention that each stage ships one: for retries, assert a failed attempt's tokens were charged and both attempts appear with non-overlapping (step, attempt); for caching, assert a cache hit cannot write an undeclared field.
Acceptance criteria
Skill level — experience required
These were deliberately left unwrapped, not overlooked, and the reasons are subtle: each one can silently invalidate the budget meter or the audit trail if passed straight through. You need a working understanding of the node wrapper, the meter, the deadline guard and replay's reconstruction before you start. State in a comment which of the four you are taking and what semantics you propose — a PR that simply forwards the argument to LangGraph will not be accepted, because that is exactly what the current code declines to do.
Summary
Four LangGraph capabilities are not wrapped by the governed kernel:
retry_policy,cache_policy,durability, and subgraphs..innerreaches them, but the execution entry points there fail closed — driving a compiled graph through raw LangGraph raisesMissingRunContextErrorrather than silently running with no budget and no trace. So.inneris an inspection escape hatch, not a way to run the graph, and these four features are currently unreachable from a governed run.Why this matters
Every one of these interacts with a guarantee this kernel makes. A retry that the runtime does not know about is spend the budget never metered and an attempt the trace never recorded. A cache hit is a node that appears to have executed for free. Making a feature available without quietly voiding the audit trail is exactly the graph engineering problem this repo exists to solve — which is why these were left out rather than passed through.
Where in the code
grapharc/runtime/graph.py—add_node,compile, the_wrapnode wrappers,_enter/_leavegrapharc/runtime/graph.py—CompiledGraphARC, and the fail-closed.innerentry pointsgrapharc/runtime/budget.py— the meter anddeadline_guard, which any retry must respectgrapharc/observe/trace.py— the event shape; noteattemptalready exists for resumegrapharc/observe/replay.py—_build_executionskeys on(node, step, attempt)Confirm none are wrapped:
What to change
Take one of these per PR — do not attempt all four at once. Each needs its semantics settled first:
retry_policy— the hardest and most valuable.(node, step, attempt)must stay unique orreplaywill merge two attempts into one execution.max_secondsdeadline. The guard's exit-time check must still refuse a node that overran across attempts.attemptcounter must be defined, not discovered.cache_policyendevent flagged as cached?metrics.nodes_executedcountsendevents, so this choice changes reported numbers.durabilitySubgraphs
replay— nested, or flattened with a path?How to verify
uv run pytest -q uv run ruff check .Whichever you take, the gate is a failure test, matching this repo's convention that each stage ships one: for retries, assert a failed attempt's tokens were charged and both attempts appear with non-overlapping
(step, attempt); for caching, assert a cache hit cannot write an undeclared field.Acceptance criteria
.innerreplayreconstructs it correctly.innerexecution entry points still fail closeduv run pytestgreen,uv run ruff check .cleanSkill level — experience required
These were deliberately left unwrapped, not overlooked, and the reasons are subtle: each one can silently invalidate the budget meter or the audit trail if passed straight through. You need a working understanding of the node wrapper, the meter, the deadline guard and
replay's reconstruction before you start. State in a comment which of the four you are taking and what semantics you propose — a PR that simply forwards the argument to LangGraph will not be accepted, because that is exactly what the current code declines to do.