v2.1 — what we decided since · 2026-05-18

1Where we are

Both production-handoff gates are closed pending stakeholder ratification. The mockup passed Cycle 20's audit (build · lint · typecheck all clean). Next step is Kamran sending two emails so the ~7-day default-ship windows can start.

v2.1 Phase D2 days ago
21-cycle loopjust shipped
Gate 1 · Schema handoverdrafted
Gate 2 · Billing passresolved + drafted
Send emailsKamran
Closed — landed in repo, drafted in docs, or ready for production Now — needs Kamran's action Next — automatic once defaults ship

2What landed in 21 cycles

Each row = one cycle, one theme, one shipped outcome.

Block 1 Unclears + Billing reframe 1 · 2 · 3 ADR-013 · 3 unclears locked · 54-item Billing triage
Block 2 Billing arc end-to-end 4 · 5 · 6 + amend 45 internal locks · 12 mockup decisions · ratification draft
Block 3 First two-pass schema ADRs 7 · 8 · 9 ADR-014 · ADR-015 · ADR-017
Block 4 Novel-shape ADRs (new tables, docket-correction) 10 · 11 · 12 ADR-010 · ADR-016 · ADR-012
Block 5 Finalize + handover begins 13 · 14 · 15 ADR-007 · ADR-018 · Packet 1 → Granjur
Block 6 Handover finish + governance 16 · 17 · 18 Packets 2 + 3 → Granjur · ADR-008 + ADR-009
Block 7 Pre-flight + audit + wrap 19 · 20 · 21 Week-0 pre-flight · audit (104 findings, 10 BLOCKERs closed) · this summary

3What shipped, by category

11
ADRs
10 new + ADR-007 finalized
3
Granjur packets
26 + 18 + 7 items · 3 collisions catalogued
45
Billing items resolved
Internal locks · 12 shipped in mockup
2
Production-prep docs
Week-0 pre-flight (1186 lines) · audit (104 findings)
Schema delta 8tables 11enums ~30columns ~20indexes 4CHECK constraints 3cross-packet collisions

4Bucket A scorecard — honest accounting

The plan estimated Bucket A (Claude resolves, no stakeholder gate) at ~85% of total work. After a 3-sweep corrective investigation, actual share lands at ~85-90% — within the plan's range. Details below the bar.

Work item distribution · 33 items total Bucket A actual: ~85-90%  ·  plan estimate: 85%
15 · A direct
5 · B→A
4 · D
3 · Lejla
3 · Usama
3 · settled
Bucket A — Claude resolved, planned (15/15 = 100% of plan) Bucket B → A — internally resolved (5 items: B1, B2, B3 via Cycle 2; B5, B8 via Cycle 4) Bucket D — Kamran orchestration confirmed (D1, D2, D3, D6) Lejla — 3 product asks (drafted) Usama — 3 engineering asks (drafted) Already settled (3) — informationals, not real asks
One item is BLOCKING: Usama's SF9 legacy coupon shape pick gates the production migration — no default ships. Every other ask carries a recommended default and ships on its window.

Honest accounting: A 3-sweep corrective investigation found that 3 items in the original "9 asks" count were already-settled informationals (OQ-SF14-1, Zoom regex, R4-Q1) — they appear in source artifacts but don't need stakeholder input. The real surface is 6 asks (1 BLOCKING + 5 ratifications-with-defaults) + 3 informationals, and Bucket A actually landed at ~85-90% of work — within the plan's headline range.

5Open questions — to discuss in the meeting

5 standalone questions for the meeting — Lejla (2) + Usama (3, one BLOCKING). Each has a recommended default; the plan is to walk through them together rather than route as email. The full ask cards live on their own page so you can share them without the 21-cycle retrospective context:

Standalone meeting prep doc. L1 Past Due display · L2 Scholarship thresholds · U1 Family Plans coupon strategy · U2 Legacy coupon shape BLOCKING · U3 billing_alerts schema.

6What's next — Kamran's actions

Process retrospective for the next loop is captured in the canonical 2026-05-18-loop-completion-summary.md → §4 Process learnings.

  1. Send the billing-ratification email. Audience split inside the doc — Lejla gets B1 + SF5, Usama gets B2a + SF9 + B5. Send date sets the ~7-day default-ship window for 5 items. 2026-05-17-billing-stakeholder-ratification.md
  2. Send the ADR-007 sign-off email to Lejla + Usama. The 2026-05-25 date in the body is firm — send before EOD today to preserve the 7-day window. 2026-05-18-ADR-007-signoff-email.md
  3. Deliver the 3 Granjur handover packets to Usama / Granjur team. Recommended bundling: one email linking all 3 packets + ADR-018 ratification + the 6 sign-off asks. → Packets at docs/admin-spec-v2-1/2026-05-18-phase-d-handover-{teacher-comm, reporting-admin, cross-cutting}.md
  4. After defaults ship (~2026-05-25) — apply confirmed answers to the billing resolutions doc + v2 spec, and land the gated follow-up mockup PR (B1, B8, SF1, SF2, SF4).
NOW Kamran sends 3 emails ~2026-05-25 Defaults ship (or stakeholders reply) FOLLOW-UP Apply answers + final PR (Cycle 5 deferrals) WEEK 0 Production handoff

AAppendix — what this work actually looks like on disk

Up to here, this page has used a lot of names — "ADR-014", "Phase D handover Packet 2", "pre-flight checklist". The appendix grounds those names in concrete files and shows one decision moving end-to-end across every layer it touches. If you've ever wondered what is the actual unified view, where do the files live, what do they contain — this section answers that.

A.1Where everything lives

A tour of the directories that hold the loop's output. Each line shows status by color:

Status Green  =  created in loop Yellow  =  edited in loop Grey  =  pre-existing, untouched
QuranFlow-Admin-Mock/ ├── docs/ │ ├── admin-spec-v2-1/ v2.1 canonical layer — where the loop wrote │ │ ├── decisions/ Architecture Decision Records (ADRs) │ │ │ ├── ADR-007-tag-as-saved-filter.md Cycle 13 finalized (Proposed → Accepted) │ │ │ ├── ADR-008-data-capture-privacy.md Cycle 18 — 3-tier privacy model │ │ │ ├── ADR-009-rbac-future-state.md Cycle 18 — 5-tier procedure model │ │ │ ├── ADR-010-multi-device-session-cap.md Cycle 10 — 3-device cap + new table │ │ │ ├── ADR-012-zoom-marketplace-api.md Cycle 12 — Zoom integration │ │ │ ├── ADR-013-reset-progress.md Cycle 1 — non-destructive Reset │ │ │ ├── ADR-014-cadence-track-enum.md Cycle 7 — dual-cadence semesters │ │ │ ├── ADR-015-evergreen-null-columns.md Cycle 8 — reserved cols │ │ │ ├── ADR-016-submission-thread.md Cycle 11 — TA audio threads │ │ │ ├── ADR-017-repeat-eligible-until-consumed.md Cycle 9 — persistence model │ │ │ └── ADR-018-family-plans-coupon-strategy.md Cycle 14 — coupon strategy │ │ │ │ │ ├── MEETING-NOTES-2026-05-05.md raw transcript — Lejla walkthrough Pt 1 │ │ ├── MEETING-NOTES-2026-05-14.md raw transcript — Scheduling deep-dive │ │ ├── _LEJLA-MOCKUP-RUN-REPORT.md raw — Lejla May 10 mockup pass │ │ ├── 01-feedback-evaluation.md 160KB — every feedback item disposed │ │ ├── ARCHITECTURE-EVALUATION-2026-05-06.md 162KB — schema architecture analysis │ │ ├── IMPACT-MAP-2026-05-05.md impact analysis of May 5 feedback │ │ │ │ │ ├── 00-execution-status.md rolling project status — every cycle adds row │ │ ├── 00-revision-summary.md v2 → v2.1 revision register │ │ │ │ │ ├── 2026-05-17-next-phase-plan.md the docket — 21 cycles planned │ │ ├── 2026-05-17-cycle-log.md journal — one entry per cycle │ │ ├── 2026-05-17-three-unclears-resolved.md Cycle 2 │ │ ├── 2026-05-17-billing-decision-triage.md Cycle 3 — 54 items triaged │ │ ├── 2026-05-17-billing-resolutions.md Cycle 4 — 45 internal locks │ │ ├── 2026-05-17-billing-stakeholder-ratification.md Cycle 6 — Lejla 2Q + Usama batch │ │ ├── 2026-05-18-ADR-007-signoff-email.md Cycle 13 — Lejla + Usama sign-off │ │ ├── 2026-05-18-phase-d-handover-teacher-comm.md Cycle 15 — 26 items → Granjur │ │ ├── 2026-05-18-phase-d-handover-reporting-admin.md Cycle 16 — 18 items → Granjur │ │ ├── 2026-05-18-phase-d-handover-cross-cutting.md Cycle 17 — 7 items → Granjur │ │ ├── 2026-05-18-production-week-0-preflight-checklist.md Cycle 19 — 1186 lines, 344 items │ │ ├── 2026-05-18-final-audit-report.md Cycle 20 — 104 findings │ │ ├── 2026-05-18-loop-completion-summary.md Cycle 21 — canonical .md companion │ │ │ │ │ ├── screen-data-bindings/ screen ↔ schema mappings (pre-loop) │ │ ├── pre-review/ 4-lens audit + depth + packages (pre-loop) │ │ └── screenshots-2026-05-14/ scheduling walkthrough screenshots │ │ │ ├── admin-spec-v2/ BEFORE-state baseline — frozen, read-only │ │ ├── 00-spec-index.md │ │ ├── 01-global-patterns.md │ │ └── ... (10 domain spec files) │ │ │ ├── admin-spec/ v1 legacy spec — frozen, reference only │ │ │ ├── production-architecture-research/ production-side design docs │ │ └── 30-design/ │ │ ├── 01-schema.md canonical production DDL — edited by ADRs │ │ ├── 00-tanstack-idioms.md tRPC + procedure conventions │ │ └── ... (other design specs) │ │ │ └── IMPLEMENTATION-PLAN.md v2 build phases — high-level roadmap │ ├── src/ the mockup — React + TypeScript + shadcn │ ├── data/ mock data (TS types + fixtures) │ │ ├── types.ts Semester.cadenceTrack (ADR-014), etc. │ │ ├── semesters.ts cadenceTrack values on each row │ │ ├── coupons.ts 6 auto_managed seed (ADR-018) │ │ └── ... (other data files) │ ├── pages/v2/ v2 + v2.1 pages — Cycle 5 + Cycle 20 edits │ └── components/v2/ end-checklist-queue audit fix, etc. │ └── public/team-updates/ team-update HTMLs (this file lives here) ├── 2026-05-16-v2-1-overview.html prior — Phase D wrap-up └── 2026-05-18-loop-completion.html this page

A.2The 5-layer stack — how artifacts relate

The work organizes into 5 layers. Raw stakeholder input flows into analysis docs, which feed decision records, which produce two parallel outputs (schema + mockup), all wrapped in coordination artifacts that move things to production. Each layer has a different shelf life and a different audience.

Layer 1 Raw input — what stakeholders said

Transcripts, mockup-run reports, walkthrough notes. Long-form prose. Owned by whoever was in the room.

MEETING-NOTES-2026-05-05.md · MEETING-NOTES-2026-05-14.md · _LEJLA-MOCKUP-RUN-REPORT.md · backend_suplementary_feedback_domains_1to3.md

analyzed via
Layer 2 Analysis — recommendations + trade-offs

Multi-option write-ups that weigh schemas / behaviors against each other. Cite transcripts; produce a recommended option without locking it in.

01-feedback-evaluation.md (160KB) · ARCHITECTURE-EVALUATION-2026-05-06.md (162KB) · IMPACT-MAP-2026-05-05.md · pre-review/_raw/ · pre-review/_depth/

formalized as
Layer 3 Decision of record — why we chose what

One markdown file per decision. Format: Context / Decision / Schema implications / Rationale / Implementation notes / Open questions / Fallback / Cross-references. Outlives the loop. Production engineers read these before writing code.

decisions/ADR-007-tag-as-saved-filter.md through ADR-018-family-plans-coupon-strategy.md — 11 ADRs landed in the loop. 8-25KB each.

shapes both
Layer 4a Schema — what production builds

Canonical DDL spec for the production Postgres database. Per-table blocks + Migration table + Indexes Summary + Source line. Granjur reads this to write Drizzle migrations.

docs/production-architecture-research/30-design/01-schema.md — ~2900 lines after loop edits. Edited by every TYPE-1 ADR cycle.

Layer 4b Mockup — what to see

React + TypeScript + shadcn/ui front-end mockup. Demonstrates that the decisions render coherently. Live at quranflow-admin.pages.dev/v2.

src/data/types.ts · src/data/*.ts · src/pages/v2/**/*.tsx · src/components/v2/**/*.tsx

wrapped by
Layer 5 Coordination — moving decisions to production

Delivery wrappers. Handover packets bundle ADRs + schema deltas for Granjur. Ratification docs ask stakeholders to confirm. Pre-flight checklist sequences the Day-1 production work. Audit report verifies the mockup. Cycle log + plan + this summary are loop-process artifacts.

3 handover packets · billing ratification + ADR-007 sign-off email · pre-flight checklist · final audit report · cycle log · plan docket · this summary

A.3End-to-end trace — one ADR from idea to mockup

When we say "ADR-014 landed," what actually happened? Following one decision — dual-cadence semesters (Recitation + Mastery running in parallel) — through every file it touches. Each step below is a real file path with a real excerpt. Click any path to open the file on GitHub.

- Multiple semester stream capability required - Current: January/May/September and March/July/November streams

What happened: Lejla raised this at the May 5 walkthrough. Two cadences run in parallel — each with its own enrollments, content schedule, TAs, and close cycle. The v2 schema had a globally-unique is_current index that breaks the moment two cadences are simultaneously active.

Step 2 · Analysis (Layer 2) docs/admin-spec-v2-1/ARCHITECTURE-EVALUATION-2026-05-06.md §Q3 (lines 286–462)
Three options weighed: Option A — drop is_current, derive from start_date / end_date ranges Option B — keep is_current, scope partial uniqueness per-cadence Option C — streams as first-class entity (own table + CRUD) First-principles call: Option B Matrix score 7-1-2; cites three documented `is_current` consumers that break under Option A; Option C is entity-weight without need.

What happened: The Architecture Evaluation doc weighed three options against each other, citing the three documented consumers of is_current (Activate Semester action, v2-CRON-F end-of-semester, Auto-Transition toggle) — all of which break if you drop the column. Option B (keep is_current, scope per-cadence) emerged from re-evaluation. Recommendation only — not yet a decision.

Step 3 · Decision of record (Layer 3) docs/admin-spec-v2-1/decisions/ADR-014-cadence-track-enum.md (Cycle 7)
# ADR-014: Stream cadence_track — per-cadence is_current uniqueness Status: Accepted · Date: 2026-05-18 Source: ARCHITECTURE-EVALUATION-2026-05-06.md Q3 (lines 284-512) ## Decision Option B from the Q3 trade-off matrix: keep `is_current`, scope its partial uniqueness to per-cadence, and add `cadence_track` as an enum column on `semesters`.

What happened: Cycle 7 of the loop. A writer-agent drafted the ADR; a review-agent cross-checked it; the reviewer caught a stale index entry as a BLOCKER, which the lead fixed before commit. The ADR file (~13KB) is the production-team reference — it has the Decision, the SQL, the rationale, and three explicit per-consumer impact rows so the production engineers don't have to reverse-engineer the intent.

↓ shapes ↓
- `is_current` boolean NOT NULL DEFAULT false — at most one row TRUE **per cadence_track** at a time (enforced by partial unique index). Read by 3 consumers: v2-CRON-F end-of-semester, Activate Semester action, Auto-Transition toggle. - `cadence_track` `cadence_track_enum` NOT NULL DEFAULT `'recitation'` — NEW v2.1 (ADR-014); cadence label set at semester creation. Two values today (`'recitation'`, `'mastery'`); add via `ALTER TYPE … ADD VALUE`. Enables parallel cadences running simultaneously. Enums: `cadence_track_enum` (`'recitation' | 'mastery'`) — ADR-014. Indexes: - `semesters_is_current_per_cadence_unique` UNIQUE on `(cadence_track) WHERE is_current = true` (ADR-014). Replaces `semesters_is_current_unique`.

What happened: The same cycle edited the production schema doc — added the new column on the semesters block, added the new enum to the §Enums sub-section, swapped the unique index entry in §5 Indexes Summary, appended ADR-014 to the §Source line. The reviewer's "standing cross-table sweep" exists precisely to catch parity drift across these four places.

↓ shapes ↓
Step 4b · Mockup (Layer 4b) src/data/types.ts:219 + src/data/semesters.ts
// src/data/types.ts:213-220 /** v2.1 ADR-014: cadence track distinguishes the per-week pacing model * for the semester. "recitation" is the default for Year 1 (L1-L4); * "mastery" applies to Year 2. Production lands as NOT NULL DEFAULT * 'recitation'. Retention denominator and Returning detection scope to * the prior _same-track_ semester. */ cadenceTrack: "recitation" | "mastery"; } // src/data/semesters.ts { ..., cadenceTrack: "recitation" } // 4 mock rows all on 'recitation'

What happened: The mockup data layer was updated in Cycle 20's final audit (a SHOULD-FIX in Slice 4): the Semester type was renamed from streamId?: "A"|"B" to the real cadenceTrack: "recitation"|"mastery", and all 4 mock semester rows updated. This is what makes the mockup honest — the prop name matches what Granjur will see in the production schema.

↓ wrapped by ↓
From Packet 2 (OQ-SF14-1 reconciliation): ADR-014 reconciliation flagged — OQ-SF14-1 (semesters.stream_id) and ADR-014 (cadence_track_enum) are the same concept under different names. Recommended canonical naming: use ADR-014's column (`cadence_track_enum`) and treat "stream" as legacy binding-doc terminology. From Pre-flight Phase 1 (Schema deploy DDL order): Phase 1.1 — Create `cadence_track_enum` (Recitation/Mastery) Phase 1.2 — Add `semesters.cadence_track` NOT NULL DEFAULT 'recitation' Phase 1.3 — Drop `semesters_is_current_unique` Phase 1.4 — Create `semesters_is_current_per_cadence_unique`

What happened: The Phase D handover Packet 2 noted that one of Granjur's existing Phase D open-questions (OQ-SF14-1 wanting a semester_stream_enum) appeared to collide with ADR-014. The pre-flight checklist Phase 1 sequenced this as a specific ordered DDL deploy. No outstanding stakeholder ask: the reconciliation is already settled across the schema doc (01-schema.md:556), the mockup (src/data/types.ts:219), and pre-flight checklist line 115 (1.1.12). Granjur sees cadence_track_enum the moment they open the schema doc; the legacy binding-doc "stream" terminology won't appear in production schema. Settled informational, not a ratification.

That's what one ADR looks like end-to-end — 5 layers, 6 distinct files touched, one open question for Granjur. The other 10 ADRs follow the same shape. ADRs that affect UI (e.g. ADR-013 Reset Progress, ADR-007 Tag-as-saved-filter) also have a Layer 4b mockup component change; ADRs that are doc-only (ADR-008 privacy, ADR-009 RBAC) skip Layer 4 entirely.

A.4Glossary — what the terms actually mean

ADR Architecture Decision Record
One markdown file per decision. Lives in docs/admin-spec-v2-1/decisions/. Format: Context / Decision / Schema implications / Rationale / Fallback / Open questions. 8-25KB. Production engineers read these before writing code.
OQ-ID Open Question
Identifier for a single schema question raised by the mockup against the production schema doc — e.g. OQ-T6-1 = Teacher Mgmt question #1. The 45 OQs across the 3 handover packets are the "schema decisions that need ratification by Granjur."
Handover Packet
Date-prefixed markdown file at the root of docs/admin-spec-v2-1/. Bundles already-shipped decisions for delivery to Granjur. Format: item-by-item table with OQ-ID, citation, recommended action.
Pre-Flight Checklist
One 1186-line file (2026-05-18-production-week-0-preflight-checklist.md) sequencing every Day-1 action for the production team. 12 phases × 344 line items + 3 appendices (landmines / collisions / gaps).
Audit Report
One file (2026-05-18-final-audit-report.md) capturing the 4-slice integration audit from Cycle 20: 104 findings, 10 BLOCKERs (all fixed), 30 SHOULD-FIXes (9 fixed, 21 deferred).
Bucket A / B / D
The plan's 3-bucket framing for resolution work. A = Claude resolves no stakeholder gate. B = needs Lejla. D = needs Kamran's strategic orchestration. (There's no Bucket C in the plan.)
Schema doc
One file at docs/production-architecture-research/30-design/01-schema.md. The canonical DDL specification — what Granjur turns into Drizzle migrations. ~2900 lines after loop edits; edited by every TYPE-1 ADR cycle.
Mockup
The React+TypeScript app at src/. Live at quranflow-admin.pages.dev/v2. v1 at /* is frozen; v2 + v2.1 at /v2/* is active.
Spec
Two layers. docs/admin-spec-v2/ is the BEFORE-state baseline (frozen reference). docs/admin-spec-v2-1/ is the AFTER-state diff + new canonical layer for v2.1 work.
Cycle log
2026-05-17-cycle-log.md — append-only journal, one entry per cycle. Captures status (in_progress / completed), agents spawned, files touched, summary, next cycle.
Plan docket
2026-05-17-next-phase-plan.md §5 — the 21-cycle list with dependencies and types. Edited in-place to strike completed cycles.
TYPE-1 / TYPE-2 / TYPE-3 / TYPE-4 / TYPE-5
Plan §5 cycle-shape taxonomy. TYPE-1 = ADR write-up. TYPE-2 = Phase D handover. TYPE-3 = pre-review pipeline (4-lens → depth → packages). TYPE-4 = doc cycle. TYPE-5 = final audit. Defines how many agents and what teamwork pattern.

A.5So where is the "unified final view"?

There isn't one single file. The system is described by three parallel tracks that all align. Granjur reads all three before they start writing code; Lejla reviews the live mockup; you (Kamran) coordinate across all three.

Track 1 · What to see
The live mockup

Deployed React app. Demonstrates that every decision renders coherently in the admin UI. Stakeholders click around to verify the design works in practice. This is the most concrete artifact — you can run it and use it.

Track 2 · What to build
The schema doc

Canonical DDL specification for the production Postgres database. Per-table column lists + enums + indexes + source citations. Granjur turns this into Drizzle migrations in production Week 1.

Track 3 · Why and how
v2.1 decisions + spec layer

The 11 ADRs (decisions of record) + the v2.1 revision summary + the 3 Phase D handover packets + the screen-data bindings. Tells Granjur why the schema is what it is and how screens use it.

The three tracks align by design. The mockup demonstrates what the schema enables. The schema doc cites the ADRs that drove each column. The ADRs cite the meeting transcripts that drove each decision. You can read in either direction — start from a screen and trace back to the transcript, or start from a transcript and forward to the live render. The loop's job was to make sure all three tracks tell the same story.

Where things get added vs overwritten:

Created new (never overwrites)

  • ADRs — one file per decision in decisions/
  • Handover packets — one file per delivery
  • Ratification + sign-off emails
  • This summary + companion HTML
  • Cycle log entries (append-only)
  • Execution-status rows (append-only)

Edited in place

  • Schema doc — every ADR modifies the relevant table block
  • Mockup (src/) — types updated, components added/refactored
  • Plan docket — strike-through on completed cycles

Frozen / not touched

  • v1 spec, v2 spec baseline
  • Meeting transcripts, mockup-run reports
  • ARCH-EVAL, IMPACT-MAP, feedback-evaluation