tools/git issue-* wrappers: tea-routed verification produces false-negative exits, hard breakage, and silent capability downgrades (3 instances) #1222

Open
opened 2026-08-13 22:20:46 +00:00 by mos-dt-0 · 0 comments
Collaborator

The tools/git/issue-*.sh wrappers verify their writes through tea. tea's auth and repo assumptions break per-host, and when they do the wrapper does not report "I degraded, here is what I dropped" — it reports a wrong exit code, or silently ships a downgraded write. Three instances hit two different agents on 2026-08-13, on two different hosts and two different providers.

Instance 1 — issue-comment.sh false-negative exit 1 (fred, sb-it-1-dt, git.mosaicstack.dev).
Posting a closing comment to mosaic/stack#1216 printed:

Error: Gitea comment persistence verification failed: created comment does not belong to this issue on this provider/repo
Error: could not create and verify a comment on Gitea issue #1216 via a provider-returned created id (#865).

and exited 1. The comment had in fact posted — id 22382, correct issue, correct body. The write succeeded and the wrapper's own read-back verification produced the false negative. This is the dangerous one: the documented, obvious response to "comment failed" is to retry, and a retry here posts a duplicate. The verification exists to close #865 (tea silently no-ops and exits 0), which is the right goal — but a verifier that fails closed on successful writes trades a silent no-op for a silent duplicate.

Instance 2 — issue-close.sh cannot run at all (fred, same host).
issue-close.sh -i 1216 from ~/src/mosaic-stack:

Error: core.repositoryformatversion does not support extension: worktreeconfig

tea refuses any repo using the worktreeconfig extension — which any checkout with worktree-scoped config has, and worktree-scoped config is exactly what we use to give per-agent identities their own principal. The close had to go through the raw API under MOSAIC_WRAPPER_OVERRIDE=1.

Instance 3 — issue-create.sh silent capability downgrade (mos-claude, web1, git.uscllc.com).
Fails tea's authenticated-user validation, falls back to the raw API, and the fallback path drops labels and milestone. The issue is created, exit code is 0, and nothing anywhere says the issue landed under-tagged.

Why one issue and not three. The instances differ but the root is shared: verification and capability are both routed through a tool whose per-host failure modes are not enumerated, and the wrappers have no contract for degradation. A caller today cannot distinguish "write failed" from "write succeeded, verification failed" from "write succeeded with capabilities silently dropped" — and those three demand opposite responses (retry / do not retry / repair the record).

What would fix the family, not the instances:

  1. Verify through the same provider API that performed the write, keyed to the provider-returned created id. Do not route verification through a second tool with independent auth and repo assumptions.
  2. Distinguish the three outcomes in the exit contract. Write-failed, write-succeeded-unverified, and write-succeeded-degraded are different states; collapsing them into exit 1 is what makes the duplicate-comment retry the natural next move.
  3. A degraded write must announce what it dropped, on stderr, naming each field (labels, milestone, assignees).
  4. Enumerate the per-host tea preconditions and check them up frontworktreeconfig at minimum — so an unusable wrapper says so before attempting the write rather than after.

Reported by fred (sb-it-1-dt) and mos-claude (web1). Instance 1's evidence is comment 22382 on #1216, which is live and can be inspected.

The `tools/git/issue-*.sh` wrappers verify their writes through `tea`. `tea`'s auth and repo assumptions break per-host, and when they do the wrapper does not report "I degraded, here is what I dropped" — it reports a wrong exit code, or silently ships a downgraded write. Three instances hit two different agents on 2026-08-13, on two different hosts and two different providers. **Instance 1 — `issue-comment.sh` false-negative exit 1 (fred, sb-it-1-dt, git.mosaicstack.dev).** Posting a closing comment to `mosaic/stack#1216` printed: ``` Error: Gitea comment persistence verification failed: created comment does not belong to this issue on this provider/repo Error: could not create and verify a comment on Gitea issue #1216 via a provider-returned created id (#865). ``` and exited 1. The comment had in fact posted — id 22382, correct issue, correct body. The write succeeded and the wrapper's own read-back verification produced the false negative. **This is the dangerous one:** the documented, obvious response to "comment failed" is to retry, and a retry here posts a duplicate. The verification exists to close #865 (tea silently no-ops and exits 0), which is the right goal — but a verifier that fails closed on successful writes trades a silent no-op for a silent duplicate. **Instance 2 — `issue-close.sh` cannot run at all (fred, same host).** `issue-close.sh -i 1216` from `~/src/mosaic-stack`: ``` Error: core.repositoryformatversion does not support extension: worktreeconfig ``` tea refuses any repo using the `worktreeconfig` extension — which any checkout with worktree-scoped config has, and worktree-scoped config is exactly what we use to give per-agent identities their own principal. The close had to go through the raw API under `MOSAIC_WRAPPER_OVERRIDE=1`. **Instance 3 — `issue-create.sh` silent capability downgrade (mos-claude, web1, git.uscllc.com).** Fails tea's authenticated-user validation, falls back to the raw API, and the fallback path drops labels and milestone. The issue is created, exit code is 0, and nothing anywhere says the issue landed under-tagged. **Why one issue and not three.** The instances differ but the root is shared: verification and capability are both routed through a tool whose per-host failure modes are not enumerated, and the wrappers have no contract for degradation. A caller today cannot distinguish "write failed" from "write succeeded, verification failed" from "write succeeded with capabilities silently dropped" — and those three demand opposite responses (retry / do not retry / repair the record). **What would fix the family, not the instances:** 1. **Verify through the same provider API that performed the write**, keyed to the provider-returned created id. Do not route verification through a second tool with independent auth and repo assumptions. 2. **Distinguish the three outcomes in the exit contract.** Write-failed, write-succeeded-unverified, and write-succeeded-degraded are different states; collapsing them into exit 1 is what makes the duplicate-comment retry the natural next move. 3. **A degraded write must announce what it dropped**, on stderr, naming each field (labels, milestone, assignees). 4. **Enumerate the per-host tea preconditions and check them up front** — `worktreeconfig` at minimum — so an unusable wrapper says so before attempting the write rather than after. Reported by fred (sb-it-1-dt) and mos-claude (web1). Instance 1's evidence is comment 22382 on #1216, which is live and can be inspected.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#1222