Gladex Agent Logs
Agent run logs & app logs · env: prod · LAN-only investor surface
Overview
| Run logs | 776 files, 36.3 MB |
| Latest run log | run-20260930-074809-374.log |
| Log directory | /data/agent-logs |
| App log directory | /opt/startup/prod/logs |
Run logs (newest first, last 50)
| File | Size | Modified (UTC) |
|---|---|---|
| run-20260930-074809-374.log | 116 KB | 2026-09-30 05:55:24 |
| run-20260930-051434-373.log | 466 KB | 2026-09-30 05:38:09 |
| run-20260930-040846-372.log | 234 KB | 2026-09-30 03:04:34 |
| run-20260930-035225-371.log | 111 KB | 2026-09-30 01:58:46 |
| run-20260930-020735-370.log | 429 KB | 2026-09-30 01:42:25 |
| run-20260930-015734-369.log | 153 B | 2026-09-29 23:57:35 |
| run-20260930-014733-368.log | 153 B | 2026-09-29 23:47:34 |
| run-20260930-013732-367.log | 153 B | 2026-09-29 23:37:33 |
| run-20260930-012732-366.log | 153 B | 2026-09-29 23:27:32 |
| run-20260930-011731-365.log | 153 B | 2026-09-29 23:17:32 |
| run-20260930-010730-364.log | 153 B | 2026-09-29 23:07:31 |
| run-20260930-005729-363.log | 153 B | 2026-09-29 22:57:30 |
| run-20260930-004729-362.log | 153 B | 2026-09-29 22:47:29 |
| run-20260930-003728-361.log | 153 B | 2026-09-29 22:37:29 |
| run-20260930-002727-360.log | 153 B | 2026-09-29 22:27:28 |
| run-20260930-001726-359.log | 153 B | 2026-09-29 22:17:27 |
| run-20260930-000726-358.log | 153 B | 2026-09-29 22:07:26 |
| run-20260929-235725-357.log | 153 B | 2026-09-29 21:57:26 |
| run-20260929-234724-356.log | 153 B | 2026-09-29 21:47:25 |
| run-20260929-233724-355.log | 153 B | 2026-09-29 21:37:24 |
| run-20260929-232723-354.log | 153 B | 2026-09-29 21:27:24 |
| run-20260929-231722-353.log | 153 B | 2026-09-29 21:17:23 |
| run-20260929-230721-352.log | 153 B | 2026-09-29 21:07:22 |
| run-20260929-224605-351.log | 171 KB | 2026-09-29 20:57:21 |
| run-20260929-201447-350.log | 508 KB | 2026-09-29 20:36:05 |
| run-20260929-192011-349.log | 227 KB | 2026-09-29 18:04:47 |
| run-20260929-184400-348.log | 464 KB | 2026-09-29 17:10:11 |
| run-20260929-175208-347.log | 226 KB | 2026-09-29 16:34:00 |
| run-20260929-171135-346.log | 238 KB | 2026-09-29 15:42:08 |
| run-20260929-162028-345.log | 263 KB | 2026-09-29 15:01:35 |
| run-20260929-161028-344.log | 153 B | 2026-09-29 14:10:28 |
| run-20260929-160027-343.log | 190 B | 2026-09-29 14:00:27 |
| run-20260929-155026-342.log | 190 B | 2026-09-29 13:50:27 |
| run-20260929-154025-341.log | 153 B | 2026-09-29 13:40:26 |
| run-20260929-153025-340.log | 153 B | 2026-09-29 13:30:25 |
| run-20260929-152024-339.log | 153 B | 2026-09-29 13:20:25 |
| run-20260929-151023-338.log | 153 B | 2026-09-29 13:10:24 |
| run-20260929-150021-337.log | 153 B | 2026-09-29 13:00:23 |
| run-20260929-145020-336.log | 153 B | 2026-09-29 12:50:21 |
| run-20260929-144019-335.log | 153 B | 2026-09-29 12:40:20 |
| run-20260929-143018-334.log | 153 B | 2026-09-29 12:30:19 |
| run-20260929-142017-333.log | 153 B | 2026-09-29 12:20:18 |
| run-20260929-141017-332.log | 153 B | 2026-09-29 12:10:17 |
| run-20260929-140016-331.log | 153 B | 2026-09-29 12:00:17 |
| run-20260929-135015-330.log | 153 B | 2026-09-29 11:50:16 |
| run-20260929-134014-329.log | 153 B | 2026-09-29 11:40:15 |
| run-20260929-133014-328.log | 153 B | 2026-09-29 11:30:14 |
| run-20260929-132013-327.log | 153 B | 2026-09-29 11:20:14 |
| run-20260929-131012-326.log | 153 B | 2026-09-29 11:10:13 |
| run-20260929-121024-325.log | 296 KB | 2026-09-29 11:00:12 |
Tail — run-20260930-074809-374.log (last 200 lines)
*
* 1. GET /api/changelog folded every section header other than
* Added|Changed|Fixed|Removed into the PREVIOUS recognised section, so
* `### Notes`, `### Verified`, `### Security`, `### Tests`,
* `### Infrastructure` and `### Verification` bullets all showed up under
* `added`/`changed`/`fixed`.
* 2. /stats read `$j['git_sha']` from `gladex version --json`, but the CLI
* emits `commit` — and until 0.4.16 it emitted it on STDERR (cobra's
* Command.Print* falls back to OutOrStderr()), which stats.php discarded
* with `2>/dev/null`. The "Go CLI" row therefore rendered EMPTY on dev and
* prod. 0.4.15 worked around it with `2>&1`; 0.4.16 fixed the root cause
* (`rootCmd.SetOut(os.Stdout)`) and the section-5 canary was INVERTED to
* require stdout-only capture with a clean stderr.
*
* Run: php tests/test_changelog_api.php
* Exit codes: 0=pass, 1=fail
*/
$pass = 0;
$fail = 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"; }
}
/**
* Collect the PHP sources the app requires (app/stats/init_db/db) for repo
* and both deployed envs (deduped by realpath). db.php matters: app.php and
* stats.php require_once it, so a deploy that copies the two but forgets the
* helper fatals at runtime.
*/
function resolve_sources(): array {
$files = ['app' => 'app.php', 'stats' => 'stats.php', 'init_db' => 'init_db.php', 'db' => 'db.php'];
$dirs = [
'/data/repo/app/src/php',
'/opt/startup/dev/src/php',
'/opt/startup/prod/src/php',
__DIR__ . '/../app/src/php',
];
$out = [];
foreach ($dirs as $dir) {
$real = realpath($dir);
if ($real === false || isset($out[$real])) continue;
$entry = [];
$complete = true;
[0m$ [0mcd /data/repo && grep -rln "changelog" tests/ | xargs grep -ln "'/changelog'\|\"/changelog\"\|/changelog?" 2>/dev/null; echo "=== assertions pinning changelog page ==="; grep -rn "changelog-desc\|version-header\|changelog-item\|section-label" tests/*.php tests/*.sh | head -30
tests/test_reduced_motion.php
tests/test_main_landmark.php
tests/test_investor_heading.php
tests/test_changelog_mobile.php
tests/test_app_contrast.php
=== assertions pinning changelog page ===
tests/test_app_contrast.php:304: 'fg_selector' => '.section-label', 'bg' => 'body', 'opacity_from' => null, 'min' => 4.5]),
tests/test_changelog_mobile.php:52: * `.container`, `.version-header`, `.version-tag`, `.version-date`,
tests/test_changelog_mobile.php:53: * `.changelog-desc`, `.changelog-item`, `.section-label` and
tests/test_changelog_mobile.php:55: * values they had BEFORE the fix, and `.version-header` is explicitly barred
tests/test_changelog_mobile.php:92: * untouched, and `.version-header` still does not wrap;
tests/test_changelog_mobile.php:236:const ROW_GAP = 12.0; // `.version-header { gap: 0.75rem }`
tests/test_changelog_mobile.php:239:const ITEM_INDENT = 18.0; // .changelog-item padding-left 1rem + border-left 2px
tests/test_changelog_mobile.php:258: if (strpos($d, 'changelog-item') !== false && strpos($d, 'version-header') !== false) $chg = $d;
tests/test_changelog_mobile.php:260:assert_true($chg !== null, 'exactly one document carries .changelog-item and .version-header');
tests/test_changelog_mobile.php:270:$need = ['*', 'body', ':root', '.container', '.nav', 'h1.changelog-title', '.changelog-desc',
tests/test_changelog_mobile.php:271: '.version-header', '.version-tag', '.version-date', '.section-label', '.changelog-item', 'pre'];
tests/test_changelog_mobile.php:433: ['.changelog-desc', 'font-size', '0.875rem'],
tests/test_changelog_mobile.php:434: ['.changelog-desc', 'margin-bottom', '1.5rem'],
tests/test_changelog_mobile.php:435: ['.changelog-item', 'font-size', '0.875rem'],
tests/test_changelog_mobile.php:436: ['.changelog-item', 'padding', '0.3rem 0 0.3rem 1rem'],
tests/test_changelog_mobile.php:437: ['.changelog-item', 'border-left', '2px solid var(--border)'],
tests/test_changelog_mobile.php:438: ['.changelog-item', 'margin-bottom', '0.25rem'],
tests/test_changelog_mobile.php:439: ['.section-label', 'text-transform', 'uppercase'],
tests/test_changelog_mobile.php:440: ['.section-label', 'margin-top', '1rem'],
tests/test_changelog_mobile.php:441: ['.version-header', 'display', 'flex'],
tests/test_changelog_mobile.php:442: ['.version-header', 'align-items', 'center'],
tests/test_changelog_mobile.php:443: ['.version-header', 'gap', '0.75rem'],
tests/test_changelog_mobile.php:444: ['.version-header', 'margin-top', '2rem'],
tests/test_changelog_mobile.php:445: ['.version-header', 'margin-bottom', '1rem'],
tests/test_changelog_mobile.php:458:assert_true(decl(rule_body($rules, '.version-header'), 'flex-wrap') === null,
tests/test_changelog_mobile.php:459: '.version-header did NOT gain flex-wrap — wrapping stacks the summary under the badge at every width, 1200px included');
tests/test_changelog_mobile.php:460:assert_true(decl(rule_body($rules, '.changelog-desc'), 'overflow-wrap') === null,
tests/test_changelog_mobile.php:461: '.changelog-desc does NOT carry its own overflow-wrap (the guard lives on .container, once)');
tests/test_changelog_mobile.php:462:assert_true(decl(rule_body($rules, '.changelog-item'), 'overflow-wrap') === null,
tests/test_changelog_mobile.php:463: '.changelog-item does NOT carry its own overflow-wrap (same reason)');
> build · mimo-v2.6-flash-free
[0m$ [0mcd /data/repo && grep -n "changelog" tests/test_main_landmark.php | head -40; echo "=== investor_heading ==="; grep -n "changelog" tests/test_investor_heading.php | head -20; echo "=== reduced_motion ==="; grep -n "changelog" tests/test_reduced_motion.php | head -10; echo "=== app_contrast ==="; grep -n "changelog" tests/test_app_contrast.php | head -10
96: * line (the rendered changelog is one line) blows the backtrack limit and
125: * version of this suite, which turned the changelog page into an empty
415: * (/investor, /budget, /trust, /changelog) and mailbox.php three (list, read
451: && strpos($src['app.php'], "if (\$path === 'changelog')") !== false,
509: '/changelog' => ['app.php', 200],
606: * changelog link the investor asked for — so it moved out of $noNav/$bare and
=== investor_heading ===
29: * the other three app.php documents (/budget, /trust, /changelog) keep
263: '/changelog' => null, // its h1 text comes from the changelog payload
=== reduced_motion ===
229: '/team', '/templates', '/changelog', '/budget', '/trust', '/docs'];
=== app_contrast ===
15: * doc 3 /changelog (nav links + section labels)
273: 'fg_inline' => 'href="/changelog"', 'bg' => '.chat-card', 'opacity_from' => null, 'min' => 4.5]),
300: // doc 3 — /changelog
427:assert_true(($titles[3] ?? '') === 'Gladex.de Changelog', 'doc 3 is /changelog');
470:$routes = [0 => '/investor', 1 => '/budget', 2 => '/trust', 3 => '/changelog'];
> build · mimo-v2.6-flash-free
[0m$ [0mcd /data/repo && sed -n '85,135p' tests/test_main_landmark.php; echo "=== 600-640 ==="; sed -n '600,640p' tests/test_main_landmark.php
* PHP SOURCE stripper: line comments, then HTML comments, then blocks.
*
* Line comments go FIRST and are decided per line, because blocks-first is
* wrong here: app.php line 60 is a // comment containing "/api/*", and that
* stray opener would swallow everything up to the next block-comment close —
* lines 60-605, the /investor route with them — so every count below would be
* taken from a fiction. Per line: a // only starts a comment if it is not
* behind a : or / (so "https://" survives) and not after a /* on that line
* (so a line that OPENS with a block comment is left to the block pass).
*
* Deliberately no regex for the line pass: a lazy prefix over a 224 kB single
* line (the rendered changelog is one line) blows the backtrack limit and
* preg_replace returns null — the whole document, gone.
*/
function strip_source_comments(string $s): string {
$out = [];
foreach (explode("\n", $s) as $line) {
$blockPos = strpos($line, '/*');
$off = 0;
while (($p = strpos($line, '//', $off)) !== false) {
$prev = $p > 0 ? $line[$p - 1] : '';
if ($prev !== ':' && $prev !== '/' && ($blockPos === false || $p < $blockPos)) {
$line = substr($line, 0, $p);
break;
}
$off = $p + 1;
}
$out[] = $line;
}
$s = implode("\n", $out);
$s = preg_replace('#<!--.*?-->#s', '', $s);
$s = preg_replace('#/\*.*?\*/#s', '', $s);
return (string)$s;
}
/**
* SERVED HTML stripper: HTML comments only.
*
* On a rendered page the // and /* are the app's own JavaScript and CSS, not
* PHP comments — stripping them here deletes the document (ask the first
* version of this suite, which turned the changelog page into an empty
* string). What can hide a landmark in served output is an HTML comment, and
* that is what goes.
*/
function strip_html_comments(string $s): string {
return (string)preg_replace('#<!--.*?-->#s', '', $s);
}
/** Count real <main ...> open tags (never </main>, never "<main" in prose). */
function main_opens(string $html): int {
return (int)preg_match_all('#<main(?:\s[^>]*)?>#', $html);
=== 600-640 ===
* straight out of <body> and need no help, but six render a nav bar between
* the two, and before this step NONE of them carried a skip link — grepping
* the whole of app/src/php for "skip" found nothing but prose. So the
* invariant the suite already claimed (2.4.1) now has its mechanism.
*
* 2026-09-29 (later the same day): landing.php gained a nav bar — the
* changelog link the investor asked for — so it moved out of $noNav/$bare and
* into the tables below. Those tables are the census of WHICH files carry a
* nav, and that fact changed; the rule did not. Seven files render a nav now.
*/
echo "\n=== 6. source: a nav bar before <main> means a working skip link (2.4.1) ===\n";
$repoPhp = '/data/repo/app/src/php';
// file => how many skip links it renders, and how many id="main" it owns.
// mailbox.php renders ONE nav-bearing shell but TWO mutually exclusive
// render paths (list + read), each with its own <main> — hence 1 / 2.
// landing.php moved from $noNav to here with its nav bar (T1): a nav before
// <main> is precisely the case this rule exists for, so it now owes 1 / 1.
$withNav = ['app.php' => 3, 'docs.php' => 1, 'mailbox.php' => 1, 'landing.php' => 1];
$wantId = ['app.php' => 3, 'docs.php' => 1, 'mailbox.php' => 2, 'landing.php' => 1];
$noNav = ['info.php', 'team.php', 'templates.php',
'download.php', 'start.php', 'stats.php', 'log.php'];
foreach ($withNav as $f => $wantAnchor) {
if (!isset($src[$f])) { skip("$f not resolved — skip-link source assertions skipped"); continue; }
$a = substr_count($src[$f], 'class="skip-link"');
$h = substr_count($src[$f], 'href="#main"');
$i = substr_count($src[$f], 'id="main"');
assert_true($a === $wantAnchor, "$f: exactly $wantAnchor skip link(s) (got $a)");
assert_true($h === $a && $a > 0, "$f: every skip link names #main ($h href against $a link)");
assert_true($i === $wantId[$f],
"$f: exactly {$wantId[$f]} id=\"main\" (got $i) — one per document this file renders");
$b = strpos($src[$f], '<body');
$l = strpos($src[$f], 'class="skip-link"');
$n = strpos($src[$f], 'class="nav"');
assert_true($b !== false && $l !== false && $b < $l,
"$f: the skip link is the first element inside <body>");
assert_true($n === false || ($l !== false && $l < $n),
"$f: the skip link comes BEFORE the nav bar it is meant to bypass");
> 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)
[Wed Sep 30 07:51:47 2026] 127.0.0.1:34598 Accepted [Wed Sep 30 07:51:47 2026] 127.0.0.1:34598 Closing [Wed Sep 30 07:51:47 2026] 127.0.0.1:34610 Accepted [Wed Sep 30 07:51:47 2026] 127.0.0.1:34610 Closing [Wed Sep 30 07:51:47 2026] 127.0.0.1:34612 Accepted [Wed Sep 30 07:51:47 2026] 127.0.0.1:34612 Closing [Wed Sep 30 07:51:47 2026] 127.0.0.1:34614 Accepted [Wed Sep 30 07:51:47 2026] 127.0.0.1:34614 Closing [Wed Sep 30 07:51:47 2026] 127.0.0.1:34616 Accepted [Wed Sep 30 07:51:47 2026] 127.0.0.1:34616 Closing [Wed Sep 30 07:51:48 2026] 127.0.0.1:34618 Accepted [Wed Sep 30 07:51:48 2026] 127.0.0.1:34618 Closing [Wed Sep 30 07:51:48 2026] 127.0.0.1:34626 Accepted [Wed Sep 30 07:51:48 2026] 127.0.0.1:34626 Closing [Wed Sep 30 07:51:48 2026] 127.0.0.1:34640 Accepted [Wed Sep 30 07:51:48 2026] 127.0.0.1:34640 Closing [Wed Sep 30 07:54:28 2026] 127.0.0.1:60534 Accepted [Wed Sep 30 07:54:28 2026] 127.0.0.1:60534 Closing [Wed Sep 30 07:54:28 2026] 127.0.0.1:60548 Accepted [Wed Sep 30 07:54:28 2026] 127.0.0.1:60548 Closing [Wed Sep 30 07:54:28 2026] 127.0.0.1:60554 Accepted [Wed Sep 30 07:54:28 2026] 127.0.0.1:60554 Closing [Wed Sep 30 07:54:28 2026] 127.0.0.1:60556 Accepted [Wed Sep 30 07:54:28 2026] 127.0.0.1:60556 Closing [Wed Sep 30 07:54:28 2026] 127.0.0.1:60570 Accepted [Wed Sep 30 07:54:28 2026] 127.0.0.1:60570 Closing [Wed Sep 30 07:54:28 2026] 127.0.0.1:60580 Accepted [Wed Sep 30 07:54:28 2026] 127.0.0.1:60580 Closing [Wed Sep 30 07:54:28 2026] 127.0.0.1:60586 Accepted [Wed Sep 30 07:54:29 2026] 127.0.0.1:60586 Closing [Wed Sep 30 07:54:29 2026] 127.0.0.1:60588 Accepted [Wed Sep 30 07:54:29 2026] 127.0.0.1:60588 Closing [Wed Sep 30 07:54:29 2026] 127.0.0.1:60604 Accepted [Wed Sep 30 07:54:29 2026] 127.0.0.1:60604 Closing [Wed Sep 30 07:54:29 2026] 127.0.0.1:60614 Accepted [Wed Sep 30 07:54:29 2026] 127.0.0.1:60614 Closing [Wed Sep 30 07:55:09 2026] 127.0.0.1:51328 Accepted [Wed Sep 30 07:55:09 2026] 127.0.0.1:51328 Closing [Wed Sep 30 07:55:09 2026] 127.0.0.1:51344 Accepted [Wed Sep 30 07:55:09 2026] 127.0.0.1:51344 Closing [Wed Sep 30 07:55:09 2026] 127.0.0.1:51354 Accepted [Wed Sep 30 07:55:09 2026] 127.0.0.1:51354 Closing [Wed Sep 30 07:55:09 2026] 127.0.0.1:51356 Accepted [Wed Sep 30 07:55:09 2026] 127.0.0.1:51356 Closing [Wed Sep 30 07:55:09 2026] 127.0.0.1:51372 Accepted [Wed Sep 30 07:55:09 2026] 127.0.0.1:51372 Closing [Wed Sep 30 07:55:09 2026] 127.0.0.1:51382 Accepted [Wed Sep 30 07:55:09 2026] 127.0.0.1:51382 Closing [Wed Sep 30 07:55:09 2026] 127.0.0.1:51384 Accepted [Wed Sep 30 07:55:10 2026] 127.0.0.1:51384 Closing [Wed Sep 30 07:55:10 2026] 127.0.0.1:51394 Accepted [Wed Sep 30 07:55:10 2026] 127.0.0.1:51394 Closing [Wed Sep 30 07:55:10 2026] 127.0.0.1:51404 Accepted [Wed Sep 30 07:55:10 2026] 127.0.0.1:51404 Closing [Wed Sep 30 07:55:10 2026] 127.0.0.1:51410 Accepted [Wed Sep 30 07:55:10 2026] 127.0.0.1:51410 Closing [Wed Sep 30 07:55:43 2026] 127.0.0.1:44230 Accepted [Wed Sep 30 07:55:43 2026] 127.0.0.1:44230 Closing [Wed Sep 30 07:55:44 2026] 127.0.0.1:44244 Accepted
Generated 2026-09-30 05:55:44 UTC · Gladex.de