Projects / Adaptive SAT
Adaptive SAT active
adaptive-sat · last seen 2026-10-26 01:19
Shipped #147 and #148: official College Board score-report parsing, and vision extraction for images on gemma4. Closed as done: #150 (BRD23-B vision), #21 (real PDF parser, REQ-19.7 — deferred since June), #136 (web nav), #147 (Firebase deploy blocker, fixed days ago).
Why the parser failed on a real PSAT: not a regex that needed loosening — we had modelled the wrong thing. CB reports contain NO per-skill correct/total counts. They give 8 content domains as performance score BANDS on the 160-760 scale plus a question-count range ("Information and Ideas / (26% of section, 12-14 questions) / Performance: 610-670"). The existing patterns hunted for "Skill 7/12", which does not appear anywhere on an official report, so every CB upload fell through to manual entry. The KD College Prep handler worked because that provider does print counts. Now parsed: 8 domains → 9 of our skills, total/RW/Math scores, and the test date. Two traps found: CB hyphenates "Problem-Solving" and our seed data doesn't (silently dropped that whole domain), and a top band over 4-6 questions rounds to 5/5 which reads as "you got everything right" when the report says no such thing — clamped, and the review screen now says CB figures are estimated from bands rather than counted.
Saravanan's out-of-order point was a live bug: get_score_report ordered by uploaded_at DESC and compute_score_trend took reports[0]/reports[-1] from upload order, so uploading an older report later made it the "latest" and produced a confident fictitious score drop. Now ordered by coalesce(test_date, uploaded_at). Only fixable because the parser can read the test date. Also: rw_score/math_score/total_score have existed since migration 030 but nothing ever wrote them — Home's report card rendered "—" for every score.
Vision (#148) is built around refusing rather than guessing, because extracted numbers land in user_skill_state and drive question selection: the prompt offers {"readable": false} as a correct answer, out-of-range values are dropped not clamped, RW+Math must equal Total or all three are discarded, dates outside 2023-today are rejected, under four readable domains sinks the extraction, temperature=0. Most of the 25 new tests assert it returns nothing. A photographed report and a PDF produce byte-identical rows — both run through cb_domains_to_entries, with a test pinning it.
gemma4 chosen: cheapest vision model in Ollama's cloud catalogue ($0.14/$0.40 per 1M) and it does text too, so one model string also switched on rationale generation (#82), which had been wired but off since the 24th. Judge stays on o4-mini — the whole point of per-role config was never moving the quality gate on cost.
202 backend tests pass (45 new); the single failure is the pre-existing test_question_validation one. NOT verified: no call has ever hit the real Ollama provider — every vision test mocks the client, so the first real call is the first image upload. Extraction accuracy is unmeasured (REQ-23.13 wants 90%); one sample report, no labelled set.
todo 12 open
Pricing $1.99/mo + $19.99/yr: Stripe prices + ASC price edit + reviewer notes
high
Code strings are shipped (#132). Remaining is dashboard config:
- Stripe: price amounts are immutable, so create NEW price objects, then add new secret versions for STRIPE_PRICE_ID and STRIPE_PRICE_ID_MONTHLY.
- App Store Connect: price is a property of the existing subscriptions — edit com.adaptivesat.premium.annual and .monthly in place. Product IDs unchanged, so RevenueCat needs nothing.
- CRITICAL: the App Review notes on version 1.0 currently quote "$0.99 per month" and "$9.99 per year". Update before submitting or the reviewer sees notes that contradict the live price — a rejection risk on its own.
Trial stays annual-only, so billing_service.give_trial needs no change. No existing subscribers, so no grandfathering or price-increase consent flow — materially harder to change later.
PR#132
added 10-24 03:00
· by saravanan@scrumclaw.ai
· claude-cowork
BRD23-C: CB label mapping + review/confirm endpoints + admin queue
high
Map College Board labels to Skill via skill_aliases (exact match on the normalised form). Unmatched rows persist with skill_id NULL and the raw label, are excluded from weak-topic ranking until mapped, then count retroactively once an alias exists.
Resolution is an ADMIN job, never the student's (REQ-23.14). CB's report taxonomy is a small fixed set, so each unknown label is mapped once and resolved for everyone; after a handful of real reports the queue goes quiet. Students only ever correct numbers they can verify against the report in their hand — they never see our internal taxonomy.
No dependency on the vision model — can start immediately, in parallel with BRD23-D.
backend/app/models/score_report.pybackend/alembic/versions/030_score_report_history.py
added 10-24 03:00
· by saravanan@scrumclaw.ai
· claude-cowork
Exam: within-module back/forward navigation + change answers + question navigator (Bluebook parity) — web AND mobile
high
Owner noticed the full exam has no back/forth between answered questions. Root cause: exam engine is forward-only by design. Backend get_next_exam_question serves the next UNSEEN question and immediately consumes it (status→ANSWERED); /answer records a single Attempt; no endpoint to re-fetch a prior question, change an answer, or list the module; ExamQuestionStatusEnum has only UNSEEN/ANSWERED/SKIPPED (no FLAGGED/REVIEW). Same limitation on WEB (frontend ExamSession.tsx) since it's the same backend — whole-product gap, not mobile-only. Real Digital SAT (Bluebook) allows free within-module navigation, changing answers, and a question navigator with mark-for-review until the module timer ends. SCOPE (multi-day, cross-cutting): backend — serve whole module, mutable per-question answers until module submit/timer, add flag/review state, add submit-module step (stop consume-on-serve); web+mobile — question navigator UI (grid + flags), Back/Next, module answer state, submit at module end. NOT an App Store blocker — sequence AFTER build 7 clears review. Refs: backend/app/services/exam_service.py (get_next_exam_question, submit_exam_answer), backend/app/models/exam_module_question.py, mobile/src/screens/ExamSessionScreen.tsx, frontend/src/app/pages/ExamSession.tsx.
backend/app/services/exam_service.pybackend/app/models/exam_module_question.pymobile/src/screens/ExamSessionScreen.tsxfrontend/src/app/pages/ExamSession.tsx
added 08-10 14:05
· by saravanan@scrumclaw.ai
· claude-cowork
from the conversationsaravanan: I need the option to go back and forth for the questions in the full test — why is it not enabled?
claude: Exam engine is forward-only (serves next UNSEEN, consumes it, one Attempt each; no revisit/flag) on web+mobile. Real feature to add; not an App Store blocker — do after build 7.
BUILT (full feature, per owner decision to include in the review build). Backend: migration 026 (exam_module_questions.selected_answer + flagged), GET /exam/module, POST /exam/flag, /answer now UPSERTs (mutable answers + fixes duplicate-Attempt bug) — backward compatible (old /next path untouched). Mobile (ExamSessionScreen) + Web (frontend ExamSession.tsx): whole-module load, Back/Next, change answers, mark-for-review flag, question-navigator grid, review-before-submit; timer/break/calculator preserved; web endExam also fixed to POST /exam/end. All verified: backend py_compile OK, mobile tsc exit 0, web tsc no new errors (only pre-existing TS6133 React-unused noise). NOT runtime-tested (no device/DB here). DEPLOY GATE: migration 026 MUST run (run-migrations) with/before the backend deploy or /answer + /module 500 on the missing column. Owner chose to bundle into the App Store review build without a separate QA pass (risk acknowledged). Files: backend/app/{services/exam_service.py,api/routes/exam.py,schemas/exam.py,models/exam_module_question.py}, alembic/versions/026_exam_answer_flag.py, mobile/src/{screens/ExamSessionScreen.tsx,api/client.ts}, frontend/src/app/{pages/ExamSession.tsx,api/client.ts}.
RESOLVED prod outage: after PR #117 deployed the new exam model, Start Exam 500'd because migration 026 hadn't run. Root cause of the migration failures: run-migrations.yml PROJECT_ID still pointed at the old GCP project (prj-crypto538-prod-260529) — fixed to prediction-383914 in PR #118, and the CI service account was missing secretmanager.secretAccessor on adaptive-sat-database-url (+ cloudsql.client on the crypto instance) — granted. Migration then ran successfully (025 -> 026), columns selected_answer + flagged now exist in prod. Exam start unblocked. Follow-up option: add `alembic upgrade head` to deploy-backend.yml so migrations auto-run on deploy and this can't recur.
Web exam highlighter shipped (PR #119, frontend deploy): ExamSession now uses the full PassageHighlighter (two-pane Bluebook layout via splitPassageStem — passage+highlight left, stem+choices right) for RW questions, single-column fallback for math/non-splitting items. Parity with PracticeSession. tsc clean. Web-only (no migration, doesn't affect mobile build). Note: mobile exam highlighter is the simpler tap-a-word style; could later be upgraded to the richer drag-select+notes version if desired.
PREVENTION wired: deploy-backend.yml now runs `alembic upgrade head` (Cloud SQL Auth Proxy → prediction-383914 secret, crypto-project instance) between build and Cloud Run deploy — build → migrate → deploy. A failed migration blocks the deploy, so new code can't serve against an un-migrated schema (the 026 outage can't recur). Uses the CI SA grants added earlier (secretAccessor + cloudsql.client). run-migrations.yml stays as the manual escape hatch. YAML validated.
Status 2026-10-06: The root cause is the forward-only exam engine. This is multi-day, cross-cutting work on web and mobile, and it's sequenced after build 7 (#38) clears.
iOS 2nd rejection (2026-07-24) remediation → build 7 resubmit
high
Apple rejected build 6 (reviewed on iPad Air M3, iPadOS 26.5.2). Four items. CODE FIXES DONE (mobile, typecheck clean, not yet committed/built): (1) 3.1.2(c) MobilePaywall now has tappable Terms of Use (EULA) + Privacy Policy links and shows title/length/price; (2) 2.1(b) SettingsScreen has a visible 'Upgrade to Premium' row opening the paywall so reviewers can locate the IAP; (3) 2.1(a) ExamStartScreen adds a 30s timeout + clear retry error so 'Start Exam' can't silently hang. ASC METADATA DONE: EULA link added to App Description (saved), Privacy Policy URL confirmed (adaptivesat.ai/privacy). PENDING (owner): check/top-up OpenAI credits (prime suspect for the iPad 'Start Exam did nothing' hang) and retest on iPad; commit+push mobile changes via ship.sh; new EAS production build (build 7); fresh screen recording (Start Exam works + Settings→Upgrade to Premium paywall + sandbox purchase); paste reply (asc_submission/apple_reply_draft.md) in Resolution Center; resubmit app+subscription+group together. Refs: MobilePaywall.tsx, SettingsScreen.tsx, ExamStartScreen.tsx.
mobile/src/components/MobilePaywall.tsxmobile/src/screens/SettingsScreen.tsxmobile/src/screens/ExamStartScreen.tsxasc_submission/apple_reply_draft.md
added 07-25 04:08
· by saravanan@scrumclaw.ai
· claude-cowork
from the conversationsaravanan: [pasted Apple's 2nd rejection: 3.1.2c EULA, 2.1a Start Exam no action on iPad, 2.1b can't find IAP]
claude: Made the 3 code fixes + ASC EULA link; remaining = OpenAI check + build 7 + recording + resubmit with reply.
ROOT CAUSE found for 2.1(a): "Start Exam did nothing" was NOT primarily OpenAI credits — it was slowness. exam_service.build_module_blueprint builds 27 questions synchronously at start, and get_question_for_exam GENERATES a question live (OpenAI + judge, ~5-15s each) the moment a specific skill+difficulty cell is empty in the bank, instead of first checking other bank cells. Thin cells → many live generations → 60s+ wait with no UI feedback → reviewer saw "nothing". (User topped up OpenAI and exam then "loaded after a while" — confirms slow-not-broken.) FIX (backend, exam-only, deploys via ship.sh→deploy-backend.yml): _get_exam_question_with_fallbacks now scans the ENTIRE existing bank first (bank-only pass, no OpenAI) and only generates as a last resort → start is near-instant when the bank has ~27 usable RW questions. FIX (mobile): ExamStart timeout 30s→60s + "Building your exam…" loading message so it never looks frozen. Both compile/typecheck clean. Residual risk: if the RW bank is genuinely thin (<27 usable), Pass-2 generation still runs — would need bulk question generation to fully de-risk. Files: backend/app/services/exam_service.py, mobile/src/screens/ExamStartScreen.tsx.
NEW BUG found in on-device testing (build with #115): pressing "Exit" during an exam → confirm popup → stayed on the same page. Cause: there was no end/abandon endpoint; mobile api.endExam faked it by LOOPING advanceExam until non-ACTIVE, which builds all 3 remaining modules (81 questions) just to quit (very slow), and handleEndExam swallowed any error silently → stuck. FIX (uncommitted, deploys via ship.sh→deploy-backend.yml): new backend POST /api/exam/end + exam_service.abandon_exam() that calls _finalize_exam (scores from answers so far, sets session ENDED) WITHOUT building remaining modules → instant exit; mobile api.endExam now calls it once then getExamResult; handleEndExam now shows an Alert on failure instead of silently sticking. py compile + tsc clean. Files: backend/app/api/routes/exam.py, backend/app/services/exam_service.py, mobile/src/api/client.ts, mobile/src/screens/ExamSessionScreen.tsx. Sequencing: push (backend endpoint deploys) BEFORE building build 7, so the new mobile endExam isn't calling a 404.
Status 2026-10-06: Code fixes are done but not committed yet. Still pending on Saravanan: top up OpenAI credits and retest on iPad, push via ship.sh, EAS build 7, record a fresh screen recording, reply in Resolution Center, then resubmit the app, subscription and group. This replaces update #20 ("Waiting for Review").
Ship Android to Google Play — build config DONE; account/store/parity pending
high
Was deferred; now started. Same Expo codebase as iOS. DONE in code/config: eas.json Android build profiles (APK dev/preview, AAB production) + submit track:internal; app.json android block already complete (package com.hopewellpartners.adaptivesat, adaptive icon, App Links intent filters) — no change needed (appVersionSource:remote manages versionCode). Apple Sign-In correctly iOS-gated; Google sign-in works on Android. PENDING (owner): Google Play Developer account ($25); `eas build --platform android --profile preview` then production AAB; Android OAuth client (SHA-1 → add to GOOGLE_OAUTH_CLIENT_IDS); App Links assetlinks.json (SHA-256) on adaptivesat.ai; Play Console listing + IARC content rating (teen audience) + Data Safety + privacy URL; service account + eas submit. Follow-ons: Google Play Billing IAP (source='google' already supported), FCM push (deferred). Full steps: docs/ANDROID_PLAY_STORE_RUNBOOK.md.
docs/ANDROID_PLAY_STORE_RUNBOOK.mdmobile/eas.jsonmobile/app.json
added 06-22 03:03
· by saravanan@scrumclaw.ai
· claude-cowork
Status 2026-10-06: Build config is done. Still pending: Play developer account ($25), builds, Android OAuth client, assetlinks.json, store listing, IARC rating, Data Safety form, and eas submit.
Deploy nightly question-quality audit cron and confirm 7 consecutive clean runs (REQ-13.11)
high
BRD v3.0 REQ-13.11 is Pending Deploy. Runbook with ready-to-paste gcloud commands exists; needs the Cloud Scheduler job created and 7 days of error-free runs to close the acceptance.
docs/QUESTION_QUALITY_CRON_SETUP.mddocs/BRD_V3_TRACKER.md
added 06-13 11:14
· by saravanan@scrumclaw.ai
· claude-cowork
Verification attempted 2026-07-23 but BLOCKED: this Cowork sandbox has no gcloud/DB/console access, so the run history can't be read from here — run from an authed env. Check for 7 consecutive successful nightly runs (REQ-13.11):
gcloud logging read 'resource.type="cloud_scheduler_job" AND resource.labels.job_id="question-nightly-audit"' --project=prediction-383914 --freshness=10d --limit=30 --format='table(timestamp, jsonPayload.status, httpRequest.status)'
Job: question-nightly-audit (prediction-383914 / us-central1), runs 09:00 UTC daily, hits https://api.adaptivesat.ai/api/notifications/cron/nightly-question-audit. Need 7 consecutive HTTP 200 / no-error invocations; window starts at first successful run, not job creation. Runbook: docs/QUESTION_QUALITY_CRON_SETUP.md. If 7 clean → close this item.
Status 2026-10-06: The runbook is ready. Still needed: create the Cloud Scheduler job, then see 7 consecutive clean nightly runs.
BRD23-E: mobile screens — upload, review, weak topics, drill
Upload (camera / photo library / file) → review-and-correct (numeric fields only) → score summary + ranked weak topics → drill screen with the four-part feedback block. Upload becomes the mobile front door (REQ-23.9); the full-length exam stays available but stops being the required entry point.
Depends on BRD23-C and BRD23-D.
Note: mobile currently has NO upload path at all — REQ-19.1 excluded it because Expo's document picker isn't installed. Web has had PDF upload since Bundle 11.
mobile/src/navigation/RootNavigator.tsx
added 10-24 03:00
· by saravanan@scrumclaw.ai
· claude-cowork
Mobile exam: add passage highlighting (parity with web PassageHighlighter, REQ-9.2)
Web has frontend/src/app/components/PassageHighlighter.tsx (Bluebook-style select-to-highlight + per-highlight notes, char-offset ranges). Mobile ExamSessionScreen renders question_text as a plain <Text> (line ~503) with no highlight/annotate. Gap noticed by owner while testing the full exam on mobile. Non-trivial in RN: no DOM selection; needs a custom passage renderer (tappable/selectable spans → highlight ranges), persisted per-question highlights, optional notes, erase/clear. NOT an App Store blocker — sequence AFTER the build-7 resubmission clears review. Ref: mobile/src/screens/ExamSessionScreen.tsx, frontend/src/app/components/PassageHighlighter.tsx.
mobile/src/screens/ExamSessionScreen.tsxfrontend/src/app/components/PassageHighlighter.tsx
added 07-27 21:18
· by saravanan@scrumclaw.ai
· claude-cowork
IMPLEMENTED for build 7 (per owner decision to include in this build). Mobile RN approach = word-level tap-to-highlight (no DOM select in RN): new mobile/src/components/PassageHighlighter.tsx (tokenizes passage, tap a word to highlight, Highlight/Erase/Clear toolbar, yellow bg; ephemeral per question, keyed by question_id). Wired into ExamSessionScreen for RW questions only (math renders plain text). tsc clean. Notes/drag-select deferred (web has notes; mobile v1 is highlight+erase+clear). Pending: ship + on-device test. Not yet committed (in the same uncommitted batch as the backend bank-first exam fix).
Status 2026-10-06: Not a blocker. Sequenced after build 7 (#38).
Technical debt: test enforcement + quality gates + silent-failure/dead-code cleanup
Consolidated tech-debt item (full register: docs/TECH_DEBT.md). Verified against the repo after a whitebox gate report (run 61e7d93e, commit 11639ae) whose own scores were unreliable. Sev1 (test enforcement): backend 51 pytest files but conditional-skip → no-op in CI (seed DB + key/mock); frontend+mobile have 0 unit tests; tsc --noEmit + lint not required PR checks (TS6133 noise). Sev2 (silent failures): bare except:pass in exam_service.py:175/194 + note_service.py:278; insights_service.py:479 most_improved/needs_attention hard-coded None (parent digest degrades). Sev3 (gates): no pre-commit secret scanning (gitleaks), no npm audit/pip-audit in CI. Sev4 (cleanup): delete mobile/App.tsx.full duplicate; remove dead comingSoon/*_ENABLED branches. Sequence Sev1→4; each ships as a small PR. No feature impact.
docs/TECH_DEBT.mdbackend/app/services/exam_service.py:175backend/app/services/insights_service.py:479mobile/App.tsx.full
added 06-22 02:17
· by saravanan@scrumclaw.ai
· claude-cowork
Scope 2026-10-06:
- CI test enforcement: backend pytest skips are no-ops, and there are 0 frontend/mobile unit tests.
- Silent `except: pass` in exam_service and note_service.
- Hard-coded None in insights_service:479.
- No gitleaks or audit gates.
- Dead code.
Plan: ship as small PRs, Sev1 first through Sev4.
Run deferred QA walkthroughs once shipped: Rush (15.8), Vocab mastery (18.7), Planner scratch→dashboard (19.6), dashboard <500ms p50 (14.8), report→queue→DELETE (13.10)
These BRD v3.0 acceptance items are code-complete but marked Ready for QA / Pending QA — manual walkthroughs and the prod p50 latency measurement were deferred until ship.
docs/BRD_V3_TRACKER.md
added 06-13 11:14
· by saravanan@scrumclaw.ai
· claude-cowork
Retire /dashboard once Home has been live long enough to trust
low
UX review items 7+8 moved students from the widget Dashboard to the Home focus view. The old page is kept at /dashboard for one release and linked from Home, deliberately: its stat cards are the only place some numbers appear, and deleting them in the same change that moves everyone's landing page would make any regression hard to attribute.
Either fold the stats worth keeping into Progress, or delete the page and its dashboard/ components. A route nobody links to is debt; Home currently links it as "All stats" so it isn't orphaned in the meantime.
frontend/src/app/pages/Dashboard.tsxfrontend/src/app/pages/Home.tsxfrontend/src/app/routes.tsx
added 10-24 17:59
· by saravanan@scrumclaw.ai
· claude-cowork
[Phase TBD] Add iPad support for iOS app (deferred — not required for initial launch)
low
Per decision on 2026-06-13, iPad support is not required for the initial App Store submission (iPhone-only). Revisit in a future phase: iPad layout/adaptivity pass + iPad screenshots in App Store Connect. No target date.
docs/BRD5_PHASE_5A_5B_NOTES.md
added 06-13 11:19
· by saravanan@scrumclaw.ai
· claude-cowork
decision 1 open
Decide whether a parent can upload a score report for their student
UX review item 15 asks for a parent read-only Home "with Upload button". The read-only summary shipped; the button did not, because POST /api/study-plan/from-score-report is gated require_student. A parent cannot write today.
This is a permissions decision, not a UI one: the endpoint writes into user_skill_state, which drives weak-skill detection and question selection for the student. Options:
1. Leave it. Parent summary says "reports are uploaded from <name>'s account". Zero risk, but parents are often the ones holding the PDF, which is the whole reason the review asked.
2. Add a parent-scoped write endpoint gated on the accepted guardianship, same pattern as the existing read endpoints, and record the uploader on score_reports so the provenance is visible to the student.
3. Parent uploads but it lands as a pending report the student confirms — slowest, safest, and consistent with the review-and-correct principle in REQ-23.3.
My read: option 2 with uploader provenance. Option 3 adds a state machine for a problem nobody has reported yet.
docs/UX_REVIEW_2026_10_24.mdbackend/app/api/routes/planner.pybackend/app/api/routes/parent.pyfrontend/src/app/components/parent/ParentHomeSummary.tsx
added 10-24 17:59
· by saravanan@scrumclaw.ai
· claude-cowork
note 4 open
Process: update the tracker and the MD docs on every push, not at session end
Saravanan's instruction, 2026-10-24: post a tracker update as soon as something is pushed, and fold the markdown doc updates into the same change rather than leaving them behind.
This mirrors the existing repo rule in docs (every feature commit folds in status-doc updates) — it had been slipping. Three PRs (#128, #132, #133) went out before the BRD23 status table and the BRD_V3_TRACKER annotations caught up, which meant the docs understated what was actually built.
Concretely, for each push: (1) ship.sh, (2) tracker_post_update with the PR and git_sha, (3) BRD/tracker markdown reflecting the new state in the same PR where possible.
added 10-24 03:19
· by saravanan@scrumclaw.ai
· claude-cowork
ScrumClaw API: working item endpoints (no todos/blockers routes)
The suggested per-kind paths returned 404. Working endpoints:
- GET /api/projects/adaptive-sat/items — all statuses
- GET /api/items?project_id=adaptive-sat — open items only
There are no separate todos/blockers/commitments routes. Every entry is an item, and its `kind` field (todo/blocker/decision/note) says which type it is.
GET /api/projects/adaptive-sat/itemsGET /api/items?project_id=adaptive-sat
added 10-06 16:56
· by saravanan@scrumclaw.ai
· claude-cowork
Tracker env configured: TRACKER_PROJECT_ID=adaptive-sat
low
Appended TRACKER_PROJECT_ID=adaptive-sat to the env file. TRACKER_USER was already saravanan@scrumclaw.ai, so it was left alone. No other lines changed; file permissions are still 600.
added 10-06 16:56
· by saravanan@scrumclaw.ai
· claude-cowork
#20 Ask AI Tutor (REQ-20.1–20.7) deferred to v3.1 per decision D6
low
All 7 Ask AI Tutor requirements are intentionally Deferred (decision D6, 2026-05-17). v3.0 scope is 13 enhancements (#9–#22 minus #20), 108 in-scope REQs. Tracking as a note so it isn't mistaken for unplanned work.
docs/BRD_V3_TRACKER.md
added 06-13 11:14
· by saravanan@scrumclaw.ai
· claude-cowork
Add item
Recently completed
Frontend deploy failing: GitHub Actions service account lacks Firebase Hosting permission (403)
blocker
done 10-26 01:19
· by saravanan@scrumclaw.ai
Fix web app navigation issues (incl. Planner / score upload not reachable from top nav)
todo
done 10-26 01:19
· by saravanan@scrumclaw.ai
Implement real PDF score-report parser (REQ-19.7, currently stub + manual entry)
todo
done 10-26 01:19
· by saravanan@scrumclaw.ai
BRD23-B: vision extraction service for score reports (image + PDF)
todo
done 10-26 01:19
· by saravanan@scrumclaw.ai
BRD23-D: drill session — adaptive length + four-part feedback + gap tracking
todo
done 10-24 03:48
· by saravanan@scrumclaw.ai
Add a managed certificate for bare cointrends.ai (browsers show a cert error; http redirects there)
todo
done 10-22 14:48
· by saravanan@scrumclaw.ai
Create a dedicated least-privilege DB user for ml-training before scheduling Batch training
todo
done 10-20 02:16
· by saravanan@scrumclaw.ai
Configure + ship native iOS IAP (RevenueCat) — code done, account/config + sandbox test pending
todo
done 07-23 20:56
· by saravanan@scrumclaw.ai
iOS App Store resubmission: ASC metadata fix + EAS production rebuild + screen recording
todo
done 07-23 20:56
· by saravanan@scrumclaw.ai
Collect 50-question sample to confirm zero named-entity hallucinations (REQ-13.9)
todo
done 06-28 03:42
· by saravanan@scrumclaw.ai
Migrate AdaptiveSAT off shared GCP project prj-crypto538-prod-260529 into its own project
todo
done 06-27 05:30
· by saravanan@scrumclaw.ai
Finish Predicted Tests Pro upgrade-flow routing — replace "Pro coming soon" alert (REQ-17.3)
todo
done 06-20 01:23
· by saravanan@scrumclaw.ai
Seed 20 hand-authored d5 questions (10 Math + 10 R&W) into question_bank as APPROVED
todo
done 06-19 16:33
· by saravanan@scrumclaw.ai
Verify subscription flow in Stripe Test mode, then switch to Live mode
todo
done 06-16 00:32
· by saravanan@scrumclaw.ai
Create 3 GCP secrets + IAM grant for Stripe keys, then ship Bundle F (deploy wiring)
todo
done 06-15 19:10
· by saravanan@scrumclaw.ai
Stripe go-live setup: create product/price, enable Tax, activate Customer Portal, create webhook endpoint
todo
done 06-15 19:10
· by saravanan@scrumclaw.ai
Fix "math questions appearing in Reading & Writing" — exam header section-label desync
todo
done 06-13 13:28
· by saravanan@scrumclaw.ai
Decide iPad support for iOS submission (open) — blocks iPad screenshots in App Store Connect
decision
done 06-13 11:19
· by saravanan@scrumclaw.ai
Log
activeShipped #147 and #148: official College Board score-report parsing, and vision extraction for images on gemma4. Closed as done: #150 (BRD23-B vision), #21 (real PDF parser, REQ-19.7 — deferred since June), #136 (web nav), #147 (Firebase deploy blocker, fixed days ago).
Why the parser failed on a real PSAT: not a regex that needed loosening — we had modelled the wrong thing. CB reports contain NO per-skill correct/total counts. They give 8 content domains as performance score BANDS on the 160-760 scale plus a question-count range ("Information and Ideas / (26% of section, 12-14 questions) / Performance: 610-670"). The existing patterns hunted for "Skill 7/12", which does not appear anywhere on an official report, so every CB upload fell through to manual entry. The KD College Prep handler worked because that provider does print counts. Now parsed: 8 domains → 9 of our skills, total/RW/Math scores, and the test date. Two traps found: CB hyphenates "Problem-Solving" and our seed data doesn't (silently dropped that whole domain), and a top band over 4-6 questions rounds to 5/5 which reads as "you got everything right" when the report says no such thing — clamped, and the review screen now says CB figures are estimated from bands rather than counted.
Saravanan's out-of-order point was a live bug: get_score_report ordered by uploaded_at DESC and compute_score_trend took reports[0]/reports[-1] from upload order, so uploading an older report later made it the "latest" and produced a confident fictitious score drop. Now ordered by coalesce(test_date, uploaded_at). Only fixable because the parser can read the test date. Also: rw_score/math_score/total_score have existed since migration 030 but nothing ever wrote them — Home's report card rendered "—" for every score.
Vision (#148) is built around refusing rather than guessing, because extracted numbers land in user_skill_state and drive question selection: the prompt offers {"readable": false} as a correct answer, out-of-range values are dropped not clamped, RW+Math must equal Total or all three are discarded, dates outside 2023-today are rejected, under four readable domains sinks the extraction, temperature=0. Most of the 25 new tests assert it returns nothing. A photographed report and a PDF produce byte-identical rows — both run through cb_domains_to_entries, with a test pinning it.
gemma4 chosen: cheapest vision model in Ollama's cloud catalogue ($0.14/$0.40 per 1M) and it does text too, so one model string also switched on rationale generation (#82), which had been wired but off since the 24th. Judge stays on o4-mini — the whole point of per-role config was never moving the quality gate on cost.
202 backend tests pass (45 new); the single failure is the pre-existing test_question_validation one. NOT verified: no call has ever hit the real Ollama provider — every vision test mocks the client, so the first real call is the first image upload. Extraction accuracy is unmeasured (REQ-23.13 wants 90%); one sample report, no labelled set.
· saravanan@scrumclaw.ai
from the conversationsaravanan: i uploaded psat score pdf but our site could not parse it properly
claude: [found CB reports carry bands not counts] built the CB parser; your file now yields 8 domains + scores + test date
saravanan: you also need to see the scores are maintained in chronic order
claude: Real bug — ordering was by upload time. Now by test date.
saravanan: how to enable vision? / go ahead
claude: Built it on gemma4; one model also turns on rationales.
activeUX review P1+P2 complete in the working tree — STAGED, NOT YET DEPLOYED. Saravanan has to run ./scripts/ship.sh; I have no gh/git credentials in this environment. 16 of 16 review items now done or explicitly parked. New: Home focus view replacing the widget Dashboard (latest report → top weak skills → one-line week strip), with the no-report state turning the whole page into the upload prompt; /upload as a real front door with a mandatory review-and-correct step; nav cut from nine items to four (Home/Practice/Progress/Full Tests) with a new /full-tests hub; Mistakes/Saved/Vocab folded into Practice as tabs and Practice defaulting to weakest-first; "Needs work / Getting there / Solid" replacing bare percentages on web and mobile; practice wrap now shows the mastery move and a "Practice 10 more"; countdown down to days, window toggle hidden until 3+ days of data, Pro badges hidden from subscribers; parent dashboard gets a read-only "where X stands" summary at the top. Two defects found while implementing, both pre-existing: (1) the Planner upload flow auto-saved whenever the parser claimed success, so a mis-read row went silently into user_skill_state and from there into weak-skill detection and question selection — /upload now never writes without confirmation; (2) parse-score-report returned 400 "File must be a .pdf", making BRD #23's own premise (photograph your score report) a dead end — images now accepted and answered with success:false plus a usable message. Verification: web + mobile typecheck clean, 165 backend tests pass (1 pre-existing failure in test_question_validation unrelated to this work), 22 new backend tests, and a link audit confirming every internal to=/href= target resolves to a declared route. vite build unverified — rollup's native binary in node_modules is darwin-only and I run on Linux, so CI is the first real build. Three decisions waiting, all written up in docs/UX_REVIEW_2026_10_24.md: can a parent upload on a student's behalf (from-score-report is require_student, so the parent summary ships read-only); mobile bottom tabs left at five rather than collapsing Exam+Predicted, because that would reverse #77; and when /dashboard gets retired. Mobile parity for Home and upload is still #87.
· saravanan@scrumclaw.ai
from the conversationsaravanan: I am stepping out - need you to complete all the UX recommendations, let me know if you need any decisions from me
claude: Took items 7-12 and 14-16. Flagged three decisions rather than guessing: parent upload permissions, mobile tab count (would reverse #77), and when to retire /dashboard. Can't push from here — ship.sh is yours to run.
activeUX review P0 block shipped and verified live on adaptivesat.ai. Six fixes from the 24 Oct UX review: (1) /history 404 now redirects to /exam/history; (2) removed "this will replace your current score report" — migration 030 made reports a history table, copy now says every report is kept; (3) /practice?skill=<id> routes straight into the drill instead of dumping users on the section picker; (4) the "take a full exam to see weak skills" prompt is now gated on getScoreReportStatus() so it hides once a report exists; (5) "Upload score report" buttons added to Dashboard and Progress (upload was previously reachable only via Planner); (6) every skill row on Progress is now a link into /drill/:skillId with a hover "Practice →" affordance. Verified against the deployed bundle assets/index-DAHnVl2K.js — /drill/ x3, "Upload score report" x2, new copy x1, old contradictory copy x0, /exam/history x3. Backlog tracked in docs/UX_REVIEW_2026_10_24.md with all 16 review items and status. Next: P1 is the Home focus view + nav reduction to four items (items 7-11), and one open decision first — "Drill" vs "Practice" as the single verb (item 13), cheap to settle now at one route and two components.
· saravanan@scrumclaw.ai
from the conversationsaravanan: [uploaded AdaptiveSAT UX Review.pdf] consume this doc
claude: 16 items; 6 are P0 copy/routing fixes under a day each. Shipping those now.
saravanan: deployed - check now
claude: All six P0 markers confirmed in the live bundle, including the old contradictory copy at zero occurrences.
activeMicro-training drill (BRD #23 REQ-23.7/7b/7c) shipped and verified live — api.adaptivesat.ai now serves 119 paths including all four /api/drill endpoints (start, next, answer, end).
A drill is a PRACTICE session with session_type='drill' and a preselected blueprint over one weak skill, reusing the existing session/attempt plumbing rather than a parallel one. Each answer returns the four-part feedback block from the sample tutoring session: verdict + running score, key clue quoted from the underline span, per-distractor rationale (student's own wrong choice first), and a gap note.
Adaptive length as decided: stops at 3 correct in a row with a floor of 3 questions, caps at 10. Supersedes the fixed 12 from the sample — 10-15 min is the length already failing on mobile, and ending once a student has demonstrably got it is better evidence than making them grind the rest.
Gap tracking is DERIVED from the session's attempts, not stored: a subtype opens on a miss, closes on a later correct, reopens on regression. Deliberately not persisted — the attempts table already knows, and a second copy is how the mastery_score defect happened.
Two places it refuses to guess: _key_clue returns None when there's no underline span rather than inventing evidence, and a rationale-provider failure degrades to the single explanation rather than breaking the drill.
24 new tests, 127 passing. NOT YET USER-REACHABLE — API only, no UI on web or mobile. Also none of it has run against a real database or a real question; the tests are pure-logic with mocks, so first real call is the actual test.
· saravanan@scrumclaw.ai
from the conversationsaravanan: 1. Build the drill — BRD23-D. - Let us do this
claude: Built: four endpoints, adaptive length, four-part feedback, derived gap tracking. 24 tests.
saravanan: deployment is going on
claude: Verified live — 119 paths, all four drill endpoints serving.
activePRs #134-#136 shipped: documentation brought back in line with reality. The implementation status doc was materially wrong, not just stale — #8 Subscription said "Not started" when Stripe web billing has been live since 2026-06-16, and #5 iOS said "Active focus, EAS Build is the gating step" when it has actually been rejected twice and sitting unsubmitted for three months. Both corrected. Added BRD #23 to the status doc with shipped-vs-remaining. Backfilled the commit log, which had stopped at 2026-04-30 — 82 commits from May through October restored from git, now 133 total. BRD_V3_TRACKER REQ-19.5/19.7 annotated as partly superseded by migration 030. BRD23 doc now carries a per-REQ build status table.
Headline risk, now written down in the status doc: #5 is the only thing in this project that has not moved. Build 7 was produced 2026-09-08 and never submitted; it now predates four merged PRs (#124 nav, #126 exam exit, #132/#133 score history), so a fresh build is required regardless. The App Review notes on the version also still quote $0.99/$9.99, which will contradict the live price once the pricing change is configured — a rejection risk on its own.
d05ff09
· saravanan@scrumclaw.ai
from the conversationsaravanan: update tracker - and going forward pls update tracker once something pushed out. and also you are missing the md file updates
claude: Both fair. Docs caught up, and I'll fold the tracker update into every push from now on.
saravanan: [on backfilling the May-July commit gap] yes
claude: 82 commits inserted from git — a commit log's value is being complete.
activePR #133 shipped: score history is now visible end to end. GET /api/study-plan/score-history returns every uploaded report plus baseline-vs-latest per-skill deltas; parent mirror at GET /api/parent/students/{id}/score-history (REQ-23.10, read-only, guardianship-gated). ScoreHistory component on web Planner + Progress and mobile PlannerScreen + ProgressScreen. 10 new tests lock the semantics: trend is baseline→latest not latest-vs-previous (20%→90%→50% reads +30, not -40); a skill only in the newest report goes to new_since_baseline rather than being reported as a swing from zero; unmapped CB labels still trend by normalised raw label. Docs updated — BRD23 now carries a per-REQ build status table, BRD_V3_TRACKER REQ-19.5/19.7 annotated as partly superseded by migration 030. Earlier in the session: frontend deploys had been failing silently since 21 Oct (firebase-tools@latest added a Service Usage precheck, github-deployer lacked serviceusage.services.get) — granted the role, pinned the CLI, and both deploy workflows now open a GitHub issue on failure. Prajith's Planner nav tab is finally live.
9b98ed8
· saravanan@scrumclaw.ai
from the conversationsaravanan: are you going to track multiple score upload data?
claude: Storage half is live; list_score_reports has no route and there's no trend UI yet.
saravanan: do these first — Planner and Progress — you considering in mobile app also right?
claude: Built on all three surfaces.
saravanan: going forward pls update tracker once something pushed out. and also you are missing the md file updates
activeBRD #23 (score-report upload → baseline → micro-training) scoped and foundations shipped. Fixed #79: mastery_score normalised to 0-100 percent (migration 027, recomputed from attempts + CHECK constraint) — the weak-skill detector was comparing an integer column against 0.7, so it returned every untouched skill instead of genuinely weak ones; 157 of 176 rows were seeded zeros. Also now excludes never-attempted skills via last_seen_at. Leverage/Today's Plan verified working in prod. Added cached per-distractor rationales (migration 028) on a swappable LLM role so high-volume rationale work can run off OpenAI without moving the judge. Reconciled a collision: Prajith and I both built score_reports on 2026-10-21 to incompatible designs — his shipped first as one-row-per-user, migration 030 converts it in place to a history table (drops the unique constraint, moves entries JSONB into score_report_entries, drops the blob) since history is the point of #23. Pricing moving to $1.99/mo + $19.99/yr. Root-caused a 2-day silent frontend outage: firebase-tools@latest added a Service Usage precheck that 403'd because github-deployer lacked serviceusage.services.get — Prajith's Planner nav tab has been invisible in prod since 21 Oct. Pinned the CLI and added failure-reporting so a broken deploy opens a GitHub issue instead of going unnoticed (third silent deploy failure this quarter).
· saravanan@scrumclaw.ai
from the conversationsaravanan: AdaptiveSAT must be able to take a screenshot of the SAT scores and create baseline level for the student... kids are not taking full test and is a failure for us to ask them that way
claude: Agreed — a 98-question timed exam is a desktop behaviour. Documented as BRD #23: upload → baseline → weak topics → short training.
saravanan: Many rows per user, is_baseline on the first — I need this
claude: History it is. Prajith's 029 is already deployed, so 030 converts his table in place rather than replacing it.
blockedPlanner changes shipped via PR (nav tab, 'score report uploaded' view with replace option, upload redirects to Progress). Backend deploy is green: migration 029 (score_reports table) applied and GET /api/study-plan/score-report is live. Frontend deploy FAILED (run 39710509068): 403 permission denied on firebasehosting.googleapis.com for the GitHub Actions service account, so the new UI is not on adaptivesat.ai yet. Tracked as a blocker. NEXT: grant the GHA service account Firebase Hosting Admin (and Service Usage Consumer) on prediction-383914, then 'gh run rerun 39710509068 --failed', hard-refresh the site and test the Planner tab with the KD PDF. Note: accounts that uploaded a report before 029 have no stored report record and must re-upload once.
· prajith.k19022003@gmail.com
from the conversationprajith: [pasted diagnosis of the failed frontend deploy] update this in the tracker
claude: Logged a blocker with the fix steps and a status update; project marked blocked on the deploy permission.
activeScore report upload fixed for KD College Prep reports and verified working on the live site. Cause: the parser in planner_service.py only matched College Board-style 'x/y' rows, but KD reports list '<type> (<ABBR>) <correct> <missed>'. Added _extract_kd_rows: reads the abbreviation, rolls up into the 11 domain-level skills (totals match the report's own domain percentages), and falls back to the old patterns. Tested on a real KD PDF (9 rows found, 64/98 correct) and shipped via PR by owner. Limits: only KD and College Board-style layouts are recognized; the History/Social Studies and Science analysis skills get no score from KD reports; no unit test yet. NEXT: fix web navigation issues (owner to list them).
· prajith.k19022003@gmail.com
from the conversationsaravanan: [PDF upload] says it couldn't find enough skill-performance rows, let's fix this first.
claude: Report is KD College Prep format (no x/y rows). Added KD row parser mapped to domain skills; owner shipped it.
saravanan: it is done and working good, but the navigation has some issues.
activeStatus refresh: 10 open / 11 done, no blockers, no due dates. Supersedes update #20 (2026-07-23, "iOS Waiting for Review") — iOS was rejected a 2nd time on 2026-07-24, tracked in #38. Critical path: #38 iOS build 7 resubmit → #71 Bluebook nav → #39 mobile highlighting. In parallel: #36 Android/Play, #17 audit cron, #35 tech debt.
· saravanan@scrumclaw.ai
from the conversationsaravanan: push these items for adaptivesat — 10 open, 11 done, last status update #20 is superseded by #38's 2nd rejection.
claude: Posted a status refresh, logged env/API notes, and added the latest detail to the existing items as comments (no duplicate items).
activeDocs now PUSHED (updates prior status): owner ran ship.sh → PR #113 (d437cd8) merged to main — docs/BRD5_RESUBMISSION_2026_07_23.md + .gitignore asc_submission/. Working tree clean. Remaining from tonight: only #17 (REQ-13.11 cron 7 clean runs) — verify with the gcloud command in the comment on #17, close if clean. iOS submission still Waiting for Review (Apple email ~48h, auto-release on approval).
d437cd8
· saravanan@scrumclaw.ai
from the conversationsaravanan: item 1 done [ran ship.sh] — what about project tracker update from your side?
claude: Confirmed PR #113 (d437cd8) on main; posted this tracker update marking docs shipped, only #17 verification left.
activeiOS resubmission SHIPPED 2026-07-23: one App Review submission bundling app v1.0 build 6 + Premium Annual subscription + AdaptiveSAT Premium subscription group — status Waiting for Review (~48h, auto-release on approval). Rejection fixes: SIWA (4.8), age rating Parental Controls→None=4+ (2.3.6), account-delete + screen recording (5.1.1v). Closed tracker #22 (resubmission) and #34 (native IAP). Documented in docs/BRD5_RESUBMISSION_2026_07_23.md (+ .gitignore asc_submission/); NOT yet pushed — no git creds in sandbox, owner runs `rm -f .git/index.lock && ./scripts/ship.sh "..."`. #17 (REQ-13.11 cron 7 clean runs) could NOT be verified from sandbox (no gcloud) — see comment on #17.
· saravanan@scrumclaw.ai
from the conversationsaravanan: Do the resubmission now ... then close #22/#34 ... good night, update tracker on status.
claude: Submitted app+sub+group together (Waiting for Review); closed #22 & #34; #17 verification needs gcloud from your env.
activeSession wrap 2026-07-01 — iOS monetization + Apple auth + a production exam bug.
IOS IAP (BRD #8 follow-on) — fully wired end-to-end (config, not just code):
• App Store Connect: created subscription group "AdaptiveSAT Premium" + auto-renewable sub product `com.adaptivesat.premium.annual`, $9.99/yr across 175 countries, English localization, and a 7-day free-trial introductory offer (Jun 2026–Jun 2027). Paid Apps agreement confirmed Active. (Review screenshot still needed at submission time.)
• RevenueCat: project + App Store app (bundle com.hopewellpartners.adaptivesat, .p8 IAP key uploaded by owner), entitlement `premium`, product, default offering ($rc_annual → App Store product), webhook → https://api.adaptivesat.ai/api/billing/revenuecat/webhook (auth secret in GCP `adaptive-sat-revenuecat-webhook-auth`, wired into deploy-backend.yml; webhook verified 401→live).
• Repo: appl_ SDK key in eas.json (PR #100); ascAppId corrected 667811167→6766082796 (was the team id — would’ve broken eas submit). Kept the existing custom MobilePaywall (chose not to adopt RevenueCat prebuilt Paywalls/Customer Center). Decision recorded: the pasted “integrate SDK” prompt was RevenueCat’s generic one — SDK already integrated; ignored its test_ key + placeholder ids.
Sign in with Apple — was missing on the new backend after migration:
• iOS native fixed: APPLE_OAUTH_AUDIENCES=com.hopewellpartners.adaptivesat added to deploy-backend.yml env.
• Web SIWA enabled (owner wanted it — Mac/US users): created Apple Services ID com.hopewellpartners.adaptivesat.web (domain adaptivesat.ai + return URL /auth/apple/callback), frontend VITE_APPLE_SERVICE_ID set (PR #103), backend audience appended (…,…adaptivesat.web). No SIWA private key needed (client id_token flow verified against Apple JWKS).
Predicted Tests discoverability (real gap the owner caught): the Premium paper hub had NO UI entry point on web or mobile (URL-only). Fixed: web top-nav + mobile-web menu link (PR #105); iOS Dashboard card (PR #106, ships next build).
PROD BUG — “Failed to start exam” (browser 503 → actually 500): root cause = OpenAI account out of quota (429 insufficient_quota) during on-the-fly question generation in exam start. NOT migration-related. Fixes: PR #107 (exam-start survives generation failures → falls back to existing bank questions, clean 400 instead of 500), #108 (email the owner on quota exhaustion, throttled hourly; openai_alert_email default saravanan.hp@gmail.com / OPENAI_ALERT_EMAIL), #109 (missing `import time` that re-crashed it), #110 (quota cool-down so it fast-fails instead of hanging ~60s). VERIFIED: exam/start now returns 200 (session created) building entirely from the existing bank — OpenAI credits now OPTIONAL (only needed for fresh/no-repeat generation). Owner got the alert email.
Also earlier this session: retired old backend (deleted adaptive-sat-api in prj-crypto538); DB pw rotation deferred (shared role); tracker items #37 (migration) + #18 (REQ-13.9) closed; REQ-13.11 cron clock running (reminder set for Jul 4).
OPEN / NEXT: (1) Task “iOS sandbox purchase test” — owner needs a fresh EAS preview build (has appl_ key + Predicted Tests card) + a Free test account (early-member accounts bypass the paywall) + sandbox Apple ID. (2) ASC subscription review screenshot before submission. (3) Top up OpenAI whenever (optional). (4) Rotate the migration GitHub PAT. (5) Android Play Store, iOS resubmission still pending per prior items.
· saravanan@scrumclaw.ai
from the conversationsaravanan: [exam/start test] 200 9.5s — session created. I received an email as well.
claude: 200 = exam works, built entirely from the existing bank; OpenAI credits now optional. Root cause was OpenAI quota exhaustion, now graceful (resilience + email alert + cool-down). Wrapping.
saravanan: yes wrap
activeSession wrap 2026-06-27. Closed the accuracy phase. (1) REQ-13.11 nightly quality cron DEPLOYED in prediction-383914 → api.adaptivesat.ai (both Scheduler jobs live + verified 2xx; 7-day clock running, closes ~2026-07-04; reminder scheduled for July 4 to verify + flip to Done). (2) REQ-13.9 DONE (item #18 closed): nightly audit re-judged all 48 served questions through the fact_safe gate — {"sampled":48,"failed_judge":0,"queued":0} = zero named-entity hallucinations; owner accepted the served-only sample (306 live-but-unserved questions get audited as they accrue attempts). Docs corrected post-migration: cron runbook (PR #97), BRD_V3_TRACKER (PR #98), IAP runbook (PR #99). NEXT (owner-gated, paused by request): mobile monetization — #34 iOS IAP config (ASC sub + .p8 key, RevenueCat project/entitlement 'premium'/offering/webhook, then wire REVENUECAT_WEBHOOK_AUTH secret line + EXPO_PUBLIC_REVENUECAT_IOS_KEY in eas.json) → #22 iOS resubmission → #36 Android. All code shipped/dormant; remaining work is Apple/RevenueCat/Google account actions only the owner can do.
· saravanan@scrumclaw.ai
activeREQ-13.11 nightly question-quality cron DEPLOYED (2026-06-27). Both Cloud Scheduler jobs created in the NEW project prediction-383914 pointing at api.adaptivesat.ai: question-wrong-rate-flag (daily 10:00 UTC) and question-nightly-audit (nightly 09:00 UTC). Enabled cloudscheduler.googleapis.com in the new project; admin key confirmed present. Verified: wrong-rate manual run = 200; nightly-audit first scheduled run (09:00 UTC) returned 2xx (status {}). The 7-consecutive-clean-runs acceptance clock for REQ-13.11 starts now — closes ~2026-07-04 if no errors. Runbook corrected to the new project + stable domain (PR #97). Remaining on item #17: confirm 7 consecutive clean runs, then mark REQ-13.11 Done.
· saravanan@scrumclaw.ai
activeGCP project migration fully closed out. AdaptiveSAT now runs entirely on its own project prediction-383914: backend on Cloud Run behind stable api.adaptivesat.ai, frontend on the new Firebase site serving adaptivesat.ai, CI (deploy-backend/frontend) retargeted to the new project. DB kept in place in prj-crypto538 and reached cross-project (cloudsql.client grant + --add-cloudsql-instances). Stripe webhook repointed to api.adaptivesat.ai AND the pre-existing 500 bug fixed (PR #90: process raw JSON dict since stripe-python StripeObject dropped dict .get(); read current_period_end from items fallback) — subscription rows now write; test user confirmed status=active. Mobile config + eas.json on the stable domain (PR #95). Old Cloud Run service adaptive-sat-api deleted from prj-crypto538; api.adaptivesat.ai still 200 after. DB password rotation DEFERRED by decision (shared adaptive_app role). Only loose end: revoke the migration GitHub PAT. Checklist closed out in docs/MIGRATION_CUTOVER_CHECKLIST.md (PR #96).
· saravanan@scrumclaw.ai
from the conversationsaravanan: deleted and run - but got 200
claude: old backend gone; api.adaptivesat.ai 200 is the NEW backend answering — clean retirement.
saravanan: lets keep the password same - my other connections will fail
claude: agreed, adaptive_app is shared; skipping rotation. push updates to tracker.
activeNative iOS IAP (RevenueCat) build SHIPPED + dormant. Code merged to main via ship.sh; migration 025 applied in prod (Run-migrations workflow, success); webhook route live and returns 503 until configured (correct dormant state). Predicted Tests Pro routing finished (REQ-17.3 Done): web Paywall, iOS native RevenueCat paywall, Android web-fallback. Docs updated: BRD8_TRACKER (operational done + IAP follow-on), BRD8_SUBSCRIPTION_SPEC §17, BRD_V3_TRACKER (REQ-17.3 + changelog), IAP_SETUP_RUNBOOK.md. Remaining (owner): App Store Connect product + RevenueCat config + GCP secret + deploy-backend.yml line + EAS build + sandbox test (item #34).
· saravanan@scrumclaw.ai
idleSession wrap. Done this session: (1) math-in-reading bug fixed + shipped (PR #83) — exam-header section-label desync, not a data bug; (2) BRD #8 Subscriptions fully LIVE — Stripe setup, GCP secrets, Bundle F (PR #84), passing trial-signup smoke test; (3) seeded 20 hand-authored+self-judged d5 questions (10 Math/10 R&W) APPROVED via scripts/seed_d5_claude_questions.sql (tag source_model='claude-d5-v1'). Open follow-ups: in-app symbol-render spot-check of the d5 batch; optional save as JSON seeds. Top remaining items: #17 nightly quality cron, #22 iOS resubmission, #19 Predicted Tests Pro routing.
· saravanan@scrumclaw.ai
activeSession wrap: (1) Math-in-reading bug fixed + shipped (PR #83) — was an exam-header section-label desync, not a data bug. (2) BRD #8 Subscriptions fully LIVE — Stripe setup, GCP secrets, Bundle F deploy (PR #84), live trial-signup smoke test passed (7-day free trial before first charge). Items #14/#15/#16 closed. User chose to let the test subscription's first charge happen in ~7 days and sort it out then.
· saravanan@scrumclaw.ai
doneBRD #8 Subscriptions COMPLETE — live checkout smoke test passed end-to-end (signup → Stripe Checkout → payment → webhook). All three go-live items (#14 Stripe setup, #15 GCP secrets + Bundle F deploy, #16 verify/live) closed. Billing live in production.
· saravanan@scrumclaw.ai
activeBRD #8 billing LIVE. Stripe dashboard (Live mode) set up: product AdaptiveSAT Premium $9.99/yr, Tax on (origin Frisco TX), Customer Portal active, webhook with 6 events. 3 Stripe secrets in GCP Secret Manager + IAM. Bundle F (deploy-backend.yml secrets wiring) merged via PR #84, backend deployed. Webhook endpoint returns 400 (signature verify active) = endpoints off 503. Remaining: end-to-end live checkout smoke test (item #16).
· saravanan@scrumclaw.ai
idleProject initialized: Adaptive SAT
· saravanan@scrumclaw.ai