Implementation Plan: P2-WP4 Create research-archive.yaml Sub-Recipe#1979
Conversation
Trecek
left a comment
There was a problem hiding this comment.
AutoSkillit PR Review — Verdict: changes_requested
| create_artifact_branch: | ||
| tool: run_cmd | ||
| with: | ||
| cmd: "bash scripts/recipe/create_artifact_branch.sh '${{ inputs.worktree_path }}' '${{ context.experiment_branch }}' '${{ inputs.base_branch }}' '${{ inputs.research_dir }}'" |
There was a problem hiding this comment.
[critical] defense: Shell injection: '${{ context.experiment_branch }}' is captured from git stdout and passed as a single-quoted shell arg. A branch name with a single-quote character breaks the command. Applies similarly to context.artifact_branch (L80), context.artifact_pr_url (L80, L91), context.archive_tag (L91). Values derived from external data should be validated before shell interpolation.
There was a problem hiding this comment.
Valid observation — flagged for design decision. Git branch names cannot technically contain single-quote characters (git enforces naming rules), so this path is not exploitable with valid branches. However, hardening quoting across all recipes consistently is a valid project-wide decision worth making deliberately. Flagged for human review.
| capture_experiment_branch: | ||
| tool: run_cmd | ||
| with: | ||
| cmd: "git -C '${{ inputs.worktree_path }}' rev-parse --abbrev-ref HEAD" |
There was a problem hiding this comment.
[warning] defense: Single-quoted shell substitution: '${{ inputs.worktree_path }}' protects against word-splitting but not against paths containing single-quote characters. A worktree_path like /tmp/it's/here would break the command. Same pattern on L69, L70, L80, L81, L91, L92, L105, L106.
There was a problem hiding this comment.
Valid observation — flagged for design decision. Worktree paths are system-generated by campaign dispatch and won't contain single quotes in practice. All other bundled recipes use the same single-quote interpolation for context variables. Hardening quoting project-wide is a valid decision to make deliberately rather than per-recipe. Flagged for human review.
Trecek
left a comment
There was a problem hiding this comment.
AutoSkillit review: changes_requested — 2 critical blocking issues found; see inline comments for details.
Blocking (critical):
research-archive.yaml:104— ARCHIVE_TAG used in printf but never assigned; close comment body will have an empty archive tagresearch-archive.yaml:69— Context values captured from external sources (git stdout) used as single-quoted shell args without sanitization
Warnings:
research-archive.yaml:129— escalate_stop is a defined stop step with no route pointing to it (unreachable)research-archive.yaml:56— run_cmd steps omit timeout; network-bound gh calls can hang indefinitelyresearch-archive.yaml:58— Single-quoted shell substitution does not protect against single-quote chars in path valuesresearch-archive.yaml:73— Captured context values (artifact_branch, artifact_pr_url) have no guard against empty captureresearch-archive.yaml:12— Summary field omits escalate_stop terminal pathresearch-archive.yaml:49— begin_archival note overly verbosetest_research_archive_recipe.py:12— class-scoped fixture: verify recipe object is picklable for xdisttest_research_archive_recipe.py:18— test_loads_without_exception is redundanttest_research_archive_recipe.py:173— escalate_stop test does not assert reachability
Trecek
left a comment
There was a problem hiding this comment.
AutoSkillit PR Review — Verdict: approved_with_comments
| capture: | ||
| archive_tag: "${{ result.archive_tag }}" | ||
| on_success: close_experiment_pr | ||
| on_failure: patch_token_summary |
There was a problem hiding this comment.
[warning] defense: context.archive_tag captured from result.archive_tag without non-empty validation. If tag_experiment_branch.sh succeeds but emits no archive_tag key, downstream steps (close_experiment_pr L104) embed an empty string in the gh pr close comment body, producing a malformed reference silently.
There was a problem hiding this comment.
Valid observation — flagged for design decision. The concern is real: context.archive_tag is captured from result.archive_tag without a non-empty guard, and close_experiment_pr (L104) embeds it in a shell printf. However, the RecipeStep schema has no on_empty_result, required_keys, or similar validation construct — such a field does not exist in the schema or any bundled recipe. The recipe's declared intent is best-effort degradation (failures route to patch_token_summary), and on_failure covers script-level exits; an empty-key-but-exit-0 gap would require either adding validation inside tag_experiment_branch.sh or introducing a new schema feature. Both require a design decision.
| capture: | ||
| artifact_pr_url: "${{ result.artifact_pr_url }}" | ||
| on_success: tag_experiment_branch | ||
| on_failure: patch_token_summary |
There was a problem hiding this comment.
[warning] defense: context.artifact_pr_url captured from result.artifact_pr_url without non-empty validation. If open_artifact_pr.sh succeeds but emits no artifact_pr_url key, tag_experiment_branch (L91) and close_experiment_pr (L103) receive an empty string in shell substitutions, producing silently incorrect tag metadata and a blank PR reference.
There was a problem hiding this comment.
Valid observation — flagged for design decision. The concern is real: context.artifact_pr_url is captured from result.artifact_pr_url without a non-empty guard, and both tag_experiment_branch (L91) and close_experiment_pr (L103) embed it in shell substitutions. However, the RecipeStep schema has no on_empty_result or required_keys mechanism. The run-cmd-emit-alignment rule explicitly exempts bash scripts/ invocations (which is the pattern used here). Remediation requires adding validation inside open_artifact_pr.sh or introducing a new schema feature — both are design-level decisions.
Trecek
left a comment
There was a problem hiding this comment.
AutoSkillit review: warning-only findings detected. See inline comments — no blocking changes required.
Extracts the 9-step archival phase from research.yaml into a standalone sub-recipe. Key design: all ingredient-sourced values (pr_url, worktree_path, research_dir) use inputs.X references instead of context.X since they are declared ingredients in the standalone recipe. Step-captured values (experiment_branch, artifact_branch, artifact_pr_url, archive_tag) correctly remain as context.X. Pack declarations are [github, ci] — the archival phase only needs GitHub CLI and CI tools, not the full research pack. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The note referenced "context.pr_url" in explanatory text, which caused test_no_context_pr_url_in_recipe (raw file text scan) to fail even though context.pr_url was not used as a variable reference. Rephrased to say "ingredient (not a captured context value)" instead. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
research-archive.yaml was added as a new bundled sub-recipe but the test_bundled_recipe_count_is_13 guard was not updated to include it.
…note - patch_token_summary.on_failure now routes to escalate_stop instead of research_complete — makes escalate_stop reachable (was a dead step) - summary updated to show '| escalate' alternate terminal path - begin_archival note: removed verbose implementation-detail sentence Addresses review comments 3193166853 (unreachable escalate_stop), 3193166858 (summary omits escalate_stop), 3193166860 (over-verbose note). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…bility test - Remove test_loads_without_exception (redundant — fixture failure gives clear errors) - test_patch_token_summary_routes_to_complete: update on_failure assertion to escalate_stop (reflects the wired routing from this PR's recipe fix) - Add test_escalate_stop_is_reachable: asserts at least one step routes to escalate_stop (stronger signal than confirming the step exists alone) Addresses review comments 3193166862 (redundant test), 3193166865 (weak reachability). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…y with sibling recipe tests
… asserting exact set
…test_step_names set equality
… covered by test_kitchen_rules_forbid_native_tools
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2c31c4e to
e56b0b7
Compare
…1979) ## Summary Create `src/autoskillit/recipes/research-archive.yaml` as a standalone sub-recipe that extracts the 9-step archival phase from `research.yaml` (lines 855–963). The critical change from the parent recipe: all ingredient-sourced values (`pr_url`, `worktree_path`, `research_dir`, `base_branch`) use `inputs.X` references instead of `context.X`, since these are declared ingredients in the standalone recipe rather than step-captured context variables. Step-captured values (`experiment_branch`, `artifact_branch`, `artifact_pr_url`, `archive_tag`) correctly remain as `context.X`. Pack declarations are `[github, ci]` (the archival phase only needs GitHub CLI and CI tools, not the full `research` pack). No `autoskillit_version` field — consistent with bundled recipe policy (removed in #1950). Only 4 ingredients: 3 campaign-sourced hidden (`worktree_path`, `research_dir`, `pr_url`) and 1 user-input (`base_branch`). The `report_path_after_finalize` and `source_dir` ingredients from the parent recipe are omitted because no archival step references them. Closes #1703 ## Implementation Plan Plan file: `/home/talon/projects/autoskillit-runs/impl-20260505-213323-163152/.autoskillit/temp/make-plan/p2_wp4_create_research_archive_yaml_sub_recipe_plan_2026-05-05_213600.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 --> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Summary
Create
src/autoskillit/recipes/research-archive.yamlas a standalone sub-recipe that extracts the 9-step archival phase fromresearch.yaml(lines 855–963). The critical change from the parent recipe: all ingredient-sourced values (pr_url,worktree_path,research_dir,base_branch) useinputs.Xreferences instead ofcontext.X, since these are declared ingredients in the standalone recipe rather than step-captured context variables. Step-captured values (experiment_branch,artifact_branch,artifact_pr_url,archive_tag) correctly remain ascontext.X. Pack declarations are[github, ci](the archival phase only needs GitHub CLI and CI tools, not the fullresearchpack). Noautoskillit_versionfield — consistent with bundled recipe policy (removed in #1950). Only 4 ingredients: 3 campaign-sourced hidden (worktree_path,research_dir,pr_url) and 1 user-input (base_branch). Thereport_path_after_finalizeandsource_diringredients from the parent recipe are omitted because no archival step references them.Closes #1703
Implementation Plan
Plan file:
/home/talon/projects/autoskillit-runs/impl-20260505-213323-163152/.autoskillit/temp/make-plan/p2_wp4_create_research_archive_yaml_sub_recipe_plan_2026-05-05_213600.md🤖 Generated with Claude Code via AutoSkillit
Token Usage Summary
Token Efficiency