Repository navigation
PMO
Established 2026-08-17. Owner: PMO role (agent). Source of truth for what is in flight, what is blocked, and what is deliberately not being done.
This file does not replace TODOS.md (the deferred-work register) or the plan docs. It sits above them and answers one question: given the dated commitments in docs/win-plan-eoy2026.md, what work actually has to happen, in what order, and what is stopping it.
The PMO does:
- Maintain the program board below and keep it reconciled with
TODOS.md, GitHub issues/PRs, and the CHANGELOG after every release. - Hold the dated milestones and report distance-to-date honestly, including when a date is already lost.
- Surface blockers that are not engineering work (an API key, a business decision, a signature) with the same weight as code, because those are what have actually stalled this project.
- Name the critical path and refuse work that isn't on it during a gate crunch.
- Record decisions so a reversal is visible as a reversal.
The PMO does not:
- Re-open settled strategy. The CEO plan, the never-build list, and the Study Arena freeze are decisions, not proposals.
- Estimate in story points, run ceremonies, or add process to a one-person engineering team.
- Invent status. Anything marked verified here has a commit, a test, a CI run, or an HTTP response behind it.
| When | What |
|---|---|
Every release (/ship) |
Reconcile TODOS.md against the CHANGELOG — close what shipped, re-file what didn't. |
| Weekly (Mon) | Run npm run metrics:weekly, update §5 runway, re-rank the board. |
| At each gate date | Write a pass/fail line in §7. A missed gate gets a written cause, not a slip. |
| On any new QA/review pass | File findings into the board with a workstream tag, not just into TODOS.md. |
From docs/win-plan-eoy2026.md §6. Five proofs, not revenue:
- WTP is real — ≥5 schools invoiced AND paid.
- Adoption is real — ≥60% teacher weekly-active, founder absent.
- Channel is real — ≥2 schools by referral.
- Founder is free — ≤1 school-day/week support.
- Cash survives — infra ≤ credits; SISFS filed.
Everything on the board below must trace to one of these. Work that traces to none is on the frozen list (§9).
| Milestone | Date | Distance |
|---|---|---|
| First invoice paid (money moved) | 2026-08-14 | 4 days past — status unknown to PMO |
| 30-school-day streak must start | 2026-09-08 | 21 days / 15 weekdays |
| Adoption read (≥60% teachers, ≥4 days, founder absent) | 2026-09-30 | 43 days / 31 weekdays |
| School #2 signed | 2026-10-31 | 74 days / 53 weekdays |
| EOY scoreboard | 2026-12-31 | 135 days / 97 weekdays |
15 weekdays is the real budget. Everything in §6 is sized against that number.
| # | Question | What it unblocks |
|---|---|---|
| D1 | Did a school pay or sign by 2026-08-14? (Branch A = paid, Branch B = not paid) | Roughly a third of TODOS.md is explicitly payment-gated. Branch B stops it all. |
| D2 | Is a real pilot school onboarded on production today, and is PILOT_SCHOOL_CODE set there? |
Whether the Sep-30 adoption gate can be measured at all. |
| D3 | Mobile/accessibility floor — unblock now or keep gated? |
TODOS.md records this gating as "an accident of drafting, not a decision". |
| D4 | Is docs/BETA_LAUNCH_PLAN.md live or superseded by the wedge-first plan? |
Two plans currently describe the launch. Only one can be the schedule. |
Ranked by whether it blocks a dated gate. WS-0 blocks everything.
| Item | Evidence | Status |
|---|---|---|
| Signup email dead in production (#322) — ops half | Production still holds an invalid Resend key. Rotate → SMTP_PASS in Secret Manager → redeploy → re-test signup on prod. Only the founder can do this; it needs credential access. Open 39 days. |
OPEN P0, founder |
| Email failures are silent (#322) — engineering half | DONE 2026-08-17. One deliver() path logs at error level with mail type + recipient and throws EmailDeliveryError; signup returns verificationEmailSent, resend returns 502 not 401, /verify-email stops claiming a dispatch that didn't happen. 12 regression cases. |
SHIPPED |
| At-risk cron crashes every run (#324.1) |
Stale issue. The SQL was fixed in 4ace341 on 2026-07-13 — inside the Azure migration PR, unlabelled — and has been in production since. What was genuinely open: the scheduler's floating promises (any failure became an anonymous unhandledRejection) and the absence of any guard that could catch SQL drift. Both closed 2026-08-17. |
SHIPPED |
GET /api/chat/dms → 404 (#324.2) |
DONE 2026-08-18. The client asked for a path the router has never registered (/users/me/dms), so the DM list was empty for everyone with no error shown. Also fixed the blank-row bug behind it: conversations were titled with username, empty for every seeded and invited account. A contract test now checks every chat-api.ts path against the router's real route table. |
SHIPPED |
| Fabricated header badges (#324.3) | DONE 2026-08-17. Both counts were literals on buttons that did nothing. The bell now shows the real unread count (no badge at zero) and both buttons navigate; the messages badge was removed rather than invented, since no server-side unread total exists. Verified in a browser against a live database, both directions. | SHIPPED |
| Attendance copy over-promises WhatsApp (#324.6) | DONE 2026-08-18. The register's own toast was already honest (v1.9.0.0) — the real gaps were /absentees saying nothing at all about dispatch state, and the public marketing promising alerts "instantly" and "from the very first morning". /absentees now reports the server's real alerts.enabled; marketing keeps the capability but drops every already-running claim (founder decision). |
SHIPPED |
CSP blocks blob: worker / data: font (#324.4/5) |
Console errors on every page. | OPEN |
A paid pilot cannot be onboarded through the front door until the key is rotated. The engineering half landed on 2026-08-17 — the failure is now loud in logs and honest on screen — but loud is not working. Until the key is replaced in production, the new banner simply tells a school the truth: no code was sent.
Of the seven P0 gaps from the 2026-08-11 /autoplan, three closed in v1.9.4.0 and TODOS.md has not been updated to say so:
- ✅ Blank editable register on read failure — fixed (register locks, retry prompt).
- ✅ Save count reported submitted-not-written — fixed (server's written count).
- ✅ Adoption denominator contaminated — mitigated via
PILOT_SCHOOL_CODEcohort scoping. ⚠️ Partly —pgGetAttendanceByClassDatenow rethrows (verified atserver/lib/db/pg-queries.ts:2790), but 38return []sites remain in the same file. The class of bug is not closed, only its worst instance.- ❌ Metric semantics frozen + metric-version stamp — no
metric_versionanywhere inscripts/metrics-weekly.ts. - ❌ Repair/invalidate already-persisted partial snapshots — no evidence of work.
- ❌ Versioned migration ledger —
server/db-pg.tsstill re-applies one idempotent schema file; no migrations table.
- Set and verify
PILOT_SCHOOL_CODEin the production environment (blocked on D2). - Freeze metric semantics before the streak starts: cohort, timezone, week boundary, adjacency, baseline, partial-week. Changing these after Sep 8 rewrites the experiment while it runs.
-
schools.is_synthetic— replace theLIKE 'E2E%'heuristic, via expand/backfill/contract, not a naiveADD COLUMN(which recreates the same false-positive and re-runs it every deploy). - Weekly metrics correctness nits: week-adjacency check, mid-week partial snapshots, UTC vs IST week windows.
- Vitest flake ~1 in 3, confirmed empirically across the v1.9.2.0 ship. The accepted gate is a 10–15 run burn-in at zero failures, not "5 greens".
- No real-Postgres unit lane — export tests mock the whole data layer, so broken SQL and schema drift cannot be caught (this is exactly how #324.1 reached production).
- No client test infra at all (
vitest.config.tsis server-only, node env). - No mobile Playwright project (desktop Chromium only).
-
server/tests/setup.ts:54manufactures empty mocks for unexpected helper calls — should throw.
Teachers mark the register on phones. Currently: 64px dead sidebar gutter on a 360px viewport (18% of screen), touch targets at 24–40px against a 44px floor, two fixed floating controls colliding with the mobile bottom nav and with each other. Same bug class as the quest-panel defect that made the register unusable in v1.9.3.0 — that one was found by QA, in production code, on the wedge workflow.
-
13 open Dependabot PRs, oldest 2026-08-09. Checks are green on the ones sampled. Several are majors (
ioredis6,google-auth-library11,azurerm5,pg) and need reading, not bulk-merging. -
image-sizeaudit allowlist (2 advisories, no patched release exists) — re-check periodically, delete when one lands. - Determine whether untrusted image bytes can reach
generatePPTX(decides whether the allowlist is safe or a live hole). - CodeQL now passing on schedule; #272/#300 (code scanning enablement, Trivy CRITICAL triage) still open.
DONE 2026-08-17. TODOS.md was stale by one release: all seven /autoplan P0s still read as open when v1.9.4.0 had closed three and partly closed a fourth. Reconciled against the code, not the changelog — each verdict carries the file and line that proves it. The [~] marker now distinguishes "partly done" from "done", which is what let the read-failure item look closed when 38 sibling sites remain. Cadence in §2 exists so this does not recur.
| Date | Gate | Result |
|---|---|---|
| 2026-08-14 | First invoice paid | unrecorded — see D1 |
| 2026-09-08 | Streak must start | pending |
| 2026-09-30 | Adoption read | pending |
| 2026-10-31 | School #2 signed | pending |
- ~~#322 fail-loud email (engineering)~~ — done 2026-08-17. Now blocked on the founder rotating the production Resend key; nothing else matters until a school can sign up. (WS-0)
- ~~#324.1 at-risk cron crash~~ — done 2026-08-17. The SQL was already fixed a month ago; the reporting hole and the missing drift guard were not. Both closed. (WS-0)
- ~~Honesty defects — fabricated badges, WhatsApp copy~~ — done 2026-08-17/18. A principal who catches the product lying once will not trust the term report. (WS-0)
-
PILOT_SCHOOL_CODEset + metric semantics frozen — must be done before day 1 of the streak, not after. (WS-2) - Mobile floor on the register only — the phone is the device. Not the whole app; the register. (WS-4)
Everything else waits. WS-3 and WS-5 are real debt but they do not move a September gate.
- Study Arena, all of it. Decision at the 2026-08-11 gate: separate option, Phase A, dark in production. It is no longer "the moat".
-
Study Arena end-to-end QA. Blocked on a valid AI key four times (07-22, 07-31, 08-06, 08-11).
GOOGLE_API_KEYhas anAQ.A…prefix; AI Studio issuesAIza…. One valid key permanently unblocks it — but per the freeze, it is not on the critical path. - Coded term report, CSV streaming, admin school selector, vernacular pass — payment-gated or blocked on an unnamed owner/decision.
- Never-build list (constitution): no foundation-model training, no standalone AI tutor, no "our AI is smarter", no single-provider coupling, no fabricated data shown to real accounts.