Cosmos Intelligence Playbook¶
Status: Live — Phase A0 + A1 + A2 shipped 12 May 2026 Owners: Sush + AI co-founder Scope: Cosmos-wide live counter + private analytics intelligence dashboard
The first deep cross-planet data layer. Single GA4 property + custom dimension tags every hit per-planet → public pill (cosmos-bar) + gated dashboard (CC Cosmos tab) + nightly summary worker. Future Phase B layers outcome events on top of this foundation.
TL;DR — what this project is¶
Sush wanted to "see who's in the cosmos right now" (live counter visible on every planet) AND a deeper "intelligence cockpit" he can open with Sunday coffee and walk away with 1–3 things to do (decisions, not just numbers). The cockpit is gated to Sush + AI only; the counter is a public vitality signal.
The architecture pivots on one event-scoped GA4 custom dimension (cosmos_planet) that every cosmos hit carries. Worker queries split data by it. Single property, single measurement ID, zero per-stream juggling.
Two rubber-duck passes + one SME code review shaped the design before any code shipped. The full critique-then-implement loop saved at least one BLOCKING bug per phase.
The 9 surfaces¶
| Slug | Domain | Kind | Identification rule |
|---|---|---|---|
earth |
www.aguidetocloud.com |
planet | host = www, path !startsWith /guided/ |
guided |
www.aguidetocloud.com/guided/ |
moon | host = www, path startsWith /guided/ |
brainbar |
cmd.aguidetocloud.com |
planet | host = cmd |
shift |
shift.aguidetocloud.com |
planet | host = shift |
plainai |
plainai.aguidetocloud.com |
planet | host = plainai, path !startsWith /learn |
curriculum |
plainai.aguidetocloud.com/learn[/...] |
moon | host = plainai, path startsWith /learn |
agentic |
agents.aguidetocloud.com |
planet | host = agents |
claw |
claw.aguidetocloud.com |
planet | host = claw |
cosmos |
cosmos.aguidetocloud.com |
hub | host = cosmos |
The slug-detection logic is duplicated in TWO places (client-side gtag config in each repo + server-side resolvePlanet in _cosmos-shared.js). Both MUST stay in sync when a new planet ships. Critical gotcha: Plain AI uses pathname.startsWith('/learn') — original indexOf('/learn/')===0 failed on /learn (no trailing slash) and silently misattributed every curriculum landing-page visit. SME caught this; if you add a new path-based split, do the same startsWith (not indexOf).
Architecture¶
┌──────────────────────────────────────────────────────────────────────────┐
│ Every planet's BaseLayout / baseof.html │
│ gtag G-2HWWZGWCD0 + cosmos_planet=<slug> │
│ Consent Mode v2 defaults: ad_*=denied, analytics_storage=granted │
└─────────────────────────────────┬────────────────────────────────────────┘
▼
GA4 property 530486519
Event-scoped custom dim: cosmos_planet (id 14859585669)
│
┌─────────────────────────┴───────────────────────────┐
▼ ▼
┌────────────────────────────────┐ ┌────────────────────────────────────┐
│ /api/stats?realtime=cosmos │ │ /api/cosmos-summary (gated) │
│ PUBLIC: returns {totalUnique}│ │ 1× per ~24h, KV-cached, SWR. │
│ GATED (intel=1): + byPlanet │ │ Pulled by CC dashboard. │
│ CORS *, 45s caches.default │ │ ~6 GA4 queries, throttled to 3. │
└──────────────┬─────────────────┘ │ Soft KV lock dedupes regens. │
│ └─────────────┬──────────────────────┘
▼ │
┌─────────────────────────────────┐ ▼
│ <cosmos-bar> live counter pill │ ┌────────────────────────────────────┐
│ On every planet's shared nav │ │ CC Dashboard — new "🌌 Cosmos" tab │
│ Polls every 45s · hides <2 │ │ 4 sections: Pulse · Leaderboard │
│ Hides after 3 fails │ │ · Signals · Stars │
│ Lifecycle-safe: 1 interval + │ │ Auth: sessionStorage.cc-p Bearer │
│ AbortController + cleanup │ │ Keyboard shortcut: c │
└─────────────────────────────────┘ └────────────────────────────────────┘
File map (what lives where)¶
Worker (aguidetocloud-revamp/functions/api/)¶
| File | Purpose |
|---|---|
_cosmos-shared.js |
SSOT for cosmos endpoints — auth, CORS, planet taxonomy, NZT week math, throttle. _ prefix = no auto-route. |
stats.js |
Hosts ?realtime=cosmos[&intel=1]. Imports from _cosmos-shared.js. |
cosmos-summary.js |
Nightly summary endpoint. Stale-while-revalidate via context.waitUntil(). |
Dashboard (aguidetocloud-revamp/)¶
| File | Change |
|---|---|
layouts/cc/list.html |
New 🌌 Cosmos tab button + panel with 4 sections + warm-up banner. |
static/js/command-centre.js |
cosmosData state + fetchCosmos + renderCosmos and 4 sub-renders + keyboard c + switchView wiring. |
static/css/command-centre.css |
Cosmos KPI cards, table, sparkline SVG, signal cards, badge variants. |
static/staticwebapp.config.json |
CSP connect-src got region1.google-analytics.com (some browsers route there). Generates public/_headers via scripts/generate-cf-config.py in CF build. |
layouts/partials/analytics.html |
Earth gtag — added cosmos_planet=earth + Consent Mode v2 defaults. |
brainbar/layouts/_default/baseof.html |
CMD gtag (NEW — Brain Bar had no analytics before). |
hugo.toml |
cache_version bumped (CSS+JS changed). |
Per-planet repos (all 7)¶
Every planet has gtag G-2HWWZGWCD0 + cosmos_planet=<slug> + Consent Mode v2 defaults injected at the bottom of <head>. Astro planets use is:inline directive; Hugo planets use {{ if hugo.IsProduction }}. PlainAI uses runtime path detection via startsWith('/learn') in the gtag('config', …) call.
| Repo | File |
|---|---|
cosmos-atlas |
src/layouts/Base.astro |
shift |
src/layouts/BaseLayout.astro |
agentic-planet |
src/layouts/BaseLayout.astro |
claw-planet |
src/layouts/BaseLayout.astro |
plainai |
build-shared.mjs (pageHead template) + public/_headers (CSP relaxed) |
guided |
src/layouts/BaseLayout.astro (existing gtag — only the cosmos_planet param + Consent Mode were added; SLA protocol was active for this commit). |
aguidetocloud-revamp/brainbar |
layouts/_default/baseof.html (had no analytics). |
Cosmos-bar shared component (cosmos-atlas/src/cosmos-bar/)¶
| File | Change |
|---|---|
component.ts |
Pill DOM + lifecycle-safe polling (single setInterval, AbortController, partial DOM updates, hide after 3 fails or count < 2). |
styles.css |
.live-pill + .live-pill-dot keyframes + mobile + reduced-motion variants. |
icons.ts |
(untouched in this project) |
Built by npm run cosmos-bar (or npm run deploy) which runs scripts/emit-cosmos-bar.mjs → emits public/cosmos-bar.js (~40KB minified IIFE). Served from https://cosmos.aguidetocloud.com/cosmos-bar.js and consumed by every planet via <script async src="…">.
Session-state artifacts (not deployed, just for reference)¶
~/.copilot/session-state/1ff2ba78-…/files/:
- plan.md — full design plan + phase tracker
- csp-audit.md — per-planet CSP findings
- measurement-dictionary.md — 3 layers of events (Layer 1 shipped; Layers 2 + 3 are Phase B roadmap)
- planet-semantics.json — SSOT for per-planet action modes (mirrored inline in _cosmos-shared.js for the worker)
- plain-ai-constitution-diff.md — proposed diff with rationale (Sush-approved + applied)
Auth model (READ THIS BEFORE TOUCHING ANYTHING GATED)¶
Setup:
- The CC password gate at /cc/ stores both sessionStorage.cc-ok='1' AND sessionStorage.cc-p=<plaintext> after the user types the right password.
- The public hash that the gate compares against is hardcoded in the HTML at layouts/cc/list.html line 502: var H='0579d11899d8171a96c04302aa2f2f7250adfce591e1a118f332f40c70027be8'. This is SHA-256 of the admin password.
- The SAME hash is the env var ADMIN_PASSWORD_HASH on the aguidetocloud-revamp Cloudflare Pages project.
Worker auth flow:
1. Dashboard sends Authorization: Bearer <sessionStorage.cc-p> — the plaintext password.
2. Worker isAuthedAsAdmin (in _cosmos-shared.js) hashes the plaintext server-side, then constant-time compares (timingSafeStrEqual) to env.ADMIN_PASSWORD_HASH.
3. Pre-hashed values are REJECTED. This was a SME-flagged issue: the hash is visible in public HTML, so accepting it as Bearer would mean anyone scraping /cc/ source could replay the hash as auth. Plaintext-only forces possession of the actual password.
If you ever need to:
- Test the gated endpoints from CLI: you need the plaintext password. ~/.copilot/secrets/guided-admin-password is a DIFFERENT password (verified — different hash). Sush has the CC plaintext.
- Change the password: update H in layouts/cc/list.html AND ADMIN_PASSWORD_HASH env var on aguidetocloud-revamp Pages (production + preview). They MUST match. Test BOTH the CC unlock UI AND the cosmos endpoints after rotation.
- Add a new gated endpoint: import isAuthedAsAdmin and cosmosJsonRes from ./_cosmos-shared.js. Use cosmosJsonRes({error:'Unauthorized'}, 401, 'no-cache') for rejections.
Timing-safe compare: timingSafeStrEqual is in _cosmos-shared.js. Always use it for password / token comparisons in this codebase, never JS ===. JS === short-circuits on first char mismatch and leaks position info → enables char-by-char brute force.
GA4 setup (critical reference)¶
- Property:
530486519(single shared across whole cosmos) - Measurement ID:
G-2HWWZGWCD0(single, deployed everywhere) - Custom dimension:
cosmos_planet— event-scoped, registered 12 May 2026 via Admin API - Dimension ID:
14859585669 - Parameter name:
cosmos_planet - Display name: "Cosmos Planet"
- Allowed values:
earth,guided,brainbar,shift,plainai,curriculum,agentic,claw,cosmos - Service account:
analytics-dashboard@aguidetocloud-mcp.iam.gserviceaccount.com - Key:
~/.copilot/secrets/ga-service-account.json+ CF Pages env varGOOGLE_SERVICE_ACCOUNT_KEY(base64-encoded) - Has Editor role (not just Viewer as the reference doc said — I successfully created the dimension via Admin API)
- API scopes used:
analytics.readonly(Data API — for queries)analytics.edit(Admin API — only used once to register the dimension; can be removed if Editor stays)
Consent Mode v2 defaults (set on every gtag in the cosmos):
gtag('consent','default',{
ad_storage:'denied',
ad_user_data:'denied',
ad_personalization:'denied',
analytics_storage:'granted'
});
GA4 Data API gotchas to remember:
- Realtime API does NOT support hostName or pagePath dimensions. Only event-scoped custom dimensions (via customEvent:cosmos_planet syntax) work in runRealtimeReport. This killed the original v0 plan; the cosmos_planet dimension was the fix.
- Historical runReport supports any dimension/metric combination GA4 considers compatible. Event-scoped dims + event-level metrics are safe. Event-scoped dim + session-level metrics (e.g. sessions, bounceRate, engagementRate) is risky — may return 4xx or empty.
- Token quota: 250k/day per property. Our load (~6 queries/day from cosmos-summary, plus realtime polls every 45s cached at edge) is well under 5% of quota.
- Concurrency limits: parallel runReport calls can 429 above ~5 in flight. Always throttle to 3 via the throttled() helper in _cosmos-shared.js.
- New dimensions have a 24–72h propagation lag before historical aggregations populate. Live data is immediate; weekly trends warm up. The warm_up: true flag in the summary response signals this state to the dashboard.
- 🪲 activeUsers inflates when you add a dimension and sum the rows (set 13 May 2026). runRealtimeReport({ dimensions: [unifiedScreenName], metrics: [activeUsers] }) returns activeUsers per dimension value. GA4 dedupes the user inside each row, NOT across rows — so a single visitor who tabbed between two pages is counted in both rows. sum(rows[].users) ≠ unique users; it's ~40 % higher in typical browsing patterns. Always run a separate no-dimension query for "unique active across the property", the way handleRealtimeCosmos and (post-fix) handleRealtime do. Caught on 13 May 2026: cosmos pill said 22, Site Analytics tile said 32, same GA4 property, same moment. Same trap also lurks in byPlanetSum inside the gated cosmos endpoint — that field is for the per-planet stack chart only, not the headline number.
Cosmos summary worker logic (the trickiest piece)¶
File: functions/api/cosmos-summary.js
Caching strategy¶
KV namespace COSMOS_SUMMARY_KV (id db3bd5e5a2aa4c22a453364ce2a25095), bound to aguidetocloud-revamp production + preview.
| Key | Value | TTL |
|---|---|---|
summary:current |
Full JSON summary | 30 days (effectively never; freshness driven by payload generated_at) |
summary:lock |
Timestamp of in-flight regen | 120s |
Freshness windows:
- < FRESH_HOURS (24h): return as-is, browser cache 30 min
- < STALE_HOURS (36h): return + context.waitUntil(buildAndStore()) background regen; mark stale:true, regenerating:!lockHeld
- >= STALE_HOURS or no cache: try to acquire lock + return 202 + spawn regen
Soft KV lock pattern:
const lock = await kv.get(KV_LOCK);
if (!lock) {
await kv.put(KV_LOCK, String(Date.now()), { expirationTtl: 120 });
context.waitUntil(buildAndStore(env));
}
Force-rebuild path: GET /api/cosmos-summary?refresh=1 (with auth) — synchronous full rebuild, no cache check, no lock. Use for debugging only.
GA4 query inventory (~6 queries per build)¶
All wrapped in throttled(tasks, 3):
| # | Query | Returns |
|---|---|---|
| 1 | Cosmos totals, this week (no dim) | users, sessions, views, userEngagementDuration |
| 2 | Cosmos totals, last week | Same (for WoW math) |
| 3 | Per-planet totals, this week (cosmos_planet) | Same per planet |
| 4 | Per-planet totals, last week | Same per planet |
| 5 | Per-planet daily series, last 30 days (planet+date) | activeUsers per (planet, day) — for sparklines |
| 6 | Top pages cosmos-wide, this week (hostName+pagePath) | views, users, engagement; planet resolved client-side via resolvePlanet |
Queries 1–5 are event-scoped-dim friendly. Query 6 deliberately omits the planet dim to avoid session-level composition issues — we resolve planet from hostName + pagePath post-fetch. This is why we need hostName (resolves / ambiguity across 8 subdomains).
NZT week boundaries¶
nztWeekRanges() in _cosmos-shared.js uses Intl.DateTimeFormat(en-CA, {timeZone:'Pacific/Auckland'}) to find what day-of-week NZT thinks today is, then computes the last complete Mon–Sun week (the one that ended on the most recent Sunday) and the week before that. Explicit ISO date strings are passed to GA4 — never relative 7daysAgo (which uses property timezone, not NZT, and shifts during DST).
Signal generation (the "Signals to Review" section)¶
Rule-based, post-query. Each signal has confidence + action_mode + suggestion (never command):
| Type | Rule |
|---|---|
growth |
users_week >= 50 && users_prev_week >= 20 && wow > 25% |
drop |
users_prev_week >= 50 && wow < -15% |
quiet |
users_week < 10 && action_mode != 'commons' && != 'hub' |
star_page |
top 3 by avg_engagement_sec where views >= 50, users >= 30, eng >= 30s |
Suppression rules:
- Curriculum (actionMode='commons', suppressGrowthPrompts:true) never gets growth/drop/quiet
- Cosmos atlas (actionMode='hub') never gets quiet (it's not supposed to be a destination)
- Bounce signal was DESIGNED but deferred — bounce metric composition with event-scoped dim is risky per rubber-duck; verify with a probe query before shipping
Signals capped at 8 per response to keep the dashboard scannable.
Cosmos-bar pill (public surface, simpler logic)¶
Lifecycle:
connectedCallback
→ fetchAtlas → render → wire → start polling (if not started)
│
▼
setInterval(45_000) ──┐
▼
fetchLiveCount → updatePill
(AbortController per fetch, partial DOM update)
disconnectedCallback → stopLiveCounter → clearInterval + abort in-flight
Hide rules (counter UX):
- total < 2: hide entirely (avoids "lonely 1 visitor" signal)
- 3 consecutive fetch failures: hide entirely (no flickering errors)
- After page nav: fresh component instance → fresh state
Why cache: 'no-store' was removed (SME critique): it defeated the CF edge cache's 45s TTL → every browser hit the worker direct → 10–100× extra worker traffic. Default fetch cache mode now respects server Cache-Control: max-age=45. CF edge caches the response for 45s and serves it to all clients of that edge POP. Big efficiency win.
Plain AI constitution change (12 May 2026)¶
The Plain AI Curriculum constitution permanent-NO list previously banned "Individual user tracking (cookies, fingerprinting, analytics events)" wholesale. This blocked GA4 from Plain AI + Curriculum surfaces. Sush narrowed the rule to ban specific behaviours instead of the technology:
Marketing tracking · retargeting · advertising signals · conversion funnels · behavioural personalisation — never. Aggregate analytics for product understanding (GA4 with ad signals denied, custom event dim
cosmos_planet) — allowed.
See ~/.copilot/plain-ai-curriculum-philosophy.md evolution log entry dated 12 May 2026 for the diff and rationale. The Wikipedia test passes: Wikipedia runs aggregate page-view analytics; they don't run ads. Same line for us.
Operational implications:
- Aggregate analytics ✅ allowed across all 9 surfaces including Plain AI + Curriculum
- Targeting an individual reader / showing different content based on history → still forbidden
- A/B testing lesson copy → still forbidden (actionMode='editorial' for Plain AI, actionMode='commons' for Curriculum — Cockpit signals respect this)
- Curriculum's suppressGrowthPrompts: true flag ensures the dashboard never recommends marketing/funnels for it
How to extend¶
Add a new planet¶
Six touch-points (in this order):
- Add to
cosmos-atlas/src/data/atlas.json— orbit, body, copy. (Cosmos philosophy rules apply — readcosmos-philosophy.md.) - Build the planet repo — Astro or Hugo. Add the gtag snippet to its BaseLayout/baseof, set
cosmos_planet: '<new-slug>'. - CSP — if the planet has a CSP, add
googletagmanager.comtoscript-srcandgoogle-analytics.com+region1.google-analytics.comtoconnect-src. (Most planets currently have no CSP. Plain AI is the strict one.) - Add the slug to
_cosmos-shared.js:COSMOS_PLANETS,COSMOS_PLANET_KINDS,HOST_TO_PLANETS,PLANET_SEMANTICS. Pick the rightactionMode. If the planet has a non-default bounce interpretation, document it inbounceInterpretation. - Test in GA4 DebugView — load the planet with
?_dbg=1and confirm hits arrive withcosmos_planet=<new-slug>parameter. - Verify on the dashboard — open
/cc/→ 🌌 Cosmos tab → the new planet should appear in the leaderboard within 24–72h once GA4 backfills the dim.
Critical: the slug-detection logic is duplicated client-side (per-planet gtag) AND server-side (resolvePlanet in _cosmos-shared.js). Both must match. Consider adding a QA check that compares atlas.json planets against COSMOS_PLANETS in a future iteration.
Add a new outcome event (Phase B work)¶
The full event catalog is designed in ~/.copilot/session-state/<id>/files/measurement-dictionary.md. Adding one:
- Register the event params as custom dimensions in GA4 Admin (event-scoped).
- Fire the event from the planet —
gtag('event', 'cosmos_bridge_click', { from_planet, to_planet, link_location })on every cross-planet click. - Extend the cosmos-summary worker with a new query that pulls per-planet event counts.
- Add a new section to the dashboard to surface the metric.
Top-priority outcome events (planned, not built):
- cosmos_bridge_click (cross-cosmos movement — would enable the journey screen)
- newsletter_signup (Shift)
- guided_checkout_start + guided_purchase (cert funnel; the latter via Stripe webhook → GA4 Measurement Protocol)
- kofi_click, youtube_click (cross-channel attribution)
Phase B / C roadmap (not built — designed)¶
- Outcome event instrumentation — see above; this is where the dashboard flips from traffic-vanity to decision-grade.
- Cross-cosmos journey screen — bridge-click matrix, multi-planet session ratio, weak-bridge editorial opportunities. Builds on
cosmos_bridge_click. - GSC per-planet — each subdomain is its own GSC property; pull into nightly summary. Top queries, low-CTR opportunities, rising terms per planet.
- LLM Sunday memo — turn the summary JSON into 200 words of prose Sush reads with coffee. Built last (data needs to be trusted + outcomes tracked first).
- Mobile responsive Cosmos tab — currently desktop-first with horizontal scroll on the leaderboard table. Defer card-style layout until data is proven valuable.
Pre-existing issues (not introduced by this work)¶
The Cosmos QA suite (cosmos-atlas/scripts/qa-audit.mjs) currently fails 6 checks from commit 870596b (V5 Wave 3 — pink Earth + layout). All are pre-existing and unrelated to this work:
- drift toggle off — UI bug (toggle doesn't deactivate on second click)
- ambient player state — audio control assertions
- guided over brainbar (desktop) — orbit collision
- guided vs earth too close (desktop) — orbit collision
- guided over brainbar (iphone) — same
- guided vs earth too close (iphone) — same
These are flagged for a separate session. My commits in this project touched Base.astro + cosmos-bar/* — none of the blocking-rule files (cosmos.ts, cosmos.css, atlas.json, PlanetIcon.astro, index.astro).
Operational reference (quick lookup)¶
| Resource | Value / Path |
|---|---|
| GA4 property ID | 530486519 |
| GA4 measurement ID | G-2HWWZGWCD0 |
| GA4 custom dim ID | 14859585669 (cosmos_planet, event-scoped) |
| KV namespace ID | db3bd5e5a2aa4c22a453364ce2a25095 (binding: COSMOS_SUMMARY_KV) |
| KV keys | summary:current, summary:lock |
| CF Pages project for worker | aguidetocloud-revamp |
| Env var (gated endpoints) | ADMIN_PASSWORD_HASH (= public hash in layouts/cc/list.html:502) |
| CF account ID | d42846fe2c29daf890ec57877fda5e04 |
| GA4 service account key | ~/.copilot/secrets/ga-service-account.json + base64 in CF env |
| Cosmos QA suite | cosmos-atlas/scripts/qa-audit.mjs (BLOCKING for atlas.json/cosmos.ts changes — but NOT for cosmos-bar component changes per rule scope) |
| Deploy command (cosmos-atlas) | npm run deploy (manual — no git auto-deploy on this project) |
| Deploy command (other planets) | git push triggers CF Pages auto-build |
Gotchas + lessons (every one cost time to discover)¶
- GA4 Realtime API doesn't support
hostNameorpagePath— killed v0 plan. Custom event dim is the only solution. runReportrealtime ≠runReporthistorical — same API surface, different dimension support. Always verify combinations before assuming they work.- GA4 custom dim propagation has 24–72h lag for historical aggregations. Live data is immediate. Dashboard shows
warm_up: truefor the first window. - CF Pages env var PATCH danger — silently wipes other secrets if you're not careful. ALWAYS verify all endpoints after PATCH. Pattern: response from CF API confirms keys; then curl 2–3 endpoints that depend on those secrets.
- CF Pages KV bindings can break deploys. Don't add a binding without redeploying immediately and verifying the worker still serves.
public/_headersis gitignored inaguidetocloud-revamp. The SOT isstatic/staticwebapp.config.json, processed byscripts/generate-cf-config.pyin the CF build command. Editingpublic/_headersdirectly is futile — overwritten on every deploy.- JS
===for password compare is a timing attack. UsetimingSafeStrEqualfrom_cosmos-shared.js. Always. - Dual-mode auth (plaintext OR pre-hashed Bearer) is dangerous when the hash is in public HTML. We dropped pre-hashed; plaintext only.
cache: 'no-store'on cross-origin fetches defeats CF edge caching. Trust the server'sCache-Controlheader; let CF do its job.liveStarted = trueBEFORE the call is a race. If the call throws, the flag sticks and no retry. Always set flags AFTER the operation that can fail.- GA4 concurrency limits are real. Throttle to 3 parallel
runReportcalls or eat 429s. indexOf('/learn/')===0is NOT the same asstartsWith('/learn')— the former fails on canonical URL/learn(no trailing slash). Cost: every Curriculum visitor mis-tagged as Plain AI for ~30 minutes between deploy and SME catch.- The cosmos-bar runs on every planet via a single CDN-hosted bundle at
https://cosmos.aguidetocloud.com/cosmos-bar.js. cosmos-atlas has NO git-auto-deploy — every cosmos-bar change requiresnpm run deployfrom the cosmos-atlas repo.
Verification checklist (when picking this work up cold)¶
# 1. All endpoints respond correctly
curl -sf https://www.aguidetocloud.com/api/stats?realtime=cosmos | jq
# Expect: { totalUnique, scope, generated_at }
curl -sf https://www.aguidetocloud.com/api/stats?realtime=cosmos\&intel=1 -w "%{http_code}\n"
# Expect: 401
curl -sf https://www.aguidetocloud.com/api/cosmos-summary -w "%{http_code}\n"
# Expect: 401
# 2. Pill is on every planet (visual check)
# Open each: cmd.aguidetocloud.com, shift.aguidetocloud.com, plainai.aguidetocloud.com,
# agents.aguidetocloud.com, claw.aguidetocloud.com, cosmos.aguidetocloud.com
# Look for amber-pulse pill between bodies and MCP relay.
# 3. Cosmos tab loads + renders (browser)
# https://www.aguidetocloud.com/cc/ → unlock → click 🌌 Cosmos
# Should show: Pulse / Leaderboard / Signals / Stars (Warm-up banner on day 1).
# 4. GA4 DebugView: every planet's hits include cosmos_planet param with correct slug.
Cross-references¶
- Constitution + voice:
~/.copilot/plain-ai-curriculum-philosophy.md(12 May 2026 narrowing entry) - Cosmos atlas philosophy:
cosmos-philosophy.md - Cosmos navigation rail:
cosmos-nav-playbook.md - Memory system / where docs live:
memory-system-architecture.md - Parallel-safe git rules:
parallel-git-rules.md - Deployment playbook:
deployment-playbook.md(the 20-step pre-push checklist) - Stripe payment playbook:
stripe-payment-playbook.md(paid product context — Guided is the only revenue surface)
Built 12 May 2026 NZT. Two rubber-duck passes + one SME code review + 14 commits across 8 repos. Shipped with 100% endpoint verification and zero regressions to existing surfaces.