False-success is a CLASS: issue-close.sh has #976's exact shape, and its checked path is the fallback not the default #977
Open
opened 2026-07-31 02:31:48 +00:00 by Mos
·
1 comment
No Branch/Tag Specified
main
next
remediation/state
feat/rm-02-gate-registry
fix/rm-01-reproducible-checkout
remediation/mission-setup
fix/hygiene-inert-format-gate
fix/1019-queue-guard-stdin
feat/mos-ste-writing-standard
fix/1007-suite-hermeticity
fix/991-comment-url-scheme-normalise
feat/push-guard-null-case-verification
mos-comms-live
docs/heartbeat-framework-layering-ms-lead
feat/869-c4-version-coupling
feat/869-c2-install-ordering-guard
feat/869-c5-doctor-activation-check
feat/per-agent-gitea-identity
fix/875-belongs-case-insensitive-slug
fix/ci-queue-wait-404-branch-absent
feat/869-c1-activation-probe
feat/869-c3-broker-supervisor
fix/865-tea-cli-comment-invocation
feat/glpi-skills
fix/860-deflake-mutator-lease-gate
fix/850-detect-platform-port-normalization
fix/856-worktree-deps-preflight
fix/835-pr-review-approve-reject-comment-flag
fix/848-truthful-evidence
fix/812-pr-review-comment
fix/849-recovery-runtime-fixture-race
docs/758-ledger-m5-001-sync
feat/834-tc-server-side-doc
feat/833-constrained-recovery-command
feat/827-gate0-probe
governance/gate0-probe3-amendment
fix/795-codex-pr-diff
fix/795-ci-base-jq
fix/795-ci-base-git
feat/791-pr3-fleet-regen
feat/791-pr2-snapshot-restore
fix/807-glpi-206
fix/808-agent-send-false-sender
feat/791-upgrade-config-protection
feat/790-mosaic-yolo-claudex-pr2
feat/790-mosaic-yolo-claudex
feat/758-v1-v2-migrator
fix/766-exact-fleet-comms
test/758-reconciler-lifecycle-gates
docs/771-kbn101-db-role-split
test/758-example-profile-dispositions
feat/758-shared-role-resolution
feat/mos-logical-identity-fencing
feat/769-kbn100-unified-schema
docs/753-kbn010-threat-gate
feat/758-roster-v2-compiler
feat/756-official-discord-plugin
docs/758-fleet-config-management
fix/mos-option2-qualification-format
docs/issue-758-m0
docs/mos-option2-qualification
mos-comms
feat/tess-interaction-agent
fix/tess-docs-format
draft/mosaic-platform-prd
fix/installer-provider-gate-and-local-gateway-redis
release/mosaic-cli-0.0.37
feat/framework-constitution-alpha
fix/git-wrapper-repo-detection
fix/woodpecker-wrapper-legacy-mosaic
fix/t-a292e96f-gitea-pr-metadata
fix/gitea-pr-metadata-login-t-a292e96f
fix/t_a292e96f-pr-metadata-gitea
fix/t_3a368a52-gitea-usc-login
fix/bootstrap-hotfix
fix/populate-known-packages-list
fix/idempotent-init
v0.0.39-alpha
mosaic-v0.0.31
fed-v0.2.0-m2
fed-v0.1.0-m1
mosaic-v0.0.29
mosaic-v0.0.28
mosaic-v0.0.27
mosaic-v0.0.26
mosaic-v0.0.25
mosaic-v0.0.24
v0.2.0
v0.1.0
v0.0.8
v0.0.7
v0.0.6
v0.0.5
v0.0.4
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: mosaicstack/stack#977
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Extends #976 from a single wrapper to a class, and identifies which wrappers are affected. Source-read only — nothing was executed.
Why this matters more than #976 alone
Gate 8 covers wrapper failure (blocked → report → stop). It says nothing about wrapper false success. Gate 5 completion is merged PR + terminal-green CI + issue closed — and two of those three are attested by the wrapper family that has now been confirmed to manufacture a PASS on a write path (#976).
issue-close.sh— identical shape to the confirmed defectThat is #976 line for line, in the wrapper that attests an issue is closed.
The three open causes from #976 all reach it
The one visible difference is the repo argument —
issue-comment.shpasses--repo REPO_SLUG,issue-close.shpasses--repo OWNER/REPO. That is not a discriminator: indetect-platform.sh,get_repo_slugisget_repo_info, andOWNER/REPOis that same value split and rejoined. For a two-segment slug the string handed toteais byte-identical. Same login resolver, sameteabinary, same slug — so login resolution, slug resolution, and tea exiting 0 having done nothing all reach it unchanged.The inversion is the filing-worthy part
issue-close.shhas a sound path — its Gitea API fallback usescurl -fsS, where-fmakes curl exit non-zero on HTTP ≥400 andset -eaborts before the echo. Genuinely fail-closed.But it is the fallback. It is reached only when login resolution fails. The blind
teapath is the default and the checked path is the exception — precisely backwards.pr-merge.sh— materially better, not cleanCorrecting an initial grep screen that flagged both wrappers as the same shape (the screen produced candidates; reading produced the finding):
A login failure or slug failure cannot produce a false success here. Its exposure is exactly one of the three causes —
teaexiting 0 having done nothing — plus a weaker residual: a 2xx is not a readback ofmerged=true.pr-review.sh— the counter-exampleIt already reads back after writing. The fix pattern exists in-tree, which is what makes this a fixable class rather than a design constraint.
Explicit bound
It has not been shown that
teamisbehaves on issue close. Nothing was run. What source establishes is detection capability:issue-close.shcould not detect the failure confirmed onissue-comment.sh, because it tests nothing at all. Whether it would fail is unmeasured — and whatever is learned chasing #976 transfers directly, since the inputs are identical.Required
issue-close.sh: make the checked path the default, or add a readback (does the issue now readstate=closed?) and condition the success line on it.pr-merge.shassertingmerged=true, not merely a 2xx.pr-review.sh's existing pattern across the family.teato exit 0 without effect — each wrapper must fail.Latent, unrelated
Reconstructing
OWNER/REPOby splitting on the first and last slash mangles any slug with more than two segments. Not currently exercised; flagged only.⚠️ AMENDMENT — the headline claim in this issue is WRONG. Retracting it.
Root cause is now established (see #976):
tea issue commentis a phantom subcommand — tea falls through totea issue list, exits 0, no write attempted.RETRACTED: "issue-close.sh is #976 line for line"
It is not, and the difference matters:
tea issue comment …tea issue close …closeis a genuinetea issuesubcommandSo the close itself is NOT defeated by this mechanism. The Gate-5 "issue closed" attestation is not silently failing for the #976 reason. This issue as originally filed implies that it is. That was the strongest claim here and it is the one that is wrong.
(Also checked the
prgroup:merge,reject,approveall exist — no phantom there either.)What stands, unchanged
tea issue closeis still unconditioned, with an unconditionalecho "Closed Gitea issue #N". It cannot detect a real close failure. That was always a detection-capability claim and it stands exactly as written.curl -fsSpath is the fallback, reached only when login resolution fails. The blind path is the default.pr-merge.shis status-checked. Unchanged.🔴 NEW — and worse than what it replaces
issue-close.shaccepts a--commentand passes it to the phantom.So the closing comment is silently discarded while the script reports success.
The closure comment is frequently where the completion evidence lives — the "closed by PR #N, CI green, review CLEAR" rationale. That evidence has been evaporating on every closure that used
--comment, with a success line printed over it. The issue closes; the reason does not.Net change to this filing
One claim retracted, one unchanged, one new defect added, and the root cause moved from three open candidates to one measured fact with a one-line fix.
How the wrong claim happened — the failure mode is reusable
The shape analysis (unconditioned call, unconditional echo) was correct. The question never asked was whether the command exists.
tea issue commentwas treated as given because it is spelled like every other verb in the file, and because a pattern already named was being hunted.What caught it was not care or re-reading — it was a semantic search run for an unrelated reason surfacing another agent's two-week-old capture of the sibling case. Rules do not stop this class; controls do.