Gladex Agent Logs

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

Overview
Run logs753 files, 35 MB
Latest run logrun-20260929-224605-351.log
Log directory/data/agent-logs
App log directory/opt/startup/prod/logs
Run logs (newest first, last 50)
FileSizeModified (UTC)
run-20260929-224605-351.log 149 KB 2026-09-29 20:55:23
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
run-20260929-110953-324.log 242 KB 2026-09-29 10:00:24
run-20260929-095926-323.log 329 KB 2026-09-29 08:59:53
run-20260929-072444-322.log 382 KB 2026-09-29 07:49:26
run-20260929-065102-321.log 175 KB 2026-09-29 05:14:44
run-20260929-052828-320.log 333 KB 2026-09-29 04:41:02
run-20260929-040138-319.log 298 KB 2026-09-29 03:18:28
run-20260929-020936-318.log 217 KB 2026-09-29 01:51:38
run-20260929-015935-317.log 153 B 2026-09-28 23:59:36
run-20260929-014935-316.log 153 B 2026-09-28 23:49:35
run-20260929-011234-315.log 247 KB 2026-09-28 23:39:35
run-20260928-234838-314.log 263 KB 2026-09-28 23:02:34
run-20260928-222402-313.log 319 KB 2026-09-28 21:38:38
run-20260928-211218-312.log 234 KB 2026-09-28 20:14:02
run-20260928-201031-311.log 248 KB 2026-09-28 19:02:18
run-20260928-184021-310.log 439 KB 2026-09-28 18:00:31
run-20260928-171725-309.log 236 KB 2026-09-28 16:30:21
run-20260928-161526-308.log 183 KB 2026-09-28 15:07:25
run-20260928-160525-307.log 153 B 2026-09-28 14:05:26
run-20260928-155524-306.log 153 B 2026-09-28 13:55:25
run-20260928-154524-305.log 153 B 2026-09-28 13:45:24
run-20260928-153523-304.log 153 B 2026-09-28 13:35:24
run-20260928-152522-303.log 153 B 2026-09-28 13:25:23
run-20260928-151521-302.log 153 B 2026-09-28 13:15:22
Tail — run-20260929-224605-351.log (last 200 lines)
    return 0
}

echo "=== A. investor app over HTTP: dev ($DEV) and prod ($PROD) ==="
for base in "$DEV" "$PROD"; do
    [ "$base" = "$DEV" ] && env=dev || env=prod

    check_page "$env /"            200 "$base/" \
        '<title>gladex.de</title>' '<h1>gladex.de</h1>' '<html lang="en">' 'name="viewport"'
    check_page "$env /team"        200 "$base/team" \
        '<title>Gladex — Team</title>' '<h1>The Team</h1>' \
        'Lena Hartmann' 'Jonas Weber' 'Mia Schneider' 'Leon Fischer'
    check_page "$env /info"        200 "$base/info" \
        '<title>Gladex — Unified AI Developer Workspace</title>'
    check_page "$env /stats"       200 "$base/stats" \
        '<title>Gladex — Container Statistics</title>'
    check_page "$env /changelog"   200 "$base/changelog" \
        '<title>Gladex.de Changelog</title>'
    check_page "$env /mailbox"     200 "$base/mailbox" \
        '<title>Gladex.de Mailbox</title>'

    # The two gates: neither may render a page.
    got=$(http_get "$base/login")
    if [ "$got" = "302" ]; then ok "$env /login -> HTTP 302 (auth gate intact)"
    else bad "$env /login -> HTTP $got, want 302"; fi

    got=$(http_get "$base/vhost-ui-smoke-no-such-route")
    if [ "$got" = "302" ]; then ok "$env unknown path -> HTTP 302 (catch-all intact)"
    else bad "$env unknown path -> HTTP $got, want 302"; fi
    if has "$base/investor" || has 'Location: /investor'; then
        ok "$env unknown path redirects to /investor"
    else
        # curl hides response headers; follow the Location instead.
        got=$(curl -sS -o "$BODY" -w '%{http_code}' --max-time "$TMO" \
            "$base/vhost-ui-smoke-no-such-route" -L 2>/dev/null || echo "000")
        if has '<title>' || [ "$got" = "200" ]; then
            ok "$env unknown path redirects to a rendered page"
        else
            bad "$env unknown path redirect target did not render"
        fi
    fi

    got=$(http_get "$base/healthz")
    if [ "$got" = "200" ] && has '"status":"ok"'; then
        ok "$env /healthz -> 200 + status ok"
    else
        bad "$env /healthz -> HTTP $got + status ok (want 200)"
    fi
done

echo
echo "=== B. HTTPS vhosts after the wildcard narrowing ==="
# The seven names gladex-ssl.conf still declares, each with the page its Host
# header selects (app.php routes on Host for info/log/stats).
check_host "apex gladex.de"          gladex.de       "/" 200 \
    '<title>gladex.de</title>' '<h1>gladex.de</h1>'
check_host "dev.gladex.de"           dev.gladex.de   "/" 200 \
    '<title>gladex.de</title>'
check_host "team.gladex.de /team"    team.gladex.de  "/team" 200 \
    '<title>Gladex — Team</title>' 'Jonas Weber' 'Leon Fischer'
# team.gladex.de's ROOT currently renders the landing page, not the team page.
# Pinned as-is on purpose: if someone makes the bare hostname serve /team,
# that is a real product decision and this line should go red and be changed
# deliberately, not drift.
check_host "team.gladex.de / (root)" team.gladex.de  "/" 200 \
    '<title>gladex.de</title>'
check_host "info.gladex.de"          info.gladex.de  "/" 200 \
    '<title>Gladex — Unified AI Developer Workspace</title>'
check_host "stats.gladex.de"         stats.gladex.de "/" 200 \
    '<title>Gladex — Container Statistics</title>'
check_host "log.gladex.de"           log.gladex.de   "/" 200 \
    '<title>Gladex — Agent Logs</title>'

# The two vhosts the change added: they must serve their own apps, NOT ours.
check_host "photos.gladex.de"        photos.gladex.de "/" 200 \
    'Immich'
# cloud.gladex.de / answered 200 directly for as long as Nextcloud was NOT
# installed. Once INBOX line 468 installed it (2026-09-29), an unauthenticated
# GET / is a single 302 to Nextcloud's own login page — correct Nextcloud
# behaviour, not a failure and not a loop — so this line now asserts WHERE THE
# REQUEST LANDS instead of the status of the first hop. The hop count is read
# explicitly because `-L` alone would swallow a redirect loop into a bare
# `000`; two assertions, exactly the two check_host() used to make (status,
# marker), so the suite's assertion count does not move.
cloud_res=$(curl -skL -o "$BODY" -w '%{http_code} %{num_redirects}' --max-time "$TMO" \
    --resolve "cloud.gladex.de:443:$IP" "https://cloud.gladex.de/" 2>/dev/null || echo "000 99")
cloud_code=${cloud_res% *}
cloud_hops=${cloud_res#* }
> build · mimo-v2.6-flash-free
$ cd /data/repo && sed -n '78,100p' tests/test_cli_version.php; echo "=== grep download markers in tests ==="; grep -rn "download-btn\|install-box\|Download Gladex CLI\|Download — Gladex" tests/ | head -20
}

/** Render download.php in a fresh PHP process; return the badge version ('' = no badge). */
function render_badge(string $file, ?string $const): string {
    $prefix = $const !== null ? 'const GLADEX_APP_VERSION = ' . var_export($const, true) . '; ' : '';
    $code = $prefix . 'ob_start(); include $argv[1]; $h = ob_get_clean(); '
          . 'if (preg_match(\'/version-badge">v([^<]+)</\', $h, $m)) echo $m[1];';
    $out = [];
    $rc = 1;
    exec('php -r ' . escapeshellarg($code) . ' ' . escapeshellarg($file), $out, $rc);
    return ($rc === 0 && $out) ? trim(implode('', $out)) : '';
}

/** All distinct versions of the two /docs CLI mentions: [download-line[], ascii-diagram[]]. */
function docs_cli_mentions(string $src): array {
    preg_match_all('/Go CLI binary \(v(\d+\.\d+\.\d+)\)/', $src, $a);
    preg_match_all('/gladex v(\d+\.\d+\.\d+)/', $src, $b);
    return [array_values(array_unique($a[1])), array_values(array_unique($b[1]))];
}

$REPO      = dirname(__DIR__);
$CHANGELOG = "$REPO/CHANGELOG.md";
$BUILD     = "$REPO/app/src/go/build.sh";
=== grep download markers in tests ===
$ cd /data/repo && sed -n '1,40p' app/src/php/download.php; echo "=== md5 checks ==="; md5sum app/bin/gladex /opt/startup/dev/bin/gladex /opt/startup/prod/bin/gladex app/src/vscode/gladex-0.1.0.vsix
<?php
/**
 * Gladex CLI Download Page — public landing for binary downloads
 *
 * CLI + app share ONE version train: the CHANGELOG top entry, surfaced by
 * app.php's GLADEX_APP_VERSION const (app.php includes this file, so the
 * const is always defined in-app). The old '$version = 0.2.0' literal went
 * permanently stale — see CHANGELOG 0.4.28. '0.0.0' is a loud sentinel for
 * standalone rendering without the const; the test suite asserts it never
 * reaches a served badge.
 */
$version = defined('GLADEX_APP_VERSION') ? GLADEX_APP_VERSION : '0.0.0';
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="Download the Gladex CLI — unified AI developer workspace for context, workflows, and tool connectivity.">
    <meta name="theme-color" content="#0a0a0f">
    <meta property="og:title" content="Download Gladex CLI">
    <meta property="og:description" content="Unified AI developer workspace. Store context, run workflows, connect AI tools.">
    <meta property="og:type" content="website">
    <title>Download — Gladex CLI</title>
    <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><rect width='100' height='100' rx='20' fill='%230a0a0f'/><text x='50' y='68' font-size='52' font-family='system-ui' font-weight='200' fill='white' text-anchor='middle'>G</text></svg>">
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            min-height: 100vh;
            background: #0a0a0f;
            color: #e8e8ed;
            font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
            line-height: 1.6;
        }
        .container {
            max-width: 680px;
            margin: 0 auto;
            padding: 4rem 2rem;
        }
        h1 {
=== md5 checks ===
50c2b4b611d086bdae268578c876cc0d  app/bin/gladex
50c2b4b611d086bdae268578c876cc0d  /opt/startup/dev/bin/gladex
50c2b4b611d086bdae268578c876cc0d  /opt/startup/prod/bin/gladex
75dc7565c4f4e2131101808ded53e086  app/src/vscode/gladex-0.1.0.vsix
> build · mimo-v2.6-flash-free
$ cd /data/repo && grep -n "download" tests/test_app_contrast.php tests/test_app_contrast_meta.php tests/test_grid_320.php tests/test_page_lang.php tests/test_investor_heading.php tests/test_docs_mobile.php tests/test_chat_a11y.php 2>/dev/null | head -30; echo "=== contrast files ==="; grep -n "files\|scan\|\$pages\|docs.php" tests/test_app_contrast.php | head -25
=== contrast files ===
233:     * is precisely the `}` the NEXT selector stands behind, so the scan lands
> build · mimo-v2.6-flash-free
$ cd /data/repo && grep -n "app.php\|landing.php\|stats.php\|glob\|scandir\|SOURCE\|\\.php'" tests/test_app_contrast.php | head -30; echo "=== meta ==="; grep -n "app.php\|files\|SOURCES" tests/test_app_contrast_meta.php | head -20
3: * Text contrast in app.php's four documents (WCAG 1.4.3 — 4.5:1 for normal text).
6: * app.php still draws accent-coloured TEXT with `--accent` (#6c5ce7), a colour
8: * a second token (`--accent-text: #9385f5`) in [0.4.58]; app.php — the four
11: * app.php is ONE file containing FOUR complete documents:
24: *   - splits app.php into its documents on `<!DOCTYPE html>`,
39: *   1. app.php splits into exactly four documents, each with a `:root` and a
42: *   2. repo == dev == prod byte-identical for app.php (an undeployed fix cannot
67:    global $pass, $fail;
73:    global $skip;
378:    global $pass, $fail;
404:echo "=== 1. app.php splits into four documents, each with a :root and a sheet ===\n";
406:$repo = '/data/repo/app/src/php/app.php';
407:assert_true(is_file($repo), 'app.php present in the repo');
443:echo "\n=== 3. repo == dev == prod (byte-identical app.php) ===\n";
446:    'repo' => '/data/repo/app/src/php/app.php',
447:    'dev'  => '/opt/startup/dev/src/php/app.php',
448:    'prod' => '/opt/startup/prod/src/php/app.php',
453:    if (!is_file($p)) { assert_true(false, "$label copy of app.php present"); $present = false; continue; }
455:    assert_true(true, "$label copy of app.php present");
499: * [0.4.58] made in templates.php. app.php has four `:root` blocks, so all four
=== meta ===
16: * against healthy files — a healthy run has nothing to skip. So this suite
34: *   F3  the REAL app.php (healthy). Section 6 must show 0 skips and all 12
39: * Hermetic by design: all three copies of app.php are redirected at the
47: * temp tree; the suite under test and app.php are never written to.
85:const APPSRC = '/data/repo/app/src/php/app.php';
162:        '/data/repo/app/src/php/app.php'  => $fixture,
163:        '/opt/startup/dev/src/php/app.php'  => $fixture,
164:        '/opt/startup/prod/src/php/app.php' => $fixture,
196:assert_true($src !== '', 'app.php readable at ' . APPSRC);
284:echo "\n=== F3: healthy app.php — section 6 must be fully checked, never skipped ===\n";
> build · mimo-v2.6-flash-free
→ Read repo/app/src/php/download.php [offset=40, limit=102]

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)
[Tue Sep 29 22:34:35 2026] 127.0.0.1:47442 Accepted
[Tue Sep 29 22:34:35 2026] 127.0.0.1:47442 Closing
[Tue Sep 29 22:34:35 2026] 127.0.0.1:47452 Accepted
[Tue Sep 29 22:34:35 2026] 127.0.0.1:47452 Closing
[Tue Sep 29 22:34:35 2026] 127.0.0.1:47454 Accepted
[Tue Sep 29 22:34:35 2026] 127.0.0.1:47454 Closing
[Tue Sep 29 22:34:35 2026] 127.0.0.1:47456 Accepted
[Tue Sep 29 22:34:35 2026] 127.0.0.1:47456 Closing
[Tue Sep 29 22:34:35 2026] 127.0.0.1:47464 Accepted
[Tue Sep 29 22:34:35 2026] 127.0.0.1:47464 Closing
[Tue Sep 29 22:34:35 2026] 127.0.0.1:47472 Accepted
[Tue Sep 29 22:34:36 2026] 127.0.0.1:47472 Closing
[Tue Sep 29 22:34:36 2026] 127.0.0.1:47484 Accepted
[Tue Sep 29 22:34:36 2026] 127.0.0.1:47484 Closing
[Tue Sep 29 22:35:15 2026] 127.0.0.1:44644 Accepted
[Tue Sep 29 22:35:15 2026] 127.0.0.1:44644 Closing
[Tue Sep 29 22:35:15 2026] 127.0.0.1:44648 Accepted
[Tue Sep 29 22:35:15 2026] 127.0.0.1:44648 Closing
[Tue Sep 29 22:38:29 2026] 127.0.0.1:45408 Accepted
[Tue Sep 29 22:38:29 2026] 127.0.0.1:45408 Closing
[Tue Sep 29 22:41:09 2026] 127.0.0.1:50328 Accepted
[Tue Sep 29 22:41:09 2026] 127.0.0.1:50328 Closing
[Tue Sep 29 22:47:12 2026] 127.0.0.1:36674 Accepted
[Tue Sep 29 22:47:12 2026] 127.0.0.1:36674 Closing
[Tue Sep 29 22:47:12 2026] 127.0.0.1:36678 Accepted
[Tue Sep 29 22:47:12 2026] 127.0.0.1:36678 Closing
[Tue Sep 29 22:47:12 2026] 127.0.0.1:36684 Accepted
[Tue Sep 29 22:47:12 2026] 127.0.0.1:36684 Closing
[Tue Sep 29 22:47:12 2026] 127.0.0.1:36686 Accepted
[Tue Sep 29 22:47:12 2026] 127.0.0.1:36686 Closing
[Tue Sep 29 22:47:12 2026] 127.0.0.1:36700 Accepted
[Tue Sep 29 22:47:12 2026] 127.0.0.1:36700 Closing
[Tue Sep 29 22:47:12 2026] 127.0.0.1:36710 Accepted
[Tue Sep 29 22:47:12 2026] 127.0.0.1:36710 Closing
[Tue Sep 29 22:47:12 2026] 127.0.0.1:36718 Accepted
[Tue Sep 29 22:47:12 2026] 127.0.0.1:36718 Closing
[Tue Sep 29 22:47:13 2026] 127.0.0.1:36730 Accepted
[Tue Sep 29 22:47:13 2026] 127.0.0.1:36730 Closing
[Tue Sep 29 22:47:13 2026] 127.0.0.1:36732 Accepted
[Tue Sep 29 22:47:13 2026] 127.0.0.1:36732 Closing
[Tue Sep 29 22:52:01 2026] 127.0.0.1:50126 Accepted
[Tue Sep 29 22:52:01 2026] 127.0.0.1:50126 Closing
[Tue Sep 29 22:52:01 2026] 127.0.0.1:50136 Accepted
[Tue Sep 29 22:52:01 2026] 127.0.0.1:50136 Closing
[Tue Sep 29 22:52:01 2026] 127.0.0.1:50152 Accepted
[Tue Sep 29 22:52:01 2026] 127.0.0.1:50152 Closing
[Tue Sep 29 22:52:01 2026] 127.0.0.1:50166 Accepted
[Tue Sep 29 22:52:01 2026] 127.0.0.1:50166 Closing
[Tue Sep 29 22:52:01 2026] 127.0.0.1:50168 Accepted
[Tue Sep 29 22:52:01 2026] 127.0.0.1:50168 Closing
[Tue Sep 29 22:52:01 2026] 127.0.0.1:50178 Accepted
[Tue Sep 29 22:52:01 2026] 127.0.0.1:50178 Closing
[Tue Sep 29 22:52:01 2026] 127.0.0.1:50190 Accepted
[Tue Sep 29 22:52:01 2026] 127.0.0.1:50190 Closing
[Tue Sep 29 22:53:53 2026] 127.0.0.1:41574 Accepted
[Tue Sep 29 22:53:53 2026] 127.0.0.1:41574 Closing
[Tue Sep 29 22:55:25 2026] 127.0.0.1:54030 Accepted
[Tue Sep 29 22:55:25 2026] 127.0.0.1:54030 Closing
[Tue Sep 29 22:55:25 2026] 127.0.0.1:54038 Accepted

Generated 2026-09-29 20:55:25 UTC · Gladex.de