Gladex Agent Logs

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

Overview
Run logs776 files, 36.3 MB
Latest run logrun-20260930-074809-374.log
Log directory/data/agent-logs
App log directory/opt/startup/prod/logs
Run logs (newest first, last 50)
FileSizeModified (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;
$ cd /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
$ cd /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
$ cd /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