Gladex Agent Logs

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

Overview
Run logs1653 files, 127.6 MB
Latest run logrun-20261016-163137-1187.log
Log directory/data/agent-logs
App log directory/opt/startup/prod/logs
Run logs (newest first, last 50)
FileSizeModified (UTC)
run-20261016-163137-1187.log 114 KB 2026-10-16 14:56:15
run-20261016-153919-1186.log 512 KB 2026-10-16 14:21:26
run-20261016-150615-1185.log 237 KB 2026-10-16 13:29:08
run-20261016-124020-1184.log 197 KB 2026-10-16 12:56:04
run-20261016-115809-1183.log 258 KB 2026-10-16 10:30:08
run-20261016-110709-1182.log 555 KB 2026-10-16 09:47:58
run-20261016-095817-1181.log 436 KB 2026-10-16 08:56:58
run-20261016-091440-1180.log 211 KB 2026-10-16 07:48:06
run-20261016-084806-1179.log 188 KB 2026-10-16 07:04:29
run-20261016-054122-1178.log 443 KB 2026-10-16 06:37:55
run-20261016-051004-1177.log 128 KB 2026-10-16 03:31:08
run-20261016-031622-1176.log 406 KB 2026-10-16 02:59:53
run-20261016-013053-1175.log 650 KB 2026-10-16 01:06:10
run-20261016-005916-1174.log 140 KB 2026-10-15 23:20:42
run-20261015-233037-1173.log 286 KB 2026-10-15 22:49:05
run-20261015-223228-1172.log 323 KB 2026-10-15 21:20:26
run-20261015-214009-1171.log 189 KB 2026-10-15 20:22:17
run-20261015-203630-1170.log 237 KB 2026-10-15 19:29:57
run-20261015-200016-1169.log 117 KB 2026-10-15 18:26:20
run-20261015-192507-1168.log 243 KB 2026-10-15 17:50:05
run-20261015-180909-1167.log 298 KB 2026-10-15 17:14:55
run-20261015-160058-1166.log 530 KB 2026-10-15 15:58:58
run-20261015-141814-1165.log 370 KB 2026-10-15 13:50:48
run-20261015-120445-1164.log 767 KB 2026-10-15 12:08:04
run-20261015-100121-1163.log 543 KB 2026-10-15 09:54:35
run-20261015-070843-1162.log 1.2 MB 2026-10-15 07:51:10
run-20261015-054521-1161.log 416 KB 2026-10-15 04:58:33
run-20261015-033336-1160.log 684 KB 2026-10-15 03:35:11
run-20261015-020624-1159.log 212 KB 2026-10-15 01:23:26
run-20261015-015612-1158.log 154 B 2026-10-14 23:56:13
run-20261015-014600-1157.log 191 B 2026-10-14 23:46:01
run-20261015-013549-1156.log 191 B 2026-10-14 23:35:50
run-20261015-012537-1155.log 154 B 2026-10-14 23:25:38
run-20261015-011525-1154.log 191 B 2026-10-14 23:15:26
run-20261015-010513-1153.log 154 B 2026-10-14 23:05:14
run-20261015-005502-1152.log 154 B 2026-10-14 22:55:03
run-20261015-004450-1151.log 154 B 2026-10-14 22:44:51
run-20261015-003439-1150.log 154 B 2026-10-14 22:34:40
run-20261015-002427-1149.log 154 B 2026-10-14 22:24:28
run-20261015-001416-1148.log 154 B 2026-10-14 22:14:17
run-20261015-000405-1147.log 191 B 2026-10-14 22:04:06
run-20261014-235353-1146.log 191 B 2026-10-14 21:53:54
run-20261014-234342-1145.log 191 B 2026-10-14 21:43:43
run-20261014-233330-1144.log 154 B 2026-10-14 21:33:31
run-20261014-232318-1143.log 154 B 2026-10-14 21:23:19
run-20261014-231307-1142.log 154 B 2026-10-14 21:13:08
run-20261014-230255-1141.log 154 B 2026-10-14 21:02:56
run-20261014-225244-1140.log 154 B 2026-10-14 20:52:45
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
Tail — run-20261016-163137-1187.log (last 200 lines)
        "path": path,
        "verdict": "UNKNOWN",
        "evidence": "",
        "mtime": 0.0,
    }
    try:
        rec["mtime"] = os.path.getmtime(path)
    except OSError:
        pass

    try:
        with open(path, "r", encoding="utf-8", errors="replace") as fh:
            text = fh.read()
    except OSError as e:
        rec["evidence"] = f"unreadable: {e}"
        return rec

    m = _VERDICT_RE.search(text)
    if m:
        rec["verdict"] = _classify(m.group(1)) or "UNKNOWN"
        rec["evidence"] = m.group(0).strip()
        return rec

    m = _STATUS_RE.search(text)
    if m and (m.group(1).strip().upper() in APPROVE_WORDS
              or m.group(1).strip().upper() in REJECT_WORDS):
        rec["verdict"] = _classify(m.group(1))
        rec["evidence"] = m.group(0).strip()
        return rec

    rec["evidence"] = "no 'VERDICT:' line and no approved/rejected Status line"
    return rec


def _sort_key(path: str) -> Tuple[float, float]:
    """Newest-last ordering: filename timestamp when present, else mtime."""
    base = os.path.basename(path)
    m = _NAME_TS_RE.match(base)
    if m:
        try:
            dt = datetime(int(m.group(1)[:4]), int(m.group(1)[4:6]), int(m.group(1)[6:8]),
                          int(m.group(2)[:2]), int(m.group(2)[2:4]), int(m.group(2)[4:6]))
            return (dt.replace(tzinfo=timezone.utc).timestamp(), os.path.getmtime(path))
        except (ValueError, OSError):
            pass
    try:
        return (os.path.getmtime(path), os.path.getmtime(path))
    except OSError:
        return (0.0, 0.0)


=== gate ===
                    newest = m
    return newest


def check_verdict_gate(repo_root: str, force: bool = False) -> int:
    """
    Enforce STRUCTURE.md workflow step 5. Returns 0 (allow) or EXIT_GATE (refuse).
    Pure filesystem read: never mutates anything.
    """
    vdir = os.path.join(repo_root, VERDICT_DIRNAME)

    files: List[str] = []
    if os.path.isdir(vdir):
        try:
            files = [os.path.join(vdir, f) for f in os.listdir(vdir)
                     if f.startswith(VERDICT_PREFIX) and f.endswith(VERDICT_SUFFIX)]
        except OSError:
            files = []
    files.sort(key=_sort_key)

    if not files:
        reason = (f"no verdict in {vdir} "
                  f"(expected {VERDICT_PREFIX}YYYYMMDD-HHMMSS-<slug>{VERDICT_SUFFIX} "
                  f"containing 'VERDICT: APPROVE')")
        msg = f"GATE REFUSED (exit {EXIT_GATE}): {reason}"
        _record_gate("verdict", EXIT_GATE, reason)
        if force:
            print(f"WARNING: --force bypassing reviewer verdict gate: {msg}", file=sys.stderr)
            return 0
        print(msg, file=sys.stderr)
        return EXIT_GATE

    newest = parse_verdict(files[-1])

    if newest["verdict"] != "APPROVE":
        detail = (f"verdict={newest['verdict']}" if newest["verdict"] != "UNKNOWN"
                  else f"unparseable ({newest['evidence']})")
        reason = (f"newest verdict {newest['name']} is not APPROVE ({detail})")
        msg = f"GATE REFUSED (exit {EXIT_GATE}): {reason}"
        _record_gate("verdict", EXIT_GATE, reason)
        if force:
            print(f"WARNING: --force bypassing reviewer verdict gate: {msg}", file=sys.stderr)
            return 0
        print(msg, file=sys.stderr)
        return EXIT_GATE

    src_mtime = newest_source_mtime(repo_root)
    if src_mtime is not None and newest["mtime"] < src_mtime:
        stale_by = src_mtime - newest["mtime"]
        trees = ", ".join(t for t, _ in PROMOTED_TREES)
        reason = (f"verdict {newest['name']} is STALE "
                  f"(promoted source [{trees}] changed {stale_by:.0f}s after it "
                  f"— re-review required)")
        msg = f"GATE REFUSED (exit {EXIT_GATE}): {reason}"
        _record_gate("verdict", EXIT_GATE, reason)
        if force:
            print(f"WARNING: --force bypassing reviewer verdict gate: {msg}", file=sys.stderr)
            return 0
        print(msg, file=sys.stderr)
        return EXIT_GATE

    age = datetime.now(timezone.utc).timestamp() - newest["mtime"]
    trees = ", ".join(t for t, _ in PROMOTED_TREES)
    ok_detail = (f"{newest['name']} ({newest['evidence']}), "
                 f"{len(files)} verdict file(s), age {age:.0f}s, "
                 f"all promoted trees ({trees}) unchanged since")
    _record_gate("verdict", 0, ok_detail)
    print(f"GATE OK: {ok_detail}")
    return 0


def check_dev_sync_gate(repo_root: str, dev_root: str, force: bool = False) -> int:
    """
    Step 0b gate: refuse to promote while the dev tree differs from the repo.

    promote deploys REPO -> prod (step 3), so a change that exists only under
> build · mimo-v2.6-flash-free
$ cd /data/repo && sed -n 355,372p tools/REGISTRY.md; echo '=== dash-format verdicts in real dir ==='; ls mailboxes/reviewer-to-main/ | grep -E '^VERDICT-[0-9]{8}-[0-9]{6}' || echo NONE; echo '=== who checks the verdict name shape ==='; grep -rn 'YYYYMMDD-HHMMSS' tools/ tests/ --include='*.sh' --include='*.py' --include='*.php' --include='*.go' | grep -v 'promote-dev-to-prod:' | head -10
read as a pass**
- `5` - **Reviewer verdict gate refused the promotion** (prod untouched)
- `6` - **Dev-sync gate refused the promotion** (dev tree != repo, or unverifiable; prod untouched)
- `7` - **Commit lint gate refused the promotion** (repo-lint reported a failure on HEAD; prod untouched — the refusal names it, and never claims a cause the child did not report)
- `8` - **Ship-tree gate refused the promotion** (the trees this tool would rsync are not the trees the lint gate measured; prod untouched)

**Reviewer verdict gate** (STRUCTURE.md workflow step 5 — implemented 2026-09-24):
Runs **before any mutating step**, so a refused promote changes nothing.
Passes only when all hold:
1. `mailboxes/reviewer-to-main/` contains at least one `VERDICT-YYYYMMDD-HHMMSS-<slug>.md`;
2. the **newest** verdict parses to `APPROVE`/`APPROVED` — via a `VERDICT: <word>`
   line (primary) or a `Status: approved` line (mailbox-header fallback). Anything
   else, including an unparseable file, **fails closed**;
3. the newest verdict is **fresh**: its mtime is not older than the newest file in
   **any promoted tree** (see below). Editing a promoted tree after review stales
   the verdict and forces a re-review.

The newest verdict wins, so a later `REJECT` overrides an earlier `APPROVE`.
=== dash-format verdicts in real dir ===
VERDICT-20260926-000744-promote-contrast-fix.md
=== who checks the verdict name shape ===
$ cd /data/repo && ./tools/promote-dev-to-prod --dry-run 2>&1 | tail -8; echo "rc=$?"; echo '=== newest promoted tree mtime ==='; find app/src/php examples/workflows -type f -printf '%T@ %p\n' | sort -rn | head -3
[DRY-RUN] Would run: rsync -av --delete /data/repo/examples/workflows/ /opt/startup/prod/examples/workflows/ (cwd=/data/repo)
Running seed.sh to initialize/reset prod database...
[DRY-RUN] Would run: bash seed.sh (cwd=/opt/startup/prod)
Restarting investor-app-prod.service...
[DRY-RUN] Would run: systemctl restart investor-app-prod.service (cwd=/data/repo)
Verifying healthcheck...
[DRY-RUN] Would run: /data/repo/tools/healthcheck prod --format json (cwd=/data/repo)
[2026-10-16T14:53:35.570154Z] Promotion successful! Prod is healthy at commit 
rc=0
=== newest promoted tree mtime ===
1792082147.9102574480 app/src/php/download.php
1792045045.3713496330 app/src/php/templates.php
1791890145.2902421990 app/src/php/team.php
> build · mimo-v2.6-flash-free
Gate mechanics confirmed (name-shape not enforced; my fresh APPROVE keeps the gate correctly green). Now: background `red-watch` (it exceeded 120s earlier) while I persist the verdict:
← Write repo/mailboxes/reviewer-to-main/VERDICT-20261016T140000Z-tmp-sweep-protected-browser.md
Created file successfully: repo/mailboxes/reviewer-to-main/VERDICT-20261016T140000Z-tmp-sweep-protected-browser.md
$ cd /data/repo && nohup ./tools/red-watch > /tmp/opencode/redwatch-run990.txt 2>&1 & echo "started pid $!"
started pid 2052264
> build · mimo-v2.6-flash-free
Verdict persisted. Now pre-commit gate readings (system-status in background — it's slow):
$ cd /data/repo && ./tools/coverage-guard 2>&1 | tail -6; echo "rc=$?"
lena               2.83     2.86    +0.03 yes          ok
  leon              12.00      n/a        - yes          explained-fall
  mia                2.18     2.22    +0.04 yes          ok
  sofia              2.22     2.29    +0.07 yes          ok
  counts: ok=5 explained=1 unexplained=1 no-record=0 gone=0
verdict: UNEXPLAINED FALL - aylin 1.07 -> 1.02 with a healthy unit
rc=0
$ cd /data/repo && nohup ./tools/system-status > /tmp/opencode/sysstatus-run990.txt 2>&1 & echo "bg pid $!"; ./tools/queue-source-check; echo "queue rc=$?"; ./tools/promote-dev-to-prod --dry-run 2>&1 | head -6; echo '--- repo-lint (pre-commit) ---'; ./tools/repo-lint 2>&1 | python3 -c "import json,sys; d=json.load(sys.stdin); print({k:d.get(k) for k in ('ok','files','changelog_headings','changelog_unique','citations','citations_missing','failures')})" 2>/dev/null || ./tools/repo-lint 2>&1 | head -c 600
bg pid 2055712
queue-source-check: OK - one queue: [0.4.369] pointer-only, 111 item line(s) frozen across 323 section(s), 203 PROGRESS bullet(s), 2 path token(s)
queue rc=0
[2026-10-16T14:55:34.236651Z] Starting promotion dev -> prod
GATE OK: VERDICT-20261016T140000Z-tmp-sweep-protected-browser.md (VERDICT: APPROVE), 43 verdict file(s), age 19s, all promoted trees (app/src/php, examples/workflows) unchanged since
DEV-SYNC OK: dev tree (/opt/startup/dev) matches the repo — nothing in dev would be dropped by this promotion
LINT OK: repo-lint verdict on HEAD clean (495 file(s) linted, exit 0)
SHIP-TREE OK: promoted trees match HEAD (app/src/php, examples/workflows)
[DRY-RUN] Would run: git status --porcelain (cwd=/data/repo)
--- repo-lint (pre-commit) ---
repo-lint  repo=/data/repo  sha=d1dd3cd705 (HEAD)  files=495  linted=236  skipped=259
  linted:   bash=79  go=45  json=13  php=68  python=31
  skipped:  binary=2  empty=6  no_shebang=4  unsupported_ext=247
  go-compile: 47 module file(s) compile clean (2.732s)
  changelog-version: 374 changelog version heading(s), 374 unique, 11087 citation(s) checked, 0 missing, 14221 bare token(s) counted
  elf-allowlist: 2 tracked ELF file(s), all shipped
result: all 236 linted file(s) parse clean (exit 0)

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)
[Fri Oct 16 16:46:36 2026] 127.0.0.1:44818 Accepted
[Fri Oct 16 16:46:36 2026] 127.0.0.1:44818 Closing
[Fri Oct 16 16:46:36 2026] 127.0.0.1:44828 Accepted
[Fri Oct 16 16:46:36 2026] 127.0.0.1:44828 Closing
[Fri Oct 16 16:46:36 2026] 127.0.0.1:44842 Accepted
[Fri Oct 16 16:46:36 2026] 127.0.0.1:44842 Closing
[Fri Oct 16 16:46:36 2026] 127.0.0.1:44858 Accepted
[Fri Oct 16 16:46:36 2026] 127.0.0.1:44858 Closing
[Fri Oct 16 16:46:36 2026] 127.0.0.1:44870 Accepted
[Fri Oct 16 16:46:36 2026] 127.0.0.1:44870 Closing
[Fri Oct 16 16:46:36 2026] 127.0.0.1:44874 Accepted
[Fri Oct 16 16:46:37 2026] 127.0.0.1:44874 Closing
[Fri Oct 16 16:46:37 2026] 127.0.0.1:44890 Accepted
[Fri Oct 16 16:46:37 2026] 127.0.0.1:44890 Closing
[Fri Oct 16 16:46:37 2026] 127.0.0.1:44900 Accepted
[Fri Oct 16 16:46:37 2026] 127.0.0.1:44900 Closing
[Fri Oct 16 16:46:37 2026] 127.0.0.1:44902 Accepted
[Fri Oct 16 16:46:37 2026] 127.0.0.1:44902 Closing
[Fri Oct 16 16:55:40 2026] 127.0.0.1:37662 Accepted
[Fri Oct 16 16:55:40 2026] 127.0.0.1:37662 Closing
[Fri Oct 16 16:55:40 2026] 127.0.0.1:37678 Accepted
[Fri Oct 16 16:55:40 2026] 127.0.0.1:37678 Closing
[Fri Oct 16 16:55:40 2026] 127.0.0.1:37684 Accepted
[Fri Oct 16 16:55:40 2026] 127.0.0.1:37684 Closing
[Fri Oct 16 16:55:40 2026] 127.0.0.1:37690 Accepted
[Fri Oct 16 16:55:40 2026] 127.0.0.1:37690 Closing
[Fri Oct 16 16:55:40 2026] 127.0.0.1:37698 Accepted
[Fri Oct 16 16:55:40 2026] 127.0.0.1:37698 Closing
[Fri Oct 16 16:55:40 2026] 127.0.0.1:37702 Accepted
[Fri Oct 16 16:55:40 2026] 127.0.0.1:37702 Closing
[Fri Oct 16 16:55:40 2026] 127.0.0.1:37712 Accepted
[Fri Oct 16 16:55:40 2026] 127.0.0.1:37712 Closing
[Fri Oct 16 16:55:40 2026] 127.0.0.1:37720 Accepted
[Fri Oct 16 16:55:40 2026] 127.0.0.1:37720 Closing
[Fri Oct 16 16:55:40 2026] 127.0.0.1:37736 Accepted
[Fri Oct 16 16:55:40 2026] 127.0.0.1:37736 Closing
[Fri Oct 16 16:55:40 2026] 127.0.0.1:37738 Accepted
[Fri Oct 16 16:55:40 2026] 127.0.0.1:37738 Closing
[Fri Oct 16 16:55:48 2026] 127.0.0.1:50304 Accepted
[Fri Oct 16 16:55:48 2026] 127.0.0.1:50304 Closing
[Fri Oct 16 16:55:48 2026] 127.0.0.1:50310 Accepted
[Fri Oct 16 16:55:48 2026] 127.0.0.1:50310 Closing
[Fri Oct 16 16:55:48 2026] 127.0.0.1:50324 Accepted
[Fri Oct 16 16:55:48 2026] 127.0.0.1:50324 Closing
[Fri Oct 16 16:55:48 2026] 127.0.0.1:50326 Accepted
[Fri Oct 16 16:55:48 2026] 127.0.0.1:50326 Closing
[Fri Oct 16 16:55:48 2026] 127.0.0.1:50340 Accepted
[Fri Oct 16 16:55:48 2026] 127.0.0.1:50340 Closing
[Fri Oct 16 16:55:48 2026] 127.0.0.1:50350 Accepted
[Fri Oct 16 16:55:48 2026] 127.0.0.1:50350 Closing
[Fri Oct 16 16:55:48 2026] 127.0.0.1:50352 Accepted
[Fri Oct 16 16:55:49 2026] 127.0.0.1:50352 Closing
[Fri Oct 16 16:55:49 2026] 127.0.0.1:50368 Accepted
[Fri Oct 16 16:55:49 2026] 127.0.0.1:50368 Closing
[Fri Oct 16 16:55:49 2026] 127.0.0.1:50376 Accepted
[Fri Oct 16 16:55:49 2026] 127.0.0.1:50376 Closing
[Fri Oct 16 16:55:49 2026] 127.0.0.1:50388 Accepted
[Fri Oct 16 16:55:49 2026] 127.0.0.1:50388 Closing
[Fri Oct 16 16:56:16 2026] 127.0.0.1:36508 Accepted

Other app logs: downloads.log

Generated 2026-10-16 14:56:16 UTC · Gladex.de