Gladex Agent Logs

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

Overview
Run logs1510 files, 103.1 MB
Latest run logrun-20261012-160950-1044.log
Log directory/data/agent-logs
App log directory/opt/startup/prod/logs
Run logs (newest first, last 50)
FileSizeModified (UTC)
run-20261012-160950-1044.log 167 KB 2026-10-12 14:22:51
run-20261012-152538-1043.log 271 KB 2026-10-12 13:59:41
run-20261012-145024-1042.log 245 KB 2026-10-12 13:15:27
run-20261012-142424-1041.log 133 KB 2026-10-12 12:40:14
run-20261012-134506-1040.log 187 KB 2026-10-12 12:14:13
run-20261012-115647-1039.log 827 KB 2026-10-12 11:34:56
run-20261012-105519-1038.log 438 KB 2026-10-12 09:46:38
run-20261012-101613-1037.log 210 KB 2026-10-12 08:45:08
run-20261012-095300-1036.log 155 KB 2026-10-12 08:06:03
run-20261012-090652-1035.log 249 KB 2026-10-12 07:42:50
run-20261012-082445-1034.log 225 KB 2026-10-12 06:56:42
run-20261012-075335-1033.log 176 KB 2026-10-12 06:14:35
run-20261012-070743-1032.log 236 KB 2026-10-12 05:43:26
run-20261012-063049-1031.log 129 KB 2026-10-12 04:57:33
run-20261012-060219-1030.log 120 KB 2026-10-12 04:20:39
run-20261012-052120-1029.log 151 KB 2026-10-12 03:52:09
run-20261012-044307-1028.log 164 KB 2026-10-12 03:11:10
run-20261012-041056-1027.log 133 KB 2026-10-12 02:32:58
run-20261012-030041-1026.log 177 KB 2026-10-12 02:00:46
run-20261012-020830-1025.log 211 KB 2026-10-12 00:50:32
run-20261012-015820-1024.log 154 B 2026-10-11 23:58:21
run-20261012-014810-1023.log 154 B 2026-10-11 23:48:11
run-20261012-013800-1022.log 154 B 2026-10-11 23:38:01
run-20261012-012750-1021.log 154 B 2026-10-11 23:27:50
run-20261012-011740-1020.log 191 B 2026-10-11 23:17:40
run-20261012-010729-1019.log 154 B 2026-10-11 23:07:30
run-20261012-005719-1018.log 154 B 2026-10-11 22:57:20
run-20261012-004709-1017.log 154 B 2026-10-11 22:47:10
run-20261012-003659-1016.log 154 B 2026-10-11 22:37:00
run-20261012-002649-1015.log 154 B 2026-10-11 22:26:49
run-20261012-001638-1014.log 154 B 2026-10-11 22:16:38
run-20261012-000627-1013.log 154 B 2026-10-11 22:06:28
run-20261011-235617-1012.log 154 B 2026-10-11 21:56:18
run-20261011-234606-1011.log 154 B 2026-10-11 21:46:07
run-20261011-233556-1010.log 154 B 2026-10-11 21:35:57
run-20261011-232546-1009.log 154 B 2026-10-11 21:25:47
run-20261011-231535-1008.log 154 B 2026-10-11 21:15:36
run-20261011-230525-1007.log 154 B 2026-10-11 21:05:25
run-20261011-225514-1006.log 154 B 2026-10-11 20:55:15
run-20261011-224503-1005.log 154 B 2026-10-11 20:45:04
run-20261011-223453-1004.log 154 B 2026-10-11 20:34:54
run-20261011-222443-1003.log 154 B 2026-10-11 20:24:44
run-20261011-221433-1002.log 154 B 2026-10-11 20:14:33
run-20261011-220422-1001.log 154 B 2026-10-11 20:04:23
run-20261011-215412-1000.log 154 B 2026-10-11 19:54:13
run-20261011-214402-999.log 153 B 2026-10-11 19:44:03
run-20261011-213352-998.log 153 B 2026-10-11 19:33:53
run-20261011-212342-997.log 153 B 2026-10-11 19:23:42
run-20261011-211332-996.log 153 B 2026-10-11 19:13:32
run-20261011-210321-995.log 153 B 2026-10-11 19:03:22
Tail — run-20261012-160950-1044.log (last 200 lines)
223:        % (window, days or "-", ua["test_marker"], ua["other"]))
246:            "ua classes:\n"
247:            "    test_marker  ua begins with gladex-dlc-test- (this repo's\n"
=== gocli_path fixture:
19: *  1. STATIC  — no deployed copy may contain the hardcoded dev-path
20: *               string literal, and every copy must carry the
25: *  2. BEHAVIOURAL — stats.php rendered as a *script* inside a synthetic
26: *               env tree whose fixture/bin/gladex is a STUB printing
27: *               KNOWN JSON (version 9.9.9-fixture): the rendered
28: *               "Go CLI" row must show the fixture's version, proving
33: *               the row would have rendered exactly dev's version.
80:echo "=== 1. static: no hardcoded dev binary path in any copy ===\n";
96:echo "\n=== 2. behavioural: rendered in a foreign env tree, runs ITS OWN binary ===\n";
98:// --- Build a synthetic env: fixture/src/php/{stats,db}.php + fixture/bin/gladex ---
103:    assert_true(false, 'fixture dirs created');
109:    if (!copy("$repoPhp/$f", "$fix/src/php/$f")) assert_true(false, "fixture copied $f");
113:$fixtureVersion = '9.9.9-fixture';
114:$fixtureCommit  = 'c0ffee1234567890';
115:$fixtureRow = "$fixtureVersion (sha: " . substr($fixtureCommit, 0, 7) . ')';
121:        'version' => $fixtureVersion,
122:        'commit'  => $fixtureCommit,
128:// Guard: the stub must really print the fixture JSON when executed directly,
129:// or "the row shows the fixture version" could never be satisfied for the
133:assert_true(is_array($dj) && ($dj['version'] ?? '') === $fixtureVersion,
134:    "fixture stub executes and prints version $fixtureVersion directly");
147:assert_true($devRow !== null && $devRow !== $fixtureRow,
148:    "live dev's binary renders a DIFFERENT row (" . ($devRow ?? 'unavailable')
151:// --- Render stats.php as a script inside the fixture tree -------------------
152:$outFile = "$fix/rendered.html";
158:assert_true($rc === 0, "stats.php renders as a script in the fixture (rc=$rc)");
159:assert_true(str_contains($html, 'Gladex Container Stats'), 'rendered HTML is the stats page');
161:/** Pull the Go CLI row out of the rendered page. */
170:assert_true($row !== null, 'rendered page contains a Go CLI row');
171:assert_true($row === $fixtureRow,
=== download_counter doc tail:
<?php
/**
 * Regression test for the append-only download counter (CHANGELOG 0.4.313):
 * the artefact REPORT.md §10 kill criterion #6 needs before its 2026-10-20
 * date — the app served /download/gladex and counted nothing, and Apache's
 * 14-day log rotation makes the 30-day window unrecoverable (run 909's
 * measurement), so the count has to come from inside the app.
 *
 * Three layers, all required:
 *
 *  1. STATIC  — app.php requires the module, calls it with the readfile()
 *               return value, and the call sits AFTER readfile() (a counter
 *               that runs first can never report what actually left the
 *               process); the module is append-only ('ab' + LOCK_EX, no
 *               truncate mode), gates non-GET methods, and carries no
 *               hardcoded /opt/startup path (the log must follow __DIR__, like
 *               db.php's messages.db). Every copy that exists must be
 *               byte-identical (repo == dev == prod) — an undeployed counter
 *               is skipped with a reason, never counted green.
 *
 *  2. BEHAVIOURAL (hermetic, temp dirs only) — real writes: append-only
 *               (second call preserves the first line byte for byte), created
 *               directories, HEAD/POST refused without a line, fopen failure
 *               returns false with NO warning and NO output, invalid UTF-8
 *               UA still lands as valid JSON-lines, long UA truncated, and a
 *               fake env tree (fakeenv/src/php/) proves the default path
 *               follows the FILE, writing fakeenv/logs/downloads.log and
 *               nothing under /data/repo.
 *
 *  3. LIVE — against the running envs, one request each, distinguished by a
 *               unique marker User-Agent so real traffic cannot be mistaken
 *               for the probe: the /download landing page writes no line, a
 *               HEAD on /download/gladex writes no line, a GET on
 *               /download/gladex writes exactly one, parsed end to end. Cost
 *               is one 13.5 MB loopback transfer per deployed env.
 *
 * Run: php tests/test_download_counter.php
 * Exit codes: 0=pass, 1=fail
 */

set_time_limit(300);

$pass = 0;
$fail = 0;
$skip = 0;

function assert_true(bool $val, string $msg): void {
    global $pass, $fail;
    if ($val) { $pass++; echo "  PASS: $msg\n"; }
    else { $fail++; echo "  FAIL: $msg\n"; }
}

function skip(string $msg): void {
    global $skip;
    $skip++;
    echo "  SKIP: $msg\n";
}

/** Capture unsuppressed warnings: the counter's failure paths must be silent. */
$warnings = [];
> build · mimo-v2.6-flash-free
Now I'll implement this run's step: the queued `/stats` row for the download counter. First the compute block in `stats.php`:
← Edit repo/app/src/php/stats.php
Index: repo/app/src/php/stats.php
===================================================================
--- repo/app/src/php/stats.php
+++ repo/app/src/php/stats.php
@@ -144,8 +144,51 @@
     $msgInvestor = $db->query("SELECT COUNT(*) FROM messages WHERE direction='investor_to_agent'")->fetchColumn();
     $msgAgent = $db->query("SELECT COUNT(*) FROM messages WHERE direction='agent_to_investor'")->fetchColumn();
 }
 
+// CLI-binary downloads — THIS env's own counter (the write side is
+// download_counter.php, the summarising reader is tools/download-stats).
+// The path expression is deliberately REPEATED, not required from
+// download_counter.php: this file has to render as a standalone copy inside a
+// synthetic env tree (tests/test_stats_dbpath.php copies ONLY stats.php and
+// db.php), so a require of a file the fixture does not carry would fatal the
+// page. Same rule as $dbPath above, for the same reason — a hardcoded
+// /opt/startup/dev path would make prod display DEV's download counts.
+$dlPath = __DIR__ . '/../../logs/downloads.log';
+$dl = [
+    'exists' => false, 'lines' => 0, 'valid' => 0, 'malformed' => 0,
+    'complete' => 0, 'incomplete' => 0, 'bytes_sent' => 0,
+    'first' => null, 'last' => null, 'external' => 0, 'probe' => 0,
+    'external_30d' => 0,
+];
+if (is_readable($dlPath) && ($dlFh = @fopen($dlPath, 'rb')) !== false) {
+    $dl['exists'] = true;
+    $dlCut = time() - 30 * 86400;   // REPORT.md §10 kill criterion #6 window
+    while (($dlLine = fgets($dlFh)) !== false) {
+        $dlLine = trim($dlLine);
+        if ($dlLine === '') continue;
+        $dl['lines']++;
+        $ev = json_decode($dlLine, true);
+        if (!is_array($ev) || !isset($ev['ts'])) { $dl['malformed']++; continue; }
+        $dl['valid']++;
+        $ts = (int)$ev['ts'];
+        if ($dl['first'] === null || $ts < $dl['first']) $dl['first'] = $ts;
+        if ($dl['last'] === null || $ts > $dl['last']) $dl['last'] = $ts;
+        $sent = (int)($ev['bytes_sent'] ?? -1);
+        if ($sent < 0) { $dl['incomplete']++; }
+        else { $dl['complete']++; $dl['bytes_sent'] += $sent; }
+        // Same split as tools/download-stats: this repo's own suite probes are
+        // not downloads, and criterion #6 asks about EXTERNAL ones only.
+        $probe = str_starts_with((string)($ev['ua'] ?? ''), 'gladex-dlc-test-');
+        if ($probe) { $dl['probe']++; }
+        else {
+            $dl['external']++;
+            if ($ts >= $dlCut) $dl['external_30d']++;
+        }
+    }
+    fclose($dlFh);
+}
+
 // Timestamp
 $now = date('Y-m-d H:i:s') . ' UTC';
 ?>
 <!DOCTYPE html>

> build · mimo-v2.6-flash-free
← Edit repo/app/src/php/stats.php
Index: repo/app/src/php/stats.php
===================================================================
--- repo/app/src/php/stats.php
+++ repo/app/src/php/stats.php
@@ -408,8 +408,23 @@
             </table>
         </div>
     </div>
 
+    <!-- CLI-binary downloads — this env's own counter. Deliberately div rows,
+         NOT a ninth table: tests/test_table_scroll_320.php pins /stats at
+         exactly 8 wrapped tables, and .log-line already carries the
+         overflow-wrap: anywhere this page's prose needs at 320px. -->
+    <div class="section">
+        <div class="section-title">Downloads (CLI binary)</div>
+        <?php if (!$dl['exists']): ?>
+            <div class="log-line">Counter: no downloads.log in this env yet (nothing recorded)</div>
+        <?php else: ?>
+            <div class="log-line">Served: <?= $dl['valid'] ?> GET &middot; complete <?= $dl['complete'] ?> / incomplete <?= $dl['incomplete'] ?> &middot; malformed <?= $dl['malformed'] ?> &middot; <?= fmtBytes($dl['bytes_sent']) ?> sent</div>
+            <div class="log-line">Window: <?= $dl['first'] !== null ? gmdate('Y-m-d H:i:s', $dl['first']) : '-' ?> &rarr; <?= $dl['last'] !== null ? gmdate('Y-m-d H:i:s', $dl['last']) : '-' ?> UTC</div>
+            <div class="log-line">External: <?= $dl['external'] ?> &middot; test probes: <?= $dl['probe'] ?> &middot; external last 30 days: <?= $dl['external_30d'] ?> (REPORT.md &sect;10 #6)</div>
+        <?php endif; ?>
+    </div>
+
     <div class="stamp">Refreshed server-side &middot; <?= htmlspecialchars($now) ?></div>
     </main>
 </body>
 </html>

> build · mimo-v2.6-flash-free
$ cd /data/repo && php -l app/src/php/stats.php && cp -p app/src/php/stats.php /opt/startup/dev/src/php/stats.php && ./tools/source-sync-check --env dev; echo "dev rc=$?"; curl -s http://127.0.0.1:8000/stats | grep -A5 "Downloads (CLI binary)"
No syntax errors detected in app/src/php/stats.php
source-sync-check  repo=/data/repo  env=dev  2026-10-12T14:22:51Z
  dev  examples/workflows       9 files  OK
  dev  src/php                 15 files  OK
result: in sync — 24 file(s) across 1 env(s) (exit 0)
dev rc=0
        <div class="section-title">Downloads (CLI binary)</div>
                    <div class="log-line">Served: 4 GET &middot; complete 4 / incomplete 0 &middot; malformed 0 &middot; 52 MB sent</div>
            <div class="log-line">Window: 2026-10-12 08:27:58 &rarr; 2026-10-12 08:36:50 UTC</div>
            <div class="log-line">External: 0 &middot; test probes: 4 &middot; external last 30 days: 0 (REPORT.md &sect;10 #6)</div>
            </div>

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

App log tail — prod-8001.log (last 60 lines)
[Mon Oct 12 16:15:19 2026] 127.0.0.1:49716 Accepted
[Mon Oct 12 16:15:19 2026] 127.0.0.1:49716 Closing
[Mon Oct 12 16:15:19 2026] 127.0.0.1:49722 Accepted
[Mon Oct 12 16:15:19 2026] 127.0.0.1:49722 Closing
[Mon Oct 12 16:15:19 2026] 127.0.0.1:49724 Accepted
[Mon Oct 12 16:15:19 2026] 127.0.0.1:49724 Closing
[Mon Oct 12 16:15:19 2026] 127.0.0.1:49732 Accepted
[Mon Oct 12 16:15:19 2026] 127.0.0.1:49732 Closing
[Mon Oct 12 16:15:19 2026] 127.0.0.1:49736 Accepted
[Mon Oct 12 16:15:19 2026] 127.0.0.1:49736 Closing
[Mon Oct 12 16:15:20 2026] 127.0.0.1:49744 Accepted
[Mon Oct 12 16:15:20 2026] 127.0.0.1:49744 Closing
[Mon Oct 12 16:16:37 2026] 127.0.0.1:50312 Accepted
[Mon Oct 12 16:16:37 2026] 127.0.0.1:50312 Closing
[Mon Oct 12 16:16:37 2026] 127.0.0.1:50322 Accepted
[Mon Oct 12 16:16:37 2026] 127.0.0.1:50322 Closing
[Mon Oct 12 16:16:37 2026] 127.0.0.1:50324 Accepted
[Mon Oct 12 16:16:37 2026] 127.0.0.1:50324 Closing
[Mon Oct 12 16:16:37 2026] 127.0.0.1:50336 Accepted
[Mon Oct 12 16:16:37 2026] 127.0.0.1:50336 Closing
[Mon Oct 12 16:16:37 2026] 127.0.0.1:50342 Accepted
[Mon Oct 12 16:16:37 2026] 127.0.0.1:50342 Closing
[Mon Oct 12 16:16:37 2026] 127.0.0.1:50354 Accepted
[Mon Oct 12 16:16:37 2026] 127.0.0.1:50354 Closing
[Mon Oct 12 16:16:37 2026] 127.0.0.1:50360 Accepted
[Mon Oct 12 16:16:37 2026] 127.0.0.1:50360 Closing
[Mon Oct 12 16:16:37 2026] 127.0.0.1:50376 Accepted
[Mon Oct 12 16:16:37 2026] 127.0.0.1:50376 Closing
[Mon Oct 12 16:16:37 2026] 127.0.0.1:50378 Accepted
[Mon Oct 12 16:16:38 2026] 127.0.0.1:50378 Closing
[Mon Oct 12 16:16:38 2026] 127.0.0.1:50384 Accepted
[Mon Oct 12 16:16:38 2026] 127.0.0.1:50384 Closing
[Mon Oct 12 16:17:19 2026] 127.0.0.1:40220 Accepted
[Mon Oct 12 16:17:19 2026] 127.0.0.1:40220 Closing
[Mon Oct 12 16:17:22 2026] 127.0.0.1:40232 Accepted
[Mon Oct 12 16:17:22 2026] 127.0.0.1:40232 Closing
[Mon Oct 12 16:17:25 2026] 127.0.0.1:43440 Accepted
[Mon Oct 12 16:17:25 2026] 127.0.0.1:43440 Closing
[Mon Oct 12 16:17:26 2026] 127.0.0.1:43456 Accepted
[Mon Oct 12 16:17:26 2026] 127.0.0.1:43456 Closing
[Mon Oct 12 16:17:29 2026] 127.0.0.1:43472 Accepted
[Mon Oct 12 16:17:29 2026] 127.0.0.1:43472 Closing
[Mon Oct 12 16:17:33 2026] 127.0.0.1:43484 Accepted
[Mon Oct 12 16:17:33 2026] 127.0.0.1:43484 Closing
[Mon Oct 12 16:17:35 2026] 127.0.0.1:44570 Accepted
[Mon Oct 12 16:17:35 2026] 127.0.0.1:44570 Closing
[Mon Oct 12 16:17:39 2026] 127.0.0.1:44576 Accepted
[Mon Oct 12 16:17:39 2026] 127.0.0.1:44576 Closing
[Mon Oct 12 16:17:41 2026] 127.0.0.1:44580 Accepted
[Mon Oct 12 16:17:41 2026] 127.0.0.1:44580 Closing
[Mon Oct 12 16:19:17 2026] 127.0.0.1:57186 Accepted
[Mon Oct 12 16:19:17 2026] 127.0.0.1:57186 Closing
[Mon Oct 12 16:19:18 2026] 127.0.0.1:57198 Accepted
[Mon Oct 12 16:19:18 2026] 127.0.0.1:57198 Closing
[Mon Oct 12 16:19:35 2026] 127.0.0.1:33266 Accepted
[Mon Oct 12 16:19:35 2026] 127.0.0.1:33266 Closing
[Mon Oct 12 16:22:33 2026] 127.0.0.1:40250 Accepted
[Mon Oct 12 16:22:34 2026] 127.0.0.1:40250 Closing
[Mon Oct 12 16:23:02 2026] 127.0.0.1:50552 Accepted

Other app logs: downloads.log

Generated 2026-10-12 14:23:02 UTC · Gladex.de