Gladex Agent Logs
Agent run logs & app logs · env: prod · LAN-only investor surface
Overview
| Run logs | 1384 files, 91.9 MB |
| Latest run log | run-20261010-081222-918.log |
| Log directory | /data/agent-logs |
| App log directory | /opt/startup/prod/logs |
Run logs (newest first, last 50)
| File | Size | Modified (UTC) |
|---|---|---|
| run-20261010-081222-918.log | 187 KB | 2026-10-10 06:27:28 |
| run-20261010-074045-917.log | 404 KB | 2026-10-10 06:02:12 |
| run-20261010-064359-916.log | 252 KB | 2026-10-10 05:30:35 |
| run-20261010-061545-915.log | 131 KB | 2026-10-10 04:33:49 |
| run-20261010-041808-914.log | 422 KB | 2026-10-10 04:05:36 |
| run-20261010-032250-913.log | 225 KB | 2026-10-10 02:07:59 |
| run-20261010-023524-912.log | 340 KB | 2026-10-10 01:12:41 |
| run-20261010-020034-911.log | 121 KB | 2026-10-10 00:25:15 |
| run-20261010-015024-910.log | 153 B | 2026-10-09 23:50:25 |
| run-20261010-014014-909.log | 153 B | 2026-10-09 23:40:15 |
| run-20261010-013004-908.log | 153 B | 2026-10-09 23:30:05 |
| run-20261010-011954-907.log | 153 B | 2026-10-09 23:19:55 |
| run-20261010-010944-906.log | 153 B | 2026-10-09 23:09:45 |
| run-20261010-005935-905.log | 153 B | 2026-10-09 22:59:35 |
| run-20261010-004925-904.log | 153 B | 2026-10-09 22:49:26 |
| run-20261010-003915-903.log | 153 B | 2026-10-09 22:39:16 |
| run-20261010-002906-902.log | 153 B | 2026-10-09 22:29:06 |
| run-20261010-001856-901.log | 153 B | 2026-10-09 22:18:57 |
| run-20261010-000846-900.log | 153 B | 2026-10-09 22:08:47 |
| run-20261009-235837-899.log | 153 B | 2026-10-09 21:58:37 |
| run-20261009-234827-898.log | 153 B | 2026-10-09 21:48:28 |
| run-20261009-233817-897.log | 153 B | 2026-10-09 21:38:18 |
| run-20261009-232808-896.log | 153 B | 2026-10-09 21:28:08 |
| run-20261009-231758-895.log | 153 B | 2026-10-09 21:17:59 |
| run-20261009-230748-894.log | 153 B | 2026-10-09 21:07:49 |
| run-20261009-225738-893.log | 153 B | 2026-10-09 20:57:39 |
| run-20261009-224729-892.log | 153 B | 2026-10-09 20:47:29 |
| run-20261009-223719-891.log | 153 B | 2026-10-09 20:37:20 |
| run-20261009-222709-890.log | 153 B | 2026-10-09 20:27:10 |
| run-20261009-221659-889.log | 153 B | 2026-10-09 20:17:00 |
| run-20261009-220649-888.log | 190 B | 2026-10-09 20:06:50 |
| run-20261009-215639-887.log | 153 B | 2026-10-09 19:56:40 |
| run-20261009-214628-886.log | 153 B | 2026-10-09 19:46:29 |
| run-20261009-213618-885.log | 153 B | 2026-10-09 19:36:19 |
| run-20261009-212608-884.log | 153 B | 2026-10-09 19:26:09 |
| run-20261009-211558-883.log | 153 B | 2026-10-09 19:15:59 |
| run-20261009-210548-882.log | 153 B | 2026-10-09 19:05:49 |
| run-20261009-205539-881.log | 190 B | 2026-10-09 18:55:39 |
| run-20261009-204528-880.log | 190 B | 2026-10-09 18:45:29 |
| run-20261009-203518-879.log | 153 B | 2026-10-09 18:35:19 |
| run-20261009-202508-878.log | 190 B | 2026-10-09 18:25:09 |
| run-20261009-201458-877.log | 153 B | 2026-10-09 18:14:59 |
| run-20261009-200448-876.log | 190 B | 2026-10-09 18:04:49 |
| run-20261009-195439-875.log | 153 B | 2026-10-09 17:54:39 |
| run-20261009-194429-874.log | 153 B | 2026-10-09 17:44:30 |
| run-20261009-193419-873.log | 153 B | 2026-10-09 17:34:20 |
| run-20261009-192410-872.log | 153 B | 2026-10-09 17:24:10 |
| run-20261009-191400-871.log | 153 B | 2026-10-09 17:14:00 |
| run-20261009-190350-870.log | 153 B | 2026-10-09 17:03:51 |
| run-20261009-185340-869.log | 153 B | 2026-10-09 16:53:41 |
Tail — run-20261010-081222-918.log (last 200 lines)
func main() {}
--- end: backend ---
package main
func main() {}
Workflow 'code-review' saved (5 steps)
Dry run: workflow 'code-review' has 5 steps
1. [context] backend
2. [set-var] task
3. [print] show-task
4. [shell] analysis
5. [context] system-prompt
Running workflow 'code-review' (run #1)...
[1/5] backend (context)... OK
[2/5] task (set-var)... OK
[3/5] show-task (print)... (Reviewing: Review for security issues) OK
[4/5] analysis (shell)... (27 bytes output) OK
[5/5] system-prompt (context)... OK
Workflow 'code-review' completed in 3ms (run #1)
#1 success started: 2026-10-10 06:26:40 finished: 2026-10-10 06:26:40
Recorded copilot → context-optimization: accepted (score: 1.000)
Recorded cursor → api-refactor: rejected (score: 0.000)
Recorded claude → security-fix: partial (score: 0.600)
copilot → context-optimization score: 1.000 updated: 2026-10-10 06:26:40
claude → security-fix score: 0.600 updated: 2026-10-10 06:26:40
cursor → api-refactor score: 0.000 updated: 2026-10-10 06:26:40
3 trust score(s) recorded.
Confidence: copilot → context-optimization
Score: 1.000
Level: HIGH
Advice: Strong track record. Suggest with confidence.
--- stream B ---
Initialized Gladex workspace in .gladex
Database: .gladex/context.db
Config: .gladex/config.json
Contexts: .gladex/contexts/
Pushed context 'frontend' (58 bytes)
Pushed context 'backend' (30 bytes)
Pushed context 'docs' (23 bytes)
Workflow 'review-all' saved (7 steps)
Running workflow 'review-all' (run #1)...
[1/7] start (print)... (Starting full code review...) OK
[2/7] load-docs (context)... OK
[3/7] load-backend (context)... OK
[4/7] review-backend (shell)... (21 bytes output) OK
[5/7] load-frontend (context)... OK
[6/7] review-frontend (shell)... (22 bytes output) OK
[7/7] done (print)... (Review complete.) OK
Workflow 'review-all' completed in 15ms (run #1)
SB=/tmp/opencode/gs-measure.qmFTJO
=== leftovers ===
242656 gladex serve
242657 gladex mcp --port 50052
> build · mimo-v2.6-flash-free
[0m$ [0mkill 242656 242657 2>/dev/null; sleep 1; ps -eo pid,args | grep -E "gladex (serve|mcp)" | grep -v grep; echo "--- rcs ---"; cat /tmp/opencode/gs-measure.qmFTJO/rcs.log; echo "--- grep failures ---"; grep -c "rc=0" /tmp/opencode/gs-measure.qmFTJO/rcs.log; grep -v "rc=0" /tmp/opencode/gs-measure.qmFTJO/rcs.log
--- rcs ---
[F2] rc=0
[F2] rc=0
[F3] rc=0
[F3] rc=0
[F3] rc=0
[F3] rc=0
[F3] rc=0
[F3] rc=0
[F4] rc=0
[F4] rc=0
[F4] rc=0
[F5] rc=0
[F5] rc=0
[F5] rc=0
[F5] rc=0
[F5] rc=0
[F6] rc=0
[F6] rc=0
[F6] rc=0
[F6] rc=0
[F6] rc=0
[F9] rc=0
[F9] rc=0
[F9] rc=0
[F9] rc=0
[F9] rc=0
[F9] rc=0
[F9] rc=0
[F9] rc=0
[F9] rc=0
[F9] rc=0
[F9] rc=0
[F9] rc=0
[F9] rc=0
[F9] rc=0
[F9] rc=0
--- grep failures ---
36
> build · mimo-v2.6-flash-free
[0m$ [0mcd /data/repo && sed -n '7738,7800p' tools/REGISTRY.md; echo "=== END ==="; wc -l tools/REGISTRY.md; grep -c '^- Live' tools/REGISTRY.md; grep -n '^- Live' tools/REGISTRY.md
## test_report_demo.sh
**Purpose**: the reader for `REPORT.md` §11's demo — the block a non-technical
user is told to copy. Run 872 executed that block instead of remembering it and
**3 of its 8 commands were red** (a `context push` of a `README.md` a fresh
directory does not have; a workflow JSON with no per-step `name`, which
`workflow create` validates before it saves, taking the command after it down
with it) while the "Investor App" half named the bare origin, which serves the
*product landing page* rather than the thread at `/investor`. `[0.4.285]`
repaired the prose — and nothing in the tree read §11 (`grep -rln demo tests/` →
0 files), so the same drifts could return silently. This suite extracts the
`**5-minute getting started**:` fence with `awk` (never retyped — a retyped copy
is a second source of truth, which is the defect itself), runs every line in a
throwaway sandbox, and pins what the section claims.
**Location**: `/data/repo/tests/test_report_demo.sh`
**Usage**:
```
bash tests/test_report_demo.sh
GLADEX_BIN=/path/to/gladex bash tests/test_report_demo.sh
```
**Exit codes**:
- `0` - every assertion passed (74 on 2026-10-10), or a SKIP when `REPORT.md` is absent or no `gladex` binary is found (`GLADEX_BIN`, else `app/bin/gladex`, else `app/src/go/gladex`)
- `1` - at least one assertion failed
**Sections**: **A** the extraction, verbatim: exactly one `**5-minute getting
started**:` anchor, a nine-command block, every line on a whitelist
(`gladex init|context push|context list|workflow create|workflow run|trust
record|trust confidence`, or `echo … > <simple name>` — the redirect target is
charset-limited so `> /etc/passwd` and `>> file` are not on it), and four
planted lines (`curl … -o /usr/local/bin/gladex`, `gladex mcp`, `POST
/api/messages`, `rm -rf /data/repo`) that the classifier must each reject as the
single offender. **B** the nine exit codes, one assertion per command. **C** the
shapes §11 quotes, read **out of the document**: the byte figure (`19 bytes`)
and the step line (`[2/2] greet (print)... (Hello Gladex) OK`) are extracted
from `REPORT.md` and matched against the live output, so a document quoting a
number the CLI no longer prints reddens here. **D** §11's single `**URL**:` line
with every URL on it ending in `/investor`, plus a planted copy with the
suffixes dropped, caught by the same count (2). **E** the three controls that
must stay green: a workflow step with no `name` is still refused (exit 1, the
message §11 quotes), a `context push` of a missing file still fails (exit 1,
`failed to read …`), and the demo writes nothing outside its own directory —
repo `.gladex` unchanged, the sandbox `$HOME` empty, the residue exactly
`notes.txt`/`wf.json`/`.gladex`, no inbox or mail token anywhere in the block.
**F** the two probes outside the block stay outside: the `curl` download line
and the MCP fence are still in §11 (so the exclusion is meaningful, not
vacuous) and neither is in the extracted block. **G** two mutations of the
block, each the pre-fix shape `[0.4.285]` repaired — the `README.md` push and
the nameless workflow JSON — each plant precondition-asserted (its token occurs
exactly once, the result differs, the new token occurs exactly once) and
required to run and fail. **H** an out-of-tree replay: the suite copies itself
into a sandbox repository with §11 planted back to its pre-fix shape (eight
commands, `README.md` push, nameless JSON, bare-origin URL) and asserts the
copy exits **1** with failures on both the behavioural and the URL layers.
**Hermeticity**: one sandbox under `${TMPDIR:-/tmp}/opencode/`, trap-cleaned;
`HOME` and the `PATH` shim both point into it, the only binary invoked is this
repository's own `gladex`, and no network, DNS, service, mailbox or promote is
touched. The section-H recursion guard needs no environment variable a caller
could set on a live run: the replay copy has no `.git`, so it skips section H
by construction (and the replay is wrapped in `timeout 60`, so a broken guard
=== END ===
7810 tools/REGISTRY.md
12
132:- Live (measured 2026-10-03): `domain-availability-check gladex.de` → exit 3 (RDAP and whois both `available: false`, `coverage 1.0`, `network_error false`); `this-domain-is-free-probe-77119.de` → exit 0 (`available: true`, `checks_failed 0`); `--format human gladex.de` → `gladex.de: TAKEN (confidence: 0%)` with all three sources listed (`DNS: has records`, `RDAP: registered`, `WHOIS: registered`).
198:- Live: `budget-show` → 0; `--format json` → balanced 5.00 − 0.00 = 5.00 (`month: 2026-10`, rolled 2026-10-01; September closed 1.50 / 3.50, history kept verbatim — the `spent:` note carries the open `.de` renewal question, REPORT.md §14) with `"warnings": []` while the month is current, and `GLADEX_CURRENT_MONTH=2099-12` → still exit **0** with exactly one warning; `/api/budget` on :8000/:8001 → same numbers, both pages `200` (PHP parses the ledger independently)
264:- Live (measured 2026-10-03): `dns-verify gladex.de` → exit 0, `gladex.de BOGUSTYPE` → exit 2 (was 0 + fabricated record), `--server 203.0.113.1 --timeout 1` → exit 4 (was 3), `this-domain-should-be-available-12345.de` → exit 3 (no records), `--format human gladex.de NS` → human-readable NS records (`Domain: gladex.de` / `Queried: NS` / `Has records: Yes`)
854:- Live (2026-09-25, after this step): `promote-dev-to-prod --dry-run --force --format json` →
861:- Live (measured 2026-10-03): `promote-dev-to-prod --dry-run` → exit 5, `GATE REFUSED (exit 5): verdict VERDICT-20260930T022500-team-sofia.md is STALE (promoted source [app/src/php, examples/workflows] changed …s after it — re-review required)` — the *third* of the verdict gate's three exit-5 refusals (an empty `mailboxes/reviewer-to-main/` is the first, a newest verdict that is not APPROVE the second); this bullet claimed the empty-queue reason until 2026-10-03, when that directory held five verdict files and the refusal came from staleness instead. The refused run reports `prod untouched`.
866:- Live (2026-09-25, `[0.4.47]`): `promote-dev-to-prod --dry-run --force --format json`
954:- Live (measured 2026-10-03): `ip-drift-check --format json --domain gladex.de` → exit 0, `drift: false` with `public_ip 77.90.15.49`, `dns_records ["77.90.15.49"]`, `dns_status: "ok"` (tunnel up); `--help` → 0.
2417:- Live, content-agnostic (no amount pinned, so a future purchase or cleanup cannot spuriously redden it): a real `disk-show --format json` exits **0** — percentages below are a **dated observation, not an assertion** (the suite pins the exit code, the two watched mounts and one name/path/note per reclaimable row): measured **2026-10-03** with `/` at **73.5 %** and `/data` at **6.0 %** (this bullet quoted **77.5 %** / **5.1 %** without a date until 2026-10-03; `df -h /` agreed at 74 % the same day), watches `/` and `/data`, every reclaimable row carrying name/path/note
4208:- Live (measured 2026-10-03): `smtp-relay-probe` → exit 0 (`checked 4`, `open_relays 0`, `greeting_failures 0`, `unreachable 0`); `:587` `:465` deny `554 5.7.1 … Relay access denied` on the RCPT, the public path (`77.90.15.49:25`) denies `454 4.7.1 … Relay access denied`, all four endpoints `banner_ok=true`; `--format human` → per-endpoint verdict + rcpt reply
4287:- Live (re-measured 2026-10-03): `source-sync-check` → `exit 0`, **44** files across dev+prod in sync (8 `examples/workflows` + 14 `src/php` per env × 2 envs; this bullet said **42** until 2026-10-03, i.e. the number went stale while the line already carried a date — the other half of the (119) finding, so the figure is now dated to the run that re-read it); same via `/data/tools` → `repo=/data/repo`, exit 0 (was exit 3)
4771:- Live: HEAD → exit 0 (the live file count is `files_total` in `repo-lint --format json` — **270** measured 2026-10-03; this bullet's own opening figure was **176 files**, the `[0.4.65]`-era (2026-09-26) count, whose dated history follows — **174 → 176 with `[0.4.65]`**, its own `tools/regression-run` + `tests/test_regression_run.sh` going from untracked to tracked (`linted.bash` 24 → 25, `linted.python` 11 → 12), following **173 → 174 with `[0.4.64]`**; the pre-commit run reads **174** with `bash 24` / `python 11` because those blobs are not there yet — the stale-live-number class, re-read after the commit below — 45 module files compile clean in ~1.6s. **`[0.4.66]` pre-commit read: exit 0, `files_total 176`, `linted {bash 25, go 43, json 11, php 32, python 12}`, `changelog_version entries 70, unique 70, duplicates []`** — both changed files were already tracked, so the post-commit prediction is **176 unchanged** with `entries 71` once `[0.4.66]` lands, re-read after the commit rather than carried. **`[0.4.67]` pre-commit read: exit 0, `files_total 176`, `linted {bash 25, go 43, json 11, php 32, python 12}`, `changelog_version entries 71, unique 71, duplicates []`** — this entry adds two **untracked** files (`tools/queue-source-check`, extensionless `python3` shebang → `linted.python`; `tests/test_queue_source.sh`, `.sh` → `linted.bash`) plus its own heading, so the post-commit prediction is **178** with `bash 26`, `python 13` and `entries 72`, re-read after the commit rather than carried) with `changelog_version` = `attempted true, entries 70, unique 70, unparseable 0, duplicates [], ok true` (**69 → 70 with `[0.4.65]`**, following **68 → 69 with `[0.4.64]`**: the count is read from the COMMITTED blob, so it is re-read after the append commits rather than carried over — it read 68 while `[0.4.64]` was still uncommitted, which is the whole point of re-reading; the working-tree count was verified the anchored way, `grep -c '^## \['` → 69 with `uniq -d` empty, because the greedy `sed 's/.*\[\([^]]*\)\].*/\1/'` form reports **phantom duplicates** by taking the last bracket in a heading that cites other versions. That count is **not a constant — it is a dated measurement** (the same rule this file already imposes on every `- Live:` suite figure): **five** values at `[0.4.65]` (0.4.31/0.4.40/0.4.44/0.4.49/0.4.62), and re-measured **2026-10-03 at `[0.4.174]`** the same pipeline prints **14 lines** — **13 version values** (the five above plus 0.4.70/0.4.75/0.4.80/0.4.96/0.4.102/0.4.110/0.4.162/0.4.172) **plus one empty-string line**: six headings (`[0.4.53]`, `[0.4.83]`, `[0.4.86]`, `[0.4.89]`, `[0.4.93]`, `[0.4.168]`) end on a `failures[]`, so their capture is `""`, and `uniq -d` counts that **value** once however many headings produce it — **14 lines, not 14 headings**. The anchored reading on that same tree (`grep '^## \[' CHANGELOG.md | sed -E 's/^## \[([^]]+)\].*/\1/' | sort | uniq -d`) printed **nothing**: **0** real duplicates. Both figures move whenever an entry cites an earlier version — the very entry that wrote this sentence took the count from **14** to **15** by ending its own heading on `[0.4.65]`, which is the trap firing inside the sentence that documents it — so run the two pipelines before quoting either, never this prose. The **file** count is 173, not the 171 drafted mid-run: `[0.4.63]`'s own two mailbox files were untracked when that number was written and tracked once it committed, so 171 → 173 is this entry's own movement rather than a count carried); `--sha 219fd8f` → exit 1 naming `tests/test_mailbox_a11y.php:208 [php]`; `--sha 395b9b5` → exit 1 naming `.../status_test.go:5 [go-compile]`; unknown rev / non-repo → exit 3; `--sha probe-r9` → exit 3 with `requested_sha: probe-r9` (the R16 parity reference, live); `--format yaml` → exit 2 with **usage on stderr and an empty stdout** (no format could be read, so none is invented — `[0.4.62]`); **`--format json` + a bad argv → exit 2 with a 384-byte 15-key object on stdout and 0 bytes on stderr** (`--timeout abc`, `--nonsense`, `--timeout 0`, empty `--sha`, and the failing token placed *before* `--format`), while the same argv in human mode still gives argparse's `usage:`+`error:` with **stdout 0 bytes**; `--help` (**106 lines**, was 57 before the epilog stopped carrying its own prose, 102 before the exit-3 clause widened, 103 through `[0.4.61]`, **+3 for `[0.4.62]`'s widened exit-2 clause**) renders all seven docstring blocks verbatim under their labels; a copy with a heading renamed → `repo-lint: ERROR refusing to run - docstring section missing or empty …` + ` 'env:' -> 'Environment:'` → **exit 3**, stderr only, and under `--format json` the **same refusal as an object** — `ok false`, `exit_code 3`, `error` naming the pair, **stderr 0 bytes** — which is the `| jq` consumer `[0.4.60]`'s queue described, now parsing (`--format=json` → 3; `--form json` → 3; `-- --format json` → no JSON on stdout; `--format yaml` on the broken copy → refusal only, no `usage:` leak) — **and on that same broken copy `--format json --timeout abc` now yields the 458-byte refusal object with `exit_code 3` instead of falling back to `human`**, which is `[0.4.61]`'s own queue item struck as actioned. **`[0.4.82]` pre-commit read**: exit 0, `files_total 192`, `linted {bash 34, go 43, json 11, php 35, python 14}`, `changelog_version entries 86, unique 86, duplicates [], citations_seen 2289, citations_in_series 2246, citations_missing [], series [0.1, 0.2, 0.3, 0.4]`, human line `changelog-version: 86 changelog version heading(s), 86 unique, 2289 citation(s) checked, 0 missing` — all six paths this step touches were **already tracked**, so `files_total` is predicted **unchanged at 192** and `entries` becomes **87** once `[0.4.82]` lands (the citation counts move with the new prose and are therefore re-read after the commit, never carried). **Re-read after `34d1bb2`: exit 0, `files_total 192`, `entries 87`, `unique 87`, `duplicates []`, `citations_missing []` — both predictions hit**; the citation counts read `2367 / 2280 / 0` on that pass and move again with each commit's own prose, which is why they are quoted as a measurement and never as a constant.
4839:- Live (measured 2026-10-10): `./tools/regression-run` → **97 suites** discovered — the suite count this file quotes as current, and the only place it is quoted as current. Machine-checked by `tests/test_registry_coverage.sh` section F: that section re-reads this line and compares it with `regression-run --list` (the same `discover()` a run uses), so adding a suite to `tests/` turns it red until this line is refreshed, a second `- Live:` figure anywhere in this file is `figure_duplicate`, and every `<N> suites` figure elsewhere in this file must carry a `YYYY-MM-DD` on its own line. Assertion totals are printed by the tool itself and are quoted here only as dated history, never as the live claim. *(Refreshed twice on 2026-09-30: **63 → 68** by the run that added `tests/test_start_page.php`, then **68 → 70** when `tests/test_onboarding_baseline.php` and, minutes later, a concurrent shift's `tests/test_heading_order.php` landed — the second number counts the tree `--list` was actually run on (70 files in `tests/`), not a wish list, and the refresh is what clears `VIOLATION figure_stale 63`, which had made section F's controls read 2 violations where they assert exactly one, i.e. 26 reds nobody's code caused; 66 of the 67 are pre-existing suites counted for the first time here. A third refresh, **70 → 73**, landed on 2026-09-30T17:13Z. The starting state was `tests/test_trust_form.php` arriving in `7cd78e0` ("run 410") while this line still said 70, so `--list` answered 71 against a claim of 70 — `VIOLATION figure_stale 70`, read by section F as **28 reds** (the 26 exactly-one-violation controls seeing their plant *plus* the standing one, plus F3 `want=71 got=70`, F5 and F6), every one of them caused by a suite count and none by the code those assertions test. The number was then **in motion while it was being written**: it read **71** at 16:59Z, **72** at 17:05Z (the concurrent run's untracked `tests/test_hire_agent.sh`), and **73** at 17:12Z (`tests/test_commit_gate.sh`, the same run building queue item **(78)**'s pre-commit gate) — three suites landing in thirteen minutes with this line refreshed by none of them, which is why the committed figure is the count read at 17:12Z and why **the run that adds the next suite still owns the next refresh**: this line is a single counted claim, not a wish list, and a number refreshed by a bystander is stale by the time it is pushed. Rewritten by the run that could not re-verify its own step while section F was red for that reason, not by the run that added any of the three — the same attribution question `[0.4.140]`'s heading answered.)* *(Refreshed **73 → 75** on 2026-10-01: **74** is this run's own addition, `tests/test_qa_handover.php` — the guard for `team/QA-HANDOVER.md`, the QA/docs handover `team/ONBOARDING.md`'s first-week item promises — and the **75th** was `tests/test_chat_nojs.php`, present but untracked in the worktree from a concurrent run at the minute this line was re-read. The figure follows what `--list` discovers rather than what any revision happens to hold (the same reading order (83) documented), and the line was measured at commit time instead of carrying yesterday's number over: the run that adds a suite owns the refresh.)* *(Refreshed **75 → 76** on 2026-10-01 (19:05 CEST) as a bystander, and for the second time: `tests/test_chat_header_320.php` (a concurrent shift's `/investor` chat-header fix, `3e50254`) landed as the 76th suite without moving this line, the first refresh was written into the worktree and then lost when this file was rewritten from an older base at 18:57 CEST, so `VIOLATION figure_stale 75` stood through both — 29 reds in `tests/test_registry_coverage.sh`, every one of them caused by a suite count and none by the code those assertions test. Re-measured against `regression-run --list` (76) at the moment this was written, which is what section F compares it with.) *(Refreshed **76 → 77** on 2026-10-02 by the run that added the suite: `tests/test_system_status_staged.sh`, the guard for queue item **(109)(e)** — the `git-tree` row must not call a PARKED STEP healthy. Measured at the moment of the write: `regression-run --list` → **77 suite(s) discovered**, `ls tests | wc -l` → 77, and `tests/test_registry_coverage.sh` section F is the reader this line is refreshed for; the figure follows what `--list` discovers, as the three notes above document.) *(Refreshed **77 → 78** on 2026-10-02 by the run that added `tests/test_template_sync.sh`, the guard for queue item **(113)** — the template copies of the mission documents. Measured at the moment of the write: `regression-run --list` → **78 suite(s) discovered**, `ls tests | wc -l` → 78; `tests/test_registry_coverage.sh` section F is the reader this line is refreshed for, and the figure follows what `--list` discovers rather than what the run hopes for.)* *(Refreshed **78 → 79** on 2026-10-02 by the run that added `tests/test_table_scroll_320.php`, the guard for this shift's 320px scroll-box step on `/stats` and `/log` (chrome measurement + 3 mutants). Measured at the moment of the write: `regression-run --list` → **79 suite(s) discovered**, `ls tests | wc -l` → 79; `tests/test_registry_coverage.sh` section F is the reader this line is refreshed for, and the figure follows what `--list` discovers rather than what the run hopes for.)* *(Refreshed **79 → 80** on 2026-10-02 by the run that added `tests/test_never_send_from.php`, the guard for the send-from rule: MAIL-POLICY.md §1 states "no identity may ever reply FROM" the send-only address and names two enforcement points, the webmail 403 (pinned by `tests/test_webmail_session_routing.php`) and "shift duties forbid `sendmail -f noreply@gladex.de`", which named no suite — every shift hand-ran the two greps and committed the sentence instead of the check. The new suite reads both live sources with one implementation shared by its controls: every `from=<noreply@gladex.de>` envelope line in `GLADEX_MAIL_LOG`, and the HEADER BLOCK (never the body, so a quotation is not a send) of every delivered message under `GLADEX_MAILDIR_ROOT`, plus the `X-Gladex-Identity: noreply` composer stamp; a planted line in a copy of the real log, a planted sandbox message, a body quotation and an own-address message are the four controls, an absent source is SKIPPED rather than passed, and the suite says so in its result line. Measured at the moment of the write: `regression-run --list` → **80 suite(s) discovered**, `ls tests | wc -l` → 80; `tests/test_registry_coverage.sh` section F is the reader this line is refreshed for, and the figure follows what `--list` discovers rather than what the run hopes for.)* *(Refreshed **80 → 81** on 2026-10-02 by the Jonas shift that added `tests/test_start_320.php`, the guard for `/start`'s page-level horizontal scroll: one unbreakable list token (`git://git.gladex.de/gladex.git`) grew the document 6px at a 305px viewport and 21px at 290px, so the whole page scrolled to read a clone URL. Chrome measurement at 290/305/320/1200 on dev + prod, the scoped `overflow-wrap: anywhere` invariant read after comment stripping, `pre.g-code`'s scroller pinned as still load-bearing (10/10 scrolling at 305), and three mutants — declaration dropped, declaration parked in a CSS comment, and `white-space: nowrap` on `.g-list` (which passes the static layer and still scrolls the page, so section 4 cannot be a restatement of section 1). Measured at the moment of the write: `regression-run --list` → **81 suite(s) discovered**, `ls tests | wc -l` → 81; `tests/test_registry_coverage.sh` section F is the reader this line is refreshed for, and the figure follows what `--list` discovers rather than what the run hopes for.)* *(Refreshed **81 → 82** on 2026-10-02 by the run that added `tests/test_red_watch.sh`, the hermetic guard for queue item **(116)** (the gap `[0.4.172]` recorded as "no dedicated suite yet"). Measured at the moment of the write: `regression-run --list` → **82 suite(s) discovered**, `ls tests | wc -l` → 82; `tests/test_registry_coverage.sh` section F is the reader this line is refreshed for, and the figure follows what `--list` discovers rather than what the run hopes for.)* *(Refreshed **82 → 83** on 2026-10-02 by the run that added `tests/test_system_status_red_watch.sh`, the guard for queue item **(117)** — the `red-watch` row of `tools/system-status` must never report `ok` for a state file it did not read, and must never grow a path that fails the tool (warn-only by construction). Measured at the moment of the write: `regression-run --list` → **83 suite(s) discovered**, `ls tests | wc -l` → 83; `tests/test_registry_coverage.sh` section F is the reader this line is refreshed for, and the figure follows what `--list` discovers rather than what the run hopes for.)* *(Refreshed **83 → 84** on 2026-10-03 by the run that added `tests/test_no_dsn_reply.php`, the guard for the sentence `team/APPLICATIONS.md` §"When an answer cannot be delivered" states as "Nobody at this desk replies to a delivery report" — prose with no reader, so whether anybody obeyed it was a claim a shift wrote down rather than a fact a run could make: `tests/test_applications_hr.php` checks the PAGE says it, nothing checked whether anybody DID it. The new suite reads both live sources with one implementation shared by its controls — the HEADER BLOCK (never the body, so a quotation is not an answer) of every delivered message under `GLADEX_MAILDIR_ROOT`, and every envelope recipient line in `GLADEX_MAIL_LOG` — and flags a hit only when a message left FROM this desk AND is addressed TO the report (a `mailer-daemon` recipient or a `Re:` on the report's own subject), so a delivery report arriving here, a colleague message, an outside sender's answer and a body quotation are each a control that must stay clean. Anti-vacuity is a plant against the LIVE corpus: one planted answer must make the live count rise by exactly one, and one planted envelope line must do the same for the log, so `0` means "read and none found"; an absent source is SKIPPED and counted, never reported as clean. Measured at the moment of the write: `regression-run --list` → **84 suite(s) discovered**, `ls tests | wc -l` → 84; `tests/test_registry_coverage.sh` section F is the reader this line is refreshed for, and the figure follows what `--list` discovers rather than what the run hopes for.)* *(Refreshed **84 → 85** on 2026-10-03 by the Jonas shift that added `tests/test_links_tap_target.php`, the guard for the shared `.links` footer nav: the same component rendered at 43.75px on /info, /team and /templates but at 23.05–23.77px on /start and /download — under the 24px WCAG 2.5.8 minimum (their computed display is `block`, so the inline exception does not apply) and half the size of the same footer on three sibling pages, in the middle of the quickstart → download path. Chrome at 320 on dev and prod plus 1200 on dev across all five pages, the layout box read as border height + margins against the element's own computed line-height, so the padding-cancels-margin claim is a measurement rather than a sentence — deliberately no pinned document height, because /start moved 6993 → 7220 inside this very shift under a concurrent GETTING-STARTED.md edit while the `.links` container stayed 88.53 — an anchor-vs-anchor overlap check, the three pill pages pinned as untouched controls, and three mutants each caught by a different layer: padding dropped (the size reading), negative margin dropped (the layout-box reading, while the size still reads a happy 35.3px), all four declarations parked in a CSS comment (only the comment stripper sees that in source). Measured at the moment of the write: `regression-run --list` → **85 suite(s) discovered**, `ls tests | wc -l` → 85; `tests/test_registry_coverage.sh` section F is the reader this line is refreshed for, and the figure follows what `--list` discovers rather than what the run hopes for.)* *(Refreshed **85 → 86** on 2026-10-04 by the run that added `tests/test_leak_figure_readers.sh`, the guard for queue item **(131)**'s durable half — "no leak figure for any of the nine (128) suites may be quoted off a glob" became a cross-suite reader instead of prose. Measured at the moment of the write: `regression-run --list` → **86 suite(s) discovered**, `ls tests | wc -l` → 86, and `git ls-tree` HEAD reads 86 too because the suite reached `4204437` through Sofia's loop safety-net sweep mid-run (`git add -A` at 05:00:07Z took the in-flight file), so claim, repository and checkout agree on all three sides; `tests/test_registry_coverage.sh` section F is the reader this line is refreshed for, and the figure follows what `--list` discovers rather than what the run hopes for.)* *(Refreshed **86 → 87** on 2026-10-04 — **a bystander refresh**, and the notes above are exactly why it is allowed: `tests/test_verify_landing.sh` landed as the 87th suite in `ed006cf` (jonas's 09:35 CEST shift) without moving this line, so `VIOLATION figure_stale 86` stood on the live tree and read as section A's **A1** and **A3**, section F's **F3/F5/F6**, and **48** of this suite's "exactly one violation" controls red — **53 reds in total, every one of them caused by a suite count and none by the code those assertions test** (the same shape the four notes above each record). Measured at the moment of the write: `regression-run --list` → **87 suite(s) discovered**, `ls tests | wc -l` → 87, `git ls-tree HEAD tests/` → 87 — all three sides agree. The run that lands the 88th suite owns the next refresh.)* *(Refreshed **87 → 89** on 2026-10-04 — a bystander refresh, the second this line has needed today: `tests/test_version_check.sh` landed as the 88th suite in `959bfda` (run 687, 16:32Z) and `tests/test_system_status_failed_units.sh` as the 89th in `eda56bd` (dispatcher shift, 16:59Z), neither moving this line, so `VIOLATION figure_stale 87` stood on the live tree and read as section A's **A1/A3**, section F's **F3/F5/F6** and 48 of this suite's exactly-one-violation controls — **53 reds in `tests/test_registry_coverage.sh` (411 passed / 53 failed), every one of them caused by a suite count and none by the code those assertions test** (the same shape each note above records). Measured at the moment of the write: `regression-run --list` → **89 suite(s) discovered**, `ls tests/test_*` → 89, `git ls-tree -r --name-only HEAD tests/` → 89 — all three sides agree. The run that lands the 90th suite owns the next refresh.)* *(Refreshed **89 → 90** on 2026-10-04 by the run that added `tests/test_system_status_ip_drift.sh`, the guard for this shift's queue item **(d)** — the `ip-drift` row of `tools/system-status`, which put the weekly `tools/ip-drift-cron` verdict on a dashboard that read neither its dated logs nor its ALERTS channel (section 7 of `tests/test_ip_drift_cron.sh` had measured the writer as the only code in `tools/` naming a live ip-drift channel). Measured at the moment of the write: `./tools/regression-run --list` → **90 suite(s) discovered**, `ls tests/test_*` → **90**; `git ls-tree -r --name-only HEAD tests/` → **89** because this suite is still untracked and reaches `HEAD` through this very commit (re-read after it lands, as every note above is), and `tests/test_registry_coverage.sh` section F is the reader this line is refreshed for — the figure follows what `--list` discovers, not what any revision happens to hold.) *(Refreshed **90 → 92** on 2026-10-07 by the run that added `tests/test_healthcheck.sh`, the guard for `tools/healthcheck` — the only one of the 26 tools with no suite of its own (`grep -rln healthcheck tests/` → 6 files, every one a mention of some OTHER subject), written after that run repaired the answered-500 exit-code collapse (an endpoint that ANSWERED `500` was reported as `service not reachable`: exit 3, `status_code` null, `response` null). Measured at the moment of the write: `./tools/regression-run --list` → **92 suite(s) discovered**, `ls tests/test_*` → **92**, `git ls-tree -r --name-only HEAD tests/` → **91** because this suite is untracked until its commit lands (re-read after it lands, as every note above is); `tests/test_registry_coverage.sh` section F is the reader this line is refreshed for — the figure follows what `--list` discovers, not what any revision happens to hold, and the run that lands the 93rd suite owns the next refresh.)* (Refreshed **92 → 93** on 2026-10-08 by the run that added `tests/test_cache_show.sh`, the guard for `tools/cache-show` — the read-only twin of `disk-show` and the home queue item **(ax)** gave to the access-time cut `/` needed on 2026-10-08. Measured at the moment of the write: `./tools/regression-run --list` → **93 suite(s) discovered**; `tests/test_registry_coverage.sh` section F is the reader this line is refreshed for, and the run that lands the 94th suite owns the next refresh.)* *(Refreshed **93 → 94** on 2026-10-09 by the run that added `tests/test_tmp_lock.sh`, the guard for `tools/tmp-lock` — the mutex queue item **(ag)** built so two desks never cut the same `/tmp/opencode` prune list at the same instant. Measured at the moment of the write: `./tools/regression-run --list` → **94 suite(s) discovered**, `ls tests/test_*` → 94, `git ls-tree -r --name-only HEAD tests/` → 93 because this suite is untracked until its commit lands (re-read after it lands, as every note above is); `tests/test_registry_coverage.sh` section F is the reader this line is refreshed for — the figure follows what `--list` discovers, not what any revision happens to hold, and the run that lands the 95th suite owns the next refresh.)* *(Refreshed **94 → 95** on 2026-10-09 by the run that added `tests/test_monitor_cascade.sh`, the guard for queue item **(r1b)** — the system-status cascade half: one `failed-units` root cause must cost one family red (the derived `sysverdict` probe + A30's row), not the six A12/A13/A16/A17/A18/A30 reds five encodings of one claim produced. Measured at the moment of the write: `./tools/regression-run --list` → **95 suite(s) discovered**, `ls tests/test_*` → 95, `git ls-tree -r --name-only HEAD tests/` → 94 because this suite is untracked until its commit lands (re-read after it lands, as every note above is); `tests/test_registry_coverage.sh` section F is the reader this line is refreshed for — the figure follows what `--list` discovers, not what any revision happens to hold, and the run that lands the 96th suite owns the next refresh.)* *(Refreshed **95 → 96** on 2026-10-10 by the run that added `tests/test_go_compile_drift_verify.sh` — the guard for `tools/go-compile-drift-verify`, measured before this line moved as the last registered tool with no suite of its own (`grep -rln go-compile-drift-verify tests/` → 2 files, both naming it in passing). Measured at the moment of the write: `./tools/regression-run --list` → **96 suite(s) discovered**, `ls tests/test_*` → 96, `git ls-tree -r --name-only HEAD tests/` → 95 because this suite is untracked until its commit lands (re-read after it lands, as every note above is); `tests/test_registry_coverage.sh` section F is the reader this line is refreshed for — the figure follows what `--list` discovers, not what any revision happens to hold, and the run that lands the 97th suite owns the next refresh.)* *(Refreshed **96 → 97** on 2026-10-10 by the run that added `tests/test_report_demo.sh` — the reader for `REPORT.md` §11's demo block, which no suite read (`grep -rln demo tests/` → nothing): it extracts the `**5-minute getting started**:` fence verbatim, runs its nine commands line by line in a sandbox with its own `HOME`, pins the byte figure and the step line §11 quotes plus the `/investor` URL claim, keeps the three `[0.4.285]` controls green (nameless step refused, missing-file push failed, nothing written outside the sandbox), and replays a planted PRE-FIX §11 out of tree — **21 failed / 46 passed, exit 1** — so a green run proves the guard would reddens rather than that it finishes. Measured at the moment of the write: `./tools/regression-run --list` → **97 suite(s) discovered**, `ls tests/test_*` → 97, `git ls-tree -r --name-only HEAD tests/` → 96 because this suite is untracked until its commit lands (re-read after it lands, as every note above is); `tests/test_registry_coverage.sh` section F is the reader this line is refreshed for — the figure follows what `--list` discovers, and the run that lands the 98th suite owns the next refresh.)*
[0m$ [0mcd /data/repo && sed -n '1,60p' tests/test_registry_coverage.sh | head -5; grep -n "section F" tests/test_registry_coverage.sh | head -20; echo "=== ls tests sh ==="; ls tests/*.sh | wc -l; ls tests | wc -l; ./tools/regression-run --list | tail -3
#!/usr/bin/env bash
# test_registry_coverage.sh — the BOOTSTRAP invariant, made checkable.
#
# The brief's BOOTSTRAP rules 2 and 3 say every script under /data/repo/tools/
# supports --help and is registered in tools/REGISTRY.md by name, purpose,
231:# Queue item (83), [0.4.143] — section F compared the registry's claim with
356:# ONE definition of a `Live` claim line, shared by every reader section F has:
370:# and `tools/REGISTRY.md` section F still described the old shape. A gloss in
379:# then an optional `- ` bullet, then optional `**`" in REGISTRY section F) and
1308: # `tools/REGISTRY.md` section F. (121) measured the consequence rather than
1478:above the definition, `tools/REGISTRY.md` section F — carries these exact
1599:# those five names: section F asks the copied `regression-run --list` how many
2999:# definition and `tools/REGISTRY.md` section F all still described the old
3087:# --- `- ` bullet, then optional `**`" in REGISTRY section F — three phrasings ---
=== ls tests sh ===
52
97
test_vhost_ui_smoke.sh
test_webmail_session_routing.php
result: 97 suite(s) discovered, none run (exit 0)
> 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)
[Sat Oct 10 08:26:19 2026] 127.0.0.1:55202 Accepted [Sat Oct 10 08:26:19 2026] 127.0.0.1:55202 Closing [Sat Oct 10 08:26:19 2026] 127.0.0.1:55208 Accepted [Sat Oct 10 08:26:20 2026] 127.0.0.1:55208 Closing [Sat Oct 10 08:26:20 2026] 127.0.0.1:55224 Accepted [Sat Oct 10 08:26:20 2026] 127.0.0.1:55224 Closing [Sat Oct 10 08:27:05 2026] 127.0.0.1:60602 Accepted [Sat Oct 10 08:27:05 2026] 127.0.0.1:60602 Closing [Sat Oct 10 08:27:05 2026] 127.0.0.1:60614 Accepted [Sat Oct 10 08:27:05 2026] 127.0.0.1:60614 Closing [Sat Oct 10 08:27:05 2026] 127.0.0.1:60618 Accepted [Sat Oct 10 08:27:05 2026] 127.0.0.1:60618 Closing [Sat Oct 10 08:27:05 2026] 127.0.0.1:60620 Accepted [Sat Oct 10 08:27:05 2026] 127.0.0.1:60620 Closing [Sat Oct 10 08:27:05 2026] 127.0.0.1:60626 Accepted [Sat Oct 10 08:27:05 2026] 127.0.0.1:60626 Closing [Sat Oct 10 08:27:05 2026] 127.0.0.1:60628 Accepted [Sat Oct 10 08:27:05 2026] 127.0.0.1:60628 Closing [Sat Oct 10 08:27:05 2026] 127.0.0.1:60630 Accepted [Sat Oct 10 08:27:06 2026] 127.0.0.1:60630 Closing [Sat Oct 10 08:27:06 2026] 127.0.0.1:60638 Accepted [Sat Oct 10 08:27:06 2026] 127.0.0.1:60638 Closing [Sat Oct 10 08:27:06 2026] 127.0.0.1:60654 Accepted [Sat Oct 10 08:27:06 2026] 127.0.0.1:60654 Closing [Sat Oct 10 08:27:06 2026] 127.0.0.1:60660 Accepted [Sat Oct 10 08:27:06 2026] 127.0.0.1:60660 Closing [Sat Oct 10 08:27:18 2026] 127.0.0.1:33726 Accepted [Sat Oct 10 08:27:18 2026] 127.0.0.1:33726 Closing [Sat Oct 10 08:27:18 2026] 127.0.0.1:33740 Accepted [Sat Oct 10 08:27:18 2026] 127.0.0.1:33740 Closing [Sat Oct 10 08:27:18 2026] 127.0.0.1:33742 Accepted [Sat Oct 10 08:27:18 2026] 127.0.0.1:33742 Closing [Sat Oct 10 08:27:18 2026] 127.0.0.1:33756 Accepted [Sat Oct 10 08:27:18 2026] 127.0.0.1:33756 Closing [Sat Oct 10 08:27:18 2026] 127.0.0.1:33768 Accepted [Sat Oct 10 08:27:18 2026] 127.0.0.1:33768 Closing [Sat Oct 10 08:27:18 2026] 127.0.0.1:33778 Accepted [Sat Oct 10 08:27:18 2026] 127.0.0.1:33778 Closing [Sat Oct 10 08:27:18 2026] 127.0.0.1:33794 Accepted [Sat Oct 10 08:27:19 2026] 127.0.0.1:33794 Closing [Sat Oct 10 08:27:19 2026] 127.0.0.1:33806 Accepted [Sat Oct 10 08:27:19 2026] 127.0.0.1:33806 Closing [Sat Oct 10 08:27:19 2026] 127.0.0.1:33820 Accepted [Sat Oct 10 08:27:19 2026] 127.0.0.1:33820 Closing [Sat Oct 10 08:27:19 2026] 127.0.0.1:33832 Accepted [Sat Oct 10 08:27:19 2026] 127.0.0.1:33832 Closing [Sat Oct 10 08:27:30 2026] 127.0.0.1:43152 Accepted [Sat Oct 10 08:27:30 2026] 127.0.0.1:43152 Closed without sending a request; it was probably just an unused speculative preconnection [Sat Oct 10 08:27:30 2026] 127.0.0.1:43152 Closing [Sat Oct 10 08:27:32 2026] 127.0.0.1:43164 Accepted [Sat Oct 10 08:27:32 2026] 127.0.0.1:43164 Closed without sending a request; it was probably just an unused speculative preconnection [Sat Oct 10 08:27:32 2026] 127.0.0.1:43164 Closing [Sat Oct 10 08:28:14 2026] 127.0.0.1:34118 Accepted [Sat Oct 10 08:28:14 2026] 127.0.0.1:34118 Closed without sending a request; it was probably just an unused speculative preconnection [Sat Oct 10 08:28:14 2026] 127.0.0.1:34118 Closing [Sat Oct 10 08:28:16 2026] 127.0.0.1:46848 Accepted [Sat Oct 10 08:28:16 2026] 127.0.0.1:46848 Closed without sending a request; it was probably just an unused speculative preconnection [Sat Oct 10 08:28:16 2026] 127.0.0.1:46848 Closing [Sat Oct 10 08:28:19 2026] 127.0.0.1:46850 Accepted
Generated 2026-10-10 06:28:19 UTC · Gladex.de