Outcome
standards cut-successor reports infrastructure failures the same way it reports findings, and apply_cut can leave partial state behind after a docstring claims it cannot.
Context
Found during the pre-merge review of PR #241 (leg relprep, standards cut-successor writer) and deferred as non-blocking. Quoting /tmp/ps529-session/reviews/review-landed.md (lines 69-72):
src/project_standards/standards_graph/cli.py (_run_cut_successor, final line) — return 1 if generated else 0 collapses a follow-on writer's exit 2 (load/write error, unsafe output path) into 1. docs/usage.md documents 1 as "the follow-on projection or catalog writer reported findings" and 2 as a load/write error, so an infrastructure failure in sync-payload-projection is reported as a findings result.
src/project_standards/package_contract/cut_successor.py apply_cut docstring — "A refused cut leaves nothing behind" holds only inside the try. _predecessor_occurrences and the scaffold write run after it; an OSError there exits 2 with the copied tree, the family index entry, and the catalog entry already written, and plan_cut then refuses the retry ("successor payload directory already exists"). Either move both inside the guarded block or narrow the docstring's claim.
src/project_standards/package_contract/cut_successor.py _insert_catalog_entry — the role-demotion replacement writes f'role = "..."' with no indent, although _SCALAR captured indent and _rewrite_payload_manifest preserves it. Harmless for the flat catalogs/*.toml in the tree; it would silently reformat an indented catalog.
Documented exit codes: docs/usage.md.
Scope
- Fix the exit-2 collapse in
_run_cut_successor so an infrastructure failure from sync-payload-projection surfaces as its own code rather than as a findings result.
- Move
_predecessor_occurrences and the scaffold write inside apply_cut's guarded try, or narrow the docstring's "leaves nothing behind" claim to match actual behavior.
- Fix the role-demotion replacement in
_insert_catalog_entry to preserve the captured indent.
Out of scope
Anything not named above; this issue is the three findings quoted, not a broader audit of cut_successor.py.
Acceptance criteria
Evidence / references
Outcome
standards cut-successorreports infrastructure failures the same way it reports findings, andapply_cutcan leave partial state behind after a docstring claims it cannot.Context
Found during the pre-merge review of PR #241 (leg
relprep,standards cut-successorwriter) and deferred as non-blocking. Quoting/tmp/ps529-session/reviews/review-landed.md(lines 69-72):src/project_standards/standards_graph/cli.py(_run_cut_successor, final line) —return 1 if generated else 0collapses a follow-on writer's exit2(load/write error, unsafe output path) into1.docs/usage.mddocuments1as "the follow-on projection or catalog writer reported findings" and2as a load/write error, so an infrastructure failure insync-payload-projectionis reported as a findings result.src/project_standards/package_contract/cut_successor.pyapply_cutdocstring — "A refused cut leaves nothing behind" holds only inside thetry._predecessor_occurrencesand the scaffold write run after it; anOSErrorthere exits2with the copied tree, the family index entry, and the catalog entry already written, andplan_cutthen refuses the retry ("successor payload directory already exists"). Either move both inside the guarded block or narrow the docstring's claim.src/project_standards/package_contract/cut_successor.py_insert_catalog_entry— the role-demotion replacement writesf'role = "..."'with no indent, although_SCALARcapturedindentand_rewrite_payload_manifestpreserves it. Harmless for the flatcatalogs/*.tomlin the tree; it would silently reformat an indented catalog.Documented exit codes:
docs/usage.md.Scope
_run_cut_successorso an infrastructure failure fromsync-payload-projectionsurfaces as its own code rather than as a findings result._predecessor_occurrencesand the scaffold write insideapply_cut's guardedtry, or narrow the docstring's "leaves nothing behind" claim to match actual behavior._insert_catalog_entryto preserve the capturedindent.Out of scope
Anything not named above; this issue is the three findings quoted, not a broader audit of
cut_successor.py.Acceptance criteria
_run_cut_successor's exit code distinguishes a follow-on writer's findings (1) from an infrastructure failure (2), matchingdocs/usage.md.apply_cuteither guards_predecessor_occurrencesand the scaffold write inside the sametryas the rest of the cut, or its docstring's "leaves nothing behind" claim is narrowed to describe actual behavior._insert_catalog_entry's role-demotion replacement preserves the original line's indent.Evidence / references
/tmp/ps529-session/reviews/review-landed.mdlines 69-72.