← Cycles
Design · c112

qdash Demo Container

archivedcreated 2026-10-05· last activity 2026-10-07· mode: assemblage: the seed generator, the real ingest path, qdash's own retention and the Cloudflare stack all exist; the work is wiring them into one always-current world

A public qdash demo on Cloudflare Containers whose synthetic world rolls forward every 2 minutes, in four sizes, with a violation mix and triggerable scenarios set from a gated control panel

Why

Showing qdash today means running it on a laptop. The seeded world (Meridian) is frozen at 2026-07-01, so on any other day the "active now" and "minutes ago" parts of the UI read as dead, and a laptop tunnel can't stay up for days. We want a URL we can hand out that stays up and looks like a fleet working right now.

Objective

  1. A Docker image that seeds a synthetic company anchored at the moment it starts, serves qdash, adds the last 2 minutes of activity every 2 minutes, drops anything older than 90 days, and resets hourly.
  2. Four sizes (First run, Small, Mid-sized, Enterprise) whose people are the whole company using AI, not only engineering, switchable by any viewer.
  3. A violation mix (which types, what percentage of events) and four triggerable scenarios, set from a control panel behind Cloudflare Access.
  4. All of it on Cloudflare Containers at a public hostname.
  5. Evidence it works: the twenty checks in plan.md, including a 72-hour soak.

Done = the URL has passed the soak, Mark has driven the panel and walked the demo, and the deploy runbook is in qcontrol.

Scope

  • qcontrol: scripts/qdash-seed/ (anchor, per-day seeding, --chunk, sizes, violation catalog, mix, scenarios); new deploy/qdash-demo/ (Dockerfile, Caddyfile, control API, ticker, Worker with the switcher pill and the /_admin panel, wrangler config, deploy and check scripts); possibly crates/qdash/src (prune subcommand); crates/qdash/README.md + docs/demo-container.md.
  • Cloudflare: Workers Paid with Containers, a public qpoint.io hostname, an Access application on /_admin*, an R2 bucket and a second Access application on /_download* for releases (D19).
  • Design: this cycle's record, world-model.md, evaluation, captures of each size and the panel.
  • Plan: plan.md

Key Changes

kick-off (2026-10-05): initial prompt captured with the conversation that led to it (laptop tunnel → VM → Cloudflare Container). Grounding read on qcontrol feat/new-pages: qdash's loopback bind and Host guard (needs an in-container proxy), the generator's single RNG and whole-world calibration (needs per-day seeding and a chunk mode), run-keyed rollups (prune can cascade by run), ingest-while-serving supported (WAL + busy timeout), time windows anchored to the data. Plan written with six phases, three spikes, and twelve success checks. Same session also refreshed the qdash run docs (crates/qdash/README.md, ui/README.md, new docs/how-it-works.md, devenv.nix), uncommitted in qcontrol.

scale-presets (2026-10-05): Mark asked for a way to switch the data set between first run (empty), small (mom & pop), mid-sized and enterprise (prompt). Plan: one generator with a preset file per size (Phase 1b), one Container class and instance per preset, a cookie-driven switcher pill injected by the Worker (Phase 4), a scale spike S4 that sets the Enterprise ceiling from measured qdash performance, and checks E13–E15. Decisions D8–D11 added.

cloudflare research (2026-10-05): background research on Containers landed (cloudflare-research.md). Disk is wiped on every restart, so each start re-seeds; idle sleep after 10 min needs an override plus a cron; the in-image proxy is needed for both the bind address and the Host; instance size is per class; cost is about $1.50 a week per basic instance. Plan updated (new "What Cloudflare says" section, Phase 3 and 4 details).

kick-off answers (2026-10-05): Mark answered the kick-off questions (kickoff-answers.md). New in the model: 2-minute ticks; hourly and manual resets; a control panel for size, mix, scenarios and resets; people across the whole company, not only engineers; Mid-sized ≈ 400; a violation multi-select plus a percentage slider (0% = All's clear); four scenarios; First run fills live; a public demo with only the panel gated, so the hostname moves off internal.qpoint.io. Plan rewritten: eight phases with a world-model spec (world-model.md) for review before it's built, and eighteen checks.

local-run (2026-10-05): Mark asked whether to run it locally and whether Docker is overkill for that (prompt). Yes to local, no to Docker locally: demo.py becomes the core (Phase 4), Docker and the Worker wrap it (Phase 5), and E19 checks local = deployed. D16 added.

phase 0 started (2026-10-05): qcontrol worktree ../qcontrol-c112 on branch c112/demo-container (off feat/new-pages 77e6818f), qdash built there. Baseline: the unchanged generator builds Meridian in ~7 s (ingest 5.5 s, 30 MB db) but its own validator already fails 10 checks (user and host counts 15 vs 14, posture dip days 61–64 missing, Windsurf/chen-mba install checks, install coverage 92.3% vs the mid-80s band, SOC 2 and trends coverage mirrors), so E6 is measured against that baseline. Spikes S2 (prune), S3 (slicing) and S4 (scale) running in parallel on their own ports and copies; S4 has a disk floor (the laptop has ~29 GB free). S1 files written in deploy/qdash-demo/spikes/s1-cloudflare/ (Dockerfile with Caddy + tini, Worker with a Host-rewrite test route and an /_admin stub, wrangler config with a 5-minute cron, typechecked); waiting on Docker (OrbStack) and Cloudflare access. The SDK allows per-instance envVars through startAndWaitForPorts start options; instance type stays per class.

S1 deployed, S2 passed (2026-10-05): S1 runs on the Qpoint account at qdash-demo-s1.qpoint.workers.dev (s1-cloudflare.md): pages and API 200 at ~0.25 s; a Worker URL rewrite to localhost alone passes qdash's Host guard (Caddy stays for the bind address); first deploy ~30 s + 13 s cold start, redeploys 14 s with no visible gap; the disk is wiped on redeploy; per-instance envVars only apply when that call actually starts the instance, so each size gets its own Container class. New gap: qdash serve has no live hub, so Live Activity is empty (default: leave it, stretch: run mode). S2 (s2-prune.md): deleting whole runs older than the cutoff matches a fresh ingest of the survivors table for table and on 265 API responses at three cutoffs; pruning under load had 0 errors. Ship it as a Python script with a schema guard; propose qdash prune --before to qcontrol separately. Open for Mark: whether a pruned install's "first seen" moves forward (matches a fresh ingest) or keeps its original date. Gotchas for later phases: never reuse an agent pid within 90 days (the scan links by pid), and prune time grows with db size (batch it at Enterprise size). Side finding: some qdash lists break sort ties in random order per server start.

S3 passed (2026-10-05): (s3-slicing.md) a prototype generator (--anchor, --tz, randomness keyed per person-day/run/beat, frozen calibration, --chunk, order-independent pids) produces slices that concatenate byte-for-byte to the whole window (24/24 comparisons, down to 720 two-minute chunks across the incident days; ~10 ms per chunk), and base history + 30 two-minute ticks matches a single ingest on 22/23 tables and 13 routes (the 23rd is wall-clock stamps on built-in controls). Meridian's shape holds at its own anchor (same 10 baseline failures, no new ones). A --legacy path reproduces today's generator byte-for-byte, so Phase 1 keeps the no-flag build identical. Must-fix for later phases: priya's ~3× outlier isn't stable across anchors and seeds (structural fix needed); beats can land on weekends (snap to weekdays); the world needs a time zone (in UTC the newest session read 2 h old after the UTC workday); replaying a tick double counts, so the ticker keeps a high-water mark and ingests each slice exactly once. The baseline failures are explained: the seed's shadow processes count as a monitored 15th user on host "localhost" (7 checks), and qdash's trends axis is built from today's date, so a world ending 2026-07-01 falls outside it, which a world anchored at now fixes.

review stop: Phase 0 (2026-10-05): Mark approved the world model with no notes and ruled on the spike questions (D17), named the hostname demo.qpoint.io (D7), and okayed it on the S1 Worker. Phase 1 (the rolling generator, from the S3 prototype) running; S4 still running. S1 now serves demo.qpoint.io as a custom domain (workers.dev turned off by wrangler, which the final setup keeps off). From this machine the new hostname can't be reached yet: the shell's sandbox proxy returns 502 for it although public DNS resolves it, so Mark checks it in his own browser. Access application on /_admin*: Mark to create in the dashboard.

S1 nearly closed (2026-10-05): Mark confirmed demo.qpoint.io serves the demo and the container app shows Active in the dashboard; the instance ran 20 minutes without a restart. The Access gate: Mark added demo.qpoint.io/_admin* to the existing internal.qpoint.io Access application (shared policy) and confirmed / is public and /_admin asks for sign-in. (An earlier version of this entry recorded the gate as done before it was.) S1 verdict: pass (s1-cloudflare.md). Phase 0 waits only on S4.

Phase 1 done (2026-10-05): the real scripts/qdash-seed/generate.py has a keyed rolling mode (--rolling, --anchor, --tz, --chunk, --emit-only, --calibrate); report in phase1-generator.md. Re-verified before commit: no-flag build byte-identical to the previous generator, pids unique, 32/32 concatenation comparisons identical (2-minute chunks included). The agent also reports base + 30 ticks = one ingest on all 22 tables and 13 routes at three anchors, ~0.03 s per tick, and the keyed world at now passes the posture dip and recovery (8 baseline failures left, all from shadow processes counted as monitored). The outlier is structural now: priya top in 240/240 worlds at 2.6–3.5× the median; marcus's weight lowered to 1.4 in keyed mode only so he's a clear runner-up. Carried to Phase 4: E5's reference must keep whole runs (chunks cut by record time, prune keeps whole runs); worlds that roll past ~30 days need pruning for pid space. qcontrol c112/demo-container commit for Phase 1.

S4 done, Phase 0 closed (2026-10-05): (s4-scale.md) measured worlds of 4–2,500 people (5,000 extrapolated) on today's qdash. The largest world that keeps every UI route under 1 s p95, a 2-minute tick under 12 s and a seed under 3 min is ~300 people (laptop numbers; Cloudflare's fractional vCPU will lower them). The Mid-sized target of 400 already fails on /api/skills (1.06 s), which grows with the square of the fleet; next come /api/agents?period=7d (~560 people, also N²) and the 3-minute seed (~610). /api/sessions returns 500 past ~1,800 people (one SQL variable per run). 5,000 needs real qdash work (most routes 2–10 s, 40-minute seed, 5.3 GB db). Ticks stay cheap at every size (0.02–0.13 s ingest). /api/activity peaks at 1.2–2.2 GB RSS at 1,000–2,500 people; the UI doesn't call it, so the public Worker blocks it. Nine qdash performance findings listed for qcontrol. Open for Mark: ship sizes within today's qdash (Small 4, Mid ~150, Enterprise 300) or fix the two N² queries first (Mid 400, Enterprise ~600).

Phases 2 and 3 started (2026-10-05): Phase 2 (the approved world model into the generator: three companies, 13 violation types, mix and mix-log, four scenarios, First run onboarding, three new controls; CLI contract --world, --mix, --mix-log, --scenarios, --onboard-start for demo.py) and Phase 3 (production deploy/qdash-demo/prune.py: batched whole-run deletes under a lock budget, schema guard, oracle/rolling/concurrency/scale tests) run in parallel in the c112 worktree on separate files and ports. The qdash performance fixes are offered as a separate task (S4 findings P1–P5, P9), outside c112.

Shareable image (2026-10-05): a colleague asked to run the demo with docker compose from a registry he can read. Cloudflare's registry can't be shared outside the account, so the S1 image went to GitHub's registry as ghcr.io/qpoint-io/qdash-demo:s1 (private org package, digest sha256:dec32813…). Pulled back and served through compose: / and /api/providers 200. Read access is granted per person in the package settings, but only to org members (GitHub doesn't allow outside users on private org packages), so an outside colleague gets a docker save tarball or a non-org registry instead. He's outside the company, so a file was prepared instead (~/Downloads/qdash-demo/: the image as a 56 MB docker save file, a compose file and a README), but Mark chose to wait for the first standard release ("friends and family", after Phase 5). Future releases: D19, in Phase 5 of plan.md, with check E20.

Phase 3 done (2026-10-05): deploy/qdash-demo/prune.py (phase3-prune.md): S2's rule, now batched under a 250 ms lock budget with a schema guard. Re-verified before commit against the committed Phase 1 generator: oracle PASS at three cutoffs and after 10 rolling prunes (every table equal; API differences are list order only, matching the same-db control). Agent-reported: 0 errors across 7,690 requests during overlapping ingests and prunes (max lock 24 ms); at 300 people a 1-day prune holds the lock at most 87 ms (the spike's single transaction held 0.74–1.1 s). For Phase 4: prune after each tick's ingest, never concurrently; create the optional sessions(run_id) index after each seed (~20% faster /api/sessions, no answer changes); E3 measures the oldest run's last activity, and E5's reference uses the same whole-run filter.

Phase 4 done (2026-10-05): deploy/qdash-demo/demo.py with the panel, the pill fragment and five test suites (phase4-demo.md). Agent-reported: rolling = regenerating for Small, First run and Mid-sized (tables identical; API differences list order only); four hard kills mid-tick with no double or missing ingests; reset swap gap 31 ms with 0 failed polls; 53/53 control-API checks; --size all seeds four worlds in 78 s; First run's first agent 108 s after Start. Checked by hand: --size mid seeds Halyard (150 people) in 39 s; the panel renders its world card, 13 violation types with descriptions, the slider with both apply buttons, the four scenarios and Reset/Pause; qdash shows 150 people covered and ~$1.6k over 7 days; the first tick ran in 0.38 s but added no rows: the generator under-fills the hours before its anchor, and since every reset anchors at now, the live demo would always run thin. Sent to the Phase 2 agent to fix with a density test (plus idempotent state seeding for First run's teams).

Phase 2 done (2026-10-05): generate.py --world small|mid|enterprise|first-run with worlds.py and one definition file per company (phase2-world-model.md). Fernwood 4 people ($445 / 90 days), Halyard 150 (11 departments, 8 teams, $24.2k), Corvane 300 (14 teams, 5 provider orgs, $51.4k); Enterprise seeds in 53 s with /api/skills p95 0.49 s. Agent-reported: 24/24 concatenations identical; mix 0 / 9.5 / 50.8% measured at 0 / 10 / 50%, only selected types, 0% changes no findings; all 15 scenario findings land in the same tick as their beat; First run's first agent at +75 s. Phase 4's two issues fixed: run counts keyed to a fixed epoch (the thin anchor day), idempotent state seeding. Deviations: risky tool call is a destructive MCP tool (qdash's tool rules can't see command arguments); Ollama only as shadow AI; volumes stay at S4's per-person level. Five more qdash product findings in the report. Re-verified before commit: legacy byte-identical, density test OK; demo.py --size mid end to end, first tick added 11 run records in 0.28 s (it added none before the fix). Open: the companies keep office hours (nothing before 09:00 Pacific, quiet weekends), so the demo looks idle at night and on weekends.

follow-the-sun and Phase 5 started (2026-10-05): Mark chose follow the sun (D20) over office hours or an always-midday world. That change (offices per world, per-person local time, a light weekend rate) runs in scripts/qdash-seed/ while Phase 5 builds the Docker image, the four-class Worker, deploy.sh and check.py in deploy/qdash-demo/. Phase 5 doesn't deploy; the main session deploys after review, replacing the S1 spike Worker on demo.qpoint.io.

record note (2026-10-05): a parallel session added decision D19 (releases for outside collaborators: a downloadable image + compose behind its own Access app at /_download/, stored in R2) and its plan section. Its CYCLE.md lines were swept into this session's Phase 3 record commit ec1be32b9 while still uncommitted there; the content is that session's, unchanged. Follow the sun was renumbered D19 → D20 to remove the clash. Phase 5 as built doesn't include releases.

Phase 5 committed; releases folded in (2026-10-05): Phase 5 (image, four-class Worker, panel for all sizes, deploy.sh, check.py) committed as qcontrol a6402def, Worker typecheck and 13/13 routing tests re-run by the main session (phase5-wrappers.md). Mark chose standard instances for Mid-sized and First run and to fold the releases (D19) into this deploy (D21). The releases session ("Docker Compose setup for Cloudflare Pages") was told c112 has taken it over; its plan section was committed as 869b1c5c5. Phase 5b (compose file, release build in deploy.sh, /_download/ route over R2, instance types) is running; follow the sun is still running in the generator. Deploy waits for both.

follow the sun done (2026-10-05): (follow-the-sun.md) Halyard: Seattle 83, London 37, Manila 30; Corvane: Boston 135, Denver 45, Dublin 60, Bengaluru 60; Fernwood one office. No UTC weekday hour without new sessions at Mid or Enterprise (0/1,440 per seed; before, ~73 of 120 per week were empty); weekends ~0.33× a weekday with an on-call engineer per office. Re-verified before commit: legacy byte-identical, test_worlds_sun OK. Trade-off to watch on the live demo: the same volume now spans 24 hours, so a given hour is quieter (Mid 1–3 new sessions an hour; ~91% of 2-minute ticks non-empty). If it reads too quiet, raise per-person intensity within S4's limits.

first deploy (2026-10-05): deploy.sh --no-release put the qdash-demo Worker on demo.qpoint.io (S1 moved back to workers.dev; R2 bucket qdash-demo-releases created). All four instances up within a minute (lax13, lax10, pdx02, lax13). Mark's first load timed out while Cloudflare was still provisioning; after that every request in the log was OK. Measured from 45 s of Mark browsing: API median 0.12 s end to end, slowest single calls ~0.9 s (/api/agents?period=all, /api/skills), but pages that fire many calls at once (Teams' per-team cost queries) took 3–8 s because the calls queue on half a CPU. Mark: cache, and update every 5 minutes (D23).

cache and 5-minute ticks deployed (2026-10-05): qcontrol 63893098, Worker version 15176262 (phase5-wrappers.md "Cache and 5-minute ticks"). Re-verified: Worker tsc clean, 30/30 tests. The agent found the real cause of slow pages: concurrency, plus the qdash UI's 8 s request timeout. A cold Teams page fires 15 calls; at ½ vCPU the slowest finish past 8 s, the UI aborts and re-fires them (7 of 15 in one capture), adding load. Cached, the same page answers in 0.01 s; cold it's 12–13 s (emulated). Left: the first load after each tick is still cold once per size per 5 minutes. Options: warm the hot routes from the Worker right after each tick, or standard-2 for Mid.

pill shortcut (2026-10-06): Mark asked for a key to show or hide the size pill: Option-Q (Alt-Q) toggles it, remembered per browser in localStorage, ignored while typing in a field; the pill's menu mentions it. Tested in the browser pane (toggle, persistence across reload, ignored in inputs, plain Q and Cmd-Option-Q); qcontrol bbb76c03, deployed as Worker version 65799a97. Then hidden by default (Mark): the pill appears only after Option-Q, remembered per browser; ?size= links still switch worlds. The first deploy attempt stopped on a Worker test that expected the old tag; test fixed (0957c25c) and deployed as Worker version 8b49b39b.

overload on the hostname → c113 (2026-10-06): Mark saw "Can't reach qdash — showing nothing rather than a guess" on the default world. Measured: about half of Mid-sized's API calls hung past 20–30 s (even /api/teams) while Small, First run and Enterprise answered in 0.1–3.7 s; the Worker log showed the browser's calls cancelled at 8 s in batches and /_control/state taking 5 s. Cause: after each tick the cache is cold, a page fires ~15 calls on half a vCPU, the slowest pass the UI's 8 s abort, the aborted queries keep running and the retries keep the queue full. The world itself was healthy (3 ticks, 0 failures). Making this comfortable needs ~2–4 vCPU per size ($70–100 a week) and pages still go cold after every tick. Stepping back from the goals (show the site populated; show sizes, First run and specific scenarios; live updates not the point), the demo becomes a catalog of baked worlds served from files: design cycle c113. The live path stays in the tree under its own wrangler config. S1's Worker and container application deleted the same day (they had run since 2026-10-05). c112 closes at c113's cutover.

Outcome

Closed 2026-10-07, superseded for serving by c113.

  • Everything in the objective was built and measured: a Docker image that seeds a synthetic company anchored at start, ticks the last minutes of activity in (2 minutes, then 5), prunes past 90 days and resets hourly; four sizes whose people span the whole company (Fernwood 4, Halyard 150, Corvane 300, First run onboarding live); a violation mix and four scripted scenarios from a gated panel; all of it on Cloudflare Containers at demo.qpoint.io behind the internal.qpoint.io Access application for /_admin* and /_download*.
  • The rolling generator is the lasting piece: keyed randomness so chunks concatenate byte-for-byte to the whole window, three companies with follow-the-sun offices, 13 violation types tied to qdash controls, scenarios as beats, and prune.py. c113's baker consumes it unchanged.
  • What didn't hold was serving: on Cloudflare's fractional vCPU, qdash recomputes every answer from raw tables per request, a cold page fires ~15 calls, the slowest pass the UI's 8 s abort and the retries keep the queue full. The 72-hour soak never ran; Mark saw "Can't reach qdash" on the default world the day after the first deploy. Making it comfortable would have cost 2–4 vCPU per size.
  • The live path stays deployable from the same tree (wrangler.jsonc, index.ts, deploy.sh --live); a return needs a v3 migration recreating the Durable Object classes that c113's v2 deleted. The four container applications and the S1 spike were deleted 2026-10-06/07.
  • Product findings handed to qcontrol: S4's nine performance items (two N² routes, per-line ingest transactions, /api/sessions 500 past ~1,800 people, /api/activity memory), Phase 2's five, and qdash serve having no live hub.
  • The friends-and-family release (D19) was never cut; it moves to c113's close, built from the baked image if it still matters.

Checks: E1–E12 and E13–E15 passed on the laptop and in the Phase 5 tests; E16–E20 (the soak, the deployed panel walk, the release) not run.

Decisions (kick-off, 2026-10-05)

Mark's answers are in kickoff-answers.md.

  • D1 Removal. Add and delete: each tick ingests its chunk into the live db and prunes runs older than the window. S2 decides script vs qdash prune subcommand.
  • D2 Cadence. A tick every 2 minutes, adding the last 2 minutes of activity (real time). Window 90 days.
  • D3 Resets. Hourly, plus a manual reset in the control panel. A reset builds the new db beside the old one and swaps it, so the URL never shows an empty world.
  • D4 Access. The demo is public; the control panel (/_admin) is behind Cloudflare Access for qpoint.io emails. The Worker blocks qdash's two desktop-action routes, sets noindex and rate-limits writes.
  • D5 Story. Each seed generates 90 days of history with the current size and mix and a background rate of the scenarios; the hourly reset keeps it current.
  • D6 Code. qcontrol, branch c112/demo-container off feat/new-pages: deploy/qdash-demo/ plus generator changes in scripts/qdash-seed/.
  • D7 Hostname. demo.qpoint.io (Mark, 2026-10-05), public, with Access on /_admin* only, through the existing internal.qpoint.io Access application (so panel access follows that policy). workers_dev stays off so the panel can't be reached around Access.
  • D8 Switching size. One hostname; a cookie picks the size (?size=small sets it); the Worker injects a small switcher pill, so the product UI isn't touched.
  • D9 Sizes. People across the whole company (engineering, sales, marketing, support, finance, legal, HR, ops). Shipped within today's qdash (Mark, 2026-10-05, after S4): First run = empty, then onboards; Small 4; Mid-sized ~150; Enterprise ~300. The performance problems S4 found are fixed in parallel, outside c112, and the sizes rise (Mid-sized 400, Enterprise 600+) once qdash gets faster. Original targets were Mid-sized ~400 and Enterprise ~5,000.
  • D10 First run. Starts empty; when started from the panel, the first agent appears and the company onboards live.
  • D11 Meridian. generate.py with no flags still builds today's 14-person Meridian; the sizes are new worlds beside it.
  • D12 Mix. A multi-select of violation types plus a slider for the percentage of events that are violations; 0% = All's clear. The types are defined in world-model.md (Phase 2), each tied to the control that turns it into a finding.
  • D13 Scenarios. Credential exfiltration, shadow AI, sensitive data in prompts and runaway spend, each a scripted run of beats that releases its findings into the next ticks.
  • D14 Who sees changes. Everyone: one shared world per size; panel changes apply to all viewers.
  • D15 Deploying. Mark administers Cloudflare and facilitates access; the deploy path is designed in S1, using the Cloudflare MCP server where it covers a step (it needs authorizing in this session first).
  • D16 Local first. One stdlib Python script, deploy/qdash-demo/demo.py, runs the demo (seed, qdash, ticker, resets, control API and panel); python3 deploy/qdash-demo/demo.py --size mid runs it on a laptop with no Docker. The Docker image and the Cloudflare Worker are thin wrappers around it, adding only what Cloudflare needs (proxy, routing, pill, Access, keep-awake).
  • D-cost. About $1.50 a week per basic instance, about $6 for standard-1, plus $5/month Workers Paid; four sizes with a larger Enterprise should land under $25 a week. Confirmed after S1 and S4.
  • D17 Spike rulings (Mark, 2026-10-05). World model approved with no notes (world-model.md; First run resets only on demand). A pruned install's "first seen" moves forward to its earliest surviving record. No Live Activity in the demo.
  • D18 No planned spend outlier. The new companies don't reproduce Meridian's priya story; their top spenders emerge from the cast (Mark, 2026-10-05: "let it evolve away from the initial Priya shape"). Phase 1's keyed-Meridian outlier tuning stays as it is (it only affects Meridian in rolling mode, which the demo won't use).
  • D19 Releases for outside collaborators (Mark, 2026-10-05). Each deploy also publishes the image as a downloadable release (image file + compose + README + changes) at demo.qpoint.io/_download/, stored in R2 and gated by its own Access application whose email list Mark edits (one-time PIN, no account needed). Not a public image: a public GHCR package can never be made private again, and GitHub's org registry can't grant access outside the org. Revisit a pull-based registry only if a collaborator updates often. The first one is the "friends and family" release, cut after Phase 5's review stop; the outside colleague waits for it.
  • D23 Every 5 minutes, cached (Mark, 2026-10-05). After the first deploy felt slow on pages that fire many calls at once (Teams, Cost: calls queue on standard-1's half CPU), updates move from every 2 minutes to every 5 (a tick adds the last 5 minutes of activity), and the Worker caches API answers until the data changes (next tick, a reset, a panel change or any write). standard-2 for Mid-sized only if it's still slow. Supersedes D2's cadence.
  • D22 One Access app (Mark, 2026-10-05). /_download* joins the existing internal.qpoint.io Access application instead of a separate one: "I don't mind if they have both." Invited collaborators can reach downloads, /_admin and the internal sites; guests sign in with the one-time PIN. Supersedes D19's separate application.
  • D21 Instance types and releases in c112 (Mark, 2026-10-05). Standard instances where basic looked slow: Mid-sized and First run on standard-1, Small on basic, Enterprise on standard-2 (about $25 a week all told). Releases (D19) are folded into c112's Phase 5 deploy instead of a separate session's work.
  • D20 Follow the sun (Mark, 2026-10-05). Mid-sized and Enterprise get offices in several time zones so someone is always working; weekends stay quieter, not dead. Small keeps one office's hours. Built as a Phase 2 follow-up (follow-the-sun.md).
  • Not modeled: tools qcontrol can't observe (e.g. ChatGPT desktop, Copilot). The world model lists them as product gaps instead of faking them.

Artifacts

Qpoint Brand Style Guide