Skip to content

[DEBT] Add integration test coverage for wf.py (git/gh I/O shell) #141

Description

@AdrienneBosch

Context

Found during the wf fast-path audit (2026-06-24). The decision logic in
wf_core.py is well covered — 86 offline tests, all green — and they
are deliberately pure (no git, no gh, no I/O). But that means wf.py,
the entire git/gh I/O shell, has no automated coverage
: gh argument
construction, JSON parsing, the status-emission contract
(ok/no-candidates/all-blocked/error/unsupported), the atomic claim
push, board GraphQL mutations, sprint narrowing, and checkout/branch logic.

This glue runs on every real workflow invocation but has no regression
net
— a refactor or a gh output-shape change could silently break a fast
path with no test failing. (Two real shape bugs already left scars in the
code: the closingIssuesReferences flat-list-vs-nodes crash, and the
-F digit-coercion of single-select option ids — see the comments at
wf.py:95 and wf_core.closing_issue_numbers.)

The atomic claim CAS was proven correct against the live remote during
the audit (create → won; different object same ref → non-fast-forward
rejection = lost; ls-remote probe distinguishes lost from error), so this
is about locking that behavior in with a repeatable test, not discovering
whether it works.

Requirements (acceptance criteria)

  • Add an integration test module (sibling to
    tests/test_decision_logic.py) that exercises wf.py's I/O shell without
    hitting GitHub.
  • Atomic claim CAS test using a real local git repo + a local
    bare remote (no network): assert create→won, a second distinct
    object to the same ref is rejected → lost, an absent-ref push failure →
    error, and release_claim removes the ref. This is the highest-value
    case and needs only local git.
  • Status-contract tests: with gh/git stubbed (a fake run() or
    a PATH shim returning recorded fixtures), assert each command emits the
    right status + exit code for: empty pool → no-candidates; all
    claimed/blocked/resolved → all-blocked; board-column/both ready-gate
    unsupported; type-capable + non-story mode → unsupported; missing
    config → error.
  • Shape-regression guards for the two historical bugs:
    closing_issue_numbers on both the flat-list and {nodes:[…]} shapes,
    and _graphql_args keeping a digit-only id as -f (string) while a real
    int goes through -F.
  • Wire the new tests into run-tests.sh / run-tests.ps1 and CI so
    they run alongside the existing suite.
  • All tests pass on macOS/Linux and Windows (the launcher already
    detects the interpreter).

Savings goal

No token saving — reliability ratchet. Goal: the git fast paths and the
status contract cannot silently regress. Success = deliberately breaking
the claim push or a status emission makes a test fail.

Notes

Companion to the all-blocked consumer-side [BUG]. Foundational: the
context-optimization stories (#136 lazy prewarm, #140 wf review-finish) push
more logic into wf — landing this coverage first de-risks all of them.

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions