Files
gupi-osint-board/docs/scene-7-todo.md

12 KiB
Raw Permalink Blame History

Scene 7: prove Barricelli was an inventor

Status: implemented and verified on scene-7-evidence-goal Demo: GUPI Demo 1 — The Barricelli Files

Outcome

Scene 7 teaches two linked ideas: a screenshot found during an OSINT search can become source evidence, and a finding is only as useful as the report that cites and explains that evidence.

The player opens a minimal OSINT board, reads “Demonstrate OSINT skill: prove Nils Aall Barricelli was an inventor,” finds the relevant Google Patents result, and pastes or uploads one screenshot. The board creates a document, extracts its text, and recognizes the source. The player connects that document to the authored Claim, completes the evidentiary statement, and files the generated Case Report.

paste screenshot -> document appears -> source is verified -> connect to Claim
                 -> submit thin report -> provenance feedback -> accepted -> Scene 8

Product decisions

  • One suitable Google Patents screenshot is sufficient evidence, but not by itself a complete investigation.
  • Clipboard paste and file upload use the same server path.
  • The image and OCR remain a real source document on the player's board.
  • A known-source fuzzy match is the fast, deterministic victory path.
  • A small semantic judge is a fallback for other credible sources and for distinguishing Nils from his father. It cannot overrule the trusted path.
  • Evidence about Barricelli's father may award an optional discovery but does not clear the assignment unless it also supports the claim about Nils.
  • The boarding-house fire belongs to the later age/rescue assignment, not Scene 7.
  • Scene 7 records scene7.nils_inventor_proved. Scene 8 owns the ceremony and awards barricelli_luggage.
  • Inconclusive evaluation never deletes or penalizes uploaded evidence.
  • Scene 7 begins with one normalized, pinned Claim exhibit: “Nils Aall Barricelli was an inventor.”
  • A new thread begins with “Proof that…”. This placeholder intentionally produces a report that must be improved.
  • An accepted source connected to the Claim can earn a qualified pass while the report is returned for missing date/source provenance.
  • The source link is encouraged but optional; date, source citation, investigator, and a completed evidentiary statement are required.
  • Story advancement requires an accepted report when the template marks its report as required.

Shared identifiers

Purpose Key
Goal barricelli.inventor-proof
Scene 7 completion scene7.nils_inventor_proved
Optional father discovery scene7.father_inventor_discovered
Scene 8 reward barricelli_luggage

All identifiers and content are template data. There must be no Barricelli conditional in React or server business logic.

Existing foundation

  • 025_level_document_flags.sql: clonable document gates and level flags.
  • 026_achievements.sql: playthrough achievements.
  • 027_evidence_text_matching.sql: asset OCR, board match rules/anchors, level-owned evaluations, and flag provenance.
  • 028_level_goals.sql: board-owned goals and normalized flag requirements.
  • 029_semantic_evidence_judging.sql: clonable semantic rules, level-owned evaluations, and semantic flag provenance.
  • 030_evidence_match_source_metadata.sql: author-only canonical source metadata.
  • 031_claim_case_reports.sql: Claim exhibits, stable exhibit citations, report configuration, immutable submissions, and normalized submission issues.
  • server/ocr.ts: plain-text extraction and Tesseract.
  • server/evidenceMatching.ts: OCR-tolerant fuzzy passage matching.
  • POST /api/levels/:id/documents: persistent upload plus OCR and matching.
  • The story runtime already tracks current_node_id and current_level_id.

Architecture contract

Recognition and completion are separate

Recognition answers what a document supports. A goal answers whether the level's authored requirements have been satisfied. level_goals and level_goal_flag_requirements clone with a template. Goal completion is derived from level flags; there is no second mutable completion boolean.

Play mode receives a goal's key, title, instructions, completion copy, status, and completion time. IDs, enabled state, required flags, target text, and judging prompts remain author-only.

Known-source fast path

The Scene 7 template owns an evidence_match_rule with distinctive text visible in the real Google Patents result: a combination of patent number/title, inventor name, and invention language. A name alone is too generic. When enough anchors match, the existing matcher awards scene7.nils_inventor_proved in the upload transaction and the goal becomes complete immediately.

Reference OCR, thresholds, source metadata, and copy live in the manifest/database, not TypeScript constants. The expected text is never returned to play mode.

Semantic fallback

A provider-neutral EvidenceJudge receives only allowlisted goal data and OCR text. It returns strictly validated structured data:

type EvidenceVerdict = {
  subject: 'target' | 'related' | 'ambiguous' | 'neither'
  supportsClaim: boolean
  evidenceExcerpt: string
  confidence: number
}

OCR is untrusted quoted material. The judge prompt explicitly ignores instructions inside it. Provider/model, timeout, input limit, and confidence threshold are environment configuration. Semantic configuration clones with the board; evaluation history belongs to the level/document/extraction and records evaluator version, provider/model, verdict, excerpt, confidence, timestamps, and sanitized failure state.

Verdict Mutation
Target + assertion supported at threshold authored success flag (scene7.nils_inventor_proved)
Related subject only + assertion supported authored related flag (scene7.father_inventor_discovered)
Ambiguous, unsupported, or below threshold none
Provider failure none; retryable

The known-source pass avoids an LLM call. After a deterministic miss, the client automatically calls an idempotent semantic endpoint. This keeps document upload durable even if an external provider times out, without requiring a demo job queue.

Story progression

Advancing from a level is server-authoritative. The server verifies the JWT user, active playthrough/current level, and enabled goal state. It promotes the Scene 7 completion fact idempotently and only then follows the level terminal. The browser cannot grant its own achievement.

The player must see the verification result before navigation. Success exposes a single Continue action to Scene 8. Scene 6 only wires into the Scene 7 level node; Scene 8 owns the luggage reward.

Work packages

S7-A — Goal model and cloning

  • Add normalized board goals and flag requirements in migration 028.
  • Clone goals during freeze, instantiation, and reset.
  • Derive pending/complete state from level flags.
  • Hide goal requirements from play payloads.
  • Return newly completed goals from document upload.
  • Add admin CRUD repository/API contracts.
  • Test migration, cloning, deterministic completion, and isolation.
  • Clear level flags/reveal state when resetting from a template.

S7-B — Barricelli content and trusted recognition

  • Add goals and evidence-match rules to the normal mystery manifest importer.
  • Create the Scene 7 template with its assignment and no solution-bearing starting document.
  • Add a reproducible screenshot-paste acceptance path that runs through local OCR.
  • Author three distinctive patent anchors.
  • Tune against the target and unrelated/father-only negative fixtures.
  • Award scene7.nils_inventor_proved and require it for the level goal.
  • Store canonical source metadata for administrators; keep player URL optional.

S7-C — Semantic judge

  • Add provider-neutral interface and strict verdict validation.
  • Add clonable semantic rule configuration and level-owned evaluations.
  • Add semantic evaluation provenance to level flags.
  • Add provider/model/timeout/input/confidence environment configuration.
  • Send OCR text rather than raw image bytes.
  • Add ownership-checked, idempotent judge endpoint.
  • Route target and father verdicts to their authored flags.
  • Make disabled provider, timeout, quota, and malformed output safe/retryable.
  • Do not log evidence text or secrets.

S7-D — Story bridge

  • Require completed enabled goals before a playthrough can leave a level.
  • Verify the current playthrough belongs to the JWT user and owns the level.
  • Promote required completion facts exactly once.
  • Return a useful pending-goal error rather than advancing early.
  • Return to the generic story runtime after success; the Scene 6/8 graph owner wires the actual neighboring nodes.
  • Keep the arbitrary achievement-grant route development-only.

S7-E — Board experience

  • Present the active goal prominently on Scene 7.
  • Preserve clipboard paste, drag/drop, and file picker equivalence.
  • Show source import/OCR and semantic checking stages.
  • Highlight the accepted document and show SOURCE VERIFIED — NILS AALL BARRICELLI: INVENTOR.
  • Show Continue only after server-confirmed completion.
  • Acknowledge father-only discovery while asking for evidence about Nils.
  • Keep inconclusive evidence and offer neutral guidance.
  • Respect reduced-motion and mobile layouts.

S7-F — Verification

  • Add a legally safe derived OCR fixture.
  • Test line breaks, punctuation, cropping, name hyphenation, unrelated patent, father-only text, empty OCR, and prompt-injection-like text.
  • Contract-test with a fake semantic provider; CI never calls a paid model.
  • Integration-test target upload -> document -> flag -> completed goal.
  • Test duplicate evaluation, provider failure/retry, two-user isolation, and story progression before/after completion.
  • Browser-test clipboard image paste through OCR and verification. Continue is covered by the generic story-gate integration until the Scene 8 node lands.
  • Run migrations on an empty database and one currently at 027.
  • Run unit, integration, build, and Docker smoke tests.

API shape

type LevelGoal = {
  key: string
  title: string
  instructions: string
  completionMessage: string
  status: 'pending' | 'complete'
  completedAt?: string
  newlyCompleted: boolean
}

type DocumentAnalysis = {
  extractionStatus: 'succeeded' | 'unsupported' | 'failed'
  matchedFlags: string[]
  awardedFlags: string[]
  goals: LevelGoal[]
}

newlyCompleted is response-local: a reload returns complete with newlyCompleted: false.

Security and cost limits

  • Require identity and level ownership on player mutations.
  • Limit upload bytes, OCR/model characters, output tokens, duration, and retries.
  • Never expose reference anchors or judge instructions to play mode.
  • Treat filenames, MIME declarations, OCR, and model output as untrusted.
  • Validate model output and confidence before mutating flags.
  • Persist enough provenance to explain completion without storing unnecessary raw provider payloads.

Out of scope

  • Scenes 16, Scene 8's ceremony/3D model, and Scene 9's fire mystery.
  • Knowledge graph, general-purpose claim ontology, or multi-document synthesis.
  • Web crawling, URL fetching, or requiring a URL for victory.
  • Custom model training or the general story graph llm_gate.
  • Deleting irrelevant evidence.

Merge guidance

Prefer new modules and narrow glue commits. High-conflict files are server/index.ts, server/narrativeRepository.ts, src/App.tsx, src/main.tsx, and src/play.tsx; one integrator should own their final changes.

Suggested order: S7-A schema -> S7-B deterministic content -> S7-C judge -> S7-D story bridge -> S7-E UI -> S7-F hardening. Reserve migration numbers before parallel schema work and never renumber an already-shared migration silently.

Definition of done

From a fresh playthrough, the player reaches Scene 7 and sees one authored Claim. They paste one accepted Google Patents screenshot, connect Exhibit 1 to the Claim, and see “Proof that…” appear in the typewriter report. The first thin submission passes the evidence but is returned for provenance; adding the date, source citation, and a proper evidentiary statement produces an accepted report and enables Continue. MinIO asset, OCR, match provenance, stable exhibit number, connection, report submissions, and scene7.nils_inventor_proved persist. A URL improves the report but remains optional, and barricelli_luggage is not awarded until Scene 8.