Gladex Agent Logs

Agent run logs & app logs · env: prod · LAN-only investor surface

Overview
Run logs716 files, 30.4 MB
Latest run logrun-20260928-234838-314.log
Log directory/data/agent-logs
App log directory/opt/startup/prod/logs
Run logs (newest first, last 50)
FileSizeModified (UTC)
run-20260928-234838-314.log 132 KB 2026-09-28 21:55:31
run-20260928-222402-313.log 319 KB 2026-09-28 21:38:38
run-20260928-211218-312.log 234 KB 2026-09-28 20:14:02
run-20260928-201031-311.log 248 KB 2026-09-28 19:02:18
run-20260928-184021-310.log 439 KB 2026-09-28 18:00:31
run-20260928-171725-309.log 236 KB 2026-09-28 16:30:21
run-20260928-161526-308.log 183 KB 2026-09-28 15:07:25
run-20260928-160525-307.log 153 B 2026-09-28 14:05:26
run-20260928-155524-306.log 153 B 2026-09-28 13:55:25
run-20260928-154524-305.log 153 B 2026-09-28 13:45:24
run-20260928-153523-304.log 153 B 2026-09-28 13:35:24
run-20260928-152522-303.log 153 B 2026-09-28 13:25:23
run-20260928-151521-302.log 153 B 2026-09-28 13:15:22
run-20260928-150521-301.log 153 B 2026-09-28 13:05:21
run-20260928-145520-300.log 153 B 2026-09-28 12:55:21
run-20260928-144519-299.log 153 B 2026-09-28 12:45:20
run-20260928-143519-298.log 153 B 2026-09-28 12:35:19
run-20260928-142518-297.log 153 B 2026-09-28 12:25:19
run-20260928-141517-296.log 153 B 2026-09-28 12:15:18
run-20260928-140517-295.log 153 B 2026-09-28 12:05:17
run-20260928-135516-294.log 153 B 2026-09-28 11:55:17
run-20260928-134515-293.log 153 B 2026-09-28 11:45:16
run-20260928-133515-292.log 153 B 2026-09-28 11:35:15
run-20260928-132514-291.log 153 B 2026-09-28 11:25:15
run-20260928-131513-290.log 153 B 2026-09-28 11:15:14
run-20260928-130513-289.log 153 B 2026-09-28 11:05:13
run-20260928-125512-288.log 153 B 2026-09-28 10:55:13
run-20260928-124511-287.log 153 B 2026-09-28 10:45:12
run-20260928-123511-286.log 153 B 2026-09-28 10:35:11
run-20260928-122510-285.log 153 B 2026-09-28 10:25:11
run-20260928-121509-284.log 153 B 2026-09-28 10:15:10
run-20260928-120509-283.log 153 B 2026-09-28 10:05:09
run-20260928-115508-282.log 153 B 2026-09-28 09:55:09
run-20260928-114507-281.log 153 B 2026-09-28 09:45:08
run-20260928-113507-280.log 153 B 2026-09-28 09:35:07
run-20260928-112506-279.log 153 B 2026-09-28 09:25:07
run-20260928-111505-278.log 153 B 2026-09-28 09:15:06
run-20260928-110505-277.log 153 B 2026-09-28 09:05:05
run-20260928-101134-276.log 189 KB 2026-09-28 08:55:05
run-20260928-084440-275.log 249 KB 2026-09-28 08:01:34
run-20260928-065526-274.log 230 KB 2026-09-28 06:34:40
run-20260928-051427-273.log 475 KB 2026-09-28 04:45:26
run-20260928-034708-272.log 266 KB 2026-09-28 03:04:27
run-20260928-024242-271.log 330 KB 2026-09-28 01:37:08
run-20260928-020359-270.log 288 KB 2026-09-28 00:32:42
run-20260928-015358-269.log 153 B 2026-09-27 23:53:59
run-20260928-014358-268.log 153 B 2026-09-27 23:43:58
run-20260928-013357-267.log 153 B 2026-09-27 23:33:58
run-20260928-012356-266.log 190 B 2026-09-27 23:23:57
run-20260928-011356-265.log 190 B 2026-09-27 23:13:56
Tail — run-20260928-234838-314.log (last 200 lines)
tot_u=0; tot_s=0; tot_extra=0
printf '%-24s %6s %6s %6s\n' tool usage strict extra
for f in "$tools_dir"/*; do
  [ -f "$f" ] || continue
  case "${f##*/}" in REGISTRY.md|.*|*.py|*.md) continue ;; esac
  h=$(timeout 20 "$f" --help 2>&1) || continue
  s=$(printf '%s\n' "$h" | sed -n 's/^ *\(--[a-z][a-z0-9-]*\) \([^ ]\{1,\}\).*/\1 \2/p' | sort -u)
  # usage-synopsis reader: only the `usage:` line(s), flags with a token
  u=$(printf '%s\n' "$h" | grep -iE '^ *usage:' \
      | grep -oE '\-\-[a-z][a-z0-9-]*[ ]+[^] ]+' \
      | awk '{print $1" "$2}' | sed 's/[),]*$//' | sort -u)
  sn=$(printf '%s\n' "$s"|grep -c .); un=$(printf '%s\n' "$u"|grep -c .)
  extra=$(comm -13 <(printf '%s\n' "$s") <(printf '%s\n' "$u") | grep -c .)
  tot_u=$((tot_u+un)); tot_s=$((tot_s+sn)); tot_extra=$((tot_extra+extra))
  printf '%-24s %6d %6d %6d\n' "${f##*/}" "$un" "$sn" "$extra"
  [ "$extra" -gt 0 ] && comm -13 <(printf '%s\n' "$s") <(printf '%s\n' "$u") | sed 's/^/        only-in-usage: /'
done
echo "TOTALS usage=$tot_u strict=$tot_s extra=$tot_extra"
EOS
bash /tmp/opencode/meas75b.sh
tool                      usage strict  extra
budget-show                   1      1      0
dns-verify                    2      3      0
domain-availability-check      1      2      0
go-compile-drift-verify       0      3      0
healthcheck                   2      2      0
immich-roundtrip              2      7      0
inbox-status                  3      5      0
ip-drift-check                2      4      0
ip-drift-cron                 0      0      0
promote-dev-to-prod           1      1      0
queue-source-check            2      2      0
regression-run                2      8      0
repo-lint                     3      4      0
smtp-relay-probe              2      3      0
source-sync-check             2      2      0
system-status                 1      1      0
tls-check                     2      5      0
verify-landing                0      2      0
version-check                 3      3      0
TOTALS usage=31 strict=58 extra=0
> build · mimo-v2.6-flash-free
$ cd /data/repo && ./tools/verify-landing --help; echo "=== variant C ==="; cat > /tmp/opencode/meas75c.sh <<'EOS'
#!/usr/bin/env bash
set -uo pipefail
tools_dir=${1:-/data/repo/tools}
tot=0; tot_extra=0
for f in "$tools_dir"/*; do
  [ -f "$f" ] || continue
  case "${f##*/}" in REGISTRY.md|.*|*.py|*.md) continue ;; esac
  h=$(timeout 20 "$f" --help 2>&1) || continue
  s=$(printf '%s\n' "$h" | sed -n 's/^ *\(--[a-z][a-z0-9-]*\) \([^ ]\{1,\}\).*/\1 \2/p' | sort -u)
  m=$(printf '%s\n' "$h" | sed -n 's/^ *\(--[a-z][a-z0-9-]*\)[ 	]\{1,\}\([A-Z][A-Z0-9_-]\{1,\}\|[{][^]}]*[}]\|[^ 	|]*[|][^ 	|]*\)\([ 	]\{2,\}\|$\).*/\1 \2/p' | sort -u)
  mn=$(printf '%s\n' "$m"|grep -c .); sn=$(printf '%s\n' "$s"|grep -c .)
  extra=$(comm -13 <(printf '%s\n' "$s") <(printf '%s\n' "$m")|grep -c .)
  tot=$((tot+mn)); tot_extra=$((tot_extra+extra))
  if [ "$extra" -gt 0 ]; then echo "DEVIATION ${f##*/} ($extra)"; comm -13 <(printf '%s\n' "$s") <(printf '%s\n' "$m")|sed 's/^/    /'; fi
  missing=$(comm -23 <(printf '%s\n' "$s") <(printf '%s\n' "$m")|grep -c .)
  [ "$missing" -gt 0 ] && echo "  (info) ${f##*/}: strict-only $missing: $(comm -23 <(printf '%s\n' "$s") <(printf '%s\n' "$m") | tr '\n' ';')"
done
echo "TOTALS metavC=$tot extra=$tot_extra"
EOS
bash /tmp/opencode/meas75c.sh
Verify Gladex.de Landing Page

Usage: ./tools/verify-landing [OPTIONS]

Options:
    --help          Show this help message
    --env ENV       Environment to check (default: dev)
    --port PORT     Port to check (default: 8000 for dev, 8001 for prod)

Exit Codes:
    0   Success - landing page is working
    1   Error - landing page not responding or incorrect content
    2   Invalid arguments

Examples:
    ./tools/verify-landing              # Check dev environment
    ./tools/verify-landing --env prod   # Check prod environment
=== variant C ===
TOTALS metavC=58 extra=0
> build · mimo-v2.6-flash-free
$ cd /data/repo && grep -n "^set -" tests/test_registry_coverage.sh; grep -n "^## \[0.4.1" CHANGELOG.md | head -3; echo "=== newest entry head ==="; sed -n "$(grep -n '^## \[0.4.1' CHANGELOG.md | head -1 | cut -d: -f1),+40p" CHANGELOG.md
70:set -u
1182:set -euo pipefail
276:## [0.4.19] - 2026-09-24 — PHP gets the same `busy_timeout` contract: one helper behind every SQLite open
305:## [0.4.18] - 2026-09-24 — workspace DB waits instead of failing: `busy_timeout` on every open (queued since 0.4.11)
328:## [0.4.17] - 2026-09-24 — friendlier `gladex status` outside a workspace
=== newest entry head ===
## [0.4.19] - 2026-09-24 — PHP gets the same `busy_timeout` contract: one helper behind every SQLite open

### Fixed
- **PHP SQLite opens carried no explicit busy-timeout** — the item queued at the end of 0.4.18 ("carry the same `busy_timeout` into the PHP-side SQLite opens"). Two traps made this worth doing carefully rather than copying the Go line:
  - pdo_sqlite's implicit default on this box is **60 000 ms** (probed: fresh `PDO('sqlite:…')` reads back `PRAGMA busy_timeout = 60000`), so a contended request could pin a worker for a full minute instead of failing fast — the opposite failure mode from the Go side's 0 ms.
  - the Go-style DSN suffix **cannot** be used: pdo_sqlite does not parse query strings, so `sqlite:/path?busy_timeout=5000` opens a file literally named `/path?busy_timeout=5000` (reproduced: the probe created `probe3.db?busy_timeout=5000`). Hence a `PRAGMA`, which is connection-scoped — exactly right, as one PDO is one connection.
  - New `app/src/php/db.php`: `gladex_pdo(string $path, bool $wal = false)` sets `ERRMODE_EXCEPTION` + `FETCH_ASSOC`, `PRAGMA busy_timeout = 5000` (`GLADEX_BUSY_TIMEOUT_MS`, mirroring Go's `dbBusyTimeoutMS`), and `journal_mode=WAL` **only** when `$wal` — i.e. exactly where WAL was and was not set before (trust-DB reads and stats stay non-WAL).
  - All **6** call sites converted: `app.php` ×4 (`getDb`, `initDbIfNeeded`, trust-DB reads ×2), `stats.php`, `init_db.php`. `new PDO` now appears in **`db.php` only**, and that is asserted.

### Added
- `tests/test_php_busy_timeout.php` — **19 assertions, ~6.6 s**, exercising the real helper under real contention (a child PHP process holds `BEGIN IMMEDIATE` for 6.5 s):
  - readback `busy_timeout = 5000` (not the 60 000 ms default);
  - control connection with `busy_timeout=0` fails in **<500 ms** → the lock scenario is genuine and shows what "no waiting" looks like;
  - `gladex_pdo` **waits ~5 s then fails** `database is locked` → pins *both* halves of the contract: it blocks (0 ms would fail instantly) **and** the cap is 5 s (a 60 s-timeout connection would still be waiting when the holder releases at 6.5 s and would therefore *succeed* instead of failing);
  - recovery: after the holder exits, writes succeed in ~3 ms with exactly the 2 expected rows;
  - `journal_mode=WAL` only on request; `new PDO` only in `db.php`.
- `test_changelog_api.php`'s repo==dev==prod identity guard extended from `app.php`+`stats.php` to **`app`/`stats`/`init_db`/`db`** — a deploy that copies the two `require_once`-ing views but forgets the helper now fails the suite instead of fataling in prod.

### Verified
- **Mutation check**: deleting the `PRAGMA busy_timeout` line from `db.php` → 4 failures (readback, "waited", cap, row count) and **exit 1**; restoring it byte-identically (md5 `98bbc94542ff3f5a406a9cd9b5da8517`) → **19/19, exit 0**. The tests are load-bearing.
- **Suites**: PHP **207** (78+49+27+19+16+11+7) + shell **26** → **233 passed, 0 failed**; Go `go test ./...` green and `go vet` clean apart from the accepted pre-existing warning (both re-run by the reviewer).
- **Deploy (reviewer-gated)**: repo → **dev** (4 files md5-identical, unit restarted, 7 routes `/healthz` `/` `/investor` `/stats` `/api/changelog` `/team` `/info` all 200) → **reviewer APPROVE** → **prod** (restart, same 7 routes 200). All 4 files byte-identical across repo/dev/prod; `tools/healthcheck` → dev **HEALTHY**, prod **HEALTHY**; full PHP-source drift scan repo↔dev↔prod → **0 drift**.
- **STEP 0**: **0 unread** `investor_to_agent` rows (dev **and** prod), **0 unhandled** `INBOX.md` entries → no reply rows owed this run. No DNS write, no config change, no API key, no spend (2026-09: 5.00 / 1.50 / 3.50, **model spend 0.00**, `*-free` only).

### Notes
- **Discovered, queued**: `stats.php` hardcodes `/opt/startup/dev/data/messages.db`, so **prod `/stats` reports dev's message counts**. Harmless only while the two DBs match; it is wrong the moment they diverge. One-line fix, next run.
- Investigated and cleared: the 8 `mb_strlen()` fatals in yesterday's prod log came from an intermediate `mailbox.php` since replaced — all three copies are now byte-identical (`5fe3808a…`) and no `mb_strlen` exists anywhere in the tree. `mbstring` is not loaded in this PHP; current code never calls it (the app's own `mb_*` helpers are its own namespace, unrelated to the extension).
- Unchanged: the **A/B/C public-gating decision** stays with the investor (msg #57, still unread by them); SOA MNAME placeholder is a provider-panel action; `mailboxes/*` still holds **0** Dispatcher assignments.

## [0.4.18] - 2026-09-24 — workspace DB waits instead of failing: `busy_timeout` on every open (queued since 0.4.11)

### Fixed
- **Two `gladex` invocations sharing one workspace `context.db` collided with `SQLITE_BUSY`** — the item queued since 0.4.11. SQLite's default is *no* busy handler (0 ms), so the second process failed on the very first lock instead of waiting for it.
  - New `commands/db.go`: `openDB(path)` wraps `sql.Open` and appends `?_busy_timeout=5000` to the DSN; `dbBusyTimeoutMS = 5000` is the single knob.
  - All **26** production `sql.Open("sqlite", dbPath)` call sites across 11 files (`root` ×5, `workflow` ×6, `trust` ×5, `serve` ×2, `mcp_server` ×2, `context_diff`, `context_export`, `context_import`, `status`, `templates`, `doctor`) now call `openDB()`, so no command can silently reopen the pre-fix path. The now-unused `"database/sql"` import was dropped from the 6 files that only needed it for `sql.Open`.
  - **Why the DSN and not a `PRAGMA` executed after opening**: `busy_timeout` is a per-connection property and `database/sql` opens a *new* underlying connection whenever the pool grows — a post-open exec would have covered only the first connection and failed exactly where it matters. `modernc.org/sqlite` applies DSN parameters on every `newConn` and strips the query off a plain filename, so no `file:` prefix is needed and the path itself is untouched.
  - Deliberately **not** bundled in: a journal-mode change. `serve` already sets `journal_mode=WAL`; converting CLI-only workspaces to WAL is a separate, riskier change and was not part of the queued item.

### Added
- **`db_test.go` — 4 tests**: (a) `TestOpenDBAppliesBusyTimeout` asserts the PRAGMA on **two distinct pooled connections** (the first handle is checked out and held so the second one must open a fresh underlying connection); (b) `TestOpenDBIsLoadBearing` — control asserting the driver default really is `0`, so (a) cannot pass vacuously; (c) `TestSecondWriterWaitsInsteadOfSQLITE_BUSY` — end-to-end reproduction: a holder keeps a write transaction open 300 ms while a second pool must block ≥250 ms, then succeed and land both rows; (d) `TestOpenDBStaysLazy` — the helper only decorates the DSN, so `locateDB`/`msgNoWorkspace` still own the missing-workspace error path.
> build · mimo-v2.6-flash-free
$ cd /data/repo && grep -n "^## \[0.4" CHANGELOG.md | tail -6 && echo "=== 119 head ===" && sed -n "$(grep -n '^## \[0.4.119\]' CHANGELOG.md | cut -d: -f1),+30p" CHANGELOG.md
4151:## [0.4.114] - 2026-09-28 — queue item (64): a documented exit code is now PROBED, not merely registered — `tests/test_registry_coverage.sh` gains section E plus controls C14/C15, suite 67 → 86
4182:## [0.4.115] - 2026-09-28 — Jonas: `/trust`'s record form was the last control on the site with no keyboard focus ring, and its `<select>` announced with an EMPTY accessible name — a 2px `:focus-visible` ring plus three `sr-only` labels, layout unchanged to 0.1px
4213:## [0.4.116] - 2026-09-28 — queue item (63): the registry quoted the regression total in six places and the one that read as current said **40** where `regression-run --list` says **59**, with no reader on either side — section F checks it against the tool, suite 86 → 120
4248:## [0.4.117] - 2026-09-28 — queue item (65): a documented exit 2 was only ever probed with a flag NO tool defines, so two parsers swallowed a bad `--format` for weeks — `system-status --format xml` ran 39s and exited 0 with human output, `version-check --format xml` printed `OK: … (match)` with exit 0, and a value-less `--format` exited 1; section G probes bad VALUES, suite 120 → 140
4283:## [0.4.118] - 2026-09-28 — queue item (69): the exit-2 probe asked *which flag*, never *what a port is* — of the 4 flags whose `--help` says `--flag PORT`, only 1 refused `not-a-number`; `verify-landing --port not-a-number` printed `HTTP 000000` with exit 1 and `version-check --dev-port not-a-number` reached curl with exit 1, both contradicting their own tables; G's third derived class reads the METAVAR, suite 140 → 154
4323:## [0.4.119] - 2026-09-28 — queue item (72): the missing-value probe was still two FLAG NAMES, and a name list can never be complete — of the 59 help lines shaped `--flag TOKEN`, exactly one tool still died in `shift 2` (`verify-landing --env`, exit 1 while its own table promised 2); G's fourth class reads the WRITING of the line, suite 154 → 168
=== 119 head ===
## [0.4.119] - 2026-09-28 — queue item (72): the missing-value probe was still two FLAG NAMES, and a name list can never be complete — of the 59 help lines shaped `--flag TOKEN`, exactly one tool still died in `shift 2` (`verify-landing --env`, exit 1 while its own table promised 2); G's fourth class reads the WRITING of the line, suite 154 → 168

### Why

`[0.4.118]` queued (72) as *"generalize the **missing-value** probe from two flag names to any `--flag METAVAR` in `--help` — measured this run … **all answer 2 except `verify-landing --env` → 1** … the choice is to derive it (and fix `--env`, which is currently unfixed on purpose) or to declare in `REGISTRY.md`"*. The fork was resolved by asking what a *name* list can never do: `--format` and `--timeout` are names, `PORT` is a metavar, and neither reading reaches a flag nobody has typed yet — so the class was derived instead, and the defect it was one line from catching was repaired in the same entry.

Measured on the live tree **before any edit**, over all 20 tools:

| scope reading | lines | notes |
|---|---|---|
| `--flag` + **one space** + any token | **59** (58 unique) | the getopt-help convention for *takes a value* |
| `--flag` + one space + UPPERCASE token | 42 (41 unique) | the (69) metavar rule — misses **17** lines whose token is `{json,human}` / `human\|json`, among them `source-sync-check --env {dev,prod,both}` |
| `--flag` + one-or-more spaces + uppercase | 48 | the looser pattern — sweeps in **6** boolean-description lines (`--help` before the word *Show*, `--force` before *Bypass*), whose flag would be probed as if it took a value |

Of the 58 unique value-taking flags, **57 already refused a missing value with exit 2**; the one that did not:

| probe | result |
|---|---|
| `verify-landing --env` (flag last, no value) | **1** ✗ dies in `shift 2` |
| the other 57 | **2** ✓ |

**Why the single space is the scope**: getopt-help writes a value-taking flag as `--flag TOKEN` and *indents* a boolean's description instead, so the convention separates the two classes without asking any tool what it accepts — one `grep` wide, forever non-stale, and both of its failure modes counted above rather than argued.

### Changed

- **`tools/verify-landing`** — the missing-value guard for `--env`, byte-for-byte the shape `[0.4.118]` added beside `--port`: `[[ $# -ge 2 ]]` before the assignment and the `shift 2`, naming the flag in `Error: --env needs a value: ENV`. Until now `--env` as the last argument died inside `shift 2` with exit **1**, so `2 - Invalid arguments` in its own table was unreachable for it — the same defect one flag over from the one (69) had already fixed, left unfixed on purpose until this entry gave it a reader.
- **`tests/test_registry_coverage.sh`** — section **G** gains a fourth class inside the same `run_check()` path: every `--help` line shaped `--flag TOKEN` (exactly one space) is probed for a **missing** value, subject `<tool>:<flag>-missing`; `--format` and metavar `PORT` are skipped *inside that loop* because those two already probe their own missing value under the same subject strings — **one probe per flag, none twice**. `miss_n` reaching 0 exits **3** with `ERROR miss_no_scope`, the same refuse-a-pass-you-earned-by-reading-nothing rule `fmt_n`/`port_n` already had; two new SUMMARY keys (`miss_n`, `miss_missing_ok`).
- **G14/G15** — the "none skipped, none twice" claim is *recounted*, not asserted: a second, separately-written reader (`sed -n 's/^ *\(--[a-z][a-z0-9-]*\) \([^ ]\{1,\}\).*/\1 \2/p'` over every live `--help`) totals the scope, and `miss + fmt + port` must equal it — measured **58 = 37 + 17 + 4**, with a floor of 30 on the recount itself. A hardcoded constant would have gone stale the day a tool gained a flag, which is the hand-list failure this suite exists to avoid.
- **Control C24** — the pre-repair shape planted exactly: a stub advertising `--env ENV` that refuses an unknown flag (so E stays green — this is *not* (64)'s defect) and swallows **only** the missing value, asserted as `exactly one violation` plus `C24g` (the `--format`/PORT siblings stay silent) and `C24i` (`miss_n − 1 == miss_missing_ok`, i.e. every *other* value-taking flag in that sandbox still answered 2).
- **Three stale control counts reconciled**: the suite's own `--help` said **22** controls while C23 made 23, and `REGISTRY.md` said **21** in one sentence and **23** in another — three numbers, three values, one truth. The help now says **24**; the registry's prose says "every negative control", which cannot drift.
- **`tools/REGISTRY.md`** — the suite's section carries the (72) derivation (all three readings of the scope, counted), its replay, `168 assertions / ~126s`, and the granularity line now saying **four** probe classes (still only code 2); `verify-landing` gains a `**Tests**` bullet for the `--env` probe.
> build · mimo-v2.6-flash-free
$ cd /data/repo && sed -n '4345,4371p' CHANGELOG.md
### Changed

- **`tools/verify-landing`** — the missing-value guard for `--env`, byte-for-byte the shape `[0.4.118]` added beside `--port`: `[[ $# -ge 2 ]]` before the assignment and the `shift 2`, naming the flag in `Error: --env needs a value: ENV`. Until now `--env` as the last argument died inside `shift 2` with exit **1**, so `2 - Invalid arguments` in its own table was unreachable for it — the same defect one flag over from the one (69) had already fixed, left unfixed on purpose until this entry gave it a reader.
- **`tests/test_registry_coverage.sh`** — section **G** gains a fourth class inside the same `run_check()` path: every `--help` line shaped `--flag TOKEN` (exactly one space) is probed for a **missing** value, subject `<tool>:<flag>-missing`; `--format` and metavar `PORT` are skipped *inside that loop* because those two already probe their own missing value under the same subject strings — **one probe per flag, none twice**. `miss_n` reaching 0 exits **3** with `ERROR miss_no_scope`, the same refuse-a-pass-you-earned-by-reading-nothing rule `fmt_n`/`port_n` already had; two new SUMMARY keys (`miss_n`, `miss_missing_ok`).
- **G14/G15** — the "none skipped, none twice" claim is *recounted*, not asserted: a second, separately-written reader (`sed -n 's/^ *\(--[a-z][a-z0-9-]*\) \([^ ]\{1,\}\).*/\1 \2/p'` over every live `--help`) totals the scope, and `miss + fmt + port` must equal it — measured **58 = 37 + 17 + 4**, with a floor of 30 on the recount itself. A hardcoded constant would have gone stale the day a tool gained a flag, which is the hand-list failure this suite exists to avoid.
- **Control C24** — the pre-repair shape planted exactly: a stub advertising `--env ENV` that refuses an unknown flag (so E stays green — this is *not* (64)'s defect) and swallows **only** the missing value, asserted as `exactly one violation` plus `C24g` (the `--format`/PORT siblings stay silent) and `C24i` (`miss_n − 1 == miss_missing_ok`, i.e. every *other* value-taking flag in that sandbox still answered 2).
- **Three stale control counts reconciled**: the suite's own `--help` said **22** controls while C23 made 23, and `REGISTRY.md` said **21** in one sentence and **23** in another — three numbers, three values, one truth. The help now says **24**; the registry's prose says "every negative control", which cannot drift.
- **`tools/REGISTRY.md`** — the suite's section carries the (72) derivation (all three readings of the scope, counted), its replay, `168 assertions / ~126s`, and the granularity line now saying **four** probe classes (still only code 2); `verify-landing` gains a `**Tests**` bullet for the `--env` probe.

### Verified

- **`bash tests/test_registry_coverage.sh` → 168 passed / 0 failed**, exit 0, **126.04s** (was **154** at 83.9s; **+14 = C24 (9) + G11–G15 (5)**), standalone on the edited tree. The child's own SUMMARY on the live tree: `fmt 17/17/17`, `timeout 6/6`, `port 4/4/4`, **`miss_n=37 miss_missing_ok=37`**, `violations=0`.
- **Pre-repair replay against `HEAD`'s `tools/verify-landing`** — copied together with `tools/` + `tests/` to `/tmp/opencode/prefix72`, md5-different on the tool (`ac0c18…` vs live `ac477b…`) and identical on the suite, working tree untouched, with the prefix's own probe run first to prove it still reproduces the old exit (**1** there, **2** live) → **146 passed / 22 failed**, and the checker's own output is the attribution: **exactly 1 violation**, `verify-landing:env-missing`, `miss_missing_ok` **36 of 37** while `fmt_*`, `timeout_*` and `port_*` stayed at full marks — the red is the new probe, not a side effect. Red: **A1, A3, G6, G13 (37 → 36)** plus twenty controls' `exactly one` counts, for the reason C16's was (the defect sits in the tree every sandbox is copied from); **C23 and C24 stayed green there by construction**, each overwriting that same file with its own stub inside its own sandbox.
- **Repair measured directly**, not inferred: `verify-landing --env` → **2** with `Error: --env needs a value: ENV`, `--env bogus` → **2** (`Invalid environment`), `--port` → **2**, `--help` → **0**. Blast radius: a grep across the tree finds `verify-landing` only in this suite, `REGISTRY.md`, this changelog and the agent logs — no caller passes it a flag.
- **Full regression, pre-commit** → see the run log below; gates read after the edits: `tools/repo-lint --format json`, `tools/queue-source-check --format json`, `tools/source-sync-check`, `tools/system-status --format json`, `tools/inbox-status`.

### Notes

- **A fault of my own, caught by a number that did not close, kept in the source**: the first draft looped `for mline in $missflags`, which word-SPLITS the `flag token` pairs — so each metavar was probed as if it were a flag. Measured: `miss_n` **95** where the scope is 37, `tls-check PEM` and `smtp-relay-probe {json,human}` reported as swallowed flags, **5 bogus violations** in the live tree, **26 red assertions** and a **184s** run (the bare words fell through to the tools' real work instead of being refused). The `while IFS= read -r` rewrite and the failed draft's numbers are written into the comment where the next reader meets them — the same "the number that did not close" rule that caught C23i's factor of two in `[0.4.118]`.
- **Runtime +42s** (83.9 → 126.0s) with no added network work: 37 new probes run in the live section *and* in each of 24 controls' `run_child` re-exec — the same shape as **(68)**/**(70)**, which already carry the caveat (a per-run snapshot plus one live re-verify, or a declared no-mutation rule for `tools/`); not queued as a new item because it is wall clock rather than a false pass, and (70) is still open with this entry's +42s as further evidence.
- **The gap the recount cannot close**: `G14`/`G15` recount with a *different reader* but the *same convention*, so an option list written `--flag  TOKEN` (two spaces) would drop out of both sides silently and its flags would never be probed — queued as **(75)**: either a one-sentence style rule in `REGISTRY.md` (option lists put exactly one space between flag and token) or a second convention in the checker that would notice the difference; not actioned because it is a documentation rule with a real cost — every future tool's `--help` must obey it — and nothing in the tree violates it today.
- **Deliberately not done**: the **value** half of a metavar still has no derivable invalid value (73), so this class probes missing values only; no non-2 code probed (still (65)'s declared half); **no queue item struck beyond (72)**; **no version-train bump** (`GLADEX_APP_VERSION` stays `0.4.28`), **no promote executed**, no service restarted, no certificate touched, **zero DNS writes**, no mail sent, Nextcloud untouched (`{"installed":false}`, §14 open), `/opt/cloud` untouched, Immich untouched (`{"res":"pong"}`, 8 accounts), INBOX line 468 **answered rather than pretended executed**, spend **0.00** (`*-free` only).
- **One tool's behaviour changed** — `verify-landing` — and only to match the table it already published.

### Queue -> agent-logs/PROGRESS.md
Authoritative next-candidate queue lives in `agent-logs/PROGRESS.md`, in the `Next-candidate queued, not actioned` bullet of the newest run entry — it is not duplicated here, and has not been since `[0.4.67]`. The 111 item lines already written into the historical `### Queue` sections are frozen history. To read the live queue, open `PROGRESS.md`; to know whether that is still true, run `tools/queue-source-check`.
> build · mimo-v2.6-flash-free

Select another run log from the list above. Only files matching run-YYYYMMDD-HHMMSS-N.log are readable.

App log tail — prod-8001.log (last 60 lines)
[Mon Sep 28 23:33:55 2026] 127.0.0.1:52434 Accepted
[Mon Sep 28 23:33:55 2026] 127.0.0.1:52434 Closing
[Mon Sep 28 23:33:55 2026] 127.0.0.1:52440 Accepted
[Mon Sep 28 23:33:55 2026] 127.0.0.1:52440 Closing
[Mon Sep 28 23:33:55 2026] 127.0.0.1:52450 Accepted
[Mon Sep 28 23:33:55 2026] 127.0.0.1:52450 Closing
[Mon Sep 28 23:33:55 2026] 127.0.0.1:52466 Accepted
[Mon Sep 28 23:33:55 2026] 127.0.0.1:52466 Closing
[Mon Sep 28 23:33:55 2026] 127.0.0.1:52468 Accepted
[Mon Sep 28 23:33:55 2026] 127.0.0.1:52468 Closing
[Mon Sep 28 23:33:56 2026] 127.0.0.1:52478 Accepted
[Mon Sep 28 23:33:56 2026] 127.0.0.1:52478 Closing
[Mon Sep 28 23:33:56 2026] 127.0.0.1:52488 Accepted
[Mon Sep 28 23:33:56 2026] 127.0.0.1:52488 Closing
[Mon Sep 28 23:33:56 2026] 127.0.0.1:52498 Accepted
[Mon Sep 28 23:33:56 2026] 127.0.0.1:52498 Closing
[Mon Sep 28 23:34:03 2026] 127.0.0.1:52514 Accepted
[Mon Sep 28 23:34:03 2026] 127.0.0.1:52514 Closing
[Mon Sep 28 23:34:03 2026] 127.0.0.1:52526 Accepted
[Mon Sep 28 23:34:03 2026] 127.0.0.1:52526 Closing
[Mon Sep 28 23:34:03 2026] 127.0.0.1:52532 Accepted
[Mon Sep 28 23:34:03 2026] 127.0.0.1:52532 Closing
[Mon Sep 28 23:34:03 2026] 127.0.0.1:52536 Accepted
[Mon Sep 28 23:34:03 2026] 127.0.0.1:52536 Closing
[Mon Sep 28 23:34:03 2026] 127.0.0.1:52550 Accepted
[Mon Sep 28 23:34:03 2026] 127.0.0.1:52550 Closing
[Mon Sep 28 23:34:03 2026] 127.0.0.1:52554 Accepted
[Mon Sep 28 23:34:03 2026] 127.0.0.1:52554 Closing
[Mon Sep 28 23:34:03 2026] 127.0.0.1:52568 Accepted
[Mon Sep 28 23:34:03 2026] 127.0.0.1:52568 Closing
[Mon Sep 28 23:34:03 2026] 127.0.0.1:52572 Accepted
[Mon Sep 28 23:34:03 2026] 127.0.0.1:52572 Closing
[Mon Sep 28 23:34:03 2026] 127.0.0.1:52588 Accepted
[Mon Sep 28 23:34:04 2026] 127.0.0.1:52588 Closing
[Mon Sep 28 23:34:04 2026] 127.0.0.1:52590 Accepted
[Mon Sep 28 23:34:04 2026] 127.0.0.1:52590 Closing
[Mon Sep 28 23:34:43 2026] 127.0.0.1:42608 Accepted
[Mon Sep 28 23:34:43 2026] 127.0.0.1:42608 Closing
[Mon Sep 28 23:34:43 2026] 127.0.0.1:42622 Accepted
[Mon Sep 28 23:34:43 2026] 127.0.0.1:42622 Closing
[Mon Sep 28 23:34:43 2026] 127.0.0.1:42628 Accepted
[Mon Sep 28 23:34:43 2026] 127.0.0.1:42628 Closing
[Mon Sep 28 23:34:43 2026] 127.0.0.1:42632 Accepted
[Mon Sep 28 23:34:43 2026] 127.0.0.1:42632 Closing
[Mon Sep 28 23:34:43 2026] 127.0.0.1:42636 Accepted
[Mon Sep 28 23:34:43 2026] 127.0.0.1:42636 Closing
[Mon Sep 28 23:34:43 2026] 127.0.0.1:42638 Accepted
[Mon Sep 28 23:34:43 2026] 127.0.0.1:42638 Closing
[Mon Sep 28 23:34:43 2026] 127.0.0.1:42644 Accepted
[Mon Sep 28 23:34:43 2026] 127.0.0.1:42644 Closing
[Mon Sep 28 23:34:43 2026] 127.0.0.1:42648 Accepted
[Mon Sep 28 23:34:43 2026] 127.0.0.1:42648 Closing
[Mon Sep 28 23:34:43 2026] 127.0.0.1:42650 Accepted
[Mon Sep 28 23:34:44 2026] 127.0.0.1:42650 Closing
[Mon Sep 28 23:34:44 2026] 127.0.0.1:42654 Accepted
[Mon Sep 28 23:34:44 2026] 127.0.0.1:42654 Closing
[Mon Sep 28 23:55:50 2026] 127.0.0.1:36376 Accepted
[Mon Sep 28 23:55:50 2026] 127.0.0.1:36376 Closing
[Mon Sep 28 23:55:50 2026] 127.0.0.1:36386 Accepted

Generated 2026-09-28 21:55:50 UTC · Gladex.de