fix(work-items): local-markdown claim lease/assignee integrity (#367)#680
Conversation
Two related lease/assignee-integrity gaps in the local-markdown adapter's claim.sh (relocated from medley by #224): Finding 1 (P1): an expired lease left assignees populated, and since reclaim is unsupported offline and list-frontier excludes assigned items, an abandoned claim never returned to the frontier. list-items now projects an expired-lease item's effective assignee as empty so the core frontier returns it to selection, without a new adapter capability; get-item still reports the stored assignee (parity with the GitHub adapter). Finding 2 (P2): claim set assignees after appending the lease marker with no return-code check, so a failed assignee write still emitted a success JSON with a live marker and empty assignees. The two writes are now one consistent operation (wit_claim_write): a failed assignee write rolls the just-appended marker back and fails the claim (exit 1), emitting no success record. Adds claim-integrity.test.sh covering both behaviors; extends CONTRACT.md's local-markdown degradation note; bumps work-items 0.14.1 -> 0.14.2. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 2m 46s —— View job PR Review — fix(work-items): local-markdown claim lease/assignee integrity
SummarySolid fix for two real integrity gaps in the local-markdown adapter. The architecture choices (projection-not-mutation for Finding 1, rollback-on-failure for Finding 2) are the right calls for an offline adapter. All nine test cases are well-targeted and the contract docs are updated in sync. One misleading error message worth fixing, one subtle silent-failure path worth noting. Findings1.
|
The exec-bit hygiene lane requires a shebang file to be tracked 100755; the Windows working tree committed it 100644. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 2m 59s —— View job PR Review — fix(work-items): local-markdown claim lease/assignee integrity
The synchronize commit ( Finding 1 — Misleading error message asserts rollback success unconditionally — MINORprintf 'claim: recording the assignee for %s failed; rolled back the lease marker\n' "$id" >&2
if tmp="$(mktemp)" && grep -vxF -- "$marker_line" "$file" >"$tmp"; then
mv "$tmp" "$file" 2>/dev/null || rm -f "$tmp"
fi
# no else — silent skip if mktemp failsSuggested fix — drop the "rolled back" claim from the caller and add an explicit warning inside
printf 'claim: recording the assignee for %s failed\n' "$id" >&2
if tmp="$(mktemp)" && grep -vxF -- "$marker_line" "$file" >"$tmp"; then
mv "$tmp" "$file" 2>/dev/null || rm -f "$tmp"
else
printf 'wit_claim_write: warning: rollback of lease marker failed — store may be inconsistent\n' >&2
fiFinding 2 — Rollback removes all exact-match lines — INFORMATIONALgrep -vxF -- "$marker_line" "$file" >"$tmp"
What's correct
Overall this is ready to merge. Finding 1 (the error message) is a low-severity nit — it doesn't affect correctness, only log accuracy in the double-failure scenario (store full AND mktemp fails). The architecture and test coverage are sound. |
Address PR review: claim.sh's failure message asserted "rolled back the lease marker" unconditionally, but wit_claim_write's rollback is best-effort and can fail under the same store condition that failed the assignee write. The message no longer claims a rollback that may not have happened; wit_claim_write now warns when the rollback itself cannot run rather than leaving the marker silently orphaned, and documents the unique-marker invariant its grep -vxF relies on. Adds a test case covering the rollback-blocked warning path. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 2m 22s —— View job PR Review — fix(work-items): local-markdown claim lease/assignee integrity
The synchronize commit ( Finding 1 — Fixed correctly
# Before
printf 'claim: recording the assignee for %s failed; rolled back the lease marker\n' "$id" >&2
# After
printf 'claim: recording the assignee for %s failed\n' "$id" >&2
if tmp="$(mktemp)" && grep -vxF -- "$marker_line" "$file" >"$tmp" && mv "$tmp" "$file" 2>/dev/null; then
return 1
fi
[[ -n "${tmp:-}" ]] && rm -f "$tmp"
printf 'wit_claim_write: rollback of the lease marker failed — the store may hold an orphaned lease marker\n' >&2
return 1All four paths are handled correctly:
Finding 2 — Addressed with a commentThe comment on the unique-marker invariant is now inline in
This is exactly what was asked for. No action needed. New test case (rollback-blocked path)
The test correctly:
What's unchanged and still correctAll findings from the previous two review cycles are confirmed resolved or acknowledged:
This PR is ready to merge. Both findings have been correctly addressed, the new test case is well-constructed, and the logic handles all failure modes explicitly. |
|
Claude finished @kyle-sexton's task in 2m 44s —— View job PR Review — fix(work-items): local-markdown claim lease/assignee integrity
SummaryThis is the third review cycle on this PR. The two previously identified findings were addressed in commit Prior Findings — ResolvedFinding 1 — Misleading error message ( printf 'claim: recording the assignee for %s failed\n' "$id" >&2Finding 2 — Silent rollback failure (
Finding 3 — Remaining Observation — Informational
Correctness Verification
This PR is ready to merge. All three review cycles produced findings that were correctly addressed, the architecture decisions are sound, and the test coverage is now comprehensive across all failure modes. |
Summary
Follow-up from #224. Closes two related lease/assignee-integrity gaps in the
local-markdownadapter'sclaim.sh(relocated byte-for-byte from medley by #224, not changed there), handled as the single hardening pass the issue calls for. No new adapter capability is introduced — this implements the issue's recommended, less-invasive candidate for Finding 1 (list-derivation projection), so it is a patch bump (0.14.1→0.14.2).Fix
Finding 1 (P1) — expired lease never cleared the assignee, so abandoned claims never returned to the frontier. An expired lease still left
assigneespopulated. Becausereclaimis unsupported for this offline adapter (it has no coordination surface to run an activity check over) and the corelist-frontierderivation always excludes assigned items, any abandoned local claim was permanently absent from selection once its TTL expired.list-itemsnow projects an expired-lease item's effective assignee as empty (wit_emit_local_itemgained an opt-inunassign-expiredmode), so the core frontier filter — which keys onassignees— returns the item to selection. No new capability, no stored mutation.get-itemstill reports the stored assignee verbatim, preserving parity with the GitHub adapter (whose assignee persists untilreclaimruns) and keeping the raw claim record inspectable.CONTRACT.md's local-markdown degradation note now documents this offline compensation.Finding 2 (P2) — a failed assignee write still reported a successful claim.
claim.shappended the inline lease marker and then calledwit_fm_set … assigneeswith no return-code check and noset -e, so a failed assignee write (store full/unwritable) was silently ignored and a success JSON was still emitted — leaving a live lease marker with an emptyassignees, whichlist-frontierpresents as available while later claims conflict on the live lease until it expires.wit_claim_write): on a failed assignee write it best-effort rolls the just-appended marker back and fails the claim with exit 1 (internal/unexpected store I/O, distinct from an exit-7 claim race), emitting no success record for a half-applied write.Verification
New
adapters/local-markdown/claim-integrity.test.shcovers both findings — Finding 1 end-to-end through the core CLI (list-frontier), Finding 2 as a deterministic, OS-portable unit test of the rollback (the abstract conformance suite runs against every adapter and cannot hold local-markdown-specific or fault-injection cases). All checks run via the repo harness (plugins/**/*.test.sh).New test (
bash claim-integrity.test.sh), exit 0:Full local-markdown conformance still green, including the offline gh/curl-blocking shim (
run-conformance.sh --binding local-markdown):ShellCheck clean on all changed scripts (
--rcfile .shellcheckrc); everyplugins/work-items/**/*.test.shpasses; changed files carry no trailing whitespace, tabs, or comment issue/TODO markers.Closes #367
Related
🤖 Generated with a Claude Code implementation subagent (issue #367)