- Option-like value = any token starting with '-' followed by an
alphanumeric (-h, -ab, --help); multi-character short clusters were
still accepted (codex blocker). Bare '-' is reserved (future stdin).
- usage_error now prints the usage text to stderr as well (codex
should-fix): usage output belonged to stdout only on the help path.
- 16/16 usage-contract suites green.
- Value guards now reject option-like values: --anything always, and
single-dash flag shapes (-h, -i). Previously -b --help consumed
--help as the body and performed the write (codex example:
issue-close -i --help proceeding to 'Closed GitHub issue #--help').
Multi-char dash-leading text (-start of a list) stays a legal value.
- Every remaining direct provider exec (gh/tea/CMD arrays across
issue-create/edit/assign/list/view, milestone-*, pr-create/edit,
pr-close, issue-close/reopen) wrapped with rc capture and normalized
to exit 1 with a stderr message — provider exit 2 no longer collides
with the reserved usage-error status.
- All 16 usage-contract suites gained option-like and short-flag arms
(16/16 green). Existing suites re-verified; test-pr-edit and
test-issue-create-interactive-auth fail identically with these
changes stashed (environment-coupled, not regressions; documented).
Upstream of brain commits 08a00149 + 971586ef + the arm-6 sandbox fix
(brain 5th commit of 2026-08-28 series):
- R1: -b/--body is the canonical comment flag (matches issue-create,
issue-edit, pr-create, pr-edit); -c/--comment stays a compatible alias.
- R4: usage errors print to stderr and exit 2, distinct from provider,
credential, and verification failures (exit 1). Value-less flags fail
loudly (previously -c with no value died silently at rc=1 via set -e on
the failed shift 2). gh failures on the GitHub path normalize to exit 1
(gh's own usage errors exit 2 and would collide with the reserved code).
- Tests: new usage-contract suite (help rc, unknown/missing/value-less rc=2
on stderr, alias parse acceptance under a sandboxed runner, GitHub-path
exit normalization with a stubbed gh, zero provider contact on parser
failure); readback suite gains case 11 (full verified write via -b) and
neutralizes seat-exported MOSAIC_GIT_IDENTITY / MOSAIC_BRAIN_HOME that
escape the sandboxed HOME (documented HTTP 401 / fail-loud shapes).
Driver: a fleet seat full-stopped on an issue-comment usage error because
usage failures were indistinguishable from provider failures and the stop
gate treated every wrapper failure as blocking.
issue-comment.sh and pr-review.sh verify a durable write by pinning the
provider-returned object URL's origin and full path. The origin included the
SCHEME verbatim. On a Gitea whose ROOT_URL is configured `http://` while every
client reaches it over `https://`, the provider returns `http://` object URLs,
so the comparison rejects the provider's own truthful answer about a write that
LANDED. The failure is deterministic, not intermittent: every comment, every
time, on such a deployment.
The scheme was never what the check defends. The forgeries it exists to catch —
look-alike host, decoy path prefix, wrong owner/repo/kind/number — all vary the
HOST or the PATH. Both stay strict. `http` and `https` now collapse to one
scheme class; any other scheme (file:, ftp:, javascript:) stays distinguishing,
and an EXPLICIT non-default port still distinguishes, because a different port
is a different service on the same host.
Consequences of the bug, both observed:
- The wrapper reports failure on a comment that is durably on the issue/PR, and
attributes it to #865 ("no durable comment created"). The write landed; the
citation is wrong. Reproduced here: the harness's persisted state contains the
record while the wrapper exits 1.
- pr-review.sh's comment path is worse. On a host where no seat can create a
review OBJECT, comment-form is the only gate-16 review record obtainable, and
this check refuses all of it.
Test gap this closes: every URL fixture in both harnesses was `https://`, and
every negative case varied only host or path. The one axis that fails in
production had zero coverage — the fixtures encoded the assumption that breaks.
Added, in both suites:
- scheme-downgrade (http vs https, otherwise correct) — must be ACCEPTED. Fails
against the unmodified wrappers, passes against the fixed ones; verified in
both directions, and the negative control's captured output is the #865
misattribution above.
- explicit non-default port (`:8443`) — must stay REJECTED.
- non-web scheme (`ftp://`) — must stay REJECTED.
Also fixes test-issue-comment-readback.sh hermeticity (#1007), without which the
suite cannot run on any seat that has a per-agent Gitea token: detect-platform's
step-0 identity lookup reads ~/.config/mosaic/gitea-tokens/<identity>, outside
both XDG_CONFIG_HOME and MOSAIC_CREDENTIALS_FILE, so the suite resolved a
PRODUCTION credential and died at HTTP 401 before case 1. Same two-part fix
already merged for test-pr-review-gitea-comment.sh in #1006: a sandboxed HOME
plus an empty REPO-LOCAL mosaic.gitIdentity to shadow the global. Note the
env-var route does NOT work — detect-platform.sh reads `${MOSAIC_GIT_IDENTITY:-}`
and `:-` treats set-but-empty identically to unset.
The owner-side half of #991 (setting the deployment's Gitea ROOT_URL to https)
is not in scope here and is not made unnecessary by this change; this makes the
wrappers correct against a deployment that returns either scheme.