T-5IG1-lease-primitives-validate-git-actually-acted
Status: closed/superseded · Impact: medium · Complexity: small
Auto-generated from a /sdlc:task-work post-mortem. Review and
promote to open/ready before picking up.
cas_create already learned a hard lesson: git push --force-with-lease
exits 0 with “Everything up-to-date” when the SHA pushed equals what
the ref already points at, silently masking a CAS loss that the
protocol contract requires us to treat as a failure. The same family
of short-circuits (no-op fast-forwards, already-present objects,
already-deleted refs) almost certainly exists for the other primitives
too. This task audits all five primitives in plugin/lib/lease/primitives.py
to confirm each one validates the post-state, not just the exit code.
Cite T-S0PK-add-lease-protocol-library-and-schemas for the
originating fix.
| Location | Role today |
|---|---|
plugin/lib/lease/primitives.py | cas_create scans stdout/stderr for the “Everything up-to-date” short-circuit and raises CASFailed; the other four primitives (cas_replace, cas_delete, fetch_ref, fetch_namespace) rely on git’s exit code alone. |
plugin/lib/lease/tests/test_primitives.py | Has the cas_create same-SHA regression test; no equivalent test for the other primitives. |
Proposed
Section titled “Proposed”Each primitive validates that the ref’s post-state matches the intended operation, not just that git exited 0. Concretely:
cas_replacere-fetches the ref after push and confirms its SHA equals the new SHA the caller asked us to write.cas_deletere-fetches the namespace and confirms the ref is genuinely absent.fetch_refconfirms the ref exists in the post-fetch local refs (not just that fetch exited 0 with nothing to do).fetch_namespaceconfirms the namespace prefix was queried (no silent empty result when the remote has refs the local pruned away).
Each primitive gets a regression test mirroring the cas_create
same-SHA test, exercising the no-op / short-circuit path against the
local-bare-repo fixture.
Approach
Section titled “Approach”- Read
cas_create’s defensive check as the reference implementation, note the exact short-circuit string git emits. - For each of the other four primitives, identify the analogous short-circuit (git docs + manual experimentation against the bare-repo fixture). Write a failing test first that asserts the primitive raises the appropriate exception on the short-circuit path.
- Update each primitive to post-validate.
- Run the full lease test suite; confirm coverage stays >90%.
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
plugin/lib/lease/primitives.py | modify | Add post-state validation to cas_replace, cas_delete, fetch_ref, fetch_namespace. |
plugin/lib/lease/tests/test_primitives.py | modify | Add short-circuit / no-op regression tests for the four primitives. |
plugin/lib/lease/exceptions.py | modify | Add any new exception types if the post-state failure mode differs from existing CASFailed / RefNotFound (likely not — reuse). |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1: Each of the five primitives in
primitives.pypost-validates the ref state, not just git’s exit code. Code review confirms the validation step on each function. - AC-2:
pytest plugin/lib/lease/tests/test_primitives.pyincludes a regression test for each primitive that exercises the no-op / short-circuit path and asserts the correct exception is raised. - AC-3: Combined line coverage on
primitives.pyremains >90% after the new tests land.
Out of scope
Section titled “Out of scope”- Rewriting the primitives to avoid
git push --force-with-leaseentirely (e.g. using libgit2). The wrapper-validates-post-state approach is sufficient.
Dependencies
Section titled “Dependencies”- T-S0PK-add-lease-protocol-library-and-schemas — must land first (this task edits files that task creates).
Discovery context
Section titled “Discovery context”Spawned by /sdlc:task-work post-mortem of T-S0PK-add-lease-protocol-library-and-schemas on 2026-05-23.
Dedup search (spawn-from-post-mortem)
Section titled “Dedup search (spawn-from-post-mortem)”Bullet: git push —force-with-lease exits 0 on same-SHA no-op. Every primitive’s wrapper needs to validate did git actually do what I asked, or did it short-circuit? CAS-CREATE silently masks a CAS loss. Keywords searched: force-with-lease, short-circuit, cas-create, primitive, same-sha, validate, actually, silently Excluded: 2026-05-23-add-lease-protocol-library-and-schemas Top candidates (score / status / headline):
- 6 / closed/done / 2026-05-19-templates-html-comment-after-frontmatter — Move template HTML comment block after frontmatter
- 6 / closed/done / 2026-05-20-task-spec-flags-schema-rejecting-placeholders — /sdlc:task-define surfaces schema-rejecting placeholders at authoring time
- 5 / closed/done / 2026-05-20-task-close-out-verifies-pr-on-main — task-close-out verifies merged PR’s mergeCommit is reachable from origin/main
- 5 / planning/backlog / 2026-05-21-task-ensure-ready-verifies-named-consuming-skills — task-ensure-ready verifies named consuming-skills lists match codebase
- 4 / closed/done / 2026-05-19-extract-start-task-script — Extract task-work Step 5b into scripts/start_task.py Decision: SPAWNED