↩
Fraud Graph Arena · 19 October 2026

🕵️ FGA 03: Screen Me Up Before You Go-Go 🐶

A detective story about screen contracts and browser history

19 min read
Hercule Perrot examines the route maze before putting every screen under contract.
0% read·19 min in this view

Part I: The Corridor Crime Scene

Another Screen Walks into the Office

The rain had returned. It struck the windows of the Academy with the persistence of a frontend defect that had survived three refactors and acquired seniority.

Inside, the investigation board from FGA 02 was finally alive. The paper could hold content. The graph panel had room to breathe. The typewriter keys behaved like controls instead of painted suggestions. Full and compact layouts could disagree about furniture without disagreeing about meaning.

The room was ready. Then three screens arrived, each with its own route, event listener, loading flag, fade timer, focus behaviour and theory about where the player should go.

Soon the application had not one navigation system, but several local customs connected by browser history and optimism.

The symptoms were familiar:

  • One component called navigate() directly.
  • Another waited 500 milliseconds before doing the same thing.
  • A third changed state first and route second.
  • A fourth mounted, fetched data and quietly performed a game command because the information was already nearby.
  • Every screen knew where it came from, where it went and how long darkness ought to last.

Nothing looked catastrophic in isolation. That was the problem.

Navigation spaghetti rarely arrives in one dramatic bowl. It appears strand by strand, each one entirely reasonable, until the application needs a fork and an incident report.

A Route Is an Address, Not Permission

The first correction was conceptual. A URL can identify a place:

/rounds/abc123/board

It cannot prove that:

  • The round exists.
  • It belongs to the current player.
  • Its opening has been completed.
  • Its status permits investigation.
  • It has not already closed.

The browser may request the board. The backend still decides whether the round is allowed to produce an active workspace.

This distinction already existed in the Academy walking skeleton. An INTRO_PENDING round could not obtain the board; the application returned an INTRO_REQUIRED problem instead. Completing the opening moved the round to ACTIVE, after which the empty workspace became available.

The screen system therefore needed to coordinate presentation without becoming a second source of game truth.

Navigation is not authority.
Animation is not state.
Mounting is not a game event.

Hercule wrote the three lines in his notebook and underlined the third.

React components have a habit of entering rooms more than once during development.
A lifecycle hook that creates rounds, spends credits or completes briefings is not convenient. It is evidence tampering with a hook name.

The Original Suspect Python Screen Classes

The first architectural idea looked respectable:

class CaseIntroductionScreen(Screen):
    async def on_load(self): ...
    async def on_enter(self): ...
    async def on_exit(self): ...

Python already controlled the backend. It knew the round. It knew the case. It knew which actions were valid. Why not let it represent the screens too?

Because knowing whether the player may enter the room is not the same as knowing where the browser should place the lamp.

Backend code should own authoritative facts:

CREATED
   ⤷ INTRO_PENDING
        ⤷ ACTIVE

Later domain iterations may extend that lifecycle with submission, evaluation, closure and recovery states.

Frontend navigation owns presentation states:

LAUNCH
   ⤷ PATH_SELECTION
       ⤷ CASE_SELECTION
           ⤷ CASE_INTRODUCTION
               ⤷ INVESTIGATION_BOARD

A future result flow can add case resolution without making the browser responsible for deciding the verdict.

Python classes could still expose safe lifecycle facts and commands. They should not reach into browser focus, animation timing, responsive layout or component mounting.

The backend knew the law. It did not need to arrange the furniture.

Part II: Five Suspects in One Corridor

Suspect One: Backend Controlled Screens

Strength: authoritative state remains central.

Weakness: presentation details cross the network boundary and become coupled to server code.

The backend can say:

The round is INTRO_PENDING.
The opening is available.
The board is forbidden.

It should not say:

Mount this React component, focus its second heading and fade
for 430 milliseconds.

Useful witness. Wrong jurisdiction.

Suspect Two: Frontend Component Hierarchy

React components naturally render browser interfaces. Shared parents can provide loading, errors and layout. Reusable components can handle cards, comics, boards and results. But component hierarchy alone does not define a journey.

Without another model, each screen begins to own:

  • Route construction
  • Transition timing
  • Recovery logic
  • Browser-history interpretation
  • Assumptions about domain state

The components render well and navigate by folklore.

Suspect Three: The State Machine

A state machine makes movement explicit:

  CASE_INTRODUCTION
          + 
INTRODUCTION_COMPLETED
  [round is ACTIVE]
          ⬇ 
  INVESTIGATION_BOARD

Now legal and illegal transitions can be tested without clicking through the whole application.

But a state machine does not render a comic, draw a board or load a catalogue. It is traffic law, not the city.

Suspect Four: JSON Driven Screens

A small excerpt shows version metadata and registered screen references:

{
  "schema_version": "1.0",
  "document_version": "1.0.0",
  "minimum_runtime_version": "1.0.0",
  "id": "CASE_INTRODUCTION",
  "component": "CASE_INTRODUCTION",
  "data_source": "ROUND_OPENING"
}

Then somebody asks for one condition.
Then a calculated target.
Then a network call.
Then a retry.

By coffee number four, the configuration has variables, expressions, inheritance and the emotional confidence of a language runtime with no debugger.

JSON is excellent evidence. It is a terrible place to hide an interpreter designed during a caffeine incident.

Suspect Five: The Hybrid

The hybrid gave every participant one narrow job:

Backend       ➜ validates game authority
State machine ➜ validates navigation
Configuration ➜ describes screens and transitions
Components    ➜ render reusable screen families
Effects       ➜ animate presentation changes
Schemas       ➜ reject invalid definitions

This architecture did not eliminate complexity. It stopped mailing copies of the complexity to every screen.

The hybrid was arrested, questioned and offered supervised employment.

Part III: The Screen Contract

Every Screen Gives a Statement Under Oath

Reusable did not mean identical. Path selection, case selection, a comic introduction and an investigation board do not share the same anatomy. Forcing them into one universal component would produce forty-seven optional properties and a switch statement large enough to require its own postcode.

They could still share one contract.

A compact excerpt from the production introduction definition looks like this:

{
  "schema_version": "1.0",
  "document_version": "1.0.0",
  "minimum_runtime_version": "1.0.0",
  "id": "CASE_INTRODUCTION",
  "component": "CASE_INTRODUCTION",
  "data_source": "ROUND_OPENING",
  "actions": [
    {
      "id": "COMPLETE_INTRO",
      "handler": "COMPLETE_INTRO"
    },
    {
      "id": "SKIP_INTRO",
      "handler": "SKIP_INTRO"
    }
  ],
  "transitions": [
    {
      "event": "INTRODUCTION_COMPLETED",
      "target": "INVESTIGATION_BOARD",
      "effect": "FADE_TO_BLACK",
      "history": "REPLACE",
      "guard": "ROUND_ACTIVE"
    },
    {
      "event": "INTRODUCTION_SKIPPED",
      "target": "INVESTIGATION_BOARD",
      "effect": "FADE_TO_BLACK",
      "history": "REPLACE",
      "guard": "ROUND_ACTIVE"
    }
  ]
}

The definition describes the participants. Typed code performs the work.

onLoad: Prepare the Room

A loader may retrieve:

  • Catalogue sections.
  • Cases for the selected path.
  • The current opening sequence.
  • The active workspace.
  • A future safe result projection.

A loader may not:

  • Create a round.
  • Complete an introduction.
  • Reveal evidence.
  • Submit a case.
  • Decide a verdict.

Loading is a read concern. Commands remain explicit.

This boundary matters because screen setup may repeat. Development checks, remounts, retries, refreshes and interrupted navigation can all cause another load. Safe reads should tolerate repetition; authoritative mutations should never depend on a component appearing exactly once.

The Academy evidence already demonstrates the right separation: round creation, start and opening completion are explicit operations; opening and workspace are reads. Start and completion are designed to be idempotent where retry safety requires it.

onEnter: Presentation, Not History

Entering a screen may:

  • Move focus to a semantic heading or landmark.
  • Announce the new view.
  • Activate keyboard handling.
  • Restore safe local presentation state.
  • Start an approved decorative effect.

It may not infer that the player has completed anything merely because the component mounted.

The final comic page being visible does not activate the round. The player action does.

The backend accepts it. Then navigation responds.

onExit: Clean Up Without Rewinding

Exiting may:

  • Cancel obsolete reads.
  • Remove screen listeners.
  • Stop decorative effects.
  • Clear transient messages.
  • Preserve an allowed local draft.

It may not undo authoritative history.

Leaving the board does not return the round to INTRO_PENDING.
Leaving a future result screen will not make the case mutable again.

Browser navigation moves through addresses; it does not negotiate with time.

Actions: Labels Are Not Identities

A visible control might say:

Enter the Academy

Its semantic identity is:

COMPLETE_INTRO

The label may be translated, shortened or moved to a typewriter key. The action remains the same.

The sequence is:

player activates control
  ⤷ registered handler sends request
      ⤷ backend accepts or rejects
          ⤷ handler emits semantic outcome
              ⤷ state machine resolves navigation

A click is a request. Not a verdict.

Transitions: Outcomes Not Route Commands

Prefer:

INTRODUCTION_COMPLETED

over:

GO_TO_BOARD

The first describes what happened. The state machine decides where that outcome leads from the current state.

This leaves room for a future briefing summary or accessibility step without changing the meaning of the action.

A transition contains four distinct ideas:

event  ➜ what happened
guard  ➜ whether movement is valid
target ➜ where the journey goes
effect ➜ how the change appears

Mixing them produces components that know too much and timeouts that know even more.

Validation: Valid JSON Can Still Lie

Parsing proves that the commas survived.

Qualification must also check:

  • Supported schema version.
  • Stable screen ID.
  • Registered component.
  • Registered data source, action handler, guard and effect.
  • Compatible references.
  • Unique action IDs.
  • Existing transition targets.
  • Reachable required screens.
  • Deliberate terminal states.
  • No forbidden unknown properties.

One screen can be individually valid and still point into the void.

Polite documents also lie when nobody compares their statements.

Part IV: Reusable Screen Families

Reuse Meaning Without Forcing Coincidence

The common renderer should not become every screen.

Its job is smaller:

load definition
  ⤷ validate
      ⤷ resolve the registered component
          ⤷ provide common lifecycle services
              ⤷ mount the screen component
                  ⤷ coordinate actions and transitions

The family component understands its room.

Path Selection

Path selection renders the canonical investigation paths returned by the catalogue:

DETECTIVE_ACADEMY
PUPPY
ADULT_DOG
SENIOR_DOG

Availability comes from the server-owned catalogue. The component does not keep a private list that eventually disagrees with it.

Selecting a path changes navigation context. It does not create a round.

Case Selection

Case selection displays safe metadata for the chosen path.

In the verified Academy baseline, the public case is:

ACADEMY_001
The Case of the Empty Evidence Board

Opening it performs an authoritative operation:

create round
  ⤷ bind path, case and case version
      ⤷ start round
          ⤷ receive INTRO_PENDING
              ⤷ enter case introduction

The component does not optimistically build a board route and hope the backend catches up.

Case Introduction

The introduction family renders a versioned opening sequence with accessible page content, progress and safe image fallbacks.

Page position is presentation state and may live in the URL:

?page=2

Completing or skipping the sequence is an explicit command. The backend moves the round to ACTIVE; only then may the board load.

Game Board

The board family mounts the office created in FGA 02:

  • Case paper
  • Graph viewport
  • Typewriter capability controls
  • Responsive full and compact compositions

The Screen Engine owns entry, loading, failure and exit.
The board owns interaction inside the room.

Selecting a graph node is not a navigation transition. Responsive recomposition is not a game event. Opening a paper section does not need to appear on the application state diagram.

The board remains intentionally empty in the verified baseline. That is not an omission disguised as suspense. It is the scope.

Case Resolution

Case resolution belongs in the contract because the journey will eventually close.

It needs a reusable family, terminal semantics and safe result data. It must never calculate the verdict in the browser or expose protected truth.

But the evidence reviewed for this article does not establish a public, fully qualified resolution route in the current playable baseline.

So the architecture prepares the door. It does not claim somebody has already walked through it.

This is less dramatic than inventing a green check mark. It is also how evidence works.

Part V: JSON as Evidence Not Sorcery

Data References and Executable Behaviour

Every value inside a screen definition belongs to one of three categories.

Data

Static, inspectable values:

  • IDs
  • Message references
  • Design viewport
  • Safe asset references
  • Bounded visual parameters
  • Version metadata

Registered References

Names resolved by approved registries:

  • Component
  • Data source
  • Action handler
  • Guard
  • Effect

Behaviour

Executable work:

  • API calls
  • State mutation
  • Validation logic
  • Focus movement
  • Cancellation
  • Animation implementation

Behaviour belongs in typed code.

The rule is simple:

Configuration may describe data and select registered capabilities. It may not smuggle arbitrary behaviour inside strings.

Conditions Without an Expression Language

This is dangerous:

{
  "visibleWhen": "round.status === 'ACTIVE' && credits > 0"
}

It looks compact because the parser, type system, debugger and security model are all missing from the screenshot.

Prefer a registered policy:

{
  "availability": "round-action-available"
}

The implementation receives a safe projection and returns a structured result:

AVAILABLE
UNAVAILABLE_PENDING
UNAVAILABLE_LOCKED
UNAVAILABLE_COMPLETED

A grey button without a reason is merely a locked door whose architect has stopped returning calls.

Bounded Sequences Without a Workflow Language

Some declarative screen runtimes support a bounded sequence of registered actions. That can be useful for controlled presentation work such as playing optional audio and running a reveal effect.

The boundary is not “arrays are forbidden.”

The boundary is:

  • the action catalogue is closed;
  • payloads are validated;
  • sequences cannot call arbitrary code;
  • domain mutations still go through explicit authoritative handlers;
  • configuration cannot invent loops, branches, retries or deep object access.

A short, typed sequence is configuration.
A general workflow engine hiding inside onEnter is a suspect with forged papers.

Schemas and Versions

Each definition should identify:

schema_version
document_version
minimum_runtime_version

These answer different questions:

  • Which contract language does the document use?
  • Which revision of this screen is it?
  • Which runtime can interpret it safely?

Unknown fields should fail where strictness is intended. References should be checked against registries. The complete catalogue should be checked as a graph.

The build rejects definitions that violate the screen schema.

Startup validation checks the loaded screen set and its registries.

One minimal recovery boundary must remain outside the declarative catalogue, because an invalid catalogue cannot be trusted to render its own obituary.

Migrate Then Render One Current Model

When a schema evolves, use an explicit versioned migration where compatibility is possible.

Do not scatter this archaeology through every render:

if oldField
else if olderField
else maybe newField

Migrate.
Validate.
Render one current internal model.

Old evidence deserves preservation, not permanent authority over the present.

Part VI: One Shared Fade

Several Screens Had Invented Darkness

The old pattern looked harmless:

setIsFading(true);
setTimeout(() => navigate(nextRoute), 500);

Another component used 400 milliseconds.
A third changed route before the fade.
A fourth waited for transitionend and assumed the browser would always deliver the invitation.

Every implementation produced black pixels. None agreed on what the application was doing while the pixels changed.

The Correct Sequence

For the Academy introduction, the transition should be:

player requests completion
⤷ action becomes pending; concurrent actions are blocked
  ⤷ backend confirms the round is ACTIVE
    ⤷ handler returns INTRODUCTION_COMPLETED
      ⤷ state machine resolves INVESTIGATION_BOARD
        ⤷ coordinator accepts and locks the transition
          ⤷ registered fade effect completes 
            (immediately when reduced motion is preferred)
            ⤷ route and history commit
              ⤷ board model loads
                ⤷ board heading receives focus and readiness 
                  is announced

Do not fade before the backend answers. Otherwise a rejected command leaves the player staring into darkness while the application decides how to reverse its confidence.

Noir permits tragedy. It does not require lying to the player.

One Transition Lock

Once a screen instance commits an outgoing transition, later requests from that instance are stale or duplicate.

This protects against:

  • Double clicks.
  • Repeated success callbacks.
  • Retries completing late.
  • Two effects competing for the same source screen.

The frontend lock protects presentation.
Backend idempotency protects authoritative state.

Both are necessary. A button being disabled is not a security boundary, and a database constraint is not a pleasant user experience.

The Old Screen Stops Accepting Input

During the exit effect, the old screen may still be visible. It should no longer behave as active.

Keyboard commands, pointer actions and duplicate semantic events must be suppressed or rejected deliberately.

The screen is present to finish leaving. It is not taking new cases.

Cancellation and Cleanup

Every effect needs deterministic disposal:

  • Cancel timers.
  • Remove effect-owned listeners.
  • Abort obsolete reads where possible.
  • Ignore stale completions.
  • Remove temporary overlays.
  • Release focus work owned by the old transition.

A transition event may never arrive if the CSS transition is cancelled or removed, so decorative completion must have a bounded fallback. The fallback does not decide navigation; it prevents decoration from holding the corridor hostage.

The lamp may fail. The door must still open.

Reduced Motion

Reduced motion changes the theatre, not the destination.

The semantic transition remains:

  CASE_INTRODUCTION
         + 
INTRODUCTION_COMPLETED
         ⬇
 INVESTIGATION_BOARD

The effect may become immediate or nearly immediate. The player should not wait through an invisible 500-millisecond ceremony merely because the animated version had one.

Focus Crosses Deliberately

After a single-page application changes views, focus must not fall onto the document body like a detective losing the address of the crime scene.

The target family defines a semantic focus destination:

SCREEN_HEADING
BOARD_LANDMARK
RESULT_SUMMARY

The component resolves the actual element. Configuration does not contain brittle CSS selectors describing the third heading inside the second div behind the sofa.

Part VII: Test the Whole Journey

One Successful Navigation Is Not an Alibi

A browser test can prove that one fortunate journey worked:

click Start
click Academy
click ACADEMY_001
complete opening
expect board

Useful.
Not sufficient.

The state model must also answer:

  • Can the board be reached before the opening completes?
  • Can an unknown event move the application?
  • Can the player become trapped in a nonterminal screen?
  • Can browser Back restore an obsolete lifecycle?
  • Can a duplicate event run the transition twice?
  • Does every target exist?
  • Can an old round be reopened after future closure?

Legal:

  CASE_INTRODUCTION
          +
INTRODUCTION_COMPLETED
   [round ACTIVE]
          ⬇
 INVESTIGATION_BOARD

Illegal:

  CASE_INTRODUCTION
          + 
INTRODUCTION_COMPLETED
[round INTRO_PENDING]
          ⬇
      rejected

Also illegal:

       LAUNCH
          + 
INTRODUCTION_COMPLETED
          ⬇ 
      rejected

A semantic event is not a global command. It is meaningful only from the correct state and context.

Test the Catalogue as a Graph

The navigation catalogue should prove:

  • One deliberate entry state.
  • Every required screen reachable.
  • Every nonterminal screen has a way forward.
  • No missing target.
  • No unexplained cycle.
  • No path bypasses a mandatory lifecycle step.

For the verified Academy flow, every route from case selection to the board must pass through the opening requirement.

The backend already blocks the bypass.

The frontend should not keep attempting the crime merely because another layer will stop it.

Route Reconstruction

A refresh starts with an address and authoritative context, not the memory of the previous component.

Given:

route = /rounds/abc123/board
round = ACTIVE

render:

INVESTIGATION_BOARD

Given the same address with:

round = INTRO_PENDING

recover to:

CASE_INTRODUCTION via the safe INTRO_REQUIRED recovery

The route is evidence. The round is authority.

Browser Back Is Not Rollback

Browser Back moves through session history. It may request an old introduction address after the round has become active.

The loader checks the round before displaying obsolete screen content.
The board remains the valid presentation.

Later, when the domain gains terminal closure, Back must not reopen a mutable investigation.

History navigation is not game-history mutation. Hercule wrote it down again in case the browser had merely overlooked the first copy.

What the Available Evidence Actually Covers

The supplied Academy contracts and tests cover the important baseline claims:

  • four canonical path identifiers.
  • Academy open while ranked paths are unavailable.
  • ACADEMY_001 bound to the Academy path.
  • CREATED ➜ INTRO_PENDING ➜ ACTIVE.
  • board access blocked before introduction completion.
  • start and completion designed as idempotent operations.
  • opening page state and board reconstruction requirements.
  • active board reporting zero evidence and zero suspects.

The declarative Screen Engine materials also show versioned screen documents, registered actions/effects and schema validation work.

They do not justify claiming that every future screen family, complete result flow and full browser qualification have already shipped.

A test plan is not a test result.
A schema is not a playable journey.
A convincing architecture diagram is not an alibi.

Part VIII: Bodies Found in the Corridor

The Double Transition

The player clicks once.
The request succeeds.
A second callback arrives before the first screen fully exits.

Both see the same valid source state.

Without a transition lock, both proceed.

The final screenshot still shows the correct board.

Behind it lie two route writes, two focus moves and a timeout wondering whether it still works here.

A correct destination does not acquit the journey that produced it.

The Screen That Loaded Twice

A component remounts and performs its loader again.

Safe read: acceptable.

Hidden round creation in onLoad: two rounds and one ghost file.

The fix is not a clever “mounted once” flag.

The fix is restoring the boundary:

Loaders prepare screens. Explicit actions change the game.

The Stale Callback

The player leaves.

An old request or effect completes.

Its response belongs to a previous path, round or screen instance.

Results must be context-bound. Transition tokens must expire. Obsolete callbacks may finish privately; they may not change the current application.

A witness who missed the interview cannot enter the verdict by post.

The Universal Component

The common renderer gradually acquires branches for every family.

Then family-specific loading.

Then comic paging.

Then board overlays.

Then result rendering.

Soon DeclarativeScreen is the entire application wearing a reusable name badge.

The renderer should resolve a family, not impersonate all of them.

Reuse stable responsibilities:

  • shell
  • focus
  • loading orchestration
  • action dispatch
  • transition coordination
  • error boundary

Keep family meaning inside family components.

The Route and State Disagree

The screen changes but the route write fails.

The player sees the board under an introduction address.

Refresh reconstructs something else.

Route and navigation state must be part of one committed transition outcome. Preparation may be temporary; public state may not maintain two versions of where the player is.

Part IX: Evidence Handling Rules

The autopsy produced a shorter constitution.

Rule 1: Routes Are Requests Not Permissions

Resolve them against current authoritative context.

Rule 2: Mounting Is Not a Domain Event

No round creation, credit spending, reveal, submission or lifecycle completion inside presentation hooks.

Rule 3: Loaders Read and Actions Command

Loaders must tolerate repetition. Commands must be explicit and idempotent where retries matter.

Rule 4: Components Emit Outcomes

Use INTRODUCTION_COMPLETED, not GO_TO_BOARD.

Rule 5: The State Machine Coordinates Navigation Only

It does not evaluate fraud, calculate credits or become the backend in a trench coat.

Rule 6: Configuration Describes and Selects

No arbitrary code, deep domain-property tunnels or surprise network clients inside JSON.

Rule 7: One Screen Instance Commits One Exit

Later events are stale, duplicate or rejected.

Rule 8: Effects Decorate Valid Movement

They do not grant it, reverse it or hold it hostage.

Rule 9: Recovery Preserves Semantic State

A failed board load remains a board failure for an active round. It does not resurrect the introduction.

Rule 10: Adding a Screen Does Not Add Traffic Laws

A new screen may require a definition, family, handler and tests.

It should not require a private router, fade, loading philosophy and storage strategy.

The project should remember these rules through schemas, architecture tests and state-model tests, because developers have other responsibilities.

Some of them are trying to draw graphs.

Part X: Playable Evidence

The Corridors Behave

Hercule launches Fraud Graph Arena.

The current entry screen loads.

He enters the path catalogue.

The server returns:

DETECTIVE_ACADEMY
PUPPY
ADULT_DOG
SENIOR_DOG

He chooses Detective Academy.

The Academy catalogue exposes:

ACADEMY_001
The Case of the Empty Evidence Board

He opens it.

A real round is created and bound to the path, case and case version.

The round starts:

CREATED ➜ INTRO_PENDING

The opening sequence loads.
Hercule reaches the final page.
The board remains forbidden.
He completes the briefing.

The backend moves the round to:

ACTIVE

Only then may the application enter the board.

The correct case appears.
The evidence count is zero.
The suspect count is zero.
The graph has nothing to confess.

This is the verified playable baseline:

Launch
  ⤷ path selection
      ⤷ Detective Academy
          ⤷ ACADEMY_001
              ⤷ opening comic
                  ⤷ explicit opening completion
                      ⤷ active empty board

The declarative Screen Engine gives that journey a common vocabulary: versioned definitions, registered actions, reusable screen families, shared effects and validation.

The evidence reviewed here does not extend the verified playable route through submission and case resolution. Those remain architectural contract and future gameplay work, not decorative green ticks.

What This Article Proves

The production Academy journey now uses a versioned screen set, registered handlers and one transition coordinator. Unit and browser tests cover route reconstruction, history, transition locking, focus and recovery.

Adding another screen no longer needs another private theory of navigation.

What It Does Not Prove

Be explicit.

  • There is still no real evidence on the verified empty board.
  • The graph remains empty.
  • The typewriter capabilities remain unavailable in that baseline.
  • No real case submission is evaluated here.
  • No public case-resolution journey is claimed as qualified by the reviewed evidence.
  • Declarative screens do not automatically create good UX.
  • Schemas cannot detect confusing copy.
  • A state machine cannot determine whether the game is fun.
  • Future authentication, recovery and long-running gameplay may require richer state structures.
  • Case packages still need a common data contract.

The corridors are organised.

The rooms are still waiting for clues.

Iteration labels may change. Architecture should not need to lie about what is already playable.

The Case Remains Open

The verdict was procedural. The backend retained game authority; one screen runtime validated the contracts and coordinated presentation. The Academy journey now follows a single route and transition model. The next file brought a different kind of trouble.

Every case still arrives carrying its own names, identifiers, files, relationships, evidence and assumptions.

One calls a company organisation.
Another calls it business_entity.
A third calls it dog_with_tax_number and appears proud of the decision.
All three insist they are perfectly normal.

Hercule returns to the board and opens a fresh notebook.

Next in the Series

FGA 04 The Dog Ate My Data Contract

Creating one common model for every case

The next investigation asks whether every case can speak the same language when it arrives:

Entities
Relationships
Events
Evidence
Provenance
Ground truth

Because “we will normalise it later” is not a plan. It is the opening sentence of a data-platform horror story.

Source Code

Browse the source code for FGA 03 on GitHub ↗


Sepia infographic summarizing FGA 03’s screen families, navigation journey, effects, test evidence, and limits.

The journey is tested, the board is still empty, and the next data contract is waiting.

89Published
44,161Visits
21,693Read
VisitsReadLAST 5 WEEKS
Week ending 16 Sep · WholeStageCodegen · 90 visits · 5 readsWeek ending 9 Sep · 62 visits · 13 readsWeek ending 2 Sep · 433 visits · 75 readsWeek ending 26 Aug · 295 visits · 19 readsWeek ending 19 Aug · 398 visits · 49 readsWeek ending 16 Sep · 5 readsWeek ending 9 Sep · 13 readsWeek ending 2 Sep · 75 readsWeek ending 26 Aug · 19 readsWeek ending 19 Aug · 49 reads