Commit 8734c63
[FIX] Pre-Prune Validity Computation Breaks Codex open_kitchen (#4068)
## Summary
The recipe loading pipeline in `load_and_validate()` computes validity
from semantic rule findings that were generated against the
**pre-prune** recipe. When the Codex backend is used, the
`backend-incompatible-skill` rule fires ERROR-severity findings against
steps that have `skip_when_false` guards — steps that would be pruned
immediately after. The stale pre-prune findings poison
`compute_recipe_validity()`, marking the recipe as `valid=False`. The
error response function then reads the empty `errors[]` list (structural
errors only) and falls back to "unknown structural error", hiding the
true cause entirely.
Part A fixes the core pipeline ordering bug in `load_and_validate()` and
surfaces semantic findings in the validation error response. Part B will
cover adding pruning support to `validate_from_path` and its full caller
chain — implement as a separate task.
## Requirements
`open_kitchen(name="implementation")` fails on the first orchestrator
message of every Codex-backend session in v0.10.752 with:
> `Recipe 'implementation' failed structural validation: unknown
structural error` (`stage=recipe_validation`, `errors=[]`, suggestions
contain only the usual warnings)
The fail-closed guard added by PR #3995 (`61802dce4`) gates on
`result["valid"]`, but `load_and_validate` computes `valid` from
semantic-rule findings evaluated on the **unpruned** recipe. With the
Codex capability override (`backend_supports_git_write="false"`), the
`backend-incompatible-skill` rule emits **13 ERROR-severity findings** —
9 on steps that are pruned immediately afterward (`skip_when_false:
inputs.backend_supports_git_write`) and 4 on
`inputs.open_pr`-route-guarded steps that the conformance test
explicitly exempts via `_ROUTE_GUARDED_COMPAT_EXCEPTIONS` but
`compute_recipe_validity` does not. So `valid=False` even though the
served (pruned) content is structurally sound.
## Root cause chain (all empirically confirmed on installed v0.10.752)
1. `CodexBackend` declares `git_metadata_writable=False`
(`execution/backends/codex.py:521`); `_backend_capability_overrides`
yields `{"backend_supports_git_write": "false"}`, merged
last/unoverridable (`tools_kitchen.py:560-561` via
`_promote_capability_keys`).
2. **Sequencing defect (the root):** in `recipe/_api.py`
(`load_and_validate`): `run_semantic_rules` runs at line 397 on the
unpruned recipe → `_prune_skipped_steps` at line 408 →
`compute_recipe_validity` at line 457 consumes the **pre-prune**
findings.
3. `backend-incompatible-skill` (`rules/rules_backend_compat.py:27-68`)
has no awareness of `skip_when_false` guards or route-guard exemptions →
13 ERROR findings for codex.
4. `compute_recipe_validity` (`registry.py:245-254`) folds any
ERROR-severity semantic/contract finding into `valid` → `valid=False`,
`content` non-empty, `errors=[]`.
5. #3995's guard trips on `not result.get("valid", False)`; the envelope
renders only the structural `errors` list → misleading "unknown
structural error".
## Scope of fix
1. **Compute validity from the post-prune recipe.** Move semantic-rule
evaluation (or at minimum the validity-relevant findings derivation)
after `_prune_skipped_steps`. The `ValidationContext` must be
**rebuilt** with the pruned recipe — not reused from the pre-prune
build.
2. **Single source of truth for route-guard exemptions.** Promote
`_ROUTE_GUARDED_COMPAT_EXCEPTIONS` (currently test-only) into a
production constant consumed by both the validity computation path and
the conformance test.
3. **Fleet parity.** `fleet/_api.py` dispatch validation must pass the
backend capability overrides so fleet's pruning matches what would
actually be served.
4. **Regression tests through the real producer.** Bundled-recipe ×
backend validity assertions through the real `load_and_validate` with
real capability overrides.
## Related work
- #3992 — predecessor bug (silent empty-content delivery) that #3995
rectified
- #3948 — prior incident of the same class: an ERROR-severity finding
promotion blocked dispatch for 10 bundled recipes
- **#4026 is hard-blocked by this issue** — asserts `valid=True` for
codex × implementation/planner via `load_and_validate` with no xfail
machinery
- **#4008** can land first; its `xfail(strict=True)` markers must be
removed after this fix lands
Closes #4059
## Implementation Plan
Plan file:
`/home/talon/projects/autoskillit-runs/remediation-20260611-063523-547628/.autoskillit/temp/rectify/rectify_pre_prune_validity_2026-06-11_063523_part_a.md`
🤖 Generated with [Claude Code](https://claude.com/claude-code) via
AutoSkillit
<!-- autoskillit:pipeline-signature
steps=prepare_pr,run_arch_lenses,compose_pr,annotate_pr_diff,review_pr
-->
## Token Usage Summary
| Step | Model | count | uncached | output | cache_read | peak_ctx |
turns | cache_write | time |
|------|-------|-------|----------|--------|------------|----------|-------|-------------|------|
| run_bem* | sonnet | 1 | 45.1k | 48.1k | 677.2k | 130.5k | 35 | 112.5k
| 17m 18s |
| dispatch:bf3ba4d0-338f-46e2-b744-1cc5af0cb74f* | sonnet | 1 | 66 |
6.1k | 324.1k | 48.4k | 17 | 29.4k | 18m 48s |
| plan* | opus[1m] | 3 | 3.6k | 45.5k | 4.0M | 103.4k | 125 | 233.9k |
29m 52s |
| verify* | sonnet | 3 | 993 | 27.7k | 1.9M | 84.4k | 107 | 142.7k | 11m
40s |
| implement* | MiniMax-M3 | 3 | 4.2M | 23.3k | 532.7k | 64.8k | 173 | 0
| 16m 35s |
| audit_impl* | sonnet | 3 | 1.1k | 21.1k | 620.0k | 45.8k | 45 | 89.0k
| 10m 59s |
| prepare_pr* | MiniMax-M3 | 3 | 460.3k | 6.1k | 85.0k | 44.1k | 38 | 0
| 3m 8s |
| compose_pr* | MiniMax-M3 | 3 | 564.7k | 4.0k | 0 | 0 | 36 | 0 | 2m 22s
|
| review_pr* | sonnet | 4 | 522 | 54.9k | 2.9M | 75.1k | 150 | 204.4k |
16m 2s |
| resolve_review* | sonnet | 1 | 133 | 9.9k | 833.6k | 66.4k | 37 |
46.2k | 5m 37s |
| dispatch:a43619bc-64d1-412e-9f66-144a95109fd1* | sonnet | 1 | 330 |
10.2k | 3.0M | 83.5k | 86 | 137.5k | 1h 5m |
| dispatch:76e5c3a5-b134-41b9-a511-2d686a4069c8* | sonnet | 1 | 362 |
14.6k | 3.4M | 88.0k | 93 | 63.6k | 38m 32s |
| **Total** | | | 5.3M | 271.5k | 18.3M | 130.5k | | 1.1M | 3h 56m |
\* *Step used a non-Anthropic provider; caching behavior may differ.*
## Token Efficiency
| Step | LoC Changed | cache_read/LoC | cache_write/LoC | output/LoC |
|------|-------------|----------------|-----------------|------------|
| run_bem | 0 | — | — | — |
| dispatch:bf3ba4d0-338f-46e2-b744-1cc5af0cb74f | 0 | — | — | — |
| plan | 0 | — | — | — |
| verify | 0 | — | — | — |
| implement | 217 | 2454.8 | 0.0 | 107.5 |
| audit_impl | 0 | — | — | — |
| prepare_pr | 0 | — | — | — |
| compose_pr | 0 | — | — | — |
| review_pr | 0 | — | — | — |
| resolve_review | 0 | — | — | — |
| dispatch:a43619bc-64d1-412e-9f66-144a95109fd1 | 0 | — | — | — |
| dispatch:76e5c3a5-b134-41b9-a511-2d686a4069c8 | 554 | 6178.5 | 114.8 |
26.3 |
| **Total** | **771** | 23758.1 | 1373.7 | 352.1 |
## Model Usage Breakdown
| Model | steps | uncached | output | cache_read | cache_write | time |
|-------|-------|----------|--------|------------|-------------|------|
| sonnet | 8 | 48.6k | 192.6k | 13.7M | 825.1k | 3h 4m |
| opus[1m] | 1 | 3.6k | 45.5k | 4.0M | 233.9k | 29m 52s |
| MiniMax-M3 | 3 | 5.2M | 33.4k | 617.7k | 0 | 22m 5s |
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>1 parent 9bb70b0 commit 8734c63
23 files changed
Lines changed: 515 additions & 51 deletions
File tree
- src/autoskillit
- core/types
- recipe
- server/tools
- skills_extended/resolve-review
- tests
- arch
- contracts
- infra
- recipe
- server
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
51 | 51 | | |
52 | 52 | | |
53 | 53 | | |
| 54 | + | |
54 | 55 | | |
55 | 56 | | |
56 | 57 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
63 | 63 | | |
64 | 64 | | |
65 | 65 | | |
| 66 | + | |
66 | 67 | | |
67 | 68 | | |
68 | 69 | | |
| |||
361 | 362 | | |
362 | 363 | | |
363 | 364 | | |
364 | | - | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
365 | 397 | | |
366 | 398 | | |
367 | 399 | | |
| |||
398 | 430 | | |
399 | 431 | | |
400 | 432 | | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
401 | 439 | | |
402 | 440 | | |
403 | 441 | | |
404 | 442 | | |
405 | 443 | | |
406 | | - | |
407 | | - | |
408 | | - | |
409 | | - | |
410 | | - | |
411 | | - | |
412 | | - | |
413 | | - | |
414 | | - | |
415 | | - | |
416 | | - | |
417 | | - | |
418 | | - | |
419 | | - | |
420 | | - | |
421 | | - | |
422 | | - | |
423 | | - | |
424 | | - | |
425 | | - | |
426 | | - | |
427 | | - | |
428 | | - | |
429 | | - | |
430 | 444 | | |
431 | 445 | | |
432 | 446 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
10 | 11 | | |
| 12 | + | |
11 | 13 | | |
12 | 14 | | |
13 | 15 | | |
14 | 16 | | |
15 | 17 | | |
16 | 18 | | |
17 | 19 | | |
| 20 | + | |
18 | 21 | | |
19 | 22 | | |
20 | 23 | | |
| |||
74 | 77 | | |
75 | 78 | | |
76 | 79 | | |
| 80 | + | |
77 | 81 | | |
78 | 82 | | |
79 | 83 | | |
| |||
120 | 124 | | |
121 | 125 | | |
122 | 126 | | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
123 | 140 | | |
124 | 141 | | |
125 | 142 | | |
| |||
129 | 146 | | |
130 | 147 | | |
131 | 148 | | |
| 149 | + | |
| 150 | + | |
132 | 151 | | |
133 | 152 | | |
134 | 153 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
347 | 347 | | |
348 | 348 | | |
349 | 349 | | |
350 | | - | |
| 350 | + | |
351 | 351 | | |
352 | 352 | | |
353 | 353 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
| 18 | + | |
18 | 19 | | |
19 | 20 | | |
20 | 21 | | |
| |||
268 | 269 | | |
269 | 270 | | |
270 | 271 | | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
123 | 123 | | |
124 | 124 | | |
125 | 125 | | |
| 126 | + | |
126 | 127 | | |
127 | 128 | | |
128 | | - | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
129 | 133 | | |
130 | 134 | | |
131 | 135 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
98 | 98 | | |
99 | 99 | | |
100 | 100 | | |
101 | | - | |
102 | | - | |
103 | | - | |
104 | | - | |
105 | | - | |
106 | | - | |
107 | | - | |
108 | | - | |
109 | | - | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
110 | 104 | | |
111 | | - | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
112 | 110 | | |
113 | | - | |
| 111 | + | |
114 | 112 | | |
115 | 113 | | |
116 | 114 | | |
117 | 115 | | |
118 | 116 | | |
119 | 117 | | |
120 | 118 | | |
121 | | - | |
| 119 | + | |
122 | 120 | | |
123 | 121 | | |
124 | 122 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
280 | 280 | | |
281 | 281 | | |
282 | 282 | | |
| 283 | + | |
283 | 284 | | |
284 | 285 | | |
285 | 286 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
506 | 506 | | |
507 | 507 | | |
508 | 508 | | |
| 509 | + | |
509 | 510 | | |
510 | 511 | | |
511 | 512 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
59 | 59 | | |
60 | 60 | | |
61 | 61 | | |
| 62 | + | |
62 | 63 | | |
63 | 64 | | |
64 | 65 | | |
| |||
0 commit comments