Skip to content

v0.20 PR 1: entrypoint dashboard sync, / redirect, /health HTML#71

Merged
mcheemaa merged 5 commits intomainfrom
v0.20-pr-01-quick-fixes
Apr 16, 2026
Merged

v0.20 PR 1: entrypoint dashboard sync, / redirect, /health HTML#71
mcheemaa merged 5 commits intomainfrom
v0.20-pr-01-quick-fixes

Conversation

@mcheemaa
Copy link
Copy Markdown
Member

Summary

Four quick fixes teed up for v0.20. The most important is fix 1: the v0.19.1 dashboard fix never reached production on existing VMs because the entrypoint only syncs a whitelist of files from the image into the phantom_public volume. Five of seven dashboard JS files on cheeks are still dated Apr 14. Fix 1 unblocks all subsequent v0.20 dashboard work.

The four fixes

  1. Entrypoint wholesale overlay for public/dashboard. scripts/docker-entrypoint.sh now replaces the entire dashboard/ directory from public-defaults/ on every container start, followed by chown -R 999:999 so the non-root phantom user retains write access. chat/, _examples/, and the named top-level files keep their existing behaviour. Agent-created HTML at the top level is still preserved (we do not touch paths outside the enumerated set).
  2. Cache-Control hardening for dashboard JS. src/ui/serve.ts returns Cache-Control: no-store, no-cache, must-revalidate plus Pragma: no-cache / Expires: 0 for *.js under /ui/dashboard/. Every other asset keeps the existing no-cache policy. Defense in depth so future dashboard deploys reach every browser without a hard refresh.
  3. / redirect to /ui/. src/core/server.ts returns a 302 redirect for bare root (/ or empty pathname) before the 404 catch-all. 302 (not 301) so we can change the destination later if we want. Nothing in Phantom today probes /; Docker HEALTHCHECK and CF probes target /health.
  4. /health HTML page with content negotiation. src/core/health-page.ts exports renderHealthHtml(payload). The /health handler returns the HTML page when the request accepts text/html (browsers) and JSON otherwise (curl, Docker healthcheck, MCP clients, jq). ?format=json overrides to JSON regardless of Accept so the embedded JS can re-fetch itself. Design matches public/index.html: warm cream tokens, Instrument Serif display, Inter body, JetBrains Mono numerics, status badge, memory dots, channel chips, evolution pill, scheduler stats, peers table. Auto-refresh every 10 seconds via setInterval. Zero console errors in both light and dark themes.

Why this lands now

  • The entrypoint fix is the deploy-skew bug from v0.19.1 finally fixed. Without it, every future public/dashboard/*.js change silently fails to reach the browser on existing VMs.
  • The no-store cache header closes the long-tail "user's cached session keeps the stale JS after the deploy" hole.
  • The / redirect replaces the current {"error":"Not found"} 404 JSON that operators see when they type the bare domain.
  • The /health HTML page replaces the raw JSON operators land on when they click the Health quick-link from /ui/.

Research

local/2026-04-16-v0.20-next-level/research/01-wave-1-quick-fixes.md

Test plan

Automated (all green locally)

  • bun run typecheck clean
  • bun run lint clean
  • bun test 1610 pass, 10 skip, 0 fail
  • bash -n scripts/docker-entrypoint.sh exits 0
  • New tests:
    • src/core/__tests__/server.test.ts covers / 302 redirect, /health JSON default, /health HTML on text/html, /health JSON on application/json, /health browser-style Accept returns HTML, /health?format=json overrides HTML Accept
    • src/ui/__tests__/serve.test.ts adds cache-control coverage: dashboard JS gets no-store, no-cache, must-revalidate, other assets keep no-cache

Manual

  • curl -I http://localhost:3000/ shows 302 with Location: /ui/
  • curl -H "Accept: text/html" http://localhost:3000/health returns HTML with the agent name in the title and display heading
  • curl http://localhost:3000/health returns JSON (default Accept behaviour preserved for Docker HEALTHCHECK)
  • curl -I http://localhost:3000/ui/dashboard/dashboard.js shows Cache-Control: no-store, no-cache, must-revalidate
  • Browser: open /health, verify HTML renders with zero console errors in both light and dark themes, auto-refreshes every 10 s
  • Deploy verification (on a staging VM): docker exec phantom md5sum /app/public/dashboard/dashboard.js /app/public-defaults/dashboard/dashboard.js returns identical MD5s after docker compose up -d --force-recreate phantom

Not in this PR

  • Version bump (v0.20.0 lands at the end of the chapter, not here)
  • Git tag
  • Merge to main

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7f682decfd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/core/server.ts
Comment on lines +146 to +147
headers: { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-store" },
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add Vary header for negotiated /health responses

The /health handler now serves different representations (HTML vs JSON) based on Accept, but the response headers do not include Vary: Accept. In any deployment with an HTTP cache/proxy in front of the app, one representation can be cached and then incorrectly reused for clients with different Accept headers (for example, a browser getting cached JSON instead of HTML). Add Vary: Accept to both representations to keep content negotiation correct.

Useful? React with 👍 / 👎.

Match the error-handling pattern used by the sibling chat sync block.
Without 2>/dev/null || true, an unexpected rm/cp/chown failure under
set -e would crash the entrypoint and the container restart-loops on
deploy.
@mcheemaa mcheemaa merged commit 21ac307 into main Apr 16, 2026
1 check passed
mcheemaa added a commit that referenced this pull request Apr 17, 2026
Bumps the version to 0.20.0 in every place it's referenced:
- package.json (1)
- src/core/server.ts VERSION constant
- src/mcp/server.ts MCP server identity
- src/cli/index.ts phantom --version output
- README.md version + tests badges
- CLAUDE.md tagline + bun test count
- CONTRIBUTING.md test count

Tests: 1,799 pass / 10 skip / 0 fail. Typecheck and lint clean. No
0.19.1 or 1,584-tests references remain in source, docs, or badges.

v0.20 shipped eight PRs on top of v0.19.1:
  #71 entrypoint dashboard sync + / redirect + /health HTML
  #72 Sessions dashboard tab
  #73 Cost dashboard tab
  #74 Scheduler tab + create-job + Sonnet describe-assist
  #75 Evolution Phase A + Memory explorer tabs
  #76 Settings page restructure (phantom.yaml, 6 sections)
  #77 Agent avatar upload across 14 identity surfaces
  #79 Landing page redesign (hero, starter tiles, live pages list)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant