feat(issue-lifecycle): add summarizing phase, code conformance review, and adversarial regression verification #156
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/issue-lifecycle-2026.07.30.1"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Bump issue-lifecycle model to 2026.07.30.1. Adds the summarizing phase
between notify and done, code conformance review resource/methods/check,
adversarial regression evidence fields and triage validation, and the
summarize method. Updates skill documentation with Phase 6, resume table
entry, and adversarial regression triage instructions.
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com
Code Review
Blocking Issues
triageregression verification logic — Thetriagemethod (extensions/models/issue_lifecycle.ts:731-751) now throws whenisRegression=truewithout all four required fields (regressionEvidence,regressionCounterEvidence,regressionVerdict,regressionVerdictReasoning), and automatically clearsisRegressionwhenregressionVerdict === "downgraded". This is the primary new behavioral feature in the PR ("Adversarial regression verification"), but neitherextensions/models/issue_lifecycle_test.tsnorissue-lifecycle/extensions/models/issue_lifecycle_test.tscontains any test covering this code path. Specifically untested:triagethrows whenisRegression=trueand evidence fields are absenttriagesetseffectiveIsRegression = false(and logs the downgrade) when verdict isdowngradedtriagesucceeds normally when all four regression fields are suppliedSuggestions
SummarySchemadoesn't export its inferred type — Every other persisted schema in_lib/schemas.tsexports a named type alias (PlanData,AdversarialReviewData,CodeConformanceReviewData,PullRequestData,StateData), butSummarySchemais missingexport type SummaryData = z.infer<typeof SummarySchema>. Not a bug since the schema itself is exported, but it breaks the established pattern.schemas_test.tsdoesn't assertsummarizinginTRANSITIONS.start— The test"TRANSITIONS: start (resume) includes pr_open, pr_failed, releasing, and notify"(line 48) was not updated to also assert thatsummarizingis in the allowed phases forstart. Sincesummarizingwas added toTRANSITIONS.startin this PR, a corresponding assertion would make the test consistent with the change.Regression validation done in
executerather than Zod — The cross-field constraint (isRegression=truerequires four other fields) is enforced by a manualifcheck in theexecutefunction rather thanz.superRefine(). This means the Zod schema fortriage's arguments accepts invalid inputs that the execute body then rejects. Not a bug, but keeping schema and validation co-located in Zod would make the constraint self-documenting and easier to test viaparseAsync.Adversarial Review
Critical / High
No critical or high severity issues found.
Medium
No test coverage for adversarial regression validation logic (
extensions/models/issue_lifecycle.ts:732-751,issue-lifecycle/extensions/models/issue_lifecycle.ts:732-751)The triage method's regression validation is entirely untested. The test file has zero references to "regression" or "isRegression". Two distinct code paths are uncovered:
isRegression=truebut any of the four evidence fields is missing, the method throws. No test verifies this throw happens, nor that the error message is correct.regressionVerdict === "downgraded",effectiveIsRegressionis set tofalse, which changes what gets written to the classification resource and the lifecycle entry. No test verifies the downgraded value propagates towriteResourceorpostLifecycleEntry.Breaking example: Someone refactors the
ifcondition at line 732 toif (args.isRegression === true)(a common "strictness" refactor) but accidentally moves the closing brace, and the downgrade block silently stops executing. Nothing catches it.Suggested fix: Add at least two tests — one asserting
executethrows whenisRegression=truewith missing evidence fields, and one asserting thatregressionVerdict: "downgraded"writesisRegression: falseto the classification resource.summarizeunconditionally closes the lifecycle even whenoutcomeMet: false(extensions/models/issue_lifecycle.ts:2150-2182,issue-lifecycle/extensions/models/issue_lifecycle.ts:2150-2182)The SKILL.md and implementation.md describe the summary as verifying "the work addressed the issue before transitioning to done." But the code transitions to
doneand poststargetStatus: "shipped"identically for bothoutcomeMet: trueandoutcomeMet: false. The only difference is the summary string prefix ("Outcome met" vs "Outcome NOT met").Breaking example: An agent calls
summarizewithoutcomeMet: falsebecause the fix didn't address the reported issue. The lifecycle completes asdone/shippedanyway. There's no mechanism to re-open, re-plan, or flag for human review. The verification step becomes a passive annotation rather than a gate.Suggested fix: If this is intentional (the summary is a record, not a gate), update the docs to say "records whether the outcome was met" rather than "verifies the work addressed the issue." If it should be a gate, have
outcomeMet: falsetransition to a different phase (e.g. back toimplementingor a newneeds_reworkphase) instead ofdone.Low
Whitespace-only strings pass regression evidence validation (
extensions/models/issue_lifecycle.ts:733-737)The falsy check
!args.regressionEvidencecatchesundefinedand empty string, but a whitespace-only string like" "passes validation. The Zod schema usesz.string()without.min(1)or.trim(), soregressionEvidence: " "satisfies both schema and runtime validation while providing no meaningful evidence.Suggested fix: Use
z.string().min(1)in the argument schema, or add.trim().length > 0to the runtime check.Regression evidence fields silently accepted without
isRegression(extensions/models/issue_lifecycle.ts:730-752)If a caller passes
regressionEvidence,regressionCounterEvidence,regressionVerdict, andregressionVerdictReasoningbut setsisRegression: false(or omits it), all evidence fields are stored in the classification resource alongsideisRegression: false. No warning is logged about the inconsistency. This could create confusing records where evidence exists but the flag is off.Suggested fix: Log a warning when regression evidence fields are present but
isRegressionis nottrue, or strip the fields whenisRegressionis falsy.Verdict
PASS — The code is structurally sound: phase transitions are correctly wired, the TRANSITIONS table matches the new phase ordering, upgrade entries are properly sequenced, tests cover the happy paths for
summarize/notify/skip_notify, and the schema additions are consistent. The two medium findings (untested regression validation logic and theoutcomeMet: falsesemantic gap) are real gaps but neither causes data loss or security issues. Both can be addressed in a follow-up.