Gladex Agent Logs
Agent run logs & app logs · env: prod · LAN-only investor surface
Overview
| Run logs | 1605 files, 117 MB |
| Latest run log | run-20261014-222900-1139.log |
| Log directory | /data/agent-logs |
| App log directory | /opt/startup/prod/logs |
Run logs (newest first, last 50)
| File | Size | Modified (UTC) |
|---|---|---|
| run-20261014-222900-1139.log | 142 KB | 2026-10-14 20:42:33 |
| run-20261014-212813-1138.log | 571 KB | 2026-10-14 20:18:50 |
| run-20261014-201639-1137.log | 370 KB | 2026-10-14 19:18:02 |
| run-20261014-174154-1136.log | 835 KB | 2026-10-14 18:06:28 |
| run-20261014-170319-1135.log | 320 KB | 2026-10-14 15:31:41 |
| run-20261014-161418-1134.log | 270 KB | 2026-10-14 14:53:09 |
| run-20261014-150444-1133.log | 323 KB | 2026-10-14 14:04:07 |
| run-20261014-133301-1132.log | 340 KB | 2026-10-14 12:54:34 |
| run-20261014-124552-1131.log | 194 KB | 2026-10-14 11:22:49 |
| run-20261014-103913-1130.log | 525 KB | 2026-10-14 10:35:42 |
| run-20261014-082946-1129.log | 630 KB | 2026-10-14 08:29:02 |
| run-20261014-061713-1128.log | 454 KB | 2026-10-14 06:19:36 |
| run-20261014-052042-1127.log | 96 KB | 2026-10-14 04:07:02 |
| run-20261014-044319-1126.log | 200 KB | 2026-10-14 03:10:30 |
| run-20261014-032502-1125.log | 531 KB | 2026-10-14 02:33:08 |
| run-20261014-024815-1124.log | 214 KB | 2026-10-14 01:14:52 |
| run-20261014-020537-1123.log | 283 KB | 2026-10-14 00:38:05 |
| run-20261014-015526-1122.log | 154 B | 2026-10-13 23:55:27 |
| run-20261014-014514-1121.log | 191 B | 2026-10-13 23:45:15 |
| run-20261014-013503-1120.log | 191 B | 2026-10-13 23:35:04 |
| run-20261014-012452-1119.log | 154 B | 2026-10-13 23:24:53 |
| run-20261014-011441-1118.log | 154 B | 2026-10-13 23:14:42 |
| run-20261014-010430-1117.log | 154 B | 2026-10-13 23:04:31 |
| run-20261014-005419-1116.log | 154 B | 2026-10-13 22:54:20 |
| run-20261014-004409-1115.log | 154 B | 2026-10-13 22:44:09 |
| run-20261014-003358-1114.log | 154 B | 2026-10-13 22:33:58 |
| run-20261014-002347-1113.log | 154 B | 2026-10-13 22:23:48 |
| run-20261014-001336-1112.log | 154 B | 2026-10-13 22:13:37 |
| run-20261014-000325-1111.log | 154 B | 2026-10-13 22:03:25 |
| run-20261013-235314-1110.log | 154 B | 2026-10-13 21:53:15 |
| run-20261013-234303-1109.log | 154 B | 2026-10-13 21:43:04 |
| run-20261013-233139-1108.log | 159 KB | 2026-10-13 21:32:53 |
| run-20261013-225919-1107.log | 255 KB | 2026-10-13 21:21:29 |
| run-20261013-222935-1106.log | 191 KB | 2026-10-13 20:49:08 |
| run-20261013-214526-1105.log | 128 KB | 2026-10-13 20:19:24 |
| run-20261013-203244-1104.log | 264 KB | 2026-10-13 19:35:16 |
| run-20261013-195951-1103.log | 283 KB | 2026-10-13 18:22:34 |
| run-20261013-192444-1102.log | 95 KB | 2026-10-13 17:49:40 |
| run-20261013-171515-1101.log | 585 KB | 2026-10-13 17:14:33 |
| run-20261013-161458-1100.log | 250 KB | 2026-10-13 15:05:05 |
| run-20261013-153047-1099.log | 183 KB | 2026-10-13 14:04:48 |
| run-20261013-144509-1098.log | 171 KB | 2026-10-13 13:20:37 |
| run-20261013-141129-1097.log | 228 KB | 2026-10-13 12:34:59 |
| run-20261013-123439-1096.log | 494 KB | 2026-10-13 12:01:17 |
| run-20261013-111017-1095.log | 471 KB | 2026-10-13 10:24:29 |
| run-20261013-102815-1094.log | 208 KB | 2026-10-13 09:00:06 |
| run-20261013-095340-1093.log | 162 KB | 2026-10-13 08:18:04 |
| run-20261013-075349-1092.log | 458 KB | 2026-10-13 07:43:30 |
| run-20261013-064410-1091.log | 387 KB | 2026-10-13 05:43:38 |
| run-20261013-052913-1090.log | 255 KB | 2026-10-13 04:34:00 |
Tail — run-20261014-222900-1139.log (last 200 lines)
### Fixed
- **Go CLI version train** (queued at 0.4.27): `app/src/go/build.sh` hardcoded `VERSION="0.2.0"`, so every rebuild reported **0.2.0** while the product train had moved to 0.4.x — the downloaded binary, the `/download` badge (`$version = '0.2.0'`) and two `/docs` mentions (`Go CLI binary (v0.2.0)` and the ASCII diagram's `gladex v0.2.0`) advertised numbers ~26 entries behind this changelog: exactly the drift class 0.4.27 closed for the app's nine stale `0.3.0` literals, just on the CLI side. `build.sh` also ignored the README-documented `VERSION=x.y.z ./build.sh` override (silently clobbered by the literal).
- **`gladex version --remote` was structurally incoherent**: it compares the local binary against `https://gladex.de/api/version` (the **app** train), so a CLI pinned at 0.2.0 reported "update available" against every already-current download — and would keep reporting it at whatever stale number the train stopped at. After this fix the check compares like with like: changelog top = app const = binary `version --json` = download badge = docs mentions.
- Fix: `build.sh` parses the top `## [x.y.z]` entry out of `CHANGELOG.md` (`VERSION=` env override preserved — README's documented custom-version invocation now actually works instead of being ignored); `/download`'s badge reads `GLADEX_APP_VERSION` instead of a literal; the two `/docs` CLI mentions carry the current train number and are now **guarded by a test** (they were unguarded, i.e. permanently stale-prone). App train moved to **0.4.28** with it (`GLADEX_APP_VERSION` + `/docs` payloads/footer, repo+dev+prod byte-identical). `build.sh` also `cd`s into its own directory first — module resolution starts at the CWD, so invoking it from anywhere but `app/src/go` (the repo root, `/tmp`) died with `go: cannot find main module` even though every other path in the script was already `SCRIPT_DIR`-relative; guarded behaviourally by building from the repo root.
- Rebuilt all four copies — `app/bin/gladex`, `app/src/go/gladex`, dev, prod — md5-identical, reporting `0.4.28`.
### Tests
- **`tests/test_cli_version.php`** (35 assertions, 3 mutations): `build.sh` derives from the changelog with no hardcoded `VERSION="x.y.z"` literal, keeps the env override and `cd`s to its script dir (behavioural: built from the repo root — the cwd trap — reporting the changelog top, and from `/tmp` with `VERSION=9.9.9` where the override must win); `download.php` has no version literal (token scan; comments don't count) and renders the badge from the const (behavioural: const `9.9.9` → badge `v9.9.9`, proving wiring not coincidence; standalone-without-const → `0.0.0` sentinel); the two `/docs` CLI mentions parse and equal the changelog top (stale number → FAIL); all four binaries report the changelog top via `version --json` with a real commit sha and are md5-identical. Mutations that MUST be detected: reintroduced `$version = '0.2.0'` (static + behavioural), reintroduced `VERSION="0.2.0"` in build.sh, stale `gladex v0.1.0` docs mention.
### Notes
- Trains are now ONE. `version.go`'s `0.1.0-dev` fallback (plain `go build`, no ldflags) is deliberate and unchanged — README documents it as the quick-build default. Binary `commit:` embeds the source commit (built after commit 1 of this run, before the binary commit).
## [0.4.27] - 2026-09-24 — version drift closed: nine stale `0.3.0` literals across app+docs collapse into one `GLADEX_APP_VERSION` constant sourced from this changelog
### Added
- **`const GLADEX_APP_VERSION`** (top of `app/src/php/app.php`) — the single place the app version lives: `/healthz`, `/api/version`, `/api/health`, `/api/changelog` and `/api/endpoints` all report it instead of five duplicated literals; CHANGELOG.md is the version train, the constant must equal its top entry.
- **`gladex_app_version_of($path)`** in `app/src/php/db.php` (included by both callers) — reads the version out of a *deployed* `app.php` copy without executing it: prefers `const GLADEX_APP_VERSION`, falls back to the old `'version' => '...'` pattern so a half-synced env copy reports its old-but-correct value instead of `unknown`. Used by the `/stats` page dev/prod rows and the `/api/stats` payload.
- **`tests/test_app_version.php`** (39 assertions, 3 mutations): constant declared exactly once and equal to the changelog top entry; five endpoint usages; no stray `'version' => 'x.y.z'` literals in app.php (the `gladex-stats` payload schema `0.1.0` is the allowlisted exception); the `db.php` helper resolves new-style, old-style, missing (`null`) and unparseable (`unknown`) fixtures plus the real file; `/docs` example payloads + footer match the constant; repo+dev+prod copies all agree with the changelog top; `php -l` on the four touched files. Mutations that MUST be detected: stale constant value, reintroduced stray literal, stale docs footer.
### Fixed
- **Version drift**: CHANGELOG has been the single version train since 0.3.0 — app features (team page, webmail, routing fixes) shipped under 0.4.x — yet every version-bearing surface still reported **0.3.0**: `/healthz`, `/api/version`, `/api/health`, `/api/changelog`, `/api/endpoints` (5 literals) and the `/docs` page (3 example payloads + `Gladex API Reference v` footer). All report 0.4.27 now: a reader of the changelog and of `/api/version` finally sees the same number.
- **`/stats` + `/api/stats` dev/prod version rows grepped `'version' => '...'`** — against the constant-based file that pattern skips past the constant and would match the `gladex-stats` schema literal, printing `0.1.0`; both rows now go through `gladex_app_version_of()`.
### Notes
- Deliberately NOT touched (separate version trains, out of scope for this step): the Go CLI (`build.sh` VERSION / `gladex version --json`) and the `gladex-stats` payload schema version.
### Verification
- repo copy first (env copies deliberately stale → suite must flag them), then dev+prod deployed: full suite green; `source-sync-check` in sync; `version-check` OK dev=prod=0.4.27; live `/healthz`, `/api/version`, `/docs` footer report 0.4.27 on both envs.
## [0.4.26] - 2026-09-24 — smtp-relay-probe now ASSERTS the 220 greeting (exit 4): a one-endpoint :25-greeting regression could no longer pass green
### Added
- **Greeting assertion in `tools/smtp-relay-probe`**: the banner phase is now
isolated and validated — an endpoint that CONNECTS but does not greet `220 `
within the socket timeout (timeout / EOF / non-220) is a hard failure, never
an "ok" and never folded into `unreachable`. New per-result `banner_ok` /
`greeting_error` fields, top-level `greeting_failures`, human `[GREETING FAIL]`
marker, and **new exit code 4** with documented precedence `1 > 4 > 3 > 0`.
Motivation: while verifying the operator's "live relay probe after the
:25-greeting fix" item, the gap was visible — the probe only *reported* the
banner, so a greeting regression on ONE of the four default endpoints would
still have exited 0.
- **`tests/test_smtp_relay_probe.sh` — 38 assertions**, hermetic (stub SMTP
servers good / openrelay / silent / bad-greeting on ephemeral ports; live
postfix and the VPS forward path never touched): relay exit 0/1/3 contracts,
`--expect-open`, both greeting-failure shapes → 4 (and NOT folded into
unreachable), the mixed-run regression guard (1 silent among healthy → 4,
previously silently 0), JSON/human/CLI contracts, static never-send-DATA
guard, and **2 mutations** (banner_ok flag defeated / 220 assertion defeated —
both mutants must actually RUN and wrongly exit 0 vs real 4; the first draft's
[0m$ [0mcd /data/repo && grep -n 'Tests\*\*' tests/test_registry_coverage.sh | head -20; echo "=== figread tests list ==="; grep -n "V1[0-9]\|shift" tests/test_registry_figure_readers.sh | head -20; echo "=== leak ==="; grep -n "shift-tally\|21-key" tests/test_leak_figure_readers.sh | head
=== figread tests list ===
268:# one (shift-deploy, **16.7 s** measured 2026-10-14 before its reader
330:V_NAMES="budget-show dns-verify disk-show source-sync-check smtp-relay-probe test_identity_wrapper.sh promote-dev-to-prod ip-drift-cron pdns-api.py domain-availability-check ip-drift-check shift-deploy immich-roundtrip regression-run system-status repo-lint"
338:# --- V2..V18: one section each — binding, extraction, then the child run ----
374:# --- V10..V13: run 951's priced-and-queued four, cheapest first -------------
395:# --- V14: run 953's queue line, the cheapest of the five sections it left ----
396:# (shift-deploy 16.7 s against immich-roundtrip 43.2, system-status 66,
399:sec_shift_deploy=$(sect "$LIVE_REG" shift-deploy)
400:fig_shift_deploy=$(printf '%s\n' "$sec_shift_deploy" | grep -E '\*\*[0-9]+ assertions\*\*' | head -1 | grep -oE '[0-9]+ assertions' | head -1 | tr -dc '0-9')
401:src_shift_deploy=$(printf '%s\n' "$sec_shift_deploy" | grep -E '\*\*[0-9]+ assertions\*\*' | head -1 | grep -oE 'tests/[A-Za-z0-9_.]+' | head -1)
402:v_check 14 shift-deploy "$fig_shift_deploy" "$src_shift_deploy"
404:# --- V15: run 955's queue line, the cheapest of the four run 954 left -------
413:# --- V16: run 956's queue line, the cheapest of the three run 955 left -------
425:# --- V17: run 957's queue line, the cheapest of the two run 956 left ---------
438:# --- V18: run 958's queue line — the LAST priced figure reader, the one run
=== leak ===
> build · mimo-v2.6-flash-free
[0m$ [0mcd /data/repo && tail -30 CHANGELOG.md | head -30; echo "=== qsc help ==="; ./tools/queue-source-check --help 2>&1 | head -60
- **`bash tests/test_attribution_gap.sh` → 80 passed / 0 failed, exit 0, 5.5 s** (was **58**), the new 22: **B7–B11** the unreadable-history class in both modes (exit 3 named, and *no clean verdict* asserted for `--all`); **F1b** an empty window excludes everything; **F4** the new `fx_split` fixture (covering shift 08:00, transcript swept again 18:00 the same day, caller's cutoff 12:00) is clean under `--all`; **F5/F5b** the same fixture under the mid-day cutoff: no gap, `window_open_day == "2026-10-13"`, both sets carrying exactly that day — the assertion run 959's queue named and section F lacked; **F6/F7** the day-granular window still *bites* (`--since 2026-10-14T00:00:00Z` reports lena's live-shape gap and nothing from the days outside it); **J4** the BARE default invocation carries a resolved window day while `--all` carries none; **J5** the agreement on `/data/repo`; and **M5/M6**, two precondition-asserted mutations of the new cut — the covering side's cut defeated (which is `[0.4.349]`'s split in its original one-sided form: caught because pre-window shift days leak into an empty window, with `--all` byte-identical under the mutant) and the touch side's symmetric half (caught *and* it moves the **gate** from 0 to 1 on a window holding no commit).
- **The negative control, run against the pre-fix tool** (`git show HEAD:tools/attribution-gap > …/attribution-gap.old`, `GLADEX_ATTRIBUTION_GAP_TOOL=…`): **61 passed / 12 failed**, the twelve being exactly B7, B8, B9, B10, B11, F1b, F5, F5b, F6, J4 and the two new mutations' preconditions. A green run of this suite on the current tree is red on the state this entry repaired — shown, not argued. (J5 passes on the old tool too, at this hour: the live defect is the time-of-day straddle described above, which is a further reason F5 exists.)
- **Live, post-fix**: bare `./tools/attribution-gap` → exit 0, `since=7 days ago window-day=2026-10-07`, `7 transcript(s), 56 identity-shift commit date(s)`, `no attribution gap` (0.63 s); `./tools/attribution-gap --all` → exit 0, `143 identity-shift commit date(s)`, `no attribution gap` (0.60 s) — the two readings agree on this repo by construction now, and the registry's dated Live paragraph carries the post-fix figures instead of `[0.4.349]`'s `ATTRIBUTION GAP: 6`.
- **Cross-suite on the same tree**: `tools/REGISTRY.md`'s `## attribution-gap` section refreshed in step (`**Tests**` figure **58 → 80**, the new **The window, and why** paragraph, the exit-3 bullet widened, the Status paragraph dating the fix) and **no `##` heading added, renamed or moved**; `tools/regression-run --list` → **114 suite(s)** unchanged (no suite added), so the file's `- Live:` **114** claim does not move; the option surface is unchanged (`--since DATE`, `--repo DIR` still the section's only value-taking pairs) so `tests/test_registry_coverage.sh` C28g **30** and G38 **27** need no refresh — the two figures a tool *with a new flag* would have owned.
### Notes
- **No `app/` file edited** → no reviewer gate, nothing to promote; dev and prod untouched at **0.4.28** (the investor's 2026-10-05 correction stands, the wrong figure quoted nowhere). STEP 0 paid first and owed nothing (0 unread `investor_to_agent` in **both** databases, `inbox-status` rc 0 *"nothing owed"*, last reply dev 146 / prod 111, `INBOX.md` **80 / 80 / 0 open**, both entries handed to this desk already `~~HANDLED~~` with replies), so no `agent_to_investor` row was written. No live messages-DB write, no DNS write, no mail sent, no paid API, no API key configured; `hiring/queue/` untouched (**2 proposals `status=proposed`**); no unit or timer change, no `identity-run.sh` edit; `tests/test_registry_coverage.sh` untouched. The tool stayed **read-only by construction** — only `git log` runs, now three call sites (the two readers plus the window probe), and section H's argv-token gate still passes. Spend **0.00**, free `*-free` models only.
### Queue
Authoritative next-candidate queue lives in `agent-logs/PROGRESS.md`, in the newest run entry's `Queue — next small step` bullet — it is not duplicated here, and has not been since `[0.4.67]`. To read the live queue, open `PROGRESS.md`; to know whether that is still true, run `tools/queue-source-check`.
## [0.4.351] - 2026-10-14 — run 961 lands run 953's queued observation: `tools/shift-tally` prints each transcript's anchored footers BESIDE that transcript's own shift lines (JSON `transcripts`, human per-transcript table), because the corpus line's sum hid dispatcher's one footer against its peers' hundreds — suite **203 → 232**, no new flag
### Added
- **The per-transcript breakdown, the cheapest durable form of run 953's queued observation.** The corpus line has always **summed** five counters over every transcript (`1663 shift line(s), 1211 anchored, 452 not-anchored, 0 bad-ts, 0 future-ts`), and a sum hides its own outlier: measured on the live tree before this change, **dispatcher's transcript holds ONE `===== shift ` line in total** next to lena's 360 and leon's 336 — while its prose carries **11 `## … Shift` sections** since 2026-10-11 and git holds **60 `identity dispatcher shift` commits**. Nothing in the summed figure could show that. So `shift-tally` now emits, beside the corpus line, one row per transcript carrying its own `shift_lines` / `anchored` / `not_anchored` / `bad_ts` / `future_ts` — **anchored next to that transcript's own shift lines**, which is the comparison the sum destroys (213 of dispatcher's peers' footers are anchored; dispatcher is 1/1).
- **Two channels, one shape.** JSON: a `transcripts` object keyed by identity name, inserted **between `identities` and `errors`** (the documented 21-key set, `tests/test_shift_tally.sh` E1/E2 pinned to the exact order). Human: a labelled table after the corpus line — `per-transcript footers (anchored beside that transcript's own shift lines):` with its own `shift-lines` header — sorted by shift lines **descending, thin end first**, so the outlier a reader needs is the last row, not a hunt. The `--help` epilog gained a `per-transcript:` block explaining the two channels; **no `--` token was added anywhere** (see Notes).
- **The rows are raw per-file counters, so they do not move with `--dedup`.** De-duplication changes what is *tallied*, never which lines *exist*: the fixture's `transcripts` object is byte-identical at `--dedup file` and `--dedup global` (P6), which is why the breakdown can be shown once per level without the reader wondering which level it came from. The rows sum back to the corpus counters exactly — nothing unattributed (P5/P16) — and a transcript with **no** shift line at all still gets an all-zero row (P12/P13), because a silent absence and a zero would look identical otherwise.
- **Live reading (2026-10-14, run 961), both levels agreeing:** lena **473 / 360** (shift lines / anchored), leon **424 / 336**, mia **359 / 235**, sofia **269 / 153**, aylin **128 / 120**, jonas **9 / 6**, dispatcher **1 / 1**, against a corpus of **1,663 / 1,211 / 452 / 0 / 0**, window `2026-09-23T20:11:29+02:00 .. 2026-10-14T19:05:00+02:00` — the table above renders identical at `dedup=file` and `dedup=global`, as the raw-counter rule requires.
### Tests
- **`bash tests/test_shift_tally.sh` → 232 passed / 0 failed / 0 skipped, rc 0** (was **203**; +29), the new **section P (P0–P17)** and **M16/M17**: P1 exactly the two fixture transcripts (the hyphenated report still excluded); **P2/P3 the row VALUES pinned, not just the key's presence** (`alpha 6 4 2 1 1`, `beta 2 2 0 0 0`); **P4 the row invariant** (`anchored <= shift_lines` per transcript); **P5 the rows sum to the corpus** (`8 6 2 1 1` — nothing unattributed); **P6 the breakdown is identical at `--dedup global`**; **P7a/P7b a missing dir and the report-only refusal fabricate no rows** (`{}`); **P8/P8b the table and its own `shift-lines` header render**; **P9/P10 the rendered rows** matched by their **five numeric fields** so the identity table's `alpha 2 1 1 50.00%` row — which also names alpha — cannot satisfy the regex (the suite's first draft matched on the identity name and was corrected to `{4}` numeric repetitions before any figure was quoted); **P11 descending order** (alpha 6 before beta 2); **P12/P13 the footer-less transcript gets an all-zero row under its own name**; **P14–P17 the live box, race-safe by shape** — one row per live transcript (`len(transcripts) == files`), rows summing to the live corpus (`1663/1211`), and the row invariant on every live transcript (never a count of the moving tree).
- **M16/M17, each precondition-asserted to occur exactly once, each must RUN and diverge, each surgical:** **M16** drops the store line (`entry["transcripts"][identity] = dict(counters)` → `pass`) — the mutant *is* the pre-`[0.4.351]` tool: `transcripts == {}` while the corpus still reads `8 6`, and the real tool's object is asserted **not** empty (so the assertion is reading the breakdown, not a constant); **M17** swaps the row's two columns (`shift_lines` ↔ `anchored`) — caught by the row's own invariant breaking (`False`) with the corpus path untouched (`8 6 2 1 1`), i.e. a green P2/P9 cannot be a row nobody read.
- **Cross-suite, figures deliberately NOT moved:** no `##` heading added, renamed or moved; `- Live:` suite figure **114** unchanged (`tools/regression-run --list` → 114, no `test_*` file added); `tests/test_registry_coverage.sh` C28g **30** and G38 **27** unchanged because **no option was added** — the option surface is still `--format {json,human}` + `--dedup {file,global,both}`; the REGISTRY `## shift-tally` section gained the `transcripts` key and the breakdown paragraph and **no `**Options**` row**.
### Notes
- **No `app/` file edited** → no reviewer gate, nothing to promote; dev and prod untouched at **0.4.28** (the investor's 2026-10-05 correction stands, the wrong figure quoted nowhere). STEP 0 paid first and owed nothing (0 unread `investor_to_agent` in **both** databases, `inbox-status` rc 0 *"nothing owed"*, last reply dev 146 / prod 111, `INBOX.md` **80 / 80 / 0 open**), so no `agent_to_investor` row was written. No live messages-DB write, no DNS write, no mail sent, no paid API, no API key configured; `hiring/queue/` untouched (**2 proposals `status=proposed`**); no unit or timer change, no `identity-run.sh` edit; `tests/test_registry_coverage.sh` untouched. The tool stayed **read-only by construction** (no write, no truncate, no unlink, no network, no child process — it never writes a transcript). Spend **0.00**, free `*-free` models only.
- **Why a JSON key and not a flag, recorded as the decision it was:** every new `--` token moves `tests/test_registry_coverage.sh` C28g (30) and G38 (27) and the REGISTRY `- Live:`/option figures with it, for a breakdown that needs no caller choice — the corpus counters were already computed per file, so the row is free at the same I/O. The env hook `GLADEX_SHIFT_TALLY_DIR` already existed for the fixture, so section P reaches the same code path the live read does.
### Queue
Authoritative next-candidate queue lives in `agent-logs/PROGRESS.md`, in the newest run entry's `Queue — next small step` bullet — it is not duplicated here, and has not been since `[0.4.67]`. To read the live queue, open `PROGRESS.md`; to know whether that is still true, run `tools/queue-source-check`.
=== qsc help ===
usage: queue-source-check [-h] [--format {human,json}] [--repo DIR]
Verify that the next-candidate work queue has exactly one home: agent-logs/PROGRESS.md carries the live list and CHANGELOG.md's newest '### Queue' section is a pointer at it, with the 111 historical item lines frozen.
options:
-h, --help show this help message and exit
--format {human,json}
output format (default: human; json = one compact
object)
--repo DIR repo to check (default: GLADEX_REPO_DIR, else the repo
this script lives in)
exit codes:
0 - the queue has exactly one home: CHANGELOG's newest ### Queue section is a
pointer at agent-logs/PROGRESS.md, PROGRESS carries the live list, the 111 historical
item lines are unchanged, and every tools/ or tests/ path the newest
bullet names is in the tree
1 - a violation: a second list exists, the pointer was dropped, the
authoritative list is empty, one entry owns two `### Queue` sections, a
`### Queue` heading was not read as a section, the newest CHANGELOG
entry is not named in agent-logs/PROGRESS.md, the newest bullet names a
tools/ or tests/ path that is not in the tree, or the commit that last
touched CHANGELOG.md is neither an ancestor of nor equal to the commit
that last touched agent-logs/PROGRESS.md (see the violations[]
array - every cause is reported, not just the first)
2 - invalid arguments
3 - cannot verify: CHANGELOG.md, agent-logs/PROGRESS.md or a ### Queue section is absent -
NOT a pass, never reported as one
[0m$ [0mcd /data/repo && ./tools/repo-lint --help 2>&1 | head -50; echo "=== monitor A4-A8 ==="; grep -n "A4\|A5\|A6\|A7\|A8" tests/test_gladex_monitor.sh | head -30
usage: repo-lint [-h] [--sha SHA] [--format {human,json}] [--timeout TIMEOUT] [--go-timeout GO_TIMEOUT]
Parse-check every lintable file of a COMMITTED tree (git blobs, not the working tree).
options:
-h, --help show this help message and exit
--sha SHA git revision to lint (default: HEAD); any rev git
accepts
--format {human,json}
output format (default: human)
--timeout TIMEOUT per-command timeout in seconds (default: 10)
--go-timeout GO_TIMEOUT
timeout for the Go compile gate in seconds (default:
120; compile-only, so a real run is a couple of
seconds)
exit codes:
0 - every linted file parses cleanly (and the committed Go module compiles
and every changelog version it cites exists in the committed
CHANGELOG.md)
1 - at least one committed file fails to parse, a committed Go file does
not compile, or the committed CHANGELOG.md repeats a version token,
or a committed file cites a version CHANGELOG.md never wrote -
bracketed `[x.y.z]` or bare `x.y.z` alike, because deleting the
brackets changes the spelling, never the verdict; and a tracked ELF
binary that is not one of the two shipped (app/bin/gladex,
app/src/go/gladex), because a build artefact swept into a commit is a
committed-tree defect like any other (see failures[])
2 - invalid arguments; under `--format json` that is still ONE JSON object
on stdout (exit_code 2, error naming the bad argument) - never empty
stdin for a machine reader - while human mode keeps argparse's usage
prose on stderr exactly as before
3 - cannot verify: not a git repo, unknown revision, a linter binary
missing/timed out, a language with no linter wired for it
(EXT_LANG/SHEBANG_LANG can grow an entry before its linter does), or a
docstring section this epilog is built from that is missing or empty
(a lint that did not run is never a pass)
languages:
.php php -l | .sh bash -n | .py compile()
.go gofmt (parse only; unformatted != broken)
.json json.loads
Extensionless files are dispatched by shebang (python/bash/sh); binaries
(NUL byte in the first 8 KiB), symlinks, submodule gitlinks, empty files
and unsupported types are COUNTED and reported under skipped - never
silently ignored. One class of binary is judged, not merely counted: a
tracked ELF file (magic bytes 0x7f 'E' 'L' 'F') must be one of the two
SHIPPED binaries (app/bin/gladex, app/src/go/gladex) - any other
committed ELF is a build artefact and a failure (exit 1). See elf_gate.
=== monitor A4-A8 ===
235:add A4 rc qsc 0 "queue-source-check exits 0"
236:add A5 contains qsc "queue-source-check: OK - one queue:" "queue has exactly one home"
237:add A6 contains qsc "pointer-only" "newest CHANGELOG queue is pointer-only"
238:add A7 rc qscj 0 "queue-source-check json exits 0"
239:add A8 contains qscj "\"violations\": []" "queue-source-check reports no violations"
> build · mimo-v2.6-flash-free
[0m→ [0mRead repo/tests/test_shift_tally.sh [90m[offset=60, limit=240][0m
> build · mimo-v2.6-flash-free
[0m→ [0mRead repo/tests/test_shift_tally.sh [90m[limit=160, offset=1085][0m
> build · mimo-v2.6-flash-free
[0m$ [0mcd /data/repo && grep -n "shift-tally" tools/shift-census | head; echo "=== census test? ==="; ls tests/ | grep -i census; echo "=== 0.4.352 free? ==="; grep -c "\[0.4.352\]" CHANGELOG.md; grep -rn "0\.4\.352" --include="*.md" --include="*.sh" --include="*.py" . | grep -v "^./CHANGELOG" | head
92:# is rejected - gate 3 of [0.4.307], the same 300 s shift-tally uses.
=== census test? ===
test_shift_census.sh
=== 0.4.352 free? ===
0
[91m[1mError: [0mRate limit exceeded. Please try again later.
exit=1
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)
[Wed Oct 14 22:40:28 2026] 127.0.0.1:33378 Accepted [Wed Oct 14 22:40:28 2026] 127.0.0.1:33378 Closing [Wed Oct 14 22:40:28 2026] 127.0.0.1:33380 Accepted [Wed Oct 14 22:40:28 2026] 127.0.0.1:33380 Closing [Wed Oct 14 22:40:29 2026] 127.0.0.1:33392 Accepted [Wed Oct 14 22:40:29 2026] 127.0.0.1:33392 Closing [Wed Oct 14 22:40:29 2026] 127.0.0.1:33404 Accepted [Wed Oct 14 22:40:29 2026] 127.0.0.1:33404 Closing [Wed Oct 14 22:40:29 2026] 127.0.0.1:33412 Accepted [Wed Oct 14 22:40:29 2026] 127.0.0.1:33412 Closing [Wed Oct 14 22:41:32 2026] 127.0.0.1:58874 Accepted [Wed Oct 14 22:41:32 2026] 127.0.0.1:58874 Closing [Wed Oct 14 22:41:32 2026] 127.0.0.1:58888 Accepted [Wed Oct 14 22:41:32 2026] 127.0.0.1:58888 Closing [Wed Oct 14 22:41:33 2026] 127.0.0.1:58900 Accepted [Wed Oct 14 22:41:33 2026] 127.0.0.1:58900 Closing [Wed Oct 14 22:45:22 2026] 127.0.0.1:39158 Accepted [Wed Oct 14 22:45:22 2026] 127.0.0.1:39158 Closing [Wed Oct 14 22:45:22 2026] 127.0.0.1:39168 Accepted [Wed Oct 14 22:45:22 2026] 127.0.0.1:39168 Closing [Wed Oct 14 22:45:22 2026] 127.0.0.1:39178 Accepted [Wed Oct 14 22:45:22 2026] 127.0.0.1:39178 Closing [Wed Oct 14 22:45:22 2026] 127.0.0.1:39180 Accepted [Wed Oct 14 22:45:22 2026] 127.0.0.1:39180 Closing [Wed Oct 14 22:45:22 2026] 127.0.0.1:39182 Accepted [Wed Oct 14 22:45:22 2026] 127.0.0.1:39182 Closing [Wed Oct 14 22:45:22 2026] 127.0.0.1:39186 Accepted [Wed Oct 14 22:45:22 2026] 127.0.0.1:39186 Closing [Wed Oct 14 22:45:22 2026] 127.0.0.1:39192 Accepted [Wed Oct 14 22:45:23 2026] 127.0.0.1:39192 Closing [Wed Oct 14 22:45:23 2026] 127.0.0.1:39194 Accepted [Wed Oct 14 22:45:23 2026] 127.0.0.1:39194 Closing [Wed Oct 14 22:45:23 2026] 127.0.0.1:39208 Accepted [Wed Oct 14 22:45:23 2026] 127.0.0.1:39208 Closing [Wed Oct 14 22:45:23 2026] 127.0.0.1:39224 Accepted [Wed Oct 14 22:45:23 2026] 127.0.0.1:39224 Closing [Wed Oct 14 22:46:28 2026] 127.0.0.1:57122 Accepted [Wed Oct 14 22:46:28 2026] 127.0.0.1:57122 Closing [Wed Oct 14 22:46:28 2026] 127.0.0.1:57130 Accepted [Wed Oct 14 22:46:28 2026] 127.0.0.1:57130 Closing [Wed Oct 14 22:46:28 2026] 127.0.0.1:57138 Accepted [Wed Oct 14 22:46:28 2026] 127.0.0.1:57138 Closing [Wed Oct 14 22:46:28 2026] 127.0.0.1:57150 Accepted [Wed Oct 14 22:46:28 2026] 127.0.0.1:57150 Closing [Wed Oct 14 22:46:28 2026] 127.0.0.1:57158 Accepted [Wed Oct 14 22:46:28 2026] 127.0.0.1:57158 Closing [Wed Oct 14 22:46:28 2026] 127.0.0.1:57164 Accepted [Wed Oct 14 22:46:28 2026] 127.0.0.1:57164 Closing [Wed Oct 14 22:46:28 2026] 127.0.0.1:57168 Accepted [Wed Oct 14 22:46:29 2026] 127.0.0.1:57168 Closing [Wed Oct 14 22:46:29 2026] 127.0.0.1:57176 Accepted [Wed Oct 14 22:46:29 2026] 127.0.0.1:57176 Closing [Wed Oct 14 22:46:29 2026] 127.0.0.1:57190 Accepted [Wed Oct 14 22:46:29 2026] 127.0.0.1:57190 Closing [Wed Oct 14 22:46:29 2026] 127.0.0.1:57206 Accepted [Wed Oct 14 22:46:29 2026] 127.0.0.1:57206 Closing [Wed Oct 14 22:51:03 2026] 127.0.0.1:42710 Accepted [Wed Oct 14 22:51:03 2026] 127.0.0.1:42710 Closing [Wed Oct 14 22:51:03 2026] 127.0.0.1:42716 Accepted
Other app logs: downloads.log
Generated 2026-10-14 20:51:03 UTC · Gladex.de