feat(issue-lifecycle): sync verification workflow from upstream swamp repo #250

Open
stack72 wants to merge 7 commits from worktree-expressive-mapping-sparrow into main
Owner

Summary

  • Syncs the issue-lifecycle extension, skill docs, and root copies with the upstream swamp repo
  • Adds the verification workflow: verify, verification_passed, verification_failed, post_attestation methods and the verifying phase
  • Adds regression verification to triage, new verification.md skill reference, swamp_club_test.ts, and upstream_extensions.json
  • Updates all three locations (root .claude/skills/, root extensions/models/, and issue-lifecycle/ package) to stay in sync

Test plan

  • Verify deno check passes on the extension files
  • Verify deno test passes for the issue_lifecycle and _lib tests
  • Confirm the skill loads correctly via /issue-lifecycle

🤖 Generated with Claude Code

## Summary - Syncs the issue-lifecycle extension, skill docs, and root copies with the upstream swamp repo - Adds the verification workflow: `verify`, `verification_passed`, `verification_failed`, `post_attestation` methods and the `verifying` phase - Adds regression verification to triage, new `verification.md` skill reference, `swamp_club_test.ts`, and `upstream_extensions.json` - Updates all three locations (root `.claude/skills/`, root `extensions/models/`, and `issue-lifecycle/` package) to stay in sync ## Test plan - [ ] Verify `deno check` passes on the extension files - [ ] Verify `deno test` passes for the issue_lifecycle and _lib tests - [ ] Confirm the skill loads correctly via `/issue-lifecycle` 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(issue-lifecycle): sync verification workflow from upstream swamp repo
Some checks failed
CI: Extensions / cve/mini-shai-hulud - check (pull_request) Has been skipped
CI: Extensions / cve/mini-shai-hulud - fmt (pull_request) Has been skipped
CI: Extensions / cve/mini-shai-hulud - lint (pull_request) Has been skipped
CI: Extensions / cve/mini-shai-hulud - test (pull_request) Has been skipped
CI: Extensions / cve/researcher - check (pull_request) Has been skipped
CI: Extensions / cve/researcher - fmt (pull_request) Has been skipped
CI: Extensions / cve/researcher - lint (pull_request) Has been skipped
CI: Extensions / cve/researcher - test (pull_request) Has been skipped
CI: Extensions / software-factory - check (pull_request) Has been skipped
CI: Extensions / software-factory - fmt (pull_request) Has been skipped
CI: Extensions / software-factory - lint (pull_request) Has been skipped
CI: Extensions / software-factory - test (pull_request) Has been skipped
CI: Extensions / container-image - check (pull_request) Has been skipped
CI: Extensions / container-image - fmt (pull_request) Has been skipped
CI: Extensions / container-image - lint (pull_request) Has been skipped
CI: Extensions / container-image - test (pull_request) Has been skipped
CI: Reviews / Detect Changes (pull_request) Successful in 19s
CI: Reviews / CI Security Review (pull_request) Has been skipped
CI / Actions Audit (pull_request) Successful in 28s
CI: Extensions / issue-lifecycle - lockfile up to date (pull_request) Successful in 24s
CI / Dependency Audit (pull_request) Successful in 2m41s
CI: Extensions / issue-lifecycle - check (pull_request) Successful in 28s
CI: Extensions / issue-lifecycle - fmt (pull_request) Successful in 23s
CI: Extensions / issue-lifecycle - lint (pull_request) Successful in 23s
CI: Extensions / issue-lifecycle - test (pull_request) Successful in 28s
CI: Reviews / Claude Code Review (pull_request) Failing after 2m47s
CI / Gate: Audit (pull_request) Successful in 0s
CI: Extensions / Gate: Extensions (pull_request) Successful in 0s
CI: Reviews / Adversarial Code Review (pull_request) Successful in 3m6s
CI: Reviews / Gate: Reviews (pull_request) Failing after 0s
c8846a50f3
Brings the issue-lifecycle extension, skill, and root copies up to date
with the swamp repo: adds the verification loop (verify, verification_passed,
verification_failed, post_attestation), the verifying phase, regression
verification in triage, and updated skill docs including the new
verification reference.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author
Owner

Code Review

Blocking Issues

  1. post_attestation "hard gate" is not enforced — link_pr can bypass it

    The description for post_attestation explicitly states: "The PR must not open without a stored attestation — this is a hard gate." However, the implementation does not enforce this:

    • post_attestation returns { dataHandles: [] } and writes no resource to the data store.
    • The verification-clear check (which gates link_pr) only reads verificationResult-main — it does not check whether an attestation was posted.
    • Both post_attestation and link_pr are valid from the verifying state (per TRANSITIONS), so the intended ordering is not enforced.

    After verification_passed transitions state to verifying, an agent can call link_pr directly without ever calling post_attestation, and no gate will stop it. The hard-gate claim in both issue-lifecycle/extensions/models/issue_lifecycle.ts:1931 and extensions/models/issue_lifecycle.ts:1931 is not implemented.

    Fix: Either (a) write a local attestation resource (e.g. "attestation-main") in post_attestation and add an attestation-clear check that gates link_pr on its existence, or (b) remove the "hard gate" claim from the description if enforcement is intentionally deferred.

  2. Missing execution tests for post_attestation

    The only test for post_attestation in both extensions/models/issue_lifecycle_test.ts:325-331 and issue-lifecycle/extensions/models/issue_lifecycle_test.ts:325-331 is a registration smoke test. The method has three distinct failure paths that are completely untested:

    • Swamp-club unreachable (sc is null → throws "swamp-club is not reachable or credentials are missing")
    • Invalid JSON input (args.attestation fails JSON.parse → throws "attestation input is not valid JSON")
    • Successful path: attestation posted, postLifecycleEntry called with attestationId, method returns { dataHandles: [] }

    swamp_club_test.ts tests postAttestation on the client, but there are no tests for the model method's orchestration logic, including the JSON-parse guard and the lifecycle entry payload. This is a new public method with external side effects and a stated security/integrity contract.

Suggestions

  1. link_pr description is stale — both model files describe link_pr as "Transitions the phase to pr_open from implementing or pr_failed" (issue_lifecycle.ts:1994), but implementing was removed from TRANSITIONS.link_pr in favor of verifying (the new verifying phase gates PR linkage). The description should be updated to reflect the actual allowed source phases (verifying, pr_open, pr_failed).

  2. README state machine and methods table are significantly outdatedextensions/models/README.md shows only the original 6-step flow and methods table, and does not mention verify, verification_passed, verification_failed, post_attestation, link_pr, pr_merged, pr_failed, ship, notify, skip_notify, or summarize. The new phases (verifying, pr_open, pr_failed, releasing, notify, summarizing) are also absent from the diagram. This will confuse users trying to understand the current lifecycle.

## Code Review ### Blocking Issues 1. **`post_attestation` "hard gate" is not enforced — `link_pr` can bypass it** The description for `post_attestation` explicitly states: _"The PR must not open without a stored attestation — this is a hard gate."_ However, the implementation does not enforce this: - `post_attestation` returns `{ dataHandles: [] }` and writes **no resource** to the data store. - The `verification-clear` check (which gates `link_pr`) only reads `verificationResult-main` — it does not check whether an attestation was posted. - Both `post_attestation` and `link_pr` are valid from the `verifying` state (per `TRANSITIONS`), so the intended ordering is not enforced. After `verification_passed` transitions state to `verifying`, an agent can call `link_pr` directly without ever calling `post_attestation`, and no gate will stop it. The hard-gate claim in both `issue-lifecycle/extensions/models/issue_lifecycle.ts:1931` and `extensions/models/issue_lifecycle.ts:1931` is not implemented. **Fix**: Either (a) write a local attestation resource (e.g. `"attestation-main"`) in `post_attestation` and add an `attestation-clear` check that gates `link_pr` on its existence, or (b) remove the "hard gate" claim from the description if enforcement is intentionally deferred. 2. **Missing execution tests for `post_attestation`** The only test for `post_attestation` in both `extensions/models/issue_lifecycle_test.ts:325-331` and `issue-lifecycle/extensions/models/issue_lifecycle_test.ts:325-331` is a registration smoke test. The method has three distinct failure paths that are completely untested: - Swamp-club unreachable (sc is null → throws `"swamp-club is not reachable or credentials are missing"`) - Invalid JSON input (`args.attestation` fails `JSON.parse` → throws `"attestation input is not valid JSON"`) - Successful path: attestation posted, `postLifecycleEntry` called with `attestationId`, method returns `{ dataHandles: [] }` `swamp_club_test.ts` tests `postAttestation` on the client, but there are no tests for the model method's orchestration logic, including the JSON-parse guard and the lifecycle entry payload. This is a new public method with external side effects and a stated security/integrity contract. ### Suggestions 1. **`link_pr` description is stale** — both model files describe `link_pr` as "Transitions the phase to pr_open from implementing or pr_failed" (`issue_lifecycle.ts:1994`), but `implementing` was removed from `TRANSITIONS.link_pr` in favor of `verifying` (the new verifying phase gates PR linkage). The description should be updated to reflect the actual allowed source phases (`verifying`, `pr_open`, `pr_failed`). 2. **README state machine and methods table are significantly outdated** — `extensions/models/README.md` shows only the original 6-step flow and methods table, and does not mention `verify`, `verification_passed`, `verification_failed`, `post_attestation`, `link_pr`, `pr_merged`, `pr_failed`, `ship`, `notify`, `skip_notify`, or `summarize`. The new phases (`verifying`, `pr_open`, `pr_failed`, `releasing`, `notify`, `summarizing`) are also absent from the diagram. This will confuse users trying to understand the current lifecycle.
Author
Owner

Adversarial Review

Critical / High

No critical or high severity findings.

Medium

  1. Stale verification result allows skipping re-verificationextensions/models/issue_lifecycle.ts:1706-1757 and extensions/models/issue_lifecycle.ts:512-556

    The verify method only transitions state to "verifying" — it does not clear or invalidate the existing verificationResult-main resource. The verification-clear check (line 512) only checks allPassed and stepsFailed without validating that the verification result corresponds to the current commit.

    Breaking scenario:

    1. Agent implements, verifies, calls verification_passed (writes passing result for commit abc123), links PR, PR fails.
    2. Agent goes back to implementing via implement, makes code changes (new commit def456).
    3. Agent calls verify (state → "verifying") but does NOT run verification_passed again.
    4. Agent calls link_pr — the verification-clear check passes because the stale verificationResult-main from step 1 still has allPassed: true.
    5. PR opens with unverified code.

    Suggested fix: Either (a) have verify clear/invalidate the existing verificationResult-main resource, or (b) have verification-clear compare the commit in the verification result against the commit in the verify call (which would require storing the target commit in state). Option (a) is simpler.

  2. post_attestation described as a "hard gate" but has no enforcement checkextensions/models/issue_lifecycle.ts:1926-1932

    The method description says "The PR must not open without a stored attestation — this is a hard gate." However, there is no corresponding check in the checks object that gates link_pr on attestation having been posted. The link_pr transitions allow verifying as a source phase, and there's no attestation-posted check in appliesTo: ["link_pr"]. An agent can skip post_attestation entirely and proceed from verifyverification_passedlink_pr without posting an attestation.

    Suggested fix: Either add an attestation-posted check that gates link_pr, or soften the description from "hard gate" to "expected step" if enforcement is handled at the skill layer.

Low

  1. verification_passed method name is misleading when recording failuresextensions/models/issue_lifecycle.ts:1759-1858

    The verification_passed method accepts steps with status: "failed" and computes allPassed: failed === 0. If called with failed steps, allPassed will be false and the method effectively records a failure. The naming suggests success-only semantics, but the implementation accepts any outcome. This could confuse callers — verification_failed exists for the failure path but records no step-level data, so there's an asymmetry in the API.

  2. complete bypasses verification entirelyextensions/models/issue_lifecycle.ts:93-94 (TRANSITIONS) and extensions/models/issue_lifecycle.ts:512-516 (verification-clear)

    The verification-clear check applies only to ["link_pr"], but complete accepts implementing as a source phase (line 94). This means complete can close the lifecycle from implementing without any verification. This appears intentional for backwards compatibility, but it means the verification gate can be entirely circumvented by calling complete instead of going through the verifylink_prpr_mergedship path.

Verdict

PASS — The code is well-structured with consistent state machine transitions, proper error handling, and thorough test coverage. The two medium findings are design-level gaps in gate enforcement rather than correctness bugs — the stale verification result scenario requires a specific multi-cycle flow, and the attestation gap is mitigated by the skill-layer instructions that guide agent behavior. The files in extensions/models/ and issue-lifecycle/extensions/models/ are correctly synchronized. Tests follow the CLAUDE.md conventions (local stubs, env var cleanup in finally blocks).

## Adversarial Review ### Critical / High No critical or high severity findings. ### Medium 1. **Stale verification result allows skipping re-verification** — `extensions/models/issue_lifecycle.ts:1706-1757` and `extensions/models/issue_lifecycle.ts:512-556` The `verify` method only transitions state to "verifying" — it does not clear or invalidate the existing `verificationResult-main` resource. The `verification-clear` check (line 512) only checks `allPassed` and `stepsFailed` without validating that the verification result corresponds to the current commit. **Breaking scenario:** 1. Agent implements, verifies, calls `verification_passed` (writes passing result for commit `abc123`), links PR, PR fails. 2. Agent goes back to `implementing` via `implement`, makes code changes (new commit `def456`). 3. Agent calls `verify` (state → "verifying") but does NOT run `verification_passed` again. 4. Agent calls `link_pr` — the `verification-clear` check passes because the stale `verificationResult-main` from step 1 still has `allPassed: true`. 5. PR opens with unverified code. **Suggested fix:** Either (a) have `verify` clear/invalidate the existing `verificationResult-main` resource, or (b) have `verification-clear` compare the commit in the verification result against the commit in the `verify` call (which would require storing the target commit in state). Option (a) is simpler. 2. **`post_attestation` described as a "hard gate" but has no enforcement check** — `extensions/models/issue_lifecycle.ts:1926-1932` The method description says "The PR must not open without a stored attestation — this is a hard gate." However, there is no corresponding check in the `checks` object that gates `link_pr` on attestation having been posted. The `link_pr` transitions allow `verifying` as a source phase, and there's no `attestation-posted` check in `appliesTo: ["link_pr"]`. An agent can skip `post_attestation` entirely and proceed from `verify` → `verification_passed` → `link_pr` without posting an attestation. **Suggested fix:** Either add an `attestation-posted` check that gates `link_pr`, or soften the description from "hard gate" to "expected step" if enforcement is handled at the skill layer. ### Low 1. **`verification_passed` method name is misleading when recording failures** — `extensions/models/issue_lifecycle.ts:1759-1858` The `verification_passed` method accepts steps with `status: "failed"` and computes `allPassed: failed === 0`. If called with failed steps, `allPassed` will be `false` and the method effectively records a failure. The naming suggests success-only semantics, but the implementation accepts any outcome. This could confuse callers — `verification_failed` exists for the failure path but records no step-level data, so there's an asymmetry in the API. 2. **`complete` bypasses verification entirely** — `extensions/models/issue_lifecycle.ts:93-94` (`TRANSITIONS`) and `extensions/models/issue_lifecycle.ts:512-516` (`verification-clear`) The `verification-clear` check applies only to `["link_pr"]`, but `complete` accepts `implementing` as a source phase (line 94). This means `complete` can close the lifecycle from `implementing` without any verification. This appears intentional for backwards compatibility, but it means the verification gate can be entirely circumvented by calling `complete` instead of going through the `verify` → `link_pr` → `pr_merged` → `ship` path. ### Verdict **PASS** — The code is well-structured with consistent state machine transitions, proper error handling, and thorough test coverage. The two medium findings are design-level gaps in gate enforcement rather than correctness bugs — the stale verification result scenario requires a specific multi-cycle flow, and the attestation gap is mitigated by the skill-layer instructions that guide agent behavior. The files in `extensions/models/` and `issue-lifecycle/extensions/models/` are correctly synchronized. Tests follow the CLAUDE.md conventions (local stubs, env var cleanup in finally blocks).
fix(issue-lifecycle): align manifest version with code version (2026.08.25.1)
Some checks failed
CI: Extensions / cve/mini-shai-hulud - test (pull_request) Has been skipped
CI: Extensions / cve/researcher - check (pull_request) Has been skipped
CI: Extensions / cve/researcher - fmt (pull_request) Has been skipped
CI: Extensions / cve/researcher - lint (pull_request) Has been skipped
CI: Extensions / cve/researcher - test (pull_request) Has been skipped
CI: Extensions / software-factory - check (pull_request) Has been skipped
CI: Extensions / software-factory - fmt (pull_request) Has been skipped
CI: Extensions / software-factory - lint (pull_request) Has been skipped
CI: Extensions / software-factory - test (pull_request) Has been skipped
CI: Extensions / container-image - fmt (pull_request) Has been skipped
CI: Extensions / container-image - lint (pull_request) Has been skipped
CI: Extensions / container-image - test (pull_request) Has been skipped
CI: Extensions / container-image - lockfile up to date (pull_request) Has been skipped
CI: Extensions / git - check (pull_request) Has been skipped
CI: Extensions / git - fmt (pull_request) Has been skipped
CI: Extensions / git - lint (pull_request) Has been skipped
CI: Extensions / git - test (pull_request) Has been skipped
CI: Reviews / CI Security Review (pull_request) Has been skipped
CI / Dependency Audit (pull_request) Has started running
CI / Actions Audit (pull_request) Successful in 31s
CI: Extensions / issue-lifecycle - check (pull_request) Successful in 29s
CI: Extensions / issue-lifecycle - fmt (pull_request) Has started running
CI: Extensions / issue-lifecycle - lint (pull_request) Has been cancelled
CI: Extensions / issue-lifecycle - test (pull_request) Has been cancelled
CI: Extensions / issue-lifecycle - lockfile up to date (pull_request) Has been cancelled
CI: Extensions / Gate: Extensions (pull_request) Has been cancelled
CI: Reviews / Claude Code Review (pull_request) Has been cancelled
CI: Reviews / Adversarial Code Review (pull_request) Has been cancelled
CI: Reviews / Gate: Reviews (pull_request) Has been cancelled
CI / Gate: Audit (pull_request) Has been cancelled
50f12d9013
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fix(issue-lifecycle): bump code version to 2026.08.28.1 to match manifest
Some checks failed
CI: Extensions / cve/researcher - fmt (pull_request) Has been skipped
CI: Extensions / cve/researcher - lint (pull_request) Has been skipped
CI: Extensions / cve/researcher - test (pull_request) Has been skipped
CI: Extensions / cve/dirtyfrag - lockfile up to date (pull_request) Has been skipped
CI: Extensions / software-factory - check (pull_request) Has been skipped
CI: Extensions / software-factory - fmt (pull_request) Has been skipped
CI: Extensions / software-factory - lint (pull_request) Has been skipped
CI: Extensions / software-factory - test (pull_request) Has been skipped
CI: Extensions / container-image - fmt (pull_request) Has been skipped
CI: Extensions / container-image - lint (pull_request) Has been skipped
CI: Extensions / container-image - test (pull_request) Has been skipped
CI: Extensions / container-image - lockfile up to date (pull_request) Has been skipped
CI: Extensions / git - check (pull_request) Has been skipped
CI: Extensions / git - fmt (pull_request) Has been skipped
CI: Extensions / git - lint (pull_request) Has been skipped
CI: Extensions / git - test (pull_request) Has been skipped
CI: Reviews / Detect Changes (pull_request) Successful in 19s
CI: Reviews / CI Security Review (pull_request) Has been skipped
CI / Actions Audit (pull_request) Successful in 24s
CI: Extensions / issue-lifecycle - lockfile up to date (pull_request) Successful in 25s
CI: Extensions / issue-lifecycle - check (pull_request) Successful in 24s
CI: Extensions / issue-lifecycle - fmt (pull_request) Failing after 30s
CI: Extensions / issue-lifecycle - lint (pull_request) Successful in 28s
CI: Extensions / issue-lifecycle - test (pull_request) Successful in 28s
CI: Extensions / Gate: Extensions (pull_request) Failing after 0s
CI / Dependency Audit (pull_request) Successful in 2m43s
CI / Gate: Audit (pull_request) Successful in 1s
CI: Reviews / Claude Code Review (pull_request) Successful in 3m40s
CI: Reviews / Adversarial Code Review (pull_request) Successful in 5m17s
CI: Reviews / Gate: Reviews (pull_request) Successful in 0s
93c5edb7f9
Restores manifest to 2026.08.28.1, bumps code version and adds upgrade
entry in both root and package copies, updates test assertions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author
Owner

Code Review

Blocking Issues

None.

Suggestions

  1. extensions/models/README.md state machine and methods table are substantially outdated. The state machine shows only 7 phases and documents complete as implementing → done, but the implementation transitions to notify. The actual model has 13 phases (verifying, pr_open, pr_failed, releasing, notify, summarizing are all missing from the diagram). The methods table lists 10 methods but the implementation exposes ~21. The README is a changed file in this PR and documents a published extension model — users reading it will get a misleading picture of how the lifecycle works.

  2. No behavioral tests for the new verification methods (verify, verification_passed, verification_failed, post_attestation) or the verification-clear policy check. These methods implement the pre-PR verification gate introduced in 2026.08.21.1 and the post_attestation flow from 2026.08.25.1. Existing coverage is limited to smoke tests that assert method/resource registration ("model: exposes the new post_attestation method definition"). The verification-clear check — which gates link_pr on allPassed — has no tests at all. The other policy checks (pr-cooldown, code-conformance-clear, adversarial-review-clear) all have behavioral tests, so the omission here stands out. Consider adding at minimum: verification_passed writing the correct resource, verification_failed transitioning back to implementing, and verification-clear passing/failing based on the stored result.

  3. Minor: complete bypasses the verification gate. verification-clear applies only to link_pr, not complete. Calling complete from implementing skips the verification loop. This appears intentional (documented as a "quick close-out" path), but the README does not mention this asymmetry, and link_pr's gating comment in the implementation doesn't cross-reference it. Worth a brief note in the README's method table or in the check's description to make the intentional bypass explicit.

## Code Review ### Blocking Issues None. ### Suggestions 1. **`extensions/models/README.md` state machine and methods table are substantially outdated.** The state machine shows only 7 phases and documents `complete` as `implementing → done`, but the implementation transitions to `notify`. The actual model has 13 phases (`verifying`, `pr_open`, `pr_failed`, `releasing`, `notify`, `summarizing` are all missing from the diagram). The methods table lists 10 methods but the implementation exposes ~21. The README is a changed file in this PR and documents a published extension model — users reading it will get a misleading picture of how the lifecycle works. 2. **No behavioral tests for the new verification methods** (`verify`, `verification_passed`, `verification_failed`, `post_attestation`) or the `verification-clear` policy check. These methods implement the pre-PR verification gate introduced in `2026.08.21.1` and the `post_attestation` flow from `2026.08.25.1`. Existing coverage is limited to smoke tests that assert method/resource registration (`"model: exposes the new post_attestation method definition"`). The `verification-clear` check — which gates `link_pr` on `allPassed` — has no tests at all. The other policy checks (`pr-cooldown`, `code-conformance-clear`, `adversarial-review-clear`) all have behavioral tests, so the omission here stands out. Consider adding at minimum: `verification_passed` writing the correct resource, `verification_failed` transitioning back to `implementing`, and `verification-clear` passing/failing based on the stored result. 3. **Minor: `complete` bypasses the verification gate.** `verification-clear` applies only to `link_pr`, not `complete`. Calling `complete` from `implementing` skips the verification loop. This appears intentional (documented as a "quick close-out" path), but the README does not mention this asymmetry, and `link_pr`'s gating comment in the implementation doesn't cross-reference it. Worth a brief note in the README's method table or in the check's `description` to make the intentional bypass explicit.
Author
Owner

Adversarial Review

Medium

  1. Vacuous pass when all verification steps are skippedextensions/models/issue_lifecycle.ts:1824

    verification_passed computes allPassed: failed === 0. If every step in the steps array has status: "skipped" (and none are "succeeded" or "failed"), then failed === 0 is true and allPassed is recorded as true. The verification-clear check (line 552) only inspects result.allPassed and result.stepsFailed — it does not verify that at least one step actually succeeded.

    Breaking example: A misconfigured verification workflow that skips all steps (e.g., empty step list or all guards evaluate to skip) would produce allPassed: true, stepsCompleted: 0, stepsTotal: N, stepsFailed: 0 and silently pass the verification-clear gate, allowing link_pr to proceed without any real verification.

    Suggested fix: Add a guard in verification_passed or in the verification-clear check. In the check, after the allPassed check, add: if result.stepsCompleted === 0, return pass false with error "No verification steps succeeded — all were skipped." Or in verification_passed, compute allPassed as failed === 0 && succeeded > 0.

  2. verification-clear does not gate completeextensions/models/issue_lifecycle.ts:519

    The verification-clear check has appliesTo: ["link_pr"], but complete (line 2303) transitions from implementing to notify without requiring verification. The code-conformance-clear check applies to both link_pr and complete, but verification is only enforced on link_pr. This means calling complete from implementing bypasses the entire verification workflow.

    This is documented as intentional ("quick close-out" path in SKILL.md), and makes sense when a PR has already been merged through CI. Flagged here for awareness — if the intent is that ALL paths through implementing require verification, add "complete" to verification-clear.appliesTo.

Low

  1. No execution tests for verification methodsextensions/models/issue_lifecycle_test.ts

    The verify, verification_passed, verification_failed, and post_attestation methods have smoke tests confirming they exist in model.methods, but no execution tests exercising their logic (state transitions, resource writes, error paths). The verification-clear check also lacks tests. Compare this with link_pr, pr_merged, pr_failed, code_conformance_review, justify_deviations, and the code-conformance-clear check, which all have thorough execution tests. The SwampClubClient.postAttestation method does have client-level tests in swamp_club_test.ts, but the lifecycle model method wrappers do not.

  2. verification_passed method name is semantically misleadingextensions/models/issue_lifecycle.ts:1766

    The method accepts a steps array where entries can have status: "failed", and records allPassed: false in that case. Despite the name verification_passed, it functions as a general "record verification results" method. The actual pass/fail gate is in the verification-clear check, not the method. The companion verification_failed method (which transitions back to implementing without recording results) creates an asymmetry: one records results regardless of outcome, the other does not record results at all. This works correctly but could confuse future maintainers.

Verdict

PASS — The state machine is well-designed, checks are properly gating the critical paths, error handling follows consistent patterns, and the code/test structure is clean. The vacuous-pass edge case (Medium #1) is unlikely in practice since the verification workflow is agent-driven, but is worth hardening. No critical or high findings.

## Adversarial Review ### Medium 1. **Vacuous pass when all verification steps are skipped** — `extensions/models/issue_lifecycle.ts:1824` `verification_passed` computes `allPassed: failed === 0`. If every step in the `steps` array has `status: "skipped"` (and none are `"succeeded"` or `"failed"`), then `failed === 0` is true and `allPassed` is recorded as `true`. The `verification-clear` check (line 552) only inspects `result.allPassed` and `result.stepsFailed` — it does not verify that at least one step actually succeeded. **Breaking example:** A misconfigured verification workflow that skips all steps (e.g., empty step list or all guards evaluate to skip) would produce `allPassed: true, stepsCompleted: 0, stepsTotal: N, stepsFailed: 0` and silently pass the `verification-clear` gate, allowing `link_pr` to proceed without any real verification. **Suggested fix:** Add a guard in `verification_passed` or in the `verification-clear` check. In the check, after the allPassed check, add: if `result.stepsCompleted === 0`, return pass false with error "No verification steps succeeded — all were skipped." Or in `verification_passed`, compute `allPassed` as `failed === 0 && succeeded > 0`. 2. **`verification-clear` does not gate `complete`** — `extensions/models/issue_lifecycle.ts:519` The `verification-clear` check has `appliesTo: ["link_pr"]`, but `complete` (line 2303) transitions from `implementing` to `notify` without requiring verification. The `code-conformance-clear` check applies to both `link_pr` and `complete`, but verification is only enforced on `link_pr`. This means calling `complete` from `implementing` bypasses the entire verification workflow. This is documented as intentional ("quick close-out" path in SKILL.md), and makes sense when a PR has already been merged through CI. Flagged here for awareness — if the intent is that ALL paths through `implementing` require verification, add `"complete"` to `verification-clear.appliesTo`. ### Low 1. **No execution tests for verification methods** — `extensions/models/issue_lifecycle_test.ts` The `verify`, `verification_passed`, `verification_failed`, and `post_attestation` methods have smoke tests confirming they exist in `model.methods`, but no execution tests exercising their logic (state transitions, resource writes, error paths). The `verification-clear` check also lacks tests. Compare this with `link_pr`, `pr_merged`, `pr_failed`, `code_conformance_review`, `justify_deviations`, and the `code-conformance-clear` check, which all have thorough execution tests. The `SwampClubClient.postAttestation` method does have client-level tests in `swamp_club_test.ts`, but the lifecycle model method wrappers do not. 2. **`verification_passed` method name is semantically misleading** — `extensions/models/issue_lifecycle.ts:1766` The method accepts a `steps` array where entries can have `status: "failed"`, and records `allPassed: false` in that case. Despite the name `verification_passed`, it functions as a general "record verification results" method. The actual pass/fail gate is in the `verification-clear` check, not the method. The companion `verification_failed` method (which transitions back to `implementing` without recording results) creates an asymmetry: one records results regardless of outcome, the other does not record results at all. This works correctly but could confuse future maintainers. ### Verdict **PASS** — The state machine is well-designed, checks are properly gating the critical paths, error handling follows consistent patterns, and the code/test structure is clean. The vacuous-pass edge case (Medium #1) is unlikely in practice since the verification workflow is agent-driven, but is worth hardening. No critical or high findings.
chore: fix deno fmt on upgrade entry description
Some checks failed
CI: Extensions / cve/mini-shai-hulud - lint (pull_request) Has been skipped
CI: Extensions / cve/mini-shai-hulud - test (pull_request) Has been skipped
CI: Extensions / cve/researcher - check (pull_request) Has been skipped
CI: Extensions / cve/researcher - fmt (pull_request) Has been skipped
CI: Extensions / cve/researcher - lint (pull_request) Has been skipped
CI: Extensions / cve/researcher - test (pull_request) Has been skipped
CI: Extensions / software-factory - lint (pull_request) Has been skipped
CI: Extensions / software-factory - test (pull_request) Has been skipped
CI: Extensions / software-factory - lockfile up to date (pull_request) Has been skipped
CI: Extensions / container-image - check (pull_request) Has been skipped
CI: Extensions / container-image - fmt (pull_request) Has been skipped
CI: Extensions / container-image - lint (pull_request) Has been skipped
CI: Extensions / container-image - test (pull_request) Has been skipped
CI: Extensions / container-image - lockfile up to date (pull_request) Has been skipped
CI: Extensions / git - check (pull_request) Has been skipped
CI: Extensions / git - fmt (pull_request) Has been skipped
CI: Extensions / git - lint (pull_request) Has been skipped
CI: Extensions / git - test (pull_request) Has been skipped
CI / Actions Audit (pull_request) Successful in 35s
CI / Dependency Audit (pull_request) Successful in 2m48s
CI: Reviews / Claude Code Review (pull_request) Successful in 4m13s
CI: Extensions / issue-lifecycle - check (pull_request) Successful in 29s
CI: Extensions / issue-lifecycle - fmt (pull_request) Successful in 23s
CI: Reviews / Adversarial Code Review (pull_request) Failing after 3m47s
CI: Extensions / issue-lifecycle - lint (pull_request) Successful in 24s
CI: Extensions / issue-lifecycle - test (pull_request) Successful in 30s
CI / Gate: Audit (pull_request) Successful in 0s
CI: Extensions / issue-lifecycle - lockfile up to date (pull_request) Successful in 29s
CI: Reviews / Gate: Reviews (pull_request) Failing after 0s
CI: Extensions / Gate: Extensions (pull_request) Successful in 0s
2dbad2e5be
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author
Owner

Code Review

Blocking Issues

None.

Suggestions

  1. README.md state machine and methods table are significantly outdated (extensions/models/README.md)

    The state machine diagram shows implementing ──[complete]──> done, but complete actually transitions to notify. The methods table lists only 10 methods and is missing all of: verify, verification_passed, verification_failed, post_attestation, link_pr, pr_merged, pr_failed, ship, notify, skip_notify, and summarize. The "Data stored" section also omits the verificationResult, pullRequest, and summary resources. This README is the primary user-facing documentation for manual CLI use and will actively mislead anyone following it.

  2. link_pr method description is wrong in both copies (extensions/models/issue_lifecycle.ts:2001, issue-lifecycle/extensions/models/issue_lifecycle.ts:2001)

    The description says "Transitions the phase to pr_open from implementing or pr_failed" but implementing has not been a valid source phase for link_pr since the verifying phase was introduced. The actual source phases are verifying, pr_open, and pr_failed (as confirmed by TRANSITIONS.link_pr).

  3. No execution-level tests for post_attestation (extensions/models/issue_lifecycle_test.ts, issue-lifecycle/extensions/models/issue_lifecycle_test.ts)

    The test suite includes only a smoke test ("model: exposes the new post_attestation method definition"). The method description calls it a "hard gate" — the PR cannot open without a posted attestation. Recommended tests: invalid JSON input (throw new Error("attestation input is not valid JSON")), swamp-club unreachable path (should throw), and the success path verifying the lifecycle entry is posted with the correct attestation payload. The underlying SwampClubClient.postAttestation is tested in swamp_club_test.ts, but the model method wrapper's JSON parsing and lifecycle-entry posting are not covered.

## Code Review ### Blocking Issues None. ### Suggestions 1. **README.md state machine and methods table are significantly outdated** (`extensions/models/README.md`) The state machine diagram shows `implementing ──[complete]──> done`, but `complete` actually transitions to `notify`. The methods table lists only 10 methods and is missing all of: `verify`, `verification_passed`, `verification_failed`, `post_attestation`, `link_pr`, `pr_merged`, `pr_failed`, `ship`, `notify`, `skip_notify`, and `summarize`. The "Data stored" section also omits the `verificationResult`, `pullRequest`, and `summary` resources. This README is the primary user-facing documentation for manual CLI use and will actively mislead anyone following it. 2. **`link_pr` method description is wrong in both copies** (`extensions/models/issue_lifecycle.ts:2001`, `issue-lifecycle/extensions/models/issue_lifecycle.ts:2001`) The description says "Transitions the phase to pr_open from implementing or pr_failed" but `implementing` has not been a valid source phase for `link_pr` since the `verifying` phase was introduced. The actual source phases are `verifying`, `pr_open`, and `pr_failed` (as confirmed by `TRANSITIONS.link_pr`). 3. **No execution-level tests for `post_attestation`** (`extensions/models/issue_lifecycle_test.ts`, `issue-lifecycle/extensions/models/issue_lifecycle_test.ts`) The test suite includes only a smoke test (`"model: exposes the new post_attestation method definition"`). The method description calls it a "hard gate" — the PR cannot open without a posted attestation. Recommended tests: invalid JSON input (`throw new Error("attestation input is not valid JSON")`), swamp-club unreachable path (should throw), and the success path verifying the lifecycle entry is posted with the correct attestation payload. The underlying `SwampClubClient.postAttestation` is tested in `swamp_club_test.ts`, but the model method wrapper's JSON parsing and lifecycle-entry posting are not covered.
Author
Owner

Adversarial Review

Critical / High

  1. Stale verification result bypasses verification-clear gate after re-verify
    issue-lifecycle/extensions/models/issue_lifecycle.tsverify method (line ~1734) and verification-clear check (line ~518)

    The verify method was simplified to only write state. The previous version (visible in the diff as removed code in the issue-lifecycle/ copy) explicitly invalidated verificationResult-main by writing allPassed: false and stepsCompleted: 0 when starting a new verification run. That invalidation was removed.

    Breaking scenario:

    1. Agent calls verify → state = verifying
    2. Agent calls verification_passed with all steps succeeded → verificationResult-main has allPassed: true
    3. Agent discovers a problem, calls verification_failed → state = implementing
    4. Agent makes code changes, calls verify again → state = verifying
    5. Agent skips verification_passed and calls link_pr directly
    6. verification-clear reads the stale verificationResult-main from step 2, sees allPassed: true, and passes

    The PR opens with unverified code. The commit SHA in the stale verification result doesn't match the current commit, but verification-clear doesn't check the commit — it only checks allPassed.

    Suggested fix: Either (a) restore the invalidation logic in verify that writes verificationResult-main with allPassed: false before starting a new run, or (b) have verification-clear compare the commit SHA in the verification result against the current HEAD to detect staleness.

  2. verification_passed accepts empty steps array, setting allPassed: true with zero actual checks
    extensions/models/issue_lifecycle.ts:1823allPassed: failed === 0

    If verification_passed is called with steps: [], then failed === 0 evaluates to true, so allPassed: true, stepsCompleted: 0, stepsTotal: 0. The verification-clear check at line 551 only reads allPassed, not stepsTotal. An agent could satisfy the verification gate by submitting an empty verification result.

    Similarly, if all steps have status: "skipped", failed === 0 is still true and allPassed is true with stepsCompleted: 0.

    Suggested fix: Add a guard: allPassed: failed === 0 && succeeded > 0 (at minimum one step must actually succeed). Or have verification-clear reject results where stepsCompleted === 0.

Medium

  1. link_pr description is inconsistent with its TRANSITIONS entry
    extensions/models/issue_lifecycle.ts:2000 — Description says "Transitions the phase to pr_open from implementing or pr_failed" but TRANSITIONS.link_pr is ["verifying", "pr_open", "pr_failed"]. The description should say "from verifying or pr_failed" since link_pr no longer accepts implementing.

  2. Test coverage regression in issue-lifecycle/ copy
    issue-lifecycle/extensions/models/issue_lifecycle_test.ts — The PR removes tests for: verify (state transition + invalidation), verification_passed (aggregated counts, allPassed=false when failed), verification_failed (state rollback), post_attestation (invalid JSON, success flow, resource writing), verification-clear (pass/fail/missing), and attestation-clear (pass/missing/invalidated). These are replaced only by triage regression tests and summarize tests. The extensions/models/ copy gains the same new tests but never had the removed tests — so the net effect is both copies now have identical but reduced test coverage for the verification workflow.

  3. Removed attestation-clear check without alternative local gate
    issue-lifecycle/extensions/models/issue_lifecycle.ts — The attestation-clear check (which verified a local attestation resource existed before link_pr) and the attestation resource itself were removed. The attestation is now only stored server-side via post_attestation. If the post_attestation call succeeds but the agent doesn't proceed to link_pr in the same session, a future session has no local record that an attestation was posted and must rely entirely on the server-side CI check (validate-attestation). This is a weaker local guarantee — the gate now depends on an external system rather than local state.

Low

  1. postAttestation response type assertion without runtime validation
    extensions/models/_lib/swamp_club.ts:213return await res.json() as { id: string; postedBy: string; postedAt: string } — If the server returns a valid JSON object that doesn't have these fields, the caller gets undefined values without any error. The post_attestation method logs result.id and result.postedBy and includes result.id in the lifecycle payload as attestationId. Unlikely to cause issues in practice but violates the implied contract.

Verdict

FAIL — The stale verification result bypass (finding #1) allows link_pr to pass the verification-clear gate with data from a previous verification run after code has changed. This defeats the purpose of the verification gate. The removed invalidation logic in verify was specifically guarding against this scenario.

## Adversarial Review ### Critical / High 1. **Stale verification result bypasses `verification-clear` gate after re-verify** `issue-lifecycle/extensions/models/issue_lifecycle.ts` — `verify` method (line ~1734) and `verification-clear` check (line ~518) The `verify` method was simplified to only write state. The previous version (visible in the diff as removed code in the `issue-lifecycle/` copy) explicitly invalidated `verificationResult-main` by writing `allPassed: false` and `stepsCompleted: 0` when starting a new verification run. That invalidation was removed. **Breaking scenario:** 1. Agent calls `verify` → state = `verifying` 2. Agent calls `verification_passed` with all steps succeeded → `verificationResult-main` has `allPassed: true` 3. Agent discovers a problem, calls `verification_failed` → state = `implementing` 4. Agent makes code changes, calls `verify` again → state = `verifying` 5. Agent skips `verification_passed` and calls `link_pr` directly 6. `verification-clear` reads the **stale** `verificationResult-main` from step 2, sees `allPassed: true`, and passes The PR opens with unverified code. The commit SHA in the stale verification result doesn't match the current commit, but `verification-clear` doesn't check the commit — it only checks `allPassed`. **Suggested fix:** Either (a) restore the invalidation logic in `verify` that writes `verificationResult-main` with `allPassed: false` before starting a new run, or (b) have `verification-clear` compare the commit SHA in the verification result against the current HEAD to detect staleness. 2. **`verification_passed` accepts empty steps array, setting `allPassed: true` with zero actual checks** `extensions/models/issue_lifecycle.ts:1823` — `allPassed: failed === 0` If `verification_passed` is called with `steps: []`, then `failed === 0` evaluates to `true`, so `allPassed: true`, `stepsCompleted: 0`, `stepsTotal: 0`. The `verification-clear` check at line 551 only reads `allPassed`, not `stepsTotal`. An agent could satisfy the verification gate by submitting an empty verification result. Similarly, if all steps have `status: "skipped"`, `failed === 0` is still true and `allPassed` is true with `stepsCompleted: 0`. **Suggested fix:** Add a guard: `allPassed: failed === 0 && succeeded > 0` (at minimum one step must actually succeed). Or have `verification-clear` reject results where `stepsCompleted === 0`. ### Medium 1. **`link_pr` description is inconsistent with its TRANSITIONS entry** `extensions/models/issue_lifecycle.ts:2000` — Description says "Transitions the phase to pr_open from implementing or pr_failed" but `TRANSITIONS.link_pr` is `["verifying", "pr_open", "pr_failed"]`. The description should say "from verifying or pr_failed" since `link_pr` no longer accepts `implementing`. 2. **Test coverage regression in `issue-lifecycle/` copy** `issue-lifecycle/extensions/models/issue_lifecycle_test.ts` — The PR removes tests for: `verify` (state transition + invalidation), `verification_passed` (aggregated counts, allPassed=false when failed), `verification_failed` (state rollback), `post_attestation` (invalid JSON, success flow, resource writing), `verification-clear` (pass/fail/missing), and `attestation-clear` (pass/missing/invalidated). These are replaced only by triage regression tests and summarize tests. The `extensions/models/` copy gains the same new tests but never had the removed tests — so the net effect is both copies now have identical but reduced test coverage for the verification workflow. 3. **Removed `attestation-clear` check without alternative local gate** `issue-lifecycle/extensions/models/issue_lifecycle.ts` — The `attestation-clear` check (which verified a local attestation resource existed before `link_pr`) and the `attestation` resource itself were removed. The attestation is now only stored server-side via `post_attestation`. If the `post_attestation` call succeeds but the agent doesn't proceed to `link_pr` in the same session, a future session has no local record that an attestation was posted and must rely entirely on the server-side CI check (`validate-attestation`). This is a weaker local guarantee — the gate now depends on an external system rather than local state. ### Low 1. **`postAttestation` response type assertion without runtime validation** `extensions/models/_lib/swamp_club.ts:213` — `return await res.json() as { id: string; postedBy: string; postedAt: string }` — If the server returns a valid JSON object that doesn't have these fields, the caller gets `undefined` values without any error. The `post_attestation` method logs `result.id` and `result.postedBy` and includes `result.id` in the lifecycle payload as `attestationId`. Unlikely to cause issues in practice but violates the implied contract. ### Verdict **FAIL** — The stale verification result bypass (finding #1) allows `link_pr` to pass the `verification-clear` gate with data from a previous verification run after code has changed. This defeats the purpose of the verification gate. The removed invalidation logic in `verify` was specifically guarding against this scenario.
fix(issue-lifecycle): close verification gate bypass bugs
Some checks failed
CI: Extensions / cve/researcher - check (pull_request) Has been skipped
CI: Extensions / cve/researcher - fmt (pull_request) Has been skipped
CI: Extensions / cve/researcher - lint (pull_request) Has been skipped
CI: Extensions / cve/researcher - test (pull_request) Has been skipped
CI: Extensions / software-factory - check (pull_request) Has been skipped
CI: Extensions / software-factory - fmt (pull_request) Has been skipped
CI: Extensions / software-factory - lint (pull_request) Has been skipped
CI: Extensions / software-factory - test (pull_request) Has been skipped
CI: Extensions / container-image - check (pull_request) Has been skipped
CI: Extensions / container-image - fmt (pull_request) Has been skipped
CI: Extensions / container-image - lint (pull_request) Has been skipped
CI: Extensions / container-image - test (pull_request) Has been skipped
CI: Extensions / git - check (pull_request) Has been skipped
CI: Extensions / git - fmt (pull_request) Has been skipped
CI: Extensions / git - lint (pull_request) Has been skipped
CI: Extensions / git - test (pull_request) Has been skipped
CI: Reviews / Detect Changes (pull_request) Successful in 21s
CI: Reviews / CI Security Review (pull_request) Has been skipped
CI / Actions Audit (pull_request) Successful in 24s
CI: Extensions / issue-lifecycle - check (pull_request) Successful in 31s
CI: Extensions / issue-lifecycle - fmt (pull_request) Successful in 25s
CI / Dependency Audit (pull_request) Successful in 2m40s
CI: Extensions / issue-lifecycle - lint (pull_request) Successful in 25s
CI: Extensions / issue-lifecycle - test (pull_request) Successful in 27s
CI: Extensions / issue-lifecycle - lockfile up to date (pull_request) Successful in 25s
CI: Reviews / Claude Code Review (pull_request) Failing after 4m38s
CI / Gate: Audit (pull_request) Successful in 0s
CI: Extensions / Gate: Extensions (pull_request) Successful in 0s
CI: Reviews / Adversarial Code Review (pull_request) Successful in 6m31s
CI: Reviews / Gate: Reviews (pull_request) Failing after 0s
c93e904902
Two bugs fixed:

1. verify() now invalidates verificationResult-main when starting a new
   run, preventing a stale allPassed:true from a previous cycle from
   satisfying the verification-clear gate after re-verify.

2. verification-clear now rejects results with stepsCompleted === 0,
   closing the empty-steps and all-skipped bypasses where failed === 0
   would set allPassed:true with no actual succeeded checks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author
Owner

Code Review

Blocking Issues

  1. Missing execution-level tests for verify, verification_passed, verification_failed, post_attestation, and the verification-clear check (extensions/models/issue_lifecycle_test.ts and issue-lifecycle/extensions/models/issue_lifecycle_test.ts)

    The PR's test files cover code_conformance_review, justify_deviations, code-conformance-clear, triage regression verification, and summarize — but the verification workflow methods and their gate check have no execution-level tests:

    • verify() — no test that it transitions to verifying or writes a sentinel verificationResult
    • verification_passed() — no test that it writes the checklist and stays in verifying
    • verification_failed() — no test that it transitions back to implementing
    • post_attestation() — no test of the execute function (only a smoke test that the method exists in the registry)
    • verification-clear check — no test that it blocks when verification hasn't run, when allPassed is false, or when stepsCompleted is 0

    The swamp_club_test.ts files do test the underlying postAttestation HTTP call, but the higher-level method's full execution path (including what happens when swamp-club is unreachable, the JSON parse gate, and the lifecycle entry) is untested.

    These methods gate the transition to link_pr — correctness of the gate is high-risk and should be verified.

Suggestions

  1. verify() writes a sentinel verificationResult that violates its own schema (extensions/models/issue_lifecycle.ts:1754–1768, same in issue-lifecycle/ copy)

    VerificationResultSchema declares workflowRunId: z.string() as required, but the sentinel written at the start of verify() omits it:

    await context.writeResource("verificationResult", "verificationResult-main", {
      allPassed: false,
      stepsCompleted: 0,
      stepsTotal: 0,
      stepsSkipped: 0,
      stepsFailed: 0,
      steps: [],
      commit: args.commit,
      branch: args.branch,
      verifiedAt: now,
      // workflowRunId is missing
    });
    

    If the framework validates resource writes against the declared schema, this will throw. If not, it creates schema-nonconformant data. A simple fix is to use a placeholder (e.g., workflowRunId: "") or make workflowRunId optional in the schema.

  2. link_pr method description is stale (extensions/models/issue_lifecycle.ts:2032–2034, same in issue-lifecycle/ copy)

    The description says "Transitions the phase to pr_open from implementing or pr_failed" but link_pr now accepts verifying, pr_open, and pr_failed as source phases (not implementing).

  3. post_attestation description overstates its enforcement (extensions/models/issue_lifecycle.ts:1966–1970, same in issue-lifecycle/ copy)

    The description says "The PR must not open without a stored attestation — this is a hard gate." However, there is no check in checks that validates attestation was posted before link_pr. The verification-clear check gates on verificationResult-main, not on an attestation endpoint record. An agent can skip post_attestation and call link_pr directly; the gate will still pass if verification_passed() wrote allPassed: true. The description should clarify that enforcement is by convention only.

  4. verification-clear error message is misleading immediately after verify() (extensions/models/issue_lifecycle.ts:555–561, same in issue-lifecycle/ copy)

    When verify() is called it writes allPassed: false, stepsFailed: 0. If link_pr is then attempted, the error reads: "Verification failed (0 step(s) failed). Fix the issues and re-verify." Zero failed steps looks like no verification ran, which is accurate, but the phrasing implies something failed. A message like "Verification is in progress — call verification_passed or verification_failed to record the result" would be clearer.

  5. README state machine diagram and method/resource tables are significantly outdated (extensions/models/README.md)

    The state machine diagram (line 20–27) still shows the old 7-phase flow ending at implementing → complete → done. It's missing verifying, pr_open, pr_failed, releasing, notify, and summarizing. The methods table (lines 131–142) and data table (lines 149–156) likewise omit the many methods and resources added since 2026.04.08.2. Since README.md is in the changed files, updating it to match the current model would prevent future confusion.

## Code Review ### Blocking Issues 1. **Missing execution-level tests for `verify`, `verification_passed`, `verification_failed`, `post_attestation`, and the `verification-clear` check** (`extensions/models/issue_lifecycle_test.ts` and `issue-lifecycle/extensions/models/issue_lifecycle_test.ts`) The PR's test files cover `code_conformance_review`, `justify_deviations`, `code-conformance-clear`, `triage` regression verification, and `summarize` — but the verification workflow methods and their gate check have no execution-level tests: - `verify()` — no test that it transitions to `verifying` or writes a sentinel `verificationResult` - `verification_passed()` — no test that it writes the checklist and stays in `verifying` - `verification_failed()` — no test that it transitions back to `implementing` - `post_attestation()` — no test of the execute function (only a smoke test that the method exists in the registry) - `verification-clear` check — no test that it blocks when verification hasn't run, when `allPassed` is false, or when `stepsCompleted` is 0 The `swamp_club_test.ts` files do test the underlying `postAttestation` HTTP call, but the higher-level method's full execution path (including what happens when `swamp-club` is unreachable, the JSON parse gate, and the lifecycle entry) is untested. These methods gate the transition to `link_pr` — correctness of the gate is high-risk and should be verified. ### Suggestions 1. **`verify()` writes a sentinel `verificationResult` that violates its own schema** (`extensions/models/issue_lifecycle.ts:1754–1768`, same in `issue-lifecycle/` copy) `VerificationResultSchema` declares `workflowRunId: z.string()` as required, but the sentinel written at the start of `verify()` omits it: ```typescript await context.writeResource("verificationResult", "verificationResult-main", { allPassed: false, stepsCompleted: 0, stepsTotal: 0, stepsSkipped: 0, stepsFailed: 0, steps: [], commit: args.commit, branch: args.branch, verifiedAt: now, // workflowRunId is missing }); ``` If the framework validates resource writes against the declared schema, this will throw. If not, it creates schema-nonconformant data. A simple fix is to use a placeholder (e.g., `workflowRunId: ""`) or make `workflowRunId` optional in the schema. 2. **`link_pr` method description is stale** (`extensions/models/issue_lifecycle.ts:2032–2034`, same in `issue-lifecycle/` copy) The description says "Transitions the phase to pr_open from implementing or pr_failed" but `link_pr` now accepts `verifying`, `pr_open`, and `pr_failed` as source phases (not `implementing`). 3. **`post_attestation` description overstates its enforcement** (`extensions/models/issue_lifecycle.ts:1966–1970`, same in `issue-lifecycle/` copy) The description says "The PR must not open without a stored attestation — this is a hard gate." However, there is no check in `checks` that validates attestation was posted before `link_pr`. The `verification-clear` check gates on `verificationResult-main`, not on an attestation endpoint record. An agent can skip `post_attestation` and call `link_pr` directly; the gate will still pass if `verification_passed()` wrote `allPassed: true`. The description should clarify that enforcement is by convention only. 4. **`verification-clear` error message is misleading immediately after `verify()`** (`extensions/models/issue_lifecycle.ts:555–561`, same in `issue-lifecycle/` copy) When `verify()` is called it writes `allPassed: false, stepsFailed: 0`. If `link_pr` is then attempted, the error reads: "Verification failed (0 step(s) failed). Fix the issues and re-verify." Zero failed steps looks like no verification ran, which is accurate, but the phrasing implies something failed. A message like "Verification is in progress — call `verification_passed` or `verification_failed` to record the result" would be clearer. 5. **README state machine diagram and method/resource tables are significantly outdated** (`extensions/models/README.md`) The state machine diagram (line 20–27) still shows the old 7-phase flow ending at `implementing → complete → done`. It's missing `verifying`, `pr_open`, `pr_failed`, `releasing`, `notify`, and `summarizing`. The methods table (lines 131–142) and data table (lines 149–156) likewise omit the many methods and resources added since 2026.04.08.2. Since README.md is in the changed files, updating it to match the current model would prevent future confusion.
Author
Owner

Adversarial Review

Critical / High

No critical or high severity findings.

Medium

  1. link_pr description incorrectly says "implementing" instead of "verifying"

    • File: extensions/models/issue_lifecycle.ts:2033 (and identical copy at issue-lifecycle/extensions/models/issue_lifecycle.ts:2033)
    • The description string says "Transitions the phase to pr_open from implementing or pr_failed." but the TRANSITIONS map at schemas.ts:90 defines link_pr: ["verifying", "pr_open", "pr_failed"] — the allowed source phase is verifying, not implementing.
    • How it breaks: An agent reading the method description will attempt to call link_pr from the implementing phase, which will be rejected by the transition pre-flight check. The agent then has to discover the correct flow (verify first) by trial and error.
    • Fix: Change the description to "Transitions the phase to pr_open from verifying or pr_failed.".
  2. verify method writes verificationResult resource missing the required workflowRunId field

    • File: extensions/models/issue_lifecycle.ts:1754-1768 (and identical copy at issue-lifecycle/extensions/models/issue_lifecycle.ts)
    • The VerificationResultSchema at schemas.ts:270 declares workflowRunId: z.string() as required. The invalidation write in verify omits this field entirely. If the framework validates resource writes against the schema, this call throws and the verify method fails — leaving the stale (possibly passing) verification result in place and the phase unchanged.
    • How it breaks: Call verification_passed for commit A. Make more changes (commit B). Call verify for commit B — the invalidation write fails due to missing workflowRunId, the old passing result for commit A survives, and link_pr can proceed against the wrong commit.
    • Fix: Add workflowRunId: "" to the invalidation write (as it was in the prior version of the issue-lifecycle copy).
  3. Significant test coverage removed from issue-lifecycle copy

    • File: issue-lifecycle/extensions/models/issue_lifecycle_test.ts
    • The PR removes execution-level tests for verify, verification_passed, verification_failed, post_attestation, verification-clear check, attestation-clear check, and attestation resource — roughly 250 lines of test code covering actual method execution, error paths, and gate enforcement. Replaced with only method-existence smoke tests (e.g. "verify" in model.methods). The extensions/models/issue_lifecycle_test.ts copy also lacks these tests.
    • How it breaks: Regressions in verification gate logic, step counting, or attestation posting won't be caught by the test suite.
    • Note: This is not blocking since the code logic itself is correct, but the test gap is notable.

Low

  1. verification_passed method accepts steps with status: "failed" without rejection

    • File: extensions/models/issue_lifecycle.ts:1798-1897
    • The method name implies verification passed, but it records whatever steps are provided — including failed ones. If called with failed steps, it writes allPassed: false and posts a lifecycle entry saying "verification_passed". The verification-clear gate catches this downstream and blocks link_pr, so there's no functional bypass, but the method name and lifecycle entry are misleading. This is by design (the gate is the enforcement point), but worth noting.
  2. start (resume) no longer accepts verifying or summarizing phases

    • File: extensions/models/_lib/schemas.ts:65-76
    • If a lifecycle gets stuck in verifying, calling start to resume will fail. The agent must instead call verification_failed (to return to implementing) or verification_passed. Similarly for summarizing, the agent must call summarize directly. There are paths out of both phases, so this isn't a dead-end — just a constraint that differs from the prior behavior where start accepted every phase except done.

Verdict

PASS — The core logic is correct: new verification phase, transition gates, attestation posting, and regression triage changes are all sound. The link_pr description mismatch and the missing workflowRunId in the invalidation write are real issues but neither is critical — the description is informational and the workflowRunId issue depends on whether the framework validates writes. The removed test coverage is regrettable but not blocking. No security vulnerabilities, no data corruption paths, no resource leaks.

## Adversarial Review ### Critical / High No critical or high severity findings. ### Medium 1. **`link_pr` description incorrectly says "implementing" instead of "verifying"** - File: `extensions/models/issue_lifecycle.ts:2033` (and identical copy at `issue-lifecycle/extensions/models/issue_lifecycle.ts:2033`) - The description string says `"Transitions the phase to pr_open from implementing or pr_failed."` but the `TRANSITIONS` map at `schemas.ts:90` defines `link_pr: ["verifying", "pr_open", "pr_failed"]` — the allowed source phase is `verifying`, not `implementing`. - **How it breaks**: An agent reading the method description will attempt to call `link_pr` from the `implementing` phase, which will be rejected by the transition pre-flight check. The agent then has to discover the correct flow (verify first) by trial and error. - **Fix**: Change the description to `"Transitions the phase to pr_open from verifying or pr_failed."`. 2. **`verify` method writes `verificationResult` resource missing the required `workflowRunId` field** - File: `extensions/models/issue_lifecycle.ts:1754-1768` (and identical copy at `issue-lifecycle/extensions/models/issue_lifecycle.ts`) - The `VerificationResultSchema` at `schemas.ts:270` declares `workflowRunId: z.string()` as required. The invalidation write in `verify` omits this field entirely. If the framework validates resource writes against the schema, this call throws and the `verify` method fails — leaving the stale (possibly passing) verification result in place and the phase unchanged. - **How it breaks**: Call `verification_passed` for commit A. Make more changes (commit B). Call `verify` for commit B — the invalidation write fails due to missing `workflowRunId`, the old passing result for commit A survives, and `link_pr` can proceed against the wrong commit. - **Fix**: Add `workflowRunId: ""` to the invalidation write (as it was in the prior version of the issue-lifecycle copy). 3. **Significant test coverage removed from issue-lifecycle copy** - File: `issue-lifecycle/extensions/models/issue_lifecycle_test.ts` - The PR removes execution-level tests for `verify`, `verification_passed`, `verification_failed`, `post_attestation`, `verification-clear` check, `attestation-clear` check, and `attestation` resource — roughly 250 lines of test code covering actual method execution, error paths, and gate enforcement. Replaced with only method-existence smoke tests (e.g. `"verify" in model.methods`). The `extensions/models/issue_lifecycle_test.ts` copy also lacks these tests. - **How it breaks**: Regressions in verification gate logic, step counting, or attestation posting won't be caught by the test suite. - **Note**: This is not blocking since the code logic itself is correct, but the test gap is notable. ### Low 1. **`verification_passed` method accepts steps with `status: "failed"` without rejection** - File: `extensions/models/issue_lifecycle.ts:1798-1897` - The method name implies verification passed, but it records whatever steps are provided — including failed ones. If called with failed steps, it writes `allPassed: false` and posts a lifecycle entry saying "verification_passed". The `verification-clear` gate catches this downstream and blocks `link_pr`, so there's no functional bypass, but the method name and lifecycle entry are misleading. This is by design (the gate is the enforcement point), but worth noting. 2. **`start` (resume) no longer accepts `verifying` or `summarizing` phases** - File: `extensions/models/_lib/schemas.ts:65-76` - If a lifecycle gets stuck in `verifying`, calling `start` to resume will fail. The agent must instead call `verification_failed` (to return to `implementing`) or `verification_passed`. Similarly for `summarizing`, the agent must call `summarize` directly. There are paths out of both phases, so this isn't a dead-end — just a constraint that differs from the prior behavior where `start` accepted every phase except `done`. ### Verdict **PASS** — The core logic is correct: new verification phase, transition gates, attestation posting, and regression triage changes are all sound. The `link_pr` description mismatch and the missing `workflowRunId` in the invalidation write are real issues but neither is critical — the description is informational and the `workflowRunId` issue depends on whether the framework validates writes. The removed test coverage is regrettable but not blocking. No security vulnerabilities, no data corruption paths, no resource leaks.
test(issue-lifecycle): add execution-level tests for verification workflow
Some checks failed
CI: Extensions / cve/researcher - fmt (pull_request) Has been skipped
CI: Extensions / cve/researcher - lint (pull_request) Has been skipped
CI: Extensions / cve/researcher - test (pull_request) Has been skipped
CI: Extensions / cve/dirtyfrag - lockfile up to date (pull_request) Has been skipped
CI: Extensions / software-factory - fmt (pull_request) Has been skipped
CI: Extensions / software-factory - lint (pull_request) Has been skipped
CI: Extensions / software-factory - test (pull_request) Has been skipped
CI: Extensions / software-factory - lockfile up to date (pull_request) Has been skipped
CI: Extensions / container-image - check (pull_request) Has been skipped
CI: Extensions / container-image - fmt (pull_request) Has been skipped
CI: Extensions / container-image - lint (pull_request) Has been skipped
CI: Extensions / container-image - test (pull_request) Has been skipped
CI: Extensions / git - fmt (pull_request) Has been skipped
CI: Extensions / git - lint (pull_request) Has been skipped
CI: Extensions / git - test (pull_request) Has been skipped
CI: Extensions / git - lockfile up to date (pull_request) Has been skipped
CI: Reviews / Detect Changes (pull_request) Successful in 17s
CI: Reviews / CI Security Review (pull_request) Has been skipped
CI / Actions Audit (pull_request) Successful in 34s
CI: Extensions / issue-lifecycle - check (pull_request) Successful in 37s
CI: Extensions / issue-lifecycle - fmt (pull_request) Failing after 25s
CI: Extensions / issue-lifecycle - lint (pull_request) Successful in 28s
CI: Extensions / issue-lifecycle - test (pull_request) Successful in 28s
CI: Extensions / issue-lifecycle - lockfile up to date (pull_request) Successful in 27s
CI: Extensions / Gate: Extensions (pull_request) Failing after 1s
CI / Dependency Audit (pull_request) Successful in 2m40s
CI / Gate: Audit (pull_request) Successful in 0s
CI: Reviews / Adversarial Code Review (pull_request) Successful in 4m14s
CI: Reviews / Claude Code Review (pull_request) Failing after 13m18s
CI: Reviews / Gate: Reviews (pull_request) Has been cancelled
54e5cb543e
Adds 11 new tests covering:
- verify: transitions to verifying, invalidates stale verificationResult
- verification_passed: writes checklist with allPassed, records failures
- verification_failed: transitions back to implementing
- post_attestation: throws when swamp-club unreachable, rejects empty input
- verification-clear check: blocks with no result, with failures, with
  zero completed steps (empty-steps bypass), passes on valid result

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author
Owner

Adversarial Review

Medium

  1. Missing required workflowRunId in verify method's invalidation write
    extensions/models/issue_lifecycle.ts:1754-1767 (and identical copy at issue-lifecycle/extensions/models/issue_lifecycle.ts)

    The verify method writes an invalidation record to verificationResult-main to prevent stale passes from satisfying the verification-clear gate. However, the write omits the workflowRunId field, which is declared as required (z.string(), not optional) in VerificationResultSchema at extensions/models/_lib/schemas.ts:270.

    Breaking scenario: If the swamp framework validates writeResource calls against the resource's declared Zod schema at write time, calling verify will throw a Zod validation error and crash. The verify method would never complete, leaving the lifecycle stuck in its previous phase.

    If the framework does NOT validate at write time, the stored data silently violates its own schema. Any downstream consumer that reads and validates this resource with VerificationResultSchema.parse() will crash.

    Current impact is mitigated because the verification-clear check at line 515-575 reads the resource with JSON.parse + as cast (no Zod validation) and only inspects allPassed, stepsFailed, and stepsCompleted — so the gate still works. But the schema contract is broken.

    Suggested fix: Add workflowRunId: "" (empty string sentinel) to the invalidation write at line 1757, matching the pattern used by verification_passed which correctly includes the field.

Low

  1. verification_passed name is misleading — it also records failures
    extensions/models/issue_lifecycle.ts:1798-1897

    The method is named verification_passed and its description says "Record that verification passed", but it accepts steps with "failed" status and correctly computes allPassed: false. The test at line 1730 explicitly validates this scenario ("records failure when a step fails"). This is functionally correct — the verification-clear gate properly blocks on allPassed: false — but the method name could mislead callers into thinking it's only valid to call when all steps actually passed.

    No code change needed — this is a naming observation, not a bug. The method works correctly in all cases.

  2. Summary truncation can split multi-byte characters
    extensions/models/_lib/swamp_club.ts:158-160

    The truncation logic summary.slice(0, LIFECYCLE_SUMMARY_MAX_CHARS - 3) + "..." operates on UTF-16 code units. If a multi-byte character (emoji, CJK, etc.) straddles position 1997, slice could split a surrogate pair, producing a malformed string sent to the API. In practice this is extremely unlikely given the 2000-char limit and typical summary content.

  3. postAttestation return type is trust-cast, not validated
    extensions/models/_lib/swamp_club.ts:207

    The response is cast with as { id: string; postedBy: string; postedAt: string } without runtime validation. If the server returns a different shape, the calling code would silently use undefined values. Low concern since the server is controlled infrastructure.

Verdict

PASS — The PR is well-structured with good test coverage for the new verification workflow, proper gate checks, and consistent sync between the two directory copies. The workflowRunId omission (Medium #1) is a real schema violation but is currently mitigated by the check's use of raw JSON parsing rather than Zod validation. It should be fixed but does not block merge.

## Adversarial Review ### Medium 1. **Missing required `workflowRunId` in `verify` method's invalidation write** `extensions/models/issue_lifecycle.ts:1754-1767` (and identical copy at `issue-lifecycle/extensions/models/issue_lifecycle.ts`) The `verify` method writes an invalidation record to `verificationResult-main` to prevent stale passes from satisfying the `verification-clear` gate. However, the write omits the `workflowRunId` field, which is declared as **required** (`z.string()`, not optional) in `VerificationResultSchema` at `extensions/models/_lib/schemas.ts:270`. **Breaking scenario**: If the swamp framework validates `writeResource` calls against the resource's declared Zod schema at write time, calling `verify` will throw a Zod validation error and crash. The `verify` method would never complete, leaving the lifecycle stuck in its previous phase. If the framework does NOT validate at write time, the stored data silently violates its own schema. Any downstream consumer that reads and validates this resource with `VerificationResultSchema.parse()` will crash. **Current impact is mitigated** because the `verification-clear` check at line 515-575 reads the resource with `JSON.parse` + `as` cast (no Zod validation) and only inspects `allPassed`, `stepsFailed`, and `stepsCompleted` — so the gate still works. But the schema contract is broken. **Suggested fix**: Add `workflowRunId: ""` (empty string sentinel) to the invalidation write at line 1757, matching the pattern used by `verification_passed` which correctly includes the field. ### Low 1. **`verification_passed` name is misleading — it also records failures** `extensions/models/issue_lifecycle.ts:1798-1897` The method is named `verification_passed` and its description says "Record that verification passed", but it accepts steps with `"failed"` status and correctly computes `allPassed: false`. The test at line 1730 explicitly validates this scenario ("records failure when a step fails"). This is functionally correct — the `verification-clear` gate properly blocks on `allPassed: false` — but the method name could mislead callers into thinking it's only valid to call when all steps actually passed. No code change needed — this is a naming observation, not a bug. The method works correctly in all cases. 2. **Summary truncation can split multi-byte characters** `extensions/models/_lib/swamp_club.ts:158-160` The truncation logic `summary.slice(0, LIFECYCLE_SUMMARY_MAX_CHARS - 3) + "..."` operates on UTF-16 code units. If a multi-byte character (emoji, CJK, etc.) straddles position 1997, `slice` could split a surrogate pair, producing a malformed string sent to the API. In practice this is extremely unlikely given the 2000-char limit and typical summary content. 3. **`postAttestation` return type is trust-cast, not validated** `extensions/models/_lib/swamp_club.ts:207` The response is cast with `as { id: string; postedBy: string; postedAt: string }` without runtime validation. If the server returns a different shape, the calling code would silently use `undefined` values. Low concern since the server is controlled infrastructure. ### Verdict **PASS** — The PR is well-structured with good test coverage for the new verification workflow, proper gate checks, and consistent sync between the two directory copies. The `workflowRunId` omission (Medium #1) is a real schema violation but is currently mitigated by the check's use of raw JSON parsing rather than Zod validation. It should be fixed but does not block merge.
fix(issue-lifecycle): add missing workflowRunId to verify invalidation, fix fmt
All checks were successful
CI: Extensions / cve/mini-shai-hulud - test (pull_request) Has been skipped
CI: Extensions / cve/researcher - check (pull_request) Has been skipped
CI: Extensions / cve/researcher - fmt (pull_request) Has been skipped
CI: Extensions / cve/researcher - lint (pull_request) Has been skipped
CI: Extensions / cve/researcher - test (pull_request) Has been skipped
CI: Extensions / software-factory - check (pull_request) Has been skipped
CI: Extensions / software-factory - fmt (pull_request) Has been skipped
CI: Extensions / software-factory - lint (pull_request) Has been skipped
CI: Extensions / software-factory - test (pull_request) Has been skipped
CI: Extensions / container-image - check (pull_request) Has been skipped
CI: Extensions / container-image - fmt (pull_request) Has been skipped
CI: Extensions / container-image - lint (pull_request) Has been skipped
CI: Extensions / container-image - test (pull_request) Has been skipped
CI: Extensions / git - lint (pull_request) Has been skipped
CI: Extensions / git - test (pull_request) Has been skipped
CI: Extensions / git - lockfile up to date (pull_request) Has been skipped
CI: Reviews / Detect Changes (pull_request) Successful in 18s
CI: Reviews / CI Security Review (pull_request) Has been skipped
CI / Actions Audit (pull_request) Successful in 27s
CI: Extensions / issue-lifecycle - lockfile up to date (pull_request) Successful in 26s
CI: Extensions / issue-lifecycle - check (pull_request) Successful in 27s
CI / Dependency Audit (pull_request) Successful in 3m7s
CI: Extensions / issue-lifecycle - fmt (pull_request) Successful in 30s
CI: Extensions / issue-lifecycle - lint (pull_request) Successful in 26s
CI: Extensions / issue-lifecycle - test (pull_request) Successful in 30s
CI: Reviews / Adversarial Code Review (pull_request) Successful in 4m9s
CI / Gate: Audit (pull_request) Successful in 1s
CI: Extensions / Gate: Extensions (pull_request) Successful in 1s
CI: Reviews / Claude Code Review (pull_request) Successful in 5m7s
CI: Reviews / Gate: Reviews (pull_request) Successful in 0s
516514dddb
The verify() sentinel write was missing the required workflowRunId field
from VerificationResultSchema. Also fixes deno fmt on the test file.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author
Owner

Adversarial Review

Critical / High

No critical or high severity findings.

Medium

  1. post_attestation payload accesses are unchecked casts (extensions/models/issue_lifecycle.ts:2020-2021, same in issue-lifecycle/ copy)

    The lifecycle entry payload blindly casts parsed.subject and parsed.gate to Record. If a caller passes an attestation where subject or gate are primitives (number, string, boolean), the cast silently succeeds and optional chaining yields undefined. The attestation itself was already POSTed successfully so no correctness impact on the gate, but the lifecycle entry payload would be misleading (missing commit/gatePassed fields).

    Breaking example: Attestation JSON with subject set to a number produces lifecycle payload with commit: undefined, gatePassed: undefined.

    Suggested fix: Validate that parsed.subject and parsed.gate are objects before accessing nested fields, or accept the current behavior since the payload is best-effort observability data.

  2. verification-clear check does not bind verification result to a specific commit (extensions/models/issue_lifecycle.ts:518-575, same in issue-lifecycle/ copy)

    The check only verifies allPassed === true and stepsCompleted > 0. It does not compare the verification result commit field against any current state. The state machine partially mitigates this: verify invalidates stale results and can only be called from implementing. But if the agent makes code changes while in verifying phase (e.g. force-pushes a new commit) without going through verification_failed then implementing then verify, the gate would pass on stale data.

    Breaking example: Agent calls verify + verification_passed on commit A, then force-pushes commit B (with a bug), then calls link_pr. The check passes despite commit B never being verified.

    Suggested fix: Store the verified commit in the state and compare it in verification-clear, or accept this as a workflow discipline issue.

Low

  1. review method uses unnecessary non-null assertion (issue_lifecycle.ts:1041 in both copies)

    context.readResource! uses non-null assertion but readResource is not optional in the method context type. Harmless but could mask a type error if the context type changes.

  2. Test fetch stub route matching uses url.includes() which could match unintended routes (issue_lifecycle_test.ts in both copies)

    A route with urlIncludes /api/v1/lab/issues/99 also matches /api/v1/lab/issues/99/lifecycle. Current ordering works because routes are distinguished by method or more-specific path segments, but this is fragile if new routes are added.

  3. README state machine diagram is stale (extensions/models/README.md)

    Shows a simplified state machine ending at implementing to done, missing verifying, pr_open, pr_failed, releasing, notify, and summarizing phases. Methods table is also incomplete. This staleness likely predates this PR.

Verdict

PASS -- The sync is clean: extensions/models/ and issue-lifecycle/extensions/models/ contain identical source and test code. The verification workflow logic is well-tested with proper state machine gates. The two medium findings are observability and workflow-discipline concerns, not correctness bugs. No critical or high issues found.

## Adversarial Review ### Critical / High No critical or high severity findings. ### Medium 1. **post_attestation payload accesses are unchecked casts** (extensions/models/issue_lifecycle.ts:2020-2021, same in issue-lifecycle/ copy) The lifecycle entry payload blindly casts parsed.subject and parsed.gate to Record. If a caller passes an attestation where subject or gate are primitives (number, string, boolean), the cast silently succeeds and optional chaining yields undefined. The attestation itself was already POSTed successfully so no correctness impact on the gate, but the lifecycle entry payload would be misleading (missing commit/gatePassed fields). **Breaking example:** Attestation JSON with subject set to a number produces lifecycle payload with commit: undefined, gatePassed: undefined. **Suggested fix:** Validate that parsed.subject and parsed.gate are objects before accessing nested fields, or accept the current behavior since the payload is best-effort observability data. 2. **verification-clear check does not bind verification result to a specific commit** (extensions/models/issue_lifecycle.ts:518-575, same in issue-lifecycle/ copy) The check only verifies allPassed === true and stepsCompleted > 0. It does not compare the verification result commit field against any current state. The state machine partially mitigates this: verify invalidates stale results and can only be called from implementing. But if the agent makes code changes while in verifying phase (e.g. force-pushes a new commit) without going through verification_failed then implementing then verify, the gate would pass on stale data. **Breaking example:** Agent calls verify + verification_passed on commit A, then force-pushes commit B (with a bug), then calls link_pr. The check passes despite commit B never being verified. **Suggested fix:** Store the verified commit in the state and compare it in verification-clear, or accept this as a workflow discipline issue. ### Low 1. **review method uses unnecessary non-null assertion** (issue_lifecycle.ts:1041 in both copies) context.readResource! uses non-null assertion but readResource is not optional in the method context type. Harmless but could mask a type error if the context type changes. 2. **Test fetch stub route matching uses url.includes() which could match unintended routes** (issue_lifecycle_test.ts in both copies) A route with urlIncludes /api/v1/lab/issues/99 also matches /api/v1/lab/issues/99/lifecycle. Current ordering works because routes are distinguished by method or more-specific path segments, but this is fragile if new routes are added. 3. **README state machine diagram is stale** (extensions/models/README.md) Shows a simplified state machine ending at implementing to done, missing verifying, pr_open, pr_failed, releasing, notify, and summarizing phases. Methods table is also incomplete. This staleness likely predates this PR. ### Verdict **PASS** -- The sync is clean: extensions/models/ and issue-lifecycle/extensions/models/ contain identical source and test code. The verification workflow logic is well-tested with proper state machine gates. The two medium findings are observability and workflow-discipline concerns, not correctness bugs. No critical or high issues found.
Author
Owner

Code Review

Blocking Issues

None.

Suggestions

  1. README.md state machine diagram is outdated (extensions/models/README.md lines 18–27). The diagram shows only 7 states (created → triaging → classified → plan_generated → approved → implementing → done) and omits verifying, pr_open, pr_failed, releasing, notify, and summarizing, which are all live phases documented in _lib/schemas.ts. Readers who rely on the README get a misleading picture of the lifecycle.

  2. gh collaborator check may not work if swamp-club/swamp is on Forgejo (both SKILL.md files, Phase 5 / implementation.md step 6). The command gh api /repos/swamp-club/swamp/collaborators targets the GitHub API. CLAUDE.md notes that this repo uses Forgejo and the fgj CLI for PRs. If swamp-club/swamp itself is also hosted on Forgejo, the gh call would silently fail or return a wrong answer, causing all contributors to be treated as external (or missing). Consider either switching to fgj api or checking collaborator status through the swamp-club API.

  3. verify method: invalidation write handle not included in dataHandles (issue_lifecycle.ts lines 1754–1769 / mirrored copy). The await context.writeResource("verificationResult", ...) call that resets allPassed: false is properly awaited (the write does happen), but its returned handle is not placed in dataHandles — only stateHandle is returned. If the framework uses dataHandles for transaction tracking or garbage-collection, the invalidation write is untracked. The test confirms the write occurs (verify: invalidates stale verificationResult-main), so this is low risk in practice, but the inconsistency is worth resolving for uniformity with every other multi-resource method that returns all handles.

## Code Review ### Blocking Issues None. ### Suggestions 1. **README.md state machine diagram is outdated** (`extensions/models/README.md` lines 18–27). The diagram shows only 7 states (`created → triaging → classified → plan_generated → approved → implementing → done`) and omits `verifying`, `pr_open`, `pr_failed`, `releasing`, `notify`, and `summarizing`, which are all live phases documented in `_lib/schemas.ts`. Readers who rely on the README get a misleading picture of the lifecycle. 2. **`gh` collaborator check may not work if `swamp-club/swamp` is on Forgejo** (both `SKILL.md` files, Phase 5 / `implementation.md` step 6). The command `gh api /repos/swamp-club/swamp/collaborators` targets the GitHub API. CLAUDE.md notes that this repo uses Forgejo and the `fgj` CLI for PRs. If `swamp-club/swamp` itself is also hosted on Forgejo, the `gh` call would silently fail or return a wrong answer, causing all contributors to be treated as external (or missing). Consider either switching to `fgj api` or checking collaborator status through the swamp-club API. 3. **`verify` method: invalidation write handle not included in `dataHandles`** (`issue_lifecycle.ts` lines 1754–1769 / mirrored copy). The `await context.writeResource("verificationResult", ...)` call that resets `allPassed: false` is properly awaited (the write does happen), but its returned handle is not placed in `dataHandles` — only `stateHandle` is returned. If the framework uses `dataHandles` for transaction tracking or garbage-collection, the invalidation write is untracked. The test confirms the write occurs (`verify: invalidates stale verificationResult-main`), so this is low risk in practice, but the inconsistency is worth resolving for uniformity with every other multi-resource method that returns all handles.
All checks were successful
CI: Extensions / Detect Changes (pull_request) Successful in 18s
CI: Extensions / agent-runner - lockfile up to date (pull_request) Has been skipped
CI: Extensions / deno-runner - lockfile up to date (pull_request) Has been skipped
CI: Extensions / ssh - lockfile up to date (pull_request) Has been skipped
CI: Extensions / kubernetes - lockfile up to date (pull_request) Has been skipped
CI: Extensions / workflows/gcs-bootstrap - lockfile up to date (pull_request) Has been skipped
CI: Extensions / workflows/s3-bootstrap - lockfile up to date (pull_request) Has been skipped
CI: Extensions / git - fmt (pull_request) Has been skipped
CI: Extensions / cve/dirtyfrag - lockfile up to date (pull_request) Has been skipped
CI: Extensions / cve/mini-shai-hulud - lockfile up to date (pull_request) Has been skipped
CI: Extensions / cve/researcher - lockfile up to date (pull_request) Has been skipped
CI: Extensions / software-factory - lockfile up to date (pull_request) Has been skipped
CI: Extensions / container-image - lockfile up to date (pull_request) Has been skipped
CI: Extensions / git - check (pull_request) Has been skipped
CI: Extensions / agent-runner - check (pull_request) Has been skipped
CI: Extensions / agent-runner - fmt (pull_request) Has been skipped
CI: Extensions / agent-runner - lint (pull_request) Has been skipped
CI: Extensions / agent-runner - test (pull_request) Has been skipped
CI: Extensions / deno-runner - check (pull_request) Has been skipped
CI: Extensions / deno-runner - fmt (pull_request) Has been skipped
CI: Extensions / deno-runner - lint (pull_request) Has been skipped
CI: Extensions / deno-runner - test (pull_request) Has been skipped
CI: Extensions / ssh - check (pull_request) Has been skipped
CI: Extensions / ssh - fmt (pull_request) Has been skipped
CI: Extensions / ssh - lint (pull_request) Has been skipped
CI: Extensions / ssh - test (pull_request) Has been skipped
CI: Extensions / kubernetes - check (pull_request) Has been skipped
CI: Extensions / kubernetes - fmt (pull_request) Has been skipped
CI: Extensions / kubernetes - lint (pull_request) Has been skipped
CI: Extensions / kubernetes - test (pull_request) Has been skipped
CI: Extensions / workflows/gcs-bootstrap - check (pull_request) Has been skipped
CI: Extensions / workflows/s3-bootstrap - check (pull_request) Has been skipped
CI: Extensions / workflows/gcs-bootstrap - fmt (pull_request) Has been skipped
CI: Extensions / workflows/s3-bootstrap - fmt (pull_request) Has been skipped
CI: Extensions / workflows/gcs-bootstrap - lint (pull_request) Has been skipped
CI: Extensions / workflows/s3-bootstrap - lint (pull_request) Has been skipped
CI: Extensions / workflows/gcs-bootstrap - test (pull_request) Has been skipped
CI: Extensions / workflows/s3-bootstrap - test (pull_request) Has been skipped
CI: Extensions / cve/dirtyfrag - check (pull_request) Has been skipped
CI: Extensions / cve/dirtyfrag - fmt (pull_request) Has been skipped
CI: Extensions / cve/dirtyfrag - lint (pull_request) Has been skipped
CI: Extensions / cve/dirtyfrag - test (pull_request) Has been skipped
CI: Extensions / cve/mini-shai-hulud - check (pull_request) Has been skipped
CI: Extensions / cve/mini-shai-hulud - fmt (pull_request) Has been skipped
CI: Extensions / cve/mini-shai-hulud - lint (pull_request) Has been skipped
CI: Extensions / cve/mini-shai-hulud - test (pull_request) Has been skipped
CI: Extensions / cve/researcher - check (pull_request) Has been skipped
CI: Extensions / cve/researcher - fmt (pull_request) Has been skipped
CI: Extensions / cve/researcher - lint (pull_request) Has been skipped
CI: Extensions / cve/researcher - test (pull_request) Has been skipped
CI: Extensions / software-factory - check (pull_request) Has been skipped
CI: Extensions / software-factory - fmt (pull_request) Has been skipped
CI: Extensions / software-factory - lint (pull_request) Has been skipped
CI: Extensions / software-factory - test (pull_request) Has been skipped
CI: Extensions / container-image - check (pull_request) Has been skipped
CI: Extensions / container-image - fmt (pull_request) Has been skipped
CI: Extensions / container-image - lint (pull_request) Has been skipped
CI: Extensions / container-image - test (pull_request) Has been skipped
CI: Extensions / git - lint (pull_request) Has been skipped
CI: Extensions / git - test (pull_request) Has been skipped
CI: Extensions / git - lockfile up to date (pull_request) Has been skipped
CI: Reviews / Detect Changes (pull_request) Successful in 18s
CI: Reviews / CI Security Review (pull_request) Has been skipped
CI / Actions Audit (pull_request) Successful in 27s
CI: Extensions / issue-lifecycle - lockfile up to date (pull_request) Successful in 26s
CI: Extensions / issue-lifecycle - check (pull_request) Successful in 27s
CI / Dependency Audit (pull_request) Successful in 3m7s
CI: Extensions / issue-lifecycle - fmt (pull_request) Successful in 30s
CI: Extensions / issue-lifecycle - lint (pull_request) Successful in 26s
CI: Extensions / issue-lifecycle - test (pull_request) Successful in 30s
CI: Reviews / Adversarial Code Review (pull_request) Successful in 4m9s
CI / Gate: Audit (pull_request) Successful in 1s
CI: Extensions / Gate: Extensions (pull_request) Successful in 1s
CI: Reviews / Claude Code Review (pull_request) Successful in 5m7s
CI: Reviews / Gate: Reviews (pull_request) Successful in 0s
This pull request can be merged automatically.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin worktree-expressive-mapping-sparrow:worktree-expressive-mapping-sparrow
git switch worktree-expressive-mapping-sparrow

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch main
git merge --no-ff worktree-expressive-mapping-sparrow
git switch worktree-expressive-mapping-sparrow
git rebase main
git switch main
git merge --ff-only worktree-expressive-mapping-sparrow
git switch worktree-expressive-mapping-sparrow
git rebase main
git switch main
git merge --no-ff worktree-expressive-mapping-sparrow
git switch main
git merge --squash worktree-expressive-mapping-sparrow
git switch main
git merge --ff-only worktree-expressive-mapping-sparrow
git switch main
git merge worktree-expressive-mapping-sparrow
git push origin main
Sign in to join this conversation.
No reviewers
No labels
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
swamp-club/swamp-extensions!250
No description provided.