A listener finds, K assigned fixers land in parallel, and every widening re-enters the gate - #98
Open
Shashankss1205 wants to merge 5 commits into
Open
A listener finds, K assigned fixers land in parallel, and every widening re-enters the gate#98Shashankss1205 wants to merge 5 commits into
Shashankss1205 wants to merge 5 commits into
Conversation
…sed first grapharc.registries.fix_issues ships the listener/fixer job under the full RegistryBundle contract: scan_issues appends one issue per entry, the planner proposes one fix_one instance per outstanding issue — all edged from the same predecessor, so they land in one superstep — and every widening re-enters the admission gate. fix_one is registered and denied by default; the scripted rehearsal runs against that default on purpose, so the free path demonstrates the refusal and ends with a report that says what was refused and how to enable it. With no model, nothing is registered: naming a kind then fails as unregistered_node at the gate, not at materialisation. Gate tests pin the refusals: the eager fixer never executes, a three-fixer round beyond the token budget is rejected with the shortfall recorded, and two fixers finishing together merge through the reducers instead of colliding. Phase 1 of the agents-as-nodes plan (PR A1). Args-carrying assignments, write leases, and the delegated tier ladder follow. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s them
ROADMAP 5.6 closed minimally. A kind may declare NodeSpec.args_schema — an
operator's Pydantic model, extra=forbid — and admission gains a sixth check:
a proposal's args for that kind must validate, one rejection per failing
field with the schema and its fields named in the remedy. The Materializer
forwards the *validated* dump and re-validates on build, so a registry
swapped underneath the decision or a proposal edited after it refuses to
build; the fingerprint already hashed args, so an approval binds who was
assigned what. Kinds without a schema keep the old contract, stated where it
was always stated: args uninspected, dropped unless forward_args=True.
The slim parse path gains args and note — a schema-declaring kind proposed
by a small model otherwise always arrived argless and was always refused —
with null and prose args tolerated down to {}, because the gate, not the
reader, is what judges whether none was enough.
fix_one now requires its FixAssignment: each fixer proposal says which issue
it takes, verbatim, and the text feeds the fixer's prompt, never a tool
call. The governance cookbook, deep dive, README limit, and both
architecture diagrams move in the same commit, so no page says five checks
over a gate that runs six.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…by name grapharc.tools.leases: the first write_file/edit_file to touch a path claims it for that node, and a second writer's call is denied with the holder named — enforcement as a harness pre-hook, per call, after permissions and before the executor, with the tools themselves untouched. An agent reads its tool refusals, so the losing fixer learns who has the file and works on something else instead of crashing the batch. Reads are never gated: serializing the listeners is the parallelism the lease exists to keep safe. Leases key on the resolved path, so a dressed-up spelling contends with the plain one; a workspace escape stays the tool's own refusal, which names the actual problem. A lease lives exactly as long as its node's execution — the fix_issues factory releases in a finally — so a later round edits what an earlier round wrote. Scope stated plainly in the module: advisory within one process, core write tools only; run_command children and delegated agents mutate un-leased. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…allowlist A delegated agent node ran Claude Code under bypassPermissions by construction — the unconfined tier was the only tier. It is now a ladder with the fail-closed rung as the default: `allowlist` hands Claude Code exactly the node's own registered tools, mapped name for name (read_file->Read, ... run_command->Bash), so one operator declaration governs both the governed loop and the delegated one; anything unlisted falls to Claude Code's headless default gating, which fails closed. `bypass` still exists and still means everything — but only by name, and the construction warning and every trace event say which tier ran. Two neighbouring defects fixed in the same change, both of the limit-that-exists-only-in-the-invocation kind: --max-tokens under --executor claude-cli was accepted and silently unapplied, and is now refused with the reason; and the subprocess deadline killed only the direct child, so Claude Code's own spawned shells survived as orphans — the CLI now runs in its own session and the deadline kills the whole group, the same way the sandbox executor does. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… each bench gains fix_all_issues — the listener/fixer shape, measured: three planted defects under src/, each file's docstring stating the invariant its code violates, graded per fix with a new files_contain check (half done is not a success), config/ protected with the temptation planted in the retry policy's own docstring. It exists to be ROADMAP milestone V1's gate for grapharc.registries.fix_issues; the row stays "mechanism done, gate not run" and now says precisely which recorded run flips it. The deep dive states the lease limit alongside the other edges: concurrent fixers conflict as data, and nothing merges divergent edits. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Phase 1 of the agents-as-nodes plan: autonomous agents as graph nodes, with the admission gate deciding every round. Five commits, each PR-sized with its own failure-mode gate tests; the full suite is green after each one (2,025 passed at HEAD).
What lands
grapharc.registries.fix_issues— the listener/fixer job under the full RegistryBundle contract:scan_issuesappends one issue per entry, the planner proposes onefix_oneinstance per outstanding issue (all edged from the same predecessor, so they execute in one superstep, concurrently), thenverify_fixesandreport. A round may carry a continuing scan and fixers for already-found issues — pipeline overlap with zero new mechanism, and every widening re-enters admission. The scripted rehearsal runs the refusal story against the default policy: round 1's eager fixer is rejectededge_deniedand never executes, and the final report says out loud how to enable fixing.NodeSpec.args_schemaputs a proposal's args under a sixth check, one rejection per failing field with the remedy naming the schema; the Materializer forwards the validated dump and re-validates on build, so an edited proposal or a swapped registry refuses to build. The slim parse path gainsargs/noteso a small model's fixer does not arrive argless.fix_onerequires itsFixAssignment— the fingerprint an approval binds now includes who was assigned what.bypassPermissionsto an allowlist mapped from the node's own tools (read_file→Read, …run_command→Bash), so one operator declaration governs both tiers;bypassis reachable only by name and stamped on every trace event. Two adjacent defects fixed:--max-tokensunder claude-cli was accepted and silently unapplied (now refused with the reason), and a timed-out delegate orphaned Claude Code's own shells (the CLI now runs in its own session and the deadline kills the whole group).fix_all_issues: three planted defects undersrc/, each file's docstring stating the invariant its code violates, graded per fix (files_contain; half done is not a success),config/protected. ROADMAP V1 stays mechanism done, gate not run and now names precisely which recorded live-model run flips it.Verified
test_fix_issues_gate.py,test_admission.py,test_slim_proposal.py,test_leases.py,test_delegate_tiers.py,test_agent_delegate.py— each pinning a refusal, not a happy path.grapharc plan "fix the issues in this repo" --registry grapharc.registries.fix_issues:build_registry --scripted --go→ rejected, admitted, admitted,goal_met, honest report.🤖 Generated with Claude Code