Rectify: audit_impl preflight rejects the plan path the recipe supplies (#4387) - #4403
Merged
Trecek merged 6 commits intoJul 28, 2026
Conversation
The audit-cycle containment chain (preflight resolver, loaded-publish,
verified-publish, reported-publish) hardcoded tool_ctx.temp_dir as
allowed_root. In clone-based pipelines, artifacts live under the
clone's .autoskillit/temp/, a structurally disjoint path. The
containment check always failed, producing a ContainmentError that
routed to register_clone_failure -> escalate_stop, indistinguishably
from a genuine NO GO verdict.
Changes:
- Add allowed_root kwarg override to InputPreflightResolver.resolve()
- DefaultInputPreflightResolver creates a fresh AuditCycleVerifier when
allowed_root is provided
- resolve_attested_input_preflight threads allowed_root to the resolver
- run_skill computes _clone_allowed_root = resolve_temp_dir(Path(cwd),
tool_ctx.config.workspace.temp_dir) before the if/elif chain and
passes it to both preflight and publish call sites
- _publish_loaded_audit_cycle, publish_verified_audit_cycle,
publish_reported_audit_cycle, publish_audit_cycle_result now take
required allowed_root: Path parameter (replacing tool_ctx.temp_dir
reads)
- implementation.yaml: route preflight:stage condition to
register_clone_failure (preserves clone for diagnosis) and
result.error to check_audit_remediation_loop (was register_clone_failure)
- Test call sites updated to pass allowed_root to publish functions
- RecordingResolver and RejectingResolver test doubles updated to
accept allowed_root kwarg
- Three new regression tests:
* test_clone_layout_containment_root_required — disjoint
orchestrator_root vs clone_temp directly reproduces #4387
* test_recipe_execution_deny_envelope_carries_preflight_stage —
locks down the deny envelope shape
* test_preflight_resolver_protocol_accepts_allowed_root_override —
exercises allowed_root kwarg override and fallback semantics
…iagram hash; update NO GO test filter for preflight routing
…t acceptance test
Empty cwd previously fell through the truthy-guarded boundary checks and anchored the audit-cycle containment root to the MCP server process's own cwd instead of failing closed. Scoped to the recipe-execution-active path (the only place the containment anchor is actually consumed) so ad-hoc skill invocations with no directory requirement remain unaffected.
…ot wiring The two existing #4387 regression tests exercise DefaultInputPreflightResolver directly and never call run_skill(), so the actual wiring bug (orchestrator temp_dir disjoint from the clone temp tree) was never reproduced through the real MCP entry point. Adds a run_skill()-level test with genuinely disjoint orchestrator/clone directory trees, verified to fail without the _clone_allowed_root fix and pass with it.
…ill regression test The newly added run_skill()-level regression test for #4387 (test_run_skill_containment_root_anchors_to_cwd_not_orchestrator_temp_dir) was written without the supporting lifecycle hooks used by every other working run_skill regression test in the same file: 1. install_recipe_execution(snapshot=...) requires a staged initialization; the test was calling it directly and raising RecipeExecutionAdmissionError('recipe execution cannot install before initialization is staged'). 2. preflight_identities were written to tool_ctx.active_recipe_execution, but run_skill reads the installed execution from recipe_initialization_state via get_recipe_execution(), so the preflight gate raised recipe_execution_preflight_identity_missing. 3. The trusted-head publish was issued BEFORE _replace_test_recipe_execution. install_recipe_execution clears the previous generation's heads via clear_generation() when previous is not installed (true for any dataclasses.replace()-derived prepared execution), so the publish was wiped before the resolver could read it, raising input_preflight_head_missing. Switch to the existing _install_test_recipe_execution helper (which stages initialization before installing) and _replace_test_recipe_execution (which threads preflight_identities into recipe_initialization_state). Reorder so the publish happens after the replace.
Trecek
force-pushed
the
audit-impl-preflight-rejects-the-plan-path-the-recipe-suppli/4387
branch
from
July 28, 2026 15:08
c78bcf4 to
2a3456c
Compare
Trecek
commented
Jul 28, 2026
Trecek
left a comment
Collaborator
Author
There was a problem hiding this comment.
AutoSkillit review passed. No blocking issues found.
Trecek
deleted the
audit-impl-preflight-rejects-the-plan-path-the-recipe-suppli/4387
branch
July 28, 2026 15:27
This was referenced Jul 28, 2026
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.
Summary
The audit-cycle containment chain — preflight resolver, loaded-publish, verified-publish, reported-publish — hardcodes
tool_ctx.temp_dir(the orchestrator's.autoskillit/temp/) asallowed_root. In clone-based pipelines, artifacts live under the clone's.autoskillit/temp/, a structurally disjoint path. The containment check always fails, producing aContainmentErrorthat routes toregister_clone_failure→escalate_stop, indistinguishably from a genuine NO GO verdict. This plan addresses all three acceptance criteria from #4387:audit_implcan reach a verdict in clone-based pipelines.Requirements
audit_implcompletes and returns a verdict on a standard clone-based remediation runwith
open_pr=true.work_diroutside the orchestrator temp) andasserts the preflight admits the recipe-supplied plan path.
Closes #4387
Implementation Plan
Plan file:
/home/talon/projects/autoskillit-runs/fix-4387-20260727-213059-759256/.autoskillit/temp/rectify/rectify_audit_impl_preflight_containment_root_2026-07-27_214500.md🤖 Generated with Claude Code via AutoSkillit