create-issue: write run artifacts into per-run sub-directories under .prflow/tmp/ and clean up at end of run - #1957
Conversation
…nup helper (checkpoint)
… references + tests (checkpoint)
…SKILL.md (checkpoint)
… coverage-map row
- Guard cleanup-create-issue-run.sh arg loop against a trailing valueless flag (bare shift 2 spun forever under set -u); add regression + mixed-root tests.
…1811 - .prflow/prompt-extensions/create-issue.md named the pre-relocation flat issue-derivation path; point it at the per-run create-issue/<slug>/ location its sibling step-2-clarify.md now requires.
- Replace a vacuous cleanup test assertion (the reaper never writes a pointer, so asserting its non-existence under root B could not flip) with a namespace- untouched assertion that flips if the absent-run-dir arm errors or over-removes.
- cleanup-create-issue-run.sh: a newline-less slug pointer made `read` return non-zero after assigning, and `|| ptr_slug=""` blanked it, skipping removal; keep the read value and pre-init. Correct the shift-cause comments (shift count exceeds $#, not set -u). Add a newline-less-pointer regression test.
#1811 - lib/test/modules/issue-audit-state.sh (a registered module) composed the old flat .prflow/tmp/issue-audit-state-<slug>.json / issue-draft-<slug>.md paths in ~33 sites, going RED after state_path()/init moved to create-issue/<slug>/. Retarget every site to the nested layout, mkdir the per-run parent before manual decoy/lock writes, and retarget the read-only-fs chmod to the nested dir.
- Trim the pointer-read comment to the 3-line cap; add reaper coverage for an interior-slash slug, an empty --root, and an unexpected positional arg.
… for issue #1811 - DEVFLOW_SYSTEM_OVERVIEW.md §11 and create-issue-context.md described the old flat .prflow/tmp/issue-* paths as current; relocate the 13 coupled path literals to the per-run create-issue/<slug>/ form (shared issue-run-slug pointer under create-issue/). Historical snapshots keep the old spelling.
…1811 - cloud-allowlist.md documented create-issue's emit-body redirect at the old flat <main-root>/.prflow/tmp/issue-body-<slug>.md; issue-template.md now composes the nested create-issue/<slug>/ form. The placeholder-prefix illustrative point holds for the nested path too.
- step-3-6-audit-shared.md's bootstrap recipe claimed the 'identical Step 4 sub-step 2 recipe' but named the shallow mkdir .prflow/tmp; Step 4 sub-step 2 was deepened to create-issue/<slug>. Deepen this mirror to match (the staged- write helper already mkdirs parents, so behavior is unchanged; this makes the identical-recipe claim true and the coupled mirror consistent).
…ue-write-run-artifacts-into-per-run-sub
…path pin (#1811) - Changing the run.sh draft-path pin literal to the per-run create-issue/<slug>/ location changed its sha256 identity, orphaning its adjudication row; move the key from the old literal hash to the new one (boundary bucket unchanged).
…ue-write-run-artifacts-into-per-run-sub # Conflicts: # lib/test/test_python_scripts.py
…ue-write-run-artifacts-into-per-run-sub
|
/prflow:review |
There was a problem hiding this comment.
Verdict: APPROVE with notes (clean mechanical scratch-relocation; strong test coverage, all required CI checks green; only low-severity Suggestions)
Issue Compliance
Reviewed against issue #1811: "create-issue: write run artifacts into per-run sub-directories under .prflow/tmp/ and clean up at end of run" — criteria from the /prflow:implement workpad comment; scope unchanged. The change satisfies every stated requirement: run artifacts now compose under .prflow/tmp/create-issue/<slug>/ (verified in scripts/issue-audit-state.py state_path/_bound_draft_file and across the skill prose); a successful run reaps its own run dir keyed to the recorded slug via the new scripts/cleanup-create-issue-run.sh, invoked at a success-only site (sub-step 5d of references/step-4-present-create.md); a run ending any other way leaves the dir in place; and pre-existing flat issue-* files are structurally untouched (the reaper only removes create-issue/<slug>/ and the pointer when it still holds this run's slug).
Test evidence
CI ground truth for the reviewed head a9efc1d7ca13758470d9e78c8b891e89d8b82f7a (read from the GitHub API): lib + python tests = success, lint (shellcheck + actionlint + ruff) = success, and every shard (…) = success. The suite was not re-run in-review; these API conclusions are the authoritative test evidence.
Verification
This engine-self-modifying diff (touches skills/**, lib/**, .prflow/prompt-extensions/*.md) was reviewed with the full Phase 3 specialist roster plus manual verification of the two code files. has_new_types is false, so type-design-analyzer was not dispatched. All five review passes returned clean:
- code-reviewer — no Critical/Important. Slug regex
^[A-Za-z0-9][A-Za-z0-9._-]*$byte-matches thestate_pathguard in Python;rm -rfis keyed to a validated single path segment (no glob/age sweep); arg-parse terminates on a trailing valueless flag;set -u+"${roots[@]:-}"is safe; no stale flat-path references remain. - silent-failure-hunter — no genuine silent failures. The reaper's suppressions are documented best-effort that fail non-destructively; the relocated Python write paths all create the deeper
create-issue/<slug>/parent (makedirs(exist_ok=True)/mkdir(parents=True)) and surface real I/O errors loudly. - comment-analyzer — no findings. All relocated docstrings (7 sites) accurate; every reaper comment names a concrete wrong change it prevents and stays within the 3-line cap.
- pr-test-analyzer — coverage adequate. All destructive-safety branches (unsafe/empty/traversal/interior-slash refusal, foreign-pointer skip, valueless-flag non-spin, newline-less pointer, multi-root, idempotent absent-dir) are directly and behaviorally covered.
- final-pass (requesting-code-review) — no Critical/Important; path references consistent, reaper at a success-only site, slug-keyed not sweep.
Intra-diff contradiction scan: no contradiction found. Truthfulness sweep: no finding promoted.
Repo prompt-extension gates
- Prompt-surface edit routing evidence gate — DISCHARGED. The diff touches trigger globs (
skills/create-issue/SKILL.md,.prflow/prompt-extensions/create-issue.md). Issue #1811's workpad carries twoWriting-skills evidence:markers, each with all four dispositions recorded:skill-loaded=yes guidance-applied=yes pressure-scenario=no micro-tests=no. All slots present, so the gate is discharged (anonever draws a finding on its own). - Wording-only pin review policy — clean. The
lib/test/run.shchange is an update of an existing draft-save-message pin (carries a valid# structural-pin-ok: cross-file-phase-contract -- <rationale>declaration), with itslib/test/pin-corpus-adjudications.tsvliteral-hash row updated in lockstep. No new wording-only presence pin was added; the added tests are behavioral (subprocess drives the reaper, asserts filesystem effects). - Shipped-prose cost audit — the ~3.7 KB net prose growth under
skills/**/.prflow/prompt-extensions/is dominated by the mechanicalcreate-issue/<slug>/path-segment insertion into existing sentences plus one new reaper-invocation step (5d) carrying a genuine instruction. No gratuitous additions warranting an Important finding. - Verification-evidence advisory — the workpad carries
Verification evidence:markers; advisory is silent.
Code Review Findings
🟡 Suggestion / Minor
scripts/cleanup-create-issue-run.sh— the pointer removal (rm -f -- "$ptr" && printf …) is asymmetric with the target-dir removal above it: a failed pointerrm -femits nowarning: could not removebreadcrumb (the&&short-circuits the success print with noelse), whereas the directory removal warns on failure. Within the best-effort/exit-0 contract this is not a defect; anelsewarning for parity would make a stuck pointer visible. (raised by 1/5 agents)docs/internal/advisory-adjudication-calibration.md:80,85— still names the pre-move flat globs.prflow/tmp/issue-audit-state-*.json/.prflow/tmp/issue-audit-*.md. This file is not touched by the PR and is a dated (2026-07-23) frozen inventory snapshot, so it is correctly left under the past-time-snapshot exemption; noted only so it is a conscious decision. (raised by 2/5 agents)scripts/cleanup-create-issue-run.sh— the arg-parse and pointer-read comment blocks sit at the 3-line cap; they satisfy §2.3 comment discipline but could be tightened if the file is edited later. (raised by 1/5 agents)
Verdict Criteria
- No verification FAIL/INCONCLUSIVE.
- No self-contradicting-diff finding.
- No finding at or above the configured verdict threshold (
critical). - Only Suggestion-level findings present → APPROVE with notes.
View run
Summary
.prflow/tmp/create-issue/<slug>/instead of as flat files directly under.prflow/tmp/, so one run's working set is no longer scattered across a directory shared with every other producer.issue-*files under.prflow/tmp/are left untouched.Changes
create-issue skill prose:
skills/create-issue/SKILL.mdand itsreferences/*.md(step-4-present-create, audit-prompt-template, step-2/3-5/3-6 references, fallback arms, issue-template, degradation-routing, revision-delta) now compose artifact paths under.prflow/tmp/create-issue/<slug>/, including the shared slug pointer at.prflow/tmp/create-issue/issue-run-slug.Audit-state path:
scripts/issue-audit-state.pyrelocates the audit-state file and the bound canonical-draft file to.prflow/tmp/create-issue/<slug>/, updatingstate_path,_bound_draft_file, and the coupled dispatch/binding docstrings and--pathhelp.Cleanup reaper: new
scripts/cleanup-create-issue-run.shremoves a completed run's<root>/.prflow/tmp/create-issue/<slug>/directory keyed to the recorded slug, refusing empty or path-unsafe slugs (delete nothing, exit 0), removing the shared slug pointer only when it still holds this run's slug, and iterating over one or more--rootvalues.Tests & coverage: the
#1811 cleanup:block inlib/test/test_python_scripts.pydrives the reaper via subprocess;lib/test/modules/issue-audit-state.shandlib/test/test_python_scripts.pycover the audit-state relocation;lib/test/modules/create-issue-contract.shcovers the coupled path enumerations (AC5); acoverage-map.jsonrow registers the reaper;lib/test/run.sh's draft-path pin andtest_render_audit_prompt.pyare updated to the per-run layout.Docs:
docs/internal/DEVFLOW_SYSTEM_OVERVIEW.md,cloud-allowlist.md, andcreate-issue-context.mdare reconciled to the per-run scratch layout.Resolves
Resolves #1811
Test Plan
lib/test/test_python_scripts.py— the#1811 cleanup:cases pass (valid-slug reap, foreign-pointer skip, empty/unsafe-handle non-destructive, traversal + interior-slash refusal, empty--root, unexpected arg, newline-less pointer, multi-root, valueless-flag termination, absent-dir idempotent).lib/test/modules/issue-audit-state.shpasses with the state file at the per-run location.lib/test/modules/create-issue-contract.shpasses (AC5 coupled path enumerations)..prflow/tmp/; a run that ends otherwise leaves its run directory in place.Visual Changes
N/A
Breaking Changes
None
Prompt-surface size
Derived at
8b4e74ccc359180cd34001a366acbb6c8783cc52against merge-base66eec8a8a2aee14677cd27359929722760691fe3(origin/main). Covered: tracked*.mdunderskills/,agents/,.prflow/prompt-extensions/..prflow/prompt-extensions/create-issue.mdskills/create-issue/SKILL.mdskills/create-issue/references/audit-prompt-template.mdskills/create-issue/references/degradation-routing.mdskills/create-issue/references/fallback-audit-dispatch-arms.mdskills/create-issue/references/fallback-no-task-tool.mdskills/create-issue/references/fallback-read-only-sandbox.mdskills/create-issue/references/issue-template.mdskills/create-issue/references/revision-delta.mdskills/create-issue/references/step-2-clarify.mdskills/create-issue/references/step-3-5-steelman.mdskills/create-issue/references/step-3-6-audit-adjudication.mdskills/create-issue/references/step-3-6-audit-dispatch.mdskills/create-issue/references/step-3-6-audit-shared.mdskills/create-issue/references/step-3-6-audit.mdskills/create-issue/references/step-4-present-create.mdGenerated via /prflow:implement (v2.34.14, claude-opus-4-8, low)