Skip to content

OGUR — MVP Scope Contract

Owner: founder. Only the owner amends this. Agents may not. MVP-1 — RELEASED 2026-08-13 as v1.1.0. · MVP-2 — the Explore backend; scope and date TBD (§1, §10 2026-08-19). Revised: 2026-08-19

Read this before acting. The active milestone is MVP-2. Until the redefinition session replaces §3, anything not listed in §3 is OUT of the active milestone by default — and §3 itself is under redefinition, so treat any new work as NEEDS-EVIDENCE unless it clearly serves the §1 MVP-2 direction.

The durable path from idea to release—including role gates, artifacts, and the handoff between milestones—is defined in product-development-workflow.md.


§1 The gates

MVP-1 gate — PASSED. Released 2026-08-13 as v1.1.0

Evidence: git tag v1.1.0, CHANGELOG.md §1.1.0, release-notes-v1.1.0.md, production path verified with named Genfit/Polygon test identities (commit 67819b76, OGUR-61/OGUR-76). The gate text below is kept verbatim as the record of what was promised.

Genfit and Polygon employees follow an authenticated link and read an auditable report aligned with what they were presented, except for explicitly documented corrections.

Two words carry the whole gate.

Authenticated — they log in as themselves. We know who read what.

Auditable — every claim on the page traces to a real source, and nothing on the page is fabricated. Not "complete," not "regenerated," not "proven generic." Auditable. A client can check any statement we make.

MVP-1 is the delivery surface. It serves the packs that exist today.

MVP-2 gate — UNDER REDEFINITION (was 2026-08-31)

Direction (2026-08-19, founder): MVP-2 is the Explore backend — align the discovery, evaluation and landscape-loop work run so far into one robust backend for discovery and exploration that generates new landscapes. The cleanest existing statement of the gap it closes is release-notes-v1.1.0.md known limitation 1: Explore's open-ended live search is not built; Ogur serves landscapes that were discovered offline and frozen into packs.

This is a direction, not a scope. The gate sentence, §3's IN list, the date and the §9 cut ladder are set in a dedicated redefinition session (§10 2026-08-19). Until then the pre-redefinition gate below and §3's content stand as candidate material — much of it (rebuild, gold-deck gates, Gates A/B/C) likely survives inside the Explore-backend milestone.

Pre-redefinition gate (2026-08-06, superseded pending redefinition):

The backend rebuilds those reports itself, and a re-run produces a semantically similar report.

Not byte-identical — upstream sources change and we don't control them. This is where generalisation, the literature layer, the gold-deck gates and the de-jargon track live. See §3.

What moved, and why

When the 2026-08-13 date was set, the previous §2 represented roughly 14–16 working days of work. It did not shrink — it split by kind:

MVP-1 (Aug 13) MVP-2 (Aug 31)
Question answered Can a client reach it and trust it? Can we rebuild it and prove it generic?
Data Frozen packs, as they are today Regenerated from the pipeline
Risk Deployment + provenance Backend correctness

Everything requiring a rebuild is MVP-2, because nothing that requires a rebuild can land in 7 days — GNS561 cannot even be rebuilt on main today (§8).


§2 MVP-1 — what was IN (released 2026-08-13)

Five items. Each one was required for a client to reach the report and trust it. All five shipped; the closure record below replaces the pre-release delivery forecast. §2.1–§2.5 are kept as the delivered contract — the record of what "auditable", "feedback" and "presented-version alignment" mean in production.

  1. Authenticated link for named Genfit / Polygon users
  2. One deployment, one URL, serving both packs — the real frontend, not a static export (§2.3)
  3. Auditable report — every client-reachable surface real, gated, or deleted per §5, and the four known-wrong claims handled per §4
  4. Feedback capture — whole-report granularity is acceptable at this date
  5. Presented-version alignment — the served Genfit and Polygon reports match what each client was shown, except for corrections whose reason and evidence are recorded (§2.4)

Closure record — released 2026-08-13

All six release gates passed. Per-gate evidence is in CHANGELOG.md §1.1.0 (organized by these gates) and the Linear project Road to MVP-1 — Aug 13 authenticated reports.

Gate Linear Closed by
Named-user authentication and report authorization OGUR-58 #241 (auth/session), #247/#255 (spend ceiling), #256 (login page)
One same-origin production deployment serving both packs OGUR-59 #240 (wheel boot), #245 (container + /data volume), #250 (Fly.io deploy + backup)
Every client-reachable surface auditable OGUR-62 #253 (VITE_DEMO_SURFACES route gate), #254 (evidence depth, OGUR-78), #257 (Gate C audit)
Durable attributable report feedback OGUR-60 #242/#249 (storage + API, reseed-stable), #251 (feedback box), #258 (Gate D audit)
Served reports aligned with client-presented artifacts OGUR-63 Gate E reconciliation (#227/#228 pack digests, #246 swimlane fix)
Production security and end-to-end smoke gate OGUR-61 OGUR-76 security review (#259 deleted unauthenticated generation routes), production verification 67819b76

§2.1 Auditable is a claim we are making to a client

Do not ship "auditable" while the page carries statements we know are wrong. Deleting the mock surfaces (§5) removes fabricated provenance. §4 is the other half: four claims that are sourced-looking and false.

Auditability also includes evidence depth. The current literature review is primarily title + abstract, and several patent paths link or synthesize from metadata/title/abstract even when the upstream query scans full-text fields. A client must not infer that Ogur read a paper body, patent description, or claims when it did not. Each source/claim path exposes one of: metadata-only · title+abstract · full document · unavailable/unknown. DeliveredOGUR-78, #254/#262 (builder-computed meta.evidence_depth, banner disclosure).

Handling them does not require a rebuild. See §4.

§2.2 Feedback

Client employees must be able to write feedback, not just read. Per-section is better; whole-report was accepted for the 2026-08-13 release and is what shipped (#242/#249 storage + API, #251 feedback box). Per-section granularity is roadmap input, not delivered.

Anchor feedback to content_hash / NCT id / PMID / publication number / section slug. Never to Signal.id.

A reseed renumbers autoincrement rows and silently re-points feedback at different claims. MVP-2 mandates rebuilds, so this trap fires the moment MVP-2 lands — after clients have written the feedback, against the only unregenerable data in the system.

Acceptance test: seed → attach feedback → reseed → assert every item still resolves to the same document.

§2.3 It has to feel like the product

MVP-1 is a static report in the sense that the data is frozen. It is not a static page. A client following the link should get a sense of what the product is, not a PDF behind a login.

Requirements:

  • Ship the real frontend. The same React app, shell, navigation, components, source chips and confidence badges that run locally. Not an HTML export, not a rendered snapshot. This is why §8's "mount the built frontend as StaticFiles(html=True), same origin" is the right deployment shape and not merely the cheap one — it deploys the actual application.
  • Same data local and deployed. The pack served on the web is byte-identical to the pack served locally. One source of truth, no divergence between what we demo and what a client sees. Assert it: compare the served pack's meta.source_digests against the local pack in a smoke check.

The consequence — reachability is now in scope

If a client can navigate, then everything reachable from the report is subject to §5, not just the report route itself. A Genfit employee poking around the shell can reach /franchise (hand-written LOE dates, phase mix, patent cliffs) and the Ask panel (scripted answers with a fake animated reasoning trace).

"It feels like the product" and "there are mock surfaces one click away" are not compatible. Every reachable surface must be either real, or unreachable.

That gave a cheap lever, and it is what shipped. Route-gating a client login to the surfaces that are real was far cheaper than making every surface real, and cheaper than deleting everything §5 lists. The release requirement was reachability, not deletion of every mock in the codebase; the §5 deletions remain the intended end state as post-release debt — now due (see the roadmap-inputs doc).

The per-surface real · gated · deleted decisions are recorded in mvp1-route-inventory-2026-08-12.md (#253, VITE_DEMO_SURFACES default-gated). §5 states the rule normatively and is the single place QA reads it from.

§2.4 Presented-version alignment

The report a client opens must not drift silently from the report discussed in the meeting. For each of Genfit and Polygon:

  1. Preserve the exact artifact that was presented.
  2. Diff it against the currently served pack.
  3. Classify every material difference as a manual presentation edit, stale source, matcher defect, unsupported synthesis, provenance defect, deliberate correction, or formatting-only change.
  4. Make the served report match, or record why the evidence-backed correction is intentionally different.
  5. Record the final pack digest and approval evidence in OGUR-63.

Done for both clients — pack digests and approval evidence recorded in OGUR-63 (#227/#228); CHANGELOG Gate E carries the summary.

This does not authorize copying manual edits blindly. Each edit is evidence about a pipeline defect. MVP-1 reconciles the frozen client surface; MVP-2 fixes the root cause unless a fix is required to prevent a false claim from being served.

§2.5 Full-text-enriched reports are stretch, not a release gate

Generating full-text-enriched Genfit and Polygon variants is valuable, but it was not required for the August 13 release and did not land before it. It is tracked as OGUR-79 and rolls into the MVP-2 redefinition as input — per the last paragraph below, the reproducible capability (not a one-off enriched pack) is the MVP-2-shaped deliverable.

The stretch output must remain a separate variant until human review compares it with the abstract-derived baseline. It must preserve retrieval provenance and evidence depth, cite the supporting passage rather than merely the document, and report what full text was unavailable because of access or licensing.

If it does not land before release, MVP-2 owns the reproducible capability: full-document retrieval → chunking → synthesis → claim-to-passage grounding → semantic/regression gates. A one-off enriched pack is not the MVP-2 deliverable.


§3 MVP-2 — what is IN (UNDER REDEFINITION; was due 2026-08-31)

2026-08-19 — this section is being redefined. MVP-2's new direction is the Explore backend (§1). Everything below is the pre-redefinition reproducibility scope, kept as candidate content: the rebuilds, the literature harvest, the recall baselines and Gates A/B/C are the strongest existing material for the redefined milestone and are expected to survive inside it, but nothing here is binding until the redefinition session rewrites this section and logs it in §10. Do not gate or estimate new work against this section until then.

§3.1 Rebuild both client reports, no hand edits

Neither can be rebuilt today. GNS561's blockers are in §8.

Reproducibility is not done when the pack matches. It is done when nothing in the codebase still pins a reality the pipeline cannot produce — every fixture, test payload, seed CSV and cached artifact either has a generator command or is deleted. That is Gate C (§3.5), and it gates §3.1.

§3.2 The GNS561 literature harvest

The literature layer is not an appendix — the served GNS561 pack carries 1,089 PMID references, Polygon's 1,358. A large share of every sourced claim traces to it.

GNS561 has no lit_harvest.py; its corpus came from a discovery result cache that expired at 7 days. A rebuild would fail or silently reuse the frozen artifact — the hand-edit failure mode §1 exists to prevent.

  • Port Polygon's lit_harvest.py to GNS561 (reverse of the original port direction). 12 fixed MeSH/OpenAlex queries, deterministic, no LLM, no DB, $0. Still openlit_harvest.py exists only under scripts/eval/polygon_discovery/
  • Land the three modules unmerged on f5559c00DONE. lit_curate.py, lit_synthesize.py and abstracts.py are on main under scripts/eval/gns561_discovery/ as of the 2026-08-10 merge (PR #227)

Hard constraint — no third copy of the citation gate. The citation gate, grounding score and overreach detector exist twice already, carried over unchanged and annotated as written in response to a real mis-bind. They enforce Gate B's "zero new unsourced claims," which §9 names never-cut. A never-cut safety property must not be guarded by three divergeable copies. One implementation; placement is a tech-lead call, and §8's wheel blocker bears on it.

By /landscape-loop-promote's five-point test this is PROMOTE: point 2 separates class-neutral mechanism from vocabulary, and it clears point 1(a) — two runs, two landscape classes.

§3.3 Reproduce siRNA + obesity at a known recall number

The Gate A baseline. See §3.5.

§3.4 Trial entity inspection — approved stretch, not a release gate

Amendment ratified 2026-08-06 under §6.1, on external user evidence — a client VP of data. It was ratified against an Aug 31 MVP-1. The date moved; the milestone it attaches to moved with it. The ratification stands, and so does the user evidence.

It is not part of the Aug 31 gate. The MVP-2 gate in §1 is the backend rebuilds those reports itself, and a re-run produces a semantically similar report. A 9.5-half-day inspection pane establishes none of that property, and §9 already pre-designates it as the second MVP-2 cut. A requirement that is both mandatory and pre-cut makes "MVP-2 done" unanswerable for QA.

So: the Aug 31 gate contains rebuild (§3.1), literature harvest (§3.2), recall baseline (§3.3), and the three quality gates (§3.5). This pane is an approved stretch item that starts once those are green, on the same terms as §2.5 — ratified scope, real user evidence, no gate authority. It is not re-litigated to build it; it simply cannot fail the milestone.

Scope: trials only. Click a trial → pane with phase, status, sponsor, why_stopped. Companies and targets are out: Polygon's scope-fit distribution is 1 core / 274 honorable-mention / 112 off-thesis, so company chips would mostly open panes on rows we ourselves flagged marginal — a client-facing quality problem that building the pane does not solve. Neither pack has a records.targets block.

Estimate: 9.5 half-days. Sequenced after PRs #209, #218, #220, #221.

Founder constraint — Monitor schema compatibility. The trial schema matches Monitor's, and the entity layer stays compatible with the Monitor workspace so an exploration can be transferred into monitoring mode. This removes an architectural problem rather than adding one: serving entities from the pack would otherwise stand up a second entity spine beside Target / DrugTarget / CompanyProfile / DrugProfile, and the next entity feature would have to guess which spine to read. Pack records project into Monitor's schema; TrialDetail becomes another arm of the existing InspectorObject union. ADR required before it ships.

The deliverable is the pane, not the chip. 24/24 GNS561 and 26/26 Polygon table NCTs already render as <SourceChip>; exactly one bare unlinked NCT exists across both packs. Chipping is finished.

Render in_cache: false distinctly from an empty why_stopped. 15 of 34 GNS561 trials never had a record. "We don't have it" and "the registry gave no reason" are different claims.

§3.5 The de-jargon track and its two gates

Replace hand-written keywords with derived vocabulary:

Layer Derive from
Targets / genes Open Targets, UniProt
Indications Mondo or EFO
Biological function Gene Ontology

No de-jargoning change ships unless it passes BOTH gates.

Gate A — recall against truth (siRNA, obesity). Hand-built gold decks exist. Run /coverage-eval; recall must not drop. The stronger gate, because it measures against reality rather than our own prior output. A change that quietly narrows the search shows up here as lost assets and lost deals.

Gate B — semantic similarity (GNS561, PLG-101). No gold deck, so the §3.1 rebuilt reports are the frozen baseline. Claims preserved, entities preserved, sources preserved, zero new unsourced claims.

Gate C — every deterministic input on the rebuild path is reproducible. Applies to §3.1.

Each fixture, test payload, seed CSV, cached JSON and frozen artifact that the GNS561 or PLG-101 rebuild actually reads either has a generator command that reproduces it, or it is deleted.

Bounded by traversal, not by file type. The gated set is the closed dependency set of the two §3.1 rebuilds: start from the two rebuild entry points, follow every file they read, and stop. A fixture nothing on that path reads is not a Gate C item. Enumerate that closed set explicitly and record the roster in the run manifest — the manifest is what makes the gate checkable and what makes its boundary auditable.

Everything else — fixtures under unrelated suites, demo payloads, workflow debris — is repository hygiene, and it is scheduled in the post-release harness reset (product-development-workflow.md, "Release transition and harness reset"), which is explicitly time-boxed. It is not a §3 release requirement.

Reproducing the MVP-1 packs is not finished when the pipeline emits a matching pack. It is finished when nothing the rebuild reads still pins a reality the pipeline cannot produce.

Why this is a gate and not a chore. A hand-made fixture makes the test suite certify the wrong thing. Tests go green against an artifact no pipeline run can regenerate, so the suite reports "reproducible" while measuring a snapshot that was typed in by hand. That is the same false-positive shape as §1's generic-landscape near-miss — self-consistent, and wrong. The larger the suite, the more convincing the wrong answer looks. Baseline is ~1,932 backend tests.

In scope — only where the §3.1 rebuild path reads them:

  • Test fixtures encoding a pack — e.g. frontend/src/test/fixtures/gns561-report-full.json — regenerated by command, not maintained by hand
  • Unit-test payloads that hardcode pipeline output for GNS561 or PLG-101
  • Seed CSVs and source_digests inputs consumed by either rebuild
  • Cached JSON with no generator on either rebuild path
  • Any frozen artifact on that path whose provenance is "someone made this once"

Out of Gate C: fixtures and payloads belonging to suites neither rebuild traverses. They are harness-reset work, not release work.

The check: enumerate the closed dependency set, then for every file in it name the command that produces it. A file whose answer is "we don't know" is deleted, and whatever depended on it is either regenerated or dropped. Record both the roster and the traversal that produced it in the run manifest.

Deleting a fixture is a valid outcome. A test resting on an artifact nobody can regenerate is not coverage — it is a claim about the past, asserted by a file.


Gate A catches narrowing; Gate B catches drift; Gate C catches unreproducible ground under both. A change passing only some is not cleared. A change that improves generality and loses recall is a failed change, not a tradeoff to negotiate.


§4 The four known-wrong claims

Documented in docs/development/polygon-genfit-alignment-plan.md. Four different root causes.

# Defect Root cause
1 SGC001 mis-staged "Phase Ib completed" — actual: Phase II, recruiting Stale fetch
2 ~4× phantom inflation in acute-cardiac candidate counts Matcher bug: substring vs token-prefix — root cause fixed, OGUR-52
3 "Genuinely failed clinically" with zero whyStopped records Unsourced synthesis
4 GDELT paragraph citing a source the runner doesn't import Phantom provenance

MVP-1 handling (shipped): suppress or annotate, not fix. Four distinct pipeline defects could not be fixed pre-release, and they were not served under an "auditable" banner: the claims were removed or visibly marked. That was not a hand edit in the sense §3.1 forbids — it removed content rather than manufacturing it.

Root-cause fixes are roadmap input (previously "MVP-2 (Aug 31)"). Defects

1, #3 and #4 still hold their suppress-or-annotate handling and each remains a

defect report against the pipeline; #2 and #4 fall out of a run manifest for free.

#2's root cause was fixed inside MVP-1 (OGUR-52), ahead of that split. It was pulled forward because the defect is not confined to the frozen text: the same matcher runs during report reconciliation and any rebuild, so suppressing the served number would have left the defect available to regenerate it. Anchors now match on word boundaries ((?<!\w)…(?!\w), not \b — a form ending in a non-word char like lp(a) breaks under a literal \b).

Measured on the 783-trial PLG-101 CT.gov corpus by scripts/eval/polygon_discovery/audit_acute_cardiac.py:

acute-cardiac candidates
before (substring) 527
after (word-boundary) 128
dropped as phantom 399 (4.12×)

Two anchors carried effectively all of it: STEMI bound 173 trials by substring and 16 by word — 157 phantom trials, whose most common host word was systemic (427 occurrences across the corpus; occurrences, not trials) — and AMI bound 416 by substring and 12 by word (404 phantom, inside cyclophosphamide, pharmacodynamics, familial). The remaining defects — #1, #3, #4 — still hold their MVP-1 suppress-or-annotate handling.


§5 Fabricated provenance — gate PASSED at release; deletions now due

CLAUDE.md principle 1: every claim carries a source chip. The surfaces below fabricated it.

How the gate was passed (2026-08-12/13): every surface in the table was gated, not deleted — the default client build ships with demo surfaces off (VITE_DEMO_SURFACES, #253, OGUR-70), and the per-surface real/gated/deleted decisions are recorded in mvp1-route-inventory-2026-08-12.md. The deletions below were declared post-release debt at the time; that debt is now due and goes to the roadmap-inputs doc.

The release rule, stated once. Every surface a logged-in client can reach must be real. A surface that is not real must be gated (unreachable from a client session) or deleted before any client login. Gated and deleted both pass; reachable-and-fabricated does not.

This is the same rule as §2.3's real · gated · deleted, and it is the only rule. Route-gating is the cheap lever and it passes the Aug 13 gate. Deleting the surfaces below is permanent debt removal and remains the intended end state, but it is post-release debt, not an Aug 13 requirement. QA checks reachability, and records the per-surface choice.

Wiring any of these to a real endpoint is not an option: conversational Ask is OUT per §6, so making the mock real would be building an out-of-scope feature.

Surface Where
MOCK_FALLBACK_ENABLED = true — scripted Ask answers with a fake animated reasoning trace frontend/src/mocks/chat-dupilumab.ts:245components/ask/AskPanel.tsx:163
CompetitiveTimeline always renders DUPIXENT_TIMELINE frontend
drugName !== 'dupilumab' hardcoded components/.../LandscapeTab.tsx:141
/franchise LOE dates, phase mix, patent cliffs are hand-written constants frontend/src/mocks/franchise-portfolio.ts
Inspector "Summarize with AI" → mockSummarize(), fake 700ms delay frontend

Corrected 2026-08-06. An earlier revision claimed Polygon's pack had no patents and no papers, withheld after the Lens key expired. Verified false — the pack digests patents_scan_cd8_depleting_PLG101.csv and scientific_papers_PLG101.csv and carries 753 PMID / 3,499 patent references, having been rebuilt at briefing v3_REVIEW. Acting on the stale line would have put a fabricated absence in front of a client, which fails this gate exactly as a fabricated presence does.

Still open (no longer gate-blocking — the gate passed; now roadmap input): Lens 401s since 2026-07 — confirm which backend produced the patent scan before a client sees it. Where a source genuinely returned nothing, state the absence in the UI; an empty result reads as "we looked and found nothing," a worse claim than an error.

Deadline pressure is not an argument in this section — the rule survives the release: any future client-reachable surface is real, gated, or deleted.


§6 What MVP-1 did NOT do

Historical record of the release exclusions. Note the "Live Explore search" row: its "Post-MVP-2" disposition is superseded by the 2026-08-19 redefinition — the Explore backend now is the MVP-2 direction (§1).

Not done before Aug 13 Why Where it went
Rebuild either client report Requires the pipeline to work; GNS561 can't rebuild on main at all §3.1
GNS561 literature harvest Doesn't exist; must be written §3.2
siRNA / obesity reproduction Gate A baseline, not a client-facing surface §3.3
Trial entity inspection 9.5 half-days, blocked behind 4 PRs §3.4
De-jargoning Needs the §3.1 baselines to exist first §3.5
Live Explore search No candidate retrieval exists Post-MVP-2 now the MVP-2 direction (§1, 2026-08-19)
Conversational Ask CLAUDE.md principle 4. The mock gets gated or deleted, never wired Out
Multi-tenant isolation Two client orgs reading their own report needs auth, not tenancy Out
Postgres / Alembic No driver, no migrations. Self-inflicted outage Out
Marketing site, perf work, new sources, new skills None serve §1 Out

Permanent exclusions (graph UI, COGS, KOL sentiment) live in docs/architecture.md §10.

§6.1 How to move something into a milestone

All four must hold. Scope is conserved.

  1. A named external user said something requiring it — quoted verbatim. "Would be cool" is a desirability statement; "I cannot do X without it" is a requirement. The difference decides condition 2.
  2. Required for that milestone's §1 gate, not merely consistent with it.
  3. A tech-lead estimate exists, naming real files, in half-days.
  4. Something is cut to pay for it, logged in §10.

Founder enthusiasm is not evidence. Competitor parity is not evidence. "It's only a few hours with Claude Code" is specifically not evidence.

An amendment that adds without subtracting is a deadline change — a legitimate founder decision, but it must be made explicitly.

§6.2 Verdict vocabulary

Verdict Meaning Consequence
IN-MVP-1 Serves the Aug 13 gate, listed in §2 Proceed to /spec
IN-MVP-2 Serves the Aug 31 gate, listed in §3 Spec after MVP-1 ships
OUT Serves neither Stop. One paragraph
NEEDS-EVIDENCE Might serve a gate, no user has asked Blocked. Name the question

Default is OUT.


§7 Blocking questions

  • Q1 — Which named people at Genfit and Polygon get logins? RESOLVED — provisional named client identities seeded and verified in production (scripts/seed/seed_users.py, OGUR-61 verification 67819b76).
  • Q2 — Auth mechanism? RESOLVED — scrypt password + opaque session cookie (OGUR-64, #241, spec specs/ogur-64-minimal-auth-session.md); per-identity daily LLM spend ceiling shipped (OGUR-65, #247/#255, DAILY_LLM_SPEND_CEILING_USD=5.00).
  • Q3 — §4: suppress or annotate? RESOLVED — handled per §4 at release; #2's root cause additionally fixed (OGUR-52).
  • Q4 — STILL OPEN — What recall number counts as "reproduced" for siRNA and obesity? Last measured: siRNA 16/32 assets · 10/12 deals; obesity 12/14 core · 11/11 companies. State the Gate A floor before de-jargoning starts, or it gets negotiated down the first time a change fails it. Goes to the MVP-2 redefinition session as an input.

§8 Known blockers

Every row here is a claim about the repository at a point in time, and the repository moves faster than this file. A resolved row that still reads as open is worse than a missing row: /next consumes this section as live blockers, so a stale entry can make a recommendation prioritise, or propose unblocking work for, something already merged. Verify a row against the current code or PR state before acting on it, and strike it here when it resolves — struck through, with the resolving PR and date, so the dependency stays legible without asserting it is still open.

Every row re-verified against the working tree on 2026-08-19 (post-release cleanup pass): four resolved rows struck; the standing rows confirmed still true (GNS561 lit_harvest.py absent from scripts/eval/gns561_discovery/, citation gate present in both discovery script trees and absent from the engine, _LANDSCAPE_CONFIG still immunology-001-only, no Polygon seeder under scripts/seed/).

Blocker Where
API cannot boot from a wheelRESOLVED 2026-08-19 audit: shipped by PR #240 (OGUR-66, packaged wheel boot). Kept as history spec: specs/ogur-66-packaged-api-wheel-boot.md
One deployment serves exactly one packRESOLVED 2026-08-05 by PR #208. Kept as history because §2.2 depended on it; it is not a live blocker ogur/api/report_pack.py now serves a roster, one cache entry per configured pack
No CORS / same-origin mountRESOLVED 2026-08-19 audit: shipped by PR #245 (OGUR-67 container; SPA catch-all after routers, same origin) ogur/api/app.py
No User / Tenant modelRESOLVED 2026-08-19 audit: shipped by PR #241 (OGUR-64; ogur/models/user.py)
Zero feedback code in frontend/srcRESOLVED 2026-08-19 audit: shipped by PRs #242/#249 (storage + API, OGUR-69) and #251 (feedback box, OGUR-71)
GNS561 cannot be rebuilt on main. Still blocking, but narrowed 2026-08-10: the figures-payload modules landed with PR #227, so what remains is no lit_harvest.py for GNS561 (only Polygon has one) and the ~160 MB untracked .eval_cache. Blocks §3.1 scripts/eval/gns561_discovery/ — present on main; lit_harvest.py is not
Citation gate exists twice, in scripts, nowhere in the engine. Engine's only literature touch is sources.py::_live_openalex — 11 lines, discovery not review ogur/engine/discovery_modality/sources.py
_LANDSCAPE_CONFIG hardcoded to immunology-001; all else 404s ogur/api/routes/evidence.py:48
Polygon has no seeder — its pack yields no Signal rows no equivalent to scripts/seed/seed_gns561_autophagy.py
Patent axis: Lens 401s since 2026-07. Pin to gpatents-db ($0/query)
ogur.db holds immunology-001 + cardiometabolic-rnai-001 + obesity-rnai-001 (verified 2026-08-19). Still 0 CompanyProfile rows; the pack is the only entity source

Deployment shape. Content SQLite + packs baked read-only into the image; persistent volume for feedback; WAL mode. Snapshot the volume daily — client feedback is the only unregenerable data in the system. Fly.io, EU region, ~$5–10/mo, kept warm. .env gitignored; inject via fly secrets; set WORKDIR explicitly because SettingsConfigDict(env_file=".env") resolves relative to cwd.


§9 Cut ladder

MVP-1 ladder — CLOSED UNUSED. The release shipped without taking either cut (feedback landed at whole-report granularity per §2.2's accepted floor, and both clients shipped). Kept as the record:

  1. Feedback granularity → single free-text box per report
  2. Polygon → Genfit only (one client at the gate, not two)

MVP-2 ladder — pending redefinition (§1, §3). The pre-redefinition ladder, kept as candidate content:

  1. Adjacent-landscape bonus runs
  2. Obesity reproduction → siRNA alone (one gold deck holding Gate A)
  3. PLG-101 rebuild → GNS561 only

Trial entity inspection (§3.4) is not on this ladder because it is not on the gate — it is an approved stretch item and drops out without a cut decision.

Never cut, at any date — these are durable invariants of the product, not release-specific constraints, and they survive the MVP-2 redefinition: fabricated provenance handled per §5 — real, gated, or deleted, never reachable · the four known-wrong claims handled (§4) · feedback anchored to content_hash · at least one gold deck holding Gate A · the per-identity spend cap · presented-versus-served alignment evidence for every client report (§2.4) · truthful evidence-depth disclosure (§2.1).

If a ladder is exhausted and it still will not land, the date moves — explicitly, as a founder decision, not by shipping something that fails §5.


§10 Decision log

Date Decision
2026-08-04 Harness established: 4 read-only gate agents, /spec, /triage
2026-08-04 QM (YC agent harness) rejected; keep its skills-promotion pattern as ADR prior art
2026-08-05 Codebase survey ratified — 6/6 spot-checks held
2026-08-06 Exit criterion corrected: named client employees, not network testers
2026-08-06 MVP-2 gate = semantic similarity on re-run, not byte-identity
2026-08-06 De-jargon track added; vocabulary derived from Open Targets / UniProt / GO, indications via Mondo / EFO
2026-08-06 siRNA + obesity promoted to MUST — the only landscapes with a gold deck
2026-08-06 Quality gate split: Gate A (recall vs truth) + Gate B (similarity vs baseline). Both must pass
2026-08-06 Feedback confirmed required, not read-only
2026-08-06 Amendment rule + verdict vocabulary restored as §6.1/§6.2
2026-08-06 GNS561 literature harvest ruled in — 1,089 PMID refs, corpus unregenerable
2026-08-06 No third copy of the citation gate. PROMOTE by /landscape-loop-promote point 2 — mechanism, not vocabulary
2026-08-06 §5 corrected — it falsely claimed Polygon had no patents or papers
2026-08-06 Trial entity inspection ratified on external user evidence; Monitor schema compatibility made a constraint; ADR required
2026-08-06 DATES CHANGED. MVP-1 → 2026-08-13, MVP-2 → 2026-08-31. MVP-1 redefined as the delivery surface: authenticated link + auditable report served from frozen packs. Everything requiring a rebuild moved to MVP-2, because nothing requiring a rebuild fits in 7 days
2026-08-06 §4 handling split by milestone. MVP-1 suppresses or annotates the four known-wrong claims; MVP-2 fixes the root causes. Suppression is not a hand edit — it removes content rather than manufacturing it
2026-08-06 §2.3 added — MVP-1 ships the real frontend, not a static export, and the deployed pack is byte-identical to the local one. Frozen data, not a frozen page
2026-08-06 Reachability pulled into scope. If a client can navigate, every reachable surface is subject to §5 — real, gated, or deleted. Route-gating is the cheap lever; §5's deletions still stand as debt removal
2026-08-07 Gate C added. Reproducing the MVP-1 packs gates on a fixture/payload/deterministic-input cleanup: each one has a generator command or is deleted. A hand-made fixture makes ~1,932 tests certify a snapshot no pipeline run can regenerate
2026-08-07 Never push to main without human or agent review. 15 commits had accumulated on local main after a parallel session switched the working directory; moved to chore/mvp-scope-contract, main reset to origin/main
2026-08-08 Presented-version alignment added to MVP-1 as Gate E. The served Genfit and Polygon reports must match what each client was shown, except for explicitly documented evidence-backed corrections. Linear: OGUR-63.
2026-08-08 Evidence-depth disclosure is gating; full-text enrichment is stretch. MVP-1 must say whether support is metadata, abstract, or full document (OGUR-78). Full-text report variants (OGUR-79) never block Aug 13 and become a reproducible MVP-2 capability if deferred.
2026-08-10 One reachability rule, stated in §5. Every client-reachable surface must be real; a non-real surface must be gated or deleted. Route-gating passes Aug 13; §5's deletions are post-release debt. §2.3 and §5 previously implied different release decisions for the same surface
2026-08-10 Gate C bounded to the §3.1 rebuild path. The gated set is the closed dependency set of the GNS561 and PLG-101 rebuilds, enumerated and recorded in the run manifest. Repository-wide fixture cleanup moves to the time-boxed post-release harness reset
2026-08-10 Trial entity inspection (§3.4) reclassified as approved stretch. The ratification and its user evidence stand, but it does not establish the MVP-2 rebuild property and was already the second pre-designated cut. Removed from the Aug 31 gate and from the cut ladder
2026-08-10 Role contracts moved to tracked .agents/roles/; .claude/agents/*.md are thin adapters. Claude Code and Codex now consume one file per role, matching the .agents/skills/ pattern in PR #235
2026-08-10 §8 single-pack row struck — resolved by PR #208, merged 2026-08-05. §8 rows are dated claims about the repo and nothing invalidates one when the work merges; /next consumes them as live blockers, so a stale row makes it recommend unblocking work that is already done. §8 now carries a verify-before-acting instruction and /next must check a row against current code or PR state before it changes a ranking. The other ten rows were re-verified and hold
2026-08-10 §3.2 and §8's GNS561 rows narrowed after merging main. PR #227 landed lit_curate.py, lit_synthesize.py and abstracts.py under scripts/eval/gns561_discovery/, so the "unmerged on f5559c00" bullet is done and the blocker's "modules live on feat/gns561-lit-review" clause is false. What still blocks §3.1: no GNS561 lit_harvest.py, and the untracked .eval_cache. Caught by applying §8's own verify-before-acting rule to the merge that created the staleness
2026-08-10 The active milestone is the earliest unreleased gate, not the earliest un-passed one. An overdue gate stays active until a founder release, a §9 cut, or a §6.1 amendment. Selecting on date would have let a missed MVP-1 stop being the gate at midnight on Aug 14 and start admitting MVP-2 work — scope expansion by clock rather than by decision
2026-08-11 Founder override of an OUT /spec verdict. "Landscape at a glance" swimlane figure (SwimlaneFigure.tsx) gained vertical scroll (was horizontal-only) — a readability fix on the served-pack main figure. product-manager returned OUT (§6.1 conditions 1 and 2 unmet: no named-user requirement, not required for the §1 gate). Founder overrode directly rather than amending §2; no §6.1 amendment, no cut logged — a one-line CSS/layout change, not new scope. Logged per §6.1's "override must be a deliberate act" rule
2026-08-12 §4 defect #2's root cause fixed inside MVP-1, not deferred to MVP-2 (OGUR-52). Anchor matching is word-boundaried; the acute-cardiac candidate count falls 527 → 128 (4.12×) on the 783-trial PLG-101 corpus. Pulled forward because the matcher runs during reconciliation and rebuild, so suppressing the served number would leave the defect able to regenerate it. #1, #3 and #4 keep their suppress-or-annotate handling. The result cache is namespaced v3v4: the payload SHAPE did not change, so only the namespace stops cached hits replaying substring linkage
2026-08-12 Two release-blocking security defects fixed inside MVP-1, not deferred (OGUR-76). Eleven briefing/evidence routes served landscape data with no authentication, and five of them ran the Synthesizer against Anthropic outside OGUR-65's spend ceiling. Both were invisible in production only because the prod content.db has no Briefing rows and ANTHROPIC_API_KEY is unset — states, not controls, and OGUR-77 is the step that sets the key. The five generation POSTs were DELETED rather than gated: on-demand generation is not an MVP-1 surface (§6) and the offline scripts remain. Login rate limiting (unthrottled password guessing) is the one finding consciously accepted rather than fixed — out of §2, and more deadline risk than it removes. Full review: docs/product/security-review-2026-08-12.md
2026-08-13 MVP-1 RELEASED as v1.1.0. All six release gates passed (OGUR-58/59/60/61/62/63); production path verified with named Genfit and Polygon test identities (67819b76). Evidence: git tag v1.1.0, CHANGELOG §1.1.0, release-notes-v1.1.0.md. Per the 2026-08-10 active-milestone rule, the active milestone advances to MVP-2. (Entry recorded 2026-08-19 — the release-day step-down in deployment.md "After the tag" was skipped at the time.)
2026-08-19 MVP-2 redefined in direction: the Explore backend. Align the discovery, evaluation and landscape-loop work into one robust backend for discovery/exploration that generates new landscapes. Scope, gate sentence and date are set in a dedicated founder redefinition session; until then §3's pre-redefinition content stands as candidate material and no new work is gated against it. The 2026-08-31 date is dropped from the header
2026-08-19 Deferred release transition executed by the documentation cleanup pass. Contract updated to released state (§1/§2 closure record, §5 passed-gate record, §7 Q1–Q3 struck, four §8 rows struck after re-verification, §9 MVP-1 ladder closed unused); README / CLAUDE.md / official docs realigned; stale run artifacts archived; roadmap inputs collected in roadmap-inputs-2026-08-19.md
2026-08-19 Record correction: the 2026-08-11 spec-log.md OUT verdict (swimlane vertical scroll) was founder-overridden the same day and shipped in #246 (already logged 2026-08-11 below); spec-log.md now records the override so the log does not read as a rejection that stood