fix(catalogue): gate courses on published snapshots - #4
Open
phibkro wants to merge 14 commits into
Open
Conversation
Committed F3 spec failed `oxfmt --check`, turning the PR tip red on falsifier #5 (`bun run validate` green). Pure whitespace normalization (double-space after periods → single); no contract/DoD change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The suite proved falsifiers #1/#3 (query gate serves zero fixture rows even with seeds present) but never exercised migration 0006 — a destructive DELETE shipped with zero coverage. Add assertions that apply 0006 against the already-ingested DB: fixture course_versions go from >0 to 0, and a re-fetched GET /v1/courses deep-equals the pre-cleanup response (removing the seeds changes NOTHING served, and the migration touches no published course version). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Base of the stacked R3a branch (off F3 tip e64e427). Verbatim design-spec: one live run ingests all ten NTNU_PROGRAMMES (real NTNU + DBH 347/208, fail loud), reconciles + atomically publishes each; GET /v1/programmes then shows programmeCount=10 / compareEnabled=true, each live-DBH-provenanced, catalogue stays fixture-free, Compare unlocks at exactly 10 (9 locked). Per-programme publish-vs-reject report is required F2 evidence. Quality gate UNCHANGED. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The R3a live breadth run surfaced that replicateNtnuCatalogue expected a
top-level JSON array, but the real all-studies endpoint returns
`{ q, numFound, docs: [...] }`. processNtnu fetches the catalogue
unconditionally (full mode does not even use it), so the shape mismatch threw
before any programme was reconciled. Read `.docs`, keep a bare-array fallback,
still fail loud on any other shape. No test covered this path.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Finding A from the R3a live run: migration 0006 (F3 fixture cleanup) deletes the `no.ntnu` institution as collateral on a fresh DB — once the fixture courses are gone nothing pins it, and the guard drops it. But `institutions` carries NO source_provider (it is real reference data, not fixture provenance), and the live reconcile path inserts courses/programmes under a NOT NULL FK to it while never provisioning the institution itself. At the real deploy migration order (0001..0007 before any run) every programme reconcile FK-failed. 0007 re-asserts NTNU as permanent reference data (idempotent INSERT OR IGNORE), leaving reconcile and the atomic publication protocol UNCHANGED. The added test applies the full 0001..0007 set then reconciles — the exact deploy order — and fails if 0007 is dropped or 0006 ever deletes the institution again (verified: red without 0007, green with it). This also closes the gap in F3's falsifier #2, whose test happened to run 0006 after a reconcile (courses then pinned no.ntnu). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The suite proved the 10-programmes-unlocked side of the operator-locked "exactly ten" Compare gate but never the lock side. Add the 9-programme boundary: meta.compareEnabled === false and compareProgrammes fails CompareUnavailableError(available 9, required 10). Guards against a regression to `> 10` or `>= 9` that the unlock-only test would miss. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pure formatting (double-space→single after periods; markdown emphasis *x*→_x_; test whitespace). No contract or logic change. Keeps `bun run validate` green at the PR tip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fold the conditional expect into a single toMatchObject on the whole Either (oxlint vitest/no-conditional-expect). Same assertion, lint-clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The real R3b deploy (first ever run) rejected the sync queue: Cloudflare Queues require message_retention_period between 60 and 86400 seconds, but alchemy.run.ts requested 345600 (4 days). tsc/local-compile never caught it because no deploy had run. Cap at 86400 (24h), the max. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
R3a: breadth-to-ten live journey unlocks Compare@10
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
F3: fixture-free, publication-gated course catalogue
The D1 course repository no longer has an unprovenanced
NOT EXISTSpassthrough./v1/coursesnow returns only course versions in the current published dataset snapshot. Migration0006removes the illustrative 0001 fixture course/version seeds (and orphaned institution rows), while published programme snapshots remain visible.Experience / verification
curl https://<api-host>/v1/coursessource.provider = "fixture"rows.0006) and repeat the request; the published catalogue is unchanged.dataset_revision_course_versionto the currentdataset_publication; there is no un-snapshotted passthrough.Checks:
bun run validate(format, lint, TS7+TS6, tests) green.Real: the end-to-end path is D1-backed and publication-gated; no advisor gate or Cloudflare deployment was run.
Update (follow-up commits):
4704cb8— normalize the committed F3 spec whitespace sooxfmt --check(hencebun run validate) is green at the PR tip (falsifier R3a: breadth-to-ten live journey unlocks Compare@10 #5).e64e427— mechanize falsifier Add study planning kernel and roadmap projections #2: a test applies migration0006against the already-ingested D1, asserts fixturecourse_versionsdrop from >0 to 0, and that a re-fetchedGET /v1/coursesdeep-equals the pre-cleanup response. Closes the coverage gap where the destructive DELETE migration shipped untested.All five falsifiers now observed green on committed content;
bun run validate= 36/36 tests, TS7+TS6 clean.