Merge branch 'main' of ssh://ramanujan.glitch.university:2222/glitch-university/gupi-osint-board
This commit is contained in:
+13
-14
@@ -65,27 +65,27 @@ The narrative layer — campaigns, NPC cutscenes, the admin authoring panel, and
|
||||
|
||||
## Milestone 5: claim-driven case report
|
||||
|
||||
The purpose of this milestone is the gameplay loop, not a knowledge graph: the player connects two exhibits, explains that one specific thread with a luggage-tag Claim, and later discovers that their accumulated explanations have become a nearly complete case report.
|
||||
The purpose of this milestone is the gameplay loop, not a knowledge graph: a Claim is a pinned proposition, source exhibits connect to it with red thread, and each thread's luggage-tag text explains how that source supports the Claim. Those explanations become the evidence section of the Case Report.
|
||||
|
||||
### 5.1 Lock the gameplay and temporal rules
|
||||
- [ ] Define a Claim as an entity owned by exactly one investigative thread; a thread has zero or one Claim. (The text associated with a claim can prove multiple points, handed by the text.
|
||||
- [ ] Keep untagged threads as ordinary connections that do not appear in the report.
|
||||
- [ ] Use the same Claim text on the luggage tag and in the report. Editing either presentation updates the same database value.
|
||||
- [x] Define a Claim as an independent pinned Exhibit which can receive one or more supporting document threads.
|
||||
- [x] Treat a claim-to-document thread label as an evidentiary statement; new threads begin with `Proof that…`.
|
||||
- [x] Use the same persisted connection statement on the luggage tag and in the report.
|
||||
- [ ] Derive the Claim date from the earliest non-null temporal date of its two endpoint exhibits; never use `created_at` or the current time.
|
||||
- [ ] Use Event `occurred_at` and a Document's primary timeline date as direct endpoint dates. For a Folder, use the earliest dated contained Document. Leave a Claim undated when neither endpoint supplies a date.
|
||||
- [ ] Place undated Claims after dated Claims in the initial report order while keeping them fully editable and reorderable.
|
||||
- [ ] Treat the derived date as the initial chronological suggestion only. Manual report ordering must not rewrite exhibit or Claim dates.
|
||||
### 5.2 Add normalized persistence
|
||||
|
||||
- [ ] Add a `claims` table with a unique foreign key to `exhibit_connections`, text, tag style, position percentage, lateral offset, and timestamps.
|
||||
- [ ] Move luggage-tag-specific text and placement fields out of `exhibit_connections`; retain curve tightness and endpoints on the connection.
|
||||
- [ ] Add one level-owned `case_report` and normalized `case_report_claims` rows with explicit `sort_order`.
|
||||
- [ ] Assign stable, level-local display numbers to cite exhibits as `Exhibit 3` independently of board position, z-index, or report order.
|
||||
- [x] Add normalized `claim_exhibits` as an Exhibit subtype; Claims are not encoded as connection labels.
|
||||
- [ ] Move luggage-tag presentation fields out of `exhibit_connections`; retain evidentiary statement, curve tightness, and endpoints on the connection.
|
||||
- [x] Add one board-owned `case_report` plus immutable level-owned submissions and normalized submission issues.
|
||||
- [x] Assign stable, board-local display numbers to cite exhibits as `Exhibit 3` independently of board position, z-index, or report order.
|
||||
- [ ] Enforce same-board ownership for the Claim's connection, both endpoint exhibits, report, and report membership.
|
||||
- [ ] Delete a Claim and its report membership transactionally when its luggage tag is removed, while retaining the now-untagged thread.
|
||||
- [ ] Delete both the Claim and connection when the thread itself is removed.
|
||||
- [ ] Clone board-owned Claims with fresh IDs during template creation and instantiation; rebuild level report membership against the cloned Claim IDs.
|
||||
- [ ] Make reset discard player-created Claims and restore exactly the Claims present in the source template version.
|
||||
- [x] Clone board-owned Claims with fresh IDs during template creation and instantiation.
|
||||
- [x] Make reset discard player-created Claims/report submissions and restore exactly the source template report configuration.
|
||||
- [ ] Keep uploaded binary evidence in MinIO. Reports and Claims reference Document exhibits and asset metadata; they never duplicate or embed asset bytes.
|
||||
|
||||
### 5.3 Expose a focused API contract
|
||||
@@ -109,16 +109,16 @@ The purpose of this milestone is the gameplay loop, not a knowledge graph: the p
|
||||
### 5.5 Build the typewriter case report
|
||||
The end goal is that a case report is prepopulated by the claims the player made during the investigation so that a skeleon of the case solution is present. The player must simply edit the case report and submit it.
|
||||
|
||||
- [ ] Add **Case Report** as a primary menu item and implement it as a persistent board view, separate from exhibits and the timeline.
|
||||
- [x] Add **Case Report** as a primary menu item and implement its first persistent report surface, separate from exhibits and the timeline.
|
||||
- [ ] Provide an empty state that explains that explaining red threads will create the report, without revealing a solution or forcing a tutorial.
|
||||
- [ ] Initially arrange Claim rows chronologically by derived date, using the order parameters on the claim as tie-breaker and undated Claims last, below a horizontal rule that says (missing date)
|
||||
- [ ] Render each row as a typewritten Claim with its date and endpoint citations, for example: `14.10.1987 — Maria Voss redirected the shipment. Exhibits 4 and 7.`
|
||||
- [x] Render the Scene 7 Claim with typewritten, stable Exhibit citations and editable date/source provenance.
|
||||
- [ ] It needs to be possible to add free text before and after the claims. Coloured inline text (use span elements) have a specific class and id can be edited
|
||||
- [ ] -Make Claim text editable inline. Persist through the Claim API so the luggage tag updates immediately.
|
||||
- [ ] Support pointer and keyboard reordering of Claim rows and persist the resulting explicit report order into order column of the claim.
|
||||
- [ ] Clicking a Claim must minimize the report as appropriate, center its thread, and briefly illuminate the curve and luggage tag.
|
||||
- [ ] Clicking an exhibit citation must locate and highlight that exhibit using the existing tray/board locator treatment.
|
||||
- [ ] Ensure the report is legible and operable on portrait mobile layouts as well as desktop.
|
||||
- [x] Ensure the first Case Report surface is legible and operable on portrait mobile layouts as well as desktop.
|
||||
- [ ] Add restrained typewriter, paper, and ink feedback while respecting reduced-motion preferences.
|
||||
|
||||
### 5.6 Test the reasoning loop
|
||||
@@ -140,4 +140,3 @@ The end goal is that a case report is prepopulated by the claims the player made
|
||||
### Milestone 5 definition of done
|
||||
A player can connect exhibits, explain each connection with a luggage-tag Claim, discover those exact words in a chronological typewriter report, improve and reorder the Claims, follow every citation back to the board, reload without loss, and reset safely to the template. No LLM is required for this experience to work.
|
||||
|
||||
|
||||
|
||||
@@ -128,7 +128,8 @@ CREATE TABLE osint.document_exhibits (
|
||||
title TEXT NOT NULL,
|
||||
published_at TIMESTAMPTZ,
|
||||
captured_at TIMESTAMPTZ,
|
||||
source_uri TEXT
|
||||
source_uri TEXT,
|
||||
citation_text TEXT NOT NULL DEFAULT ''
|
||||
);
|
||||
|
||||
CREATE TABLE osint.image_documents (
|
||||
@@ -154,6 +155,24 @@ CREATE TABLE osint.event_exhibits (
|
||||
|
||||
The service validates that every base exhibit has exactly one subtype row matching `exhibit_type_id`.
|
||||
|
||||
### Claim and report semantics
|
||||
|
||||
A Claim is a pinned proposition the investigator is asked to establish, such as
|
||||
**“Nils Aall Barricelli was an inventor.”** It is an Exhibit subtype rather than
|
||||
text hidden in a widget or a connection. One Claim can therefore receive multiple
|
||||
supporting red threads without becoming a knowledge-graph hub.
|
||||
|
||||
For a Claim-to-Document connection, the connection label is the evidentiary
|
||||
statement—initially `Proof that…`—and the Document supplies the source date,
|
||||
human-readable `citation_text`, and optional `source_uri`. Stable board-local
|
||||
numbers live in `exhibit_citations`; they do not depend on z-order or position.
|
||||
|
||||
`case_reports` holds clonable board configuration. Mutable, server-evaluated
|
||||
filings live in `case_report_submissions`, with individual deficiencies in
|
||||
`case_report_submission_issues`. A report can therefore record the useful state
|
||||
“evidence accepted, report incomplete” without weakening the evidence match or
|
||||
pretending the level has been fully accepted.
|
||||
|
||||
### Event semantics
|
||||
|
||||
An event is an investigator-authored assertion: **“this happened.”** It is not source evidence and must not silently inherit a document's publication time.
|
||||
|
||||
+145
-9
@@ -1,11 +1,3 @@
|
||||
# Scene 7 TODO: Prove Barricelli was an inventor
|
||||
|
||||
Status: **ready for implementation planning**
|
||||
Suggested feature branch: `scene-7-evidence-goal`
|
||||
Demo: **GUPI Demo 1 — The Barricelli Files**
|
||||
|
||||
## Outcome
|
||||
|
||||
Scene 7 teaches one idea: a screenshot found during an OSINT search can become
|
||||
source evidence.
|
||||
|
||||
@@ -20,7 +12,20 @@ The normal path must feel like one continuous action:
|
||||
```text
|
||||
paste screenshot -> document appears -> scanning feedback -> source verified
|
||||
-> Scene 7 complete -> continue to Scene 8
|
||||
```
|
||||
=======
|
||||
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.
|
||||
|
||||
```text
|
||||
paste screenshot -> document appears -> source is verified -> connect to Claim
|
||||
-> submit thin report -> provenance feedback -> accepted -> Scene 8
|
||||
|
||||
## Product decisions
|
||||
|
||||
@@ -137,6 +142,93 @@ structured data, for example:
|
||||
type EvidenceVerdict = {
|
||||
subject: 'nils' | 'father' | 'ambiguous' | 'neither'
|
||||
supportsInventorClaim: boolean
|
||||
=======
|
||||
- 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:
|
||||
|
||||
```ts
|
||||
type EvidenceVerdict = {
|
||||
subject: 'target' | 'related' | 'ambiguous' | 'neither'
|
||||
supportsClaim: boolean
|
||||
evidenceExcerpt: string
|
||||
confidence: number
|
||||
}
|
||||
@@ -399,3 +491,47 @@ document and completed state, repeating the evaluation grants nothing twice,
|
||||
another player's level is unaffected, no URL was required, and
|
||||
`barricelli_luggage` has not yet been awarded.
|
||||
|
||||
=======
|
||||
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 1–6, 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.
|
||||
inIO asset, OCR, match provenance, stable exhibit number, connection, report
|
||||
|
||||
Reference in New Issue
Block a user