Sense 19: The Simulation
Sense 19 · Steady · Last touched 2026-08-20
- last_verified: 2026-07-27
Synced from
docs/design/sense_19_the_simulation.mdin the engine repo — that’s the source; this page is a build-time mirror.
Don’t guess. Model it.
If the suggestion is concrete enough to describe as an intervention, and the intervention is deterministic enough to apply to data, then you can build the future before you live it.
Status: proposed Author: the owner + Claude (inspire walkthrough, 2026-04-17)
What pulled us in
Section titled “What pulled us in”jinflow tells you what’s wrong (Signals), asks whether it’s real (Theses), explains why (Verdicts), and frames it strategically (Observations + Explanations + Contributing Factors). It even suggests what to do (Suggestions).
But then it stops. The user is left with a recommendation and a leap of faith. “Tighten the revenue leakage threshold to 5%” — okay, but what happens if we do? How many new findings? What’s the exposure delta? Does it break something downstream?
Today the only way to answer is to manually edit the AFS, rebuild, and
compare. That works — jin make is a pure function, the AFS is
branchable, the Diff Loupe exists. But it’s a developer workflow, not a
product experience.
The Vocabulary
Section titled “The Vocabulary”Four new terms complete the jinflow Experience from observation to action:
Suggestion
Section titled “Suggestion”A human-readable recommendation for improvement. Any kind — process change, system fix, data cleanup, threshold adjustment, structural reorganisation. Not tied to a specific signal type or technical mechanism. A Suggestion is what to do.
suggestion_id: sug_tighten_revenue_leakagecategory: thresholdtarget: signal_revenue_leakagedescription: en: "Tighten the revenue leakage threshold from 10% to 5%."priority: highorigin: verdict_billing_workflow_gap # where this came fromSuggestions can originate from:
- Verdicts — the root-cause analysis recommends an action
- Subject Matter — an expert notes a known workaround
- Observations — the strategic review identifies an opportunity
- Human judgment — the analyst writes one from scratch
Intervention
Section titled “Intervention”A deterministic, executable parameter change. The technical realisation of a Suggestion. An Intervention is precise enough that a machine can apply it to the AFS without ambiguity.
intervention_id: int_set_threshold_005suggestion_id: sug_tighten_revenue_leakagetype: yaml_edittarget_file: signals/signal_revenue_leakage.yamlchanges: - path: threshold from: 0.10 to: 0.05deterministic: truereversible: trueIntervention types (initial set):
yaml_edit— change a value in a YAML artifactartifact_add— add a new signal/thesis/verdict/smebitartifact_remove— remove an instrumentconfig_change— modify tenant configseed_edit— modify a seed CSV (e.g., update a reference table)
An Intervention is how to do it — concrete, diffable, auditable.
Scenario
Section titled “Scenario”Reality + Interventions = Scenario. A Scenario is a named, branchable alternative state of the AFS with one or more Interventions applied.
scenario_id: scn_tighter_leakagedescription: en: "What if we tighten revenue leakage to 5%?"base: main # the branch this scenario diverges frominterventions: - int_set_threshold_005status: draft # draft → built → compared → adopted | archivedA Scenario IS an AFS branch. The branch name is the scenario_id:
scenario/scn_tighter_leakage. This aligns with the existing
branching model in docs/design/afs_artifact_store.md.
Simulation
Section titled “Simulation”Build the Scenario branch, compare the output KLS to production, and
present the delta. A Simulation is the act of running jin make on the
scenario branch and showing what changed.
The simulation output:
- Finding delta — new findings, removed findings, severity changes
- Exposure delta — CHF at risk: production vs. scenario
- Thesis verdict changes — did any thesis flip from plausible to confirmed (or vice versa)?
- Entity health delta — perspective scores before/after
- Signal coverage — new signals added, old signals removed
Presented in the Diff Loupe (already exists for snapshot comparison) or a dedicated Simulation Results view.
The Complete Journey
Section titled “The Complete Journey”Signal → Finding → Perspective → Thesis → Verdict → Observation → Explanation → Contributing Factor → Suggestion → Intervention → Scenario → SimulationOr, in the language of the user:
| Step | Question | Answer |
|---|---|---|
| Signal | What patterns exist in the data? | Findings |
| Thesis | Is this pattern real? | Verdict (confirmed / plausible) |
| Observation | What does this mean strategically? | Signed claim |
| Explanation | How is it manifested? | Evidence + hypothesis |
| Contributing Factor | What composes the explanation? | Structured causes |
| Suggestion | What should we do? | Recommendation |
| Intervention | How exactly? | Deterministic parameter change |
| Scenario | What would the world look like? | Reality + interventions |
| Simulation | What happens? | Build, compare, decide |
Why This Works in jinflow
Section titled “Why This Works in jinflow”jinflow’s architecture was built for this without knowing it:
makeis a pure function. AFS in → KLS out. No side effects. A scenario build produces an independent KLS with full fidelity.- The AFS is branchable. Git branches are free. A scenario IS a branch. Merging a scenario IS adopting the intervention.
- The Diff Loupe exists. Snapshot comparison already works. Scenario comparison is the same mechanism with a different label.
- Interventions are YAML edits. The AFS is declarative. A threshold change is a one-line YAML diff. No code, no migration, no deploy.
- KLS is self-describing. The scenario KLS carries its own AFS
archive (
_jinflow_afs_archive), so the interventions that produced it travel with the result.
The UX Flow
Section titled “The UX Flow”1. Suggest (from Verdict detail page)
Section titled “1. Suggest (from Verdict detail page)”The user reads a confirmed Verdict: “The cause is a process gap between OR completion and billing entry.” Below the verdict, a Suggestions section lists actionable recommendations. The user clicks “What if?“
2. Configure (Scenario Builder)
Section titled “2. Configure (Scenario Builder)”A lightweight editor shows:
- The Suggestion’s proposed Intervention(s)
- A preview of the YAML diff (what changes, old → new)
- A “Build Scenario” button
3. Build (background)
Section titled “3. Build (background)”jin make --scenario scn_tighter_leakage runs in the background.
Progress bar in JinDesk. The user can continue browsing while it
builds. When done, a notification: “Scenario ready — view results.”
4. Compare (Diff Loupe / Simulation Results)
Section titled “4. Compare (Diff Loupe / Simulation Results)”Side-by-side: production KLS vs. scenario KLS.
- Finding delta table (new / removed / changed severity)
- Exposure bar chart (CHF production vs. scenario)
- Thesis verdict flip table
- Entity health heatmap delta
5. Decide
Section titled “5. Decide”The user reviews the simulation and either:
- Adopts — merge the scenario branch into main. The intervention
becomes production on the next
jin make. - Archives — keep the scenario for reference but don’t merge.
- Iterates — adjust the intervention and re-simulate.
Implementation Phases
Section titled “Implementation Phases”Phase 1 — Suggestion + Intervention (YAML artifacts) [shipped 2026-05-22]
Section titled “Phase 1 — Suggestion + Intervention (YAML artifacts) [shipped 2026-05-22]”New instrument types: suggestions/*.yaml and interventions/*.yaml.
Contracts at contracts/suggestion_contract.v1.json and
contracts/intervention_contract.v1.json. Validators at
scripts/suggestioncheck.py and scripts/interventioncheck.py.
Tier split. Suggestions are A-tier — they live on the
suggestions orphan branch alongside notes / bookmarks / recents /
bell, shared across every scenario. Interventions are B-tier —
branch-bound (main + each scenario carries its own intervention set),
because different scenarios are defined by different interventions.
Bake. bake_suggestion_registry and bake_intervention_registry
in jinflow/cli/commands/baking.py read the AFS YAMLs and write
_<tenant>.suggestion_registry + _<tenant>.intervention_registry
to the KLS at every jin make. Hooked into all three make paths
(metadata-only rebake, incremental, full clean).
Forward/reverse refs. A Suggestion declares interventions: [...];
an Intervention declares suggestion_id. Both directions land in the
registries so JinDesk can navigate either way.
Safety. The Intervention checker rejects absolute paths in
target_file and any path containing .. segments — defense in
depth before Phase 2’s apply step ever touches the filesystem. Only
deterministic: true interventions will be applied (Phase 1 emits a
warning otherwise; Phase 2 will refuse).
What Phase 1 does NOT do: actually apply interventions. Phase 1
makes them addressable, validatable, queryable, durably stored,
shared across scenarios. The apply step lives in Phase 2 alongside
jin scenario create.
Phase 2 — Scenario Builder [shipped 2026-05-22]
Section titled “Phase 2 — Scenario Builder [shipped 2026-05-22]”AFS branching via jin scenario create. Applies interventions to the
branch deterministically; commits the result. CLI-first, JinDesk
later. Building the scenario KLS uses ordinary jin make —
scenarios are normal git branches.
Verbs:
jin scenario create <id> int_X [int_Y …] [--base BRANCH] [--tenant pack.tenant]jin scenario listImplementation:
jinflow/scenarios/apply.py—apply_intervention(afs_root, intervention_doc)does one deterministic yaml_edit. Uses ruamel.yaml for round-trip preservation: comments, key order, and quoting in the target YAML survive untouched, so the scenario branch’s diff against base is exactly the bytes the intervention changes. Refuses non-yaml_edittypes, refuses to create missing keys, refuses absolute /..-escapingtarget_file.jinflow/scenarios/create.py—create_scenario(afs_root, scenario_id, intervention_ids, base_branch=...)orchestrates the full flow: refuses dirty working tree, refuses pre-existing branches, createsscenario/<id>off the base, applies interventions in declared order, commits with a structured message. Rolls back the branch on any apply failure — half-applied scenarios are never left behind.jinflow/cli/commands/scenario.py—cmd_scenario_create,cmd_scenario_list. The CLI surfaces are thin wrappers over the package.
Drift semantics: each change carries a from value the
intervention expects to find at the path. If the actual value
differs, the apply refuses. Stacked interventions on the same
path see the post-previous-intervention state, because applies
run sequentially against the working tree (not against a
pre-computed in-memory copy). Authoring two interventions where
int_b.from is int_a.to works correctly.
What Phase 2 does NOT do: build the scenario KLS automatically.
The user runs jin make <tenant> against the scenario branch when
they’re ready. This keeps the verb surface small and aligns with
the established “make is the build” convention.
Phase 3 — Simulation Results [shipped 2026-05-22]
Section titled “Phase 3 — Simulation Results [shipped 2026-05-22]”Two new verbs that turn the Phase 2 scenario branch into a buildable, inspectable artifact:
jin scenario build <id> [--tenant pack.tenant]jin scenario list # now shows BUILT yes/no per rowWhere the scenario KLS lives. The existing jin make --branch
infrastructure routes branch builds to a branch-named KLS file:
<pack>_<tenant>_<safe_branch>_kls.duckdb in the store dir. For a
scenario branch named scenario/lower_thresholds that resolves to
<pack>_<tenant>_scenario_lower_thresholds_kls.duckdb — coexisting
with the production working KLS at <pack>_<tenant>_kls.duckdb.
The Compare route picks both up automatically; no new
infrastructure was needed there.
jin scenario build is a thin wrapper over jin make --branch scenario/<id>. It exists for ergonomics and to catch
missing-branch errors early (clearer message than what jin make
would surface). The convention for KLS placement lives in one
place: _scenario_kls_path in jinflow/cli/commands/scenario.py,
which must stay in sync with the safe_branch logic in
make.py. The test test_scenario_kls_path_convention pins
both.
jin scenario list now annotates each scenario row with its
build status, derived from KLS-file presence at the conventional
path. So a typical flow surfaces clearly:
$ jin scenario listBRANCH CREATED BUILT SUBJECTscenario/lower_thresholds 2026-05-22 yes scenario: lower_thresholdsscenario/tighter_or_documentation 2026-05-22 no scenario: tighter_or_documentationThe Compare route’s existing snapshot-comparison machinery —
already present in explorer/src/routes/[tenant]/compare/ —
reads every *_kls.duckdb in the store and lets the user pick two
sides to diff. Scenario KLSes show up there with their full filename
(e.g., numetrix_rmc_scenario_lower_thresholds_kls.duckdb). The
finding/exposure/thesis deltas, entity-health heatmap, and side-by-
side rendering ALL already exist. Phase 3 didn’t need to touch the
JinDesk — the Phase 2 KLS-naming-convention plus Phase 3’s
documentation closed the loop.
What Phase 3 does NOT do: auto-label scenario KLSes distinctly
from snapshot KLSes in the Compare UI (today they’re both
*_kls.duckdb in the same list). That landed in Phase 4 (next
section).
Phase 4 — Compare UI scenario mode [shipped 2026-05-22]
Section titled “Phase 4 — Compare UI scenario mode [shipped 2026-05-22]”Three additions that make scenarios self-describing in JinDesk:
1. Scenario metadata bake. A new
bake_scenario_metadata(kls_path, tenant_id, afs_root) runs at
the end of every jin make and detects whether the current AFS
branch is scenario/<id>. If yes, it parses the structured commit
message that create_scenario wrote (with base branch and
intervention list) and writes a row to
_<tenant>.scenario_metadata:
CREATE TABLE _<tenant>.scenario_metadata ( scenario_id VARCHAR PRIMARY KEY, base_branch VARCHAR, base_commit VARCHAR, interventions VARCHAR -- JSON array of intervention_ids)On non-scenario branches the bake is a no-op — the table is not
created, so Compare can feature-detect via information_schema.
2. Compare server picks it up. When the Compare page loads each
KLS to gather stats, it also queries scenario_metadata (best-
effort, swallows the missing-table error). The new fields
scenarioId, scenarioBase, scenarioInterventions land on
the KlsVersion interface.
3. Compare UI surfaces scenarios distinctly.
- The two
<select>dropdowns split into<optgroup>blocks: “Production” (working + named snapshots) vs “Scenarios” (KLSes with baked metadata). - The side-by-side cards render a scenario panel below the existing
build info when
scenarioIdis populated, listing the intervention IDs in an amber-tinted box. - A “Compare to production” button on the scenario card pre-fills the other side with the working KLS and navigates — one click from “I’m looking at this scenario” to “delta vs current production.”
Why the commit message as source of truth. The interventions
applied to a scenario are determined at scenario-create time. The
commit message that create_scenario wrote is git’s canonical
record of that act. Reading it back at bake time keeps the metadata
flowing without a sidecar file. If the commit gets amended into an
unstructured shape, the bake gracefully no-ops (better no metadata
than wrong metadata).
Phase 5 — Inline “What if?” UX
Section titled “Phase 5 — Inline “What if?” UX”“What if?” button on Verdict detail → Scenario Builder → background build → notification → Simulation Results. Full loop in the browser. Not in scope for the 2026-05-22 weekend; the substrate is ready when it is.
How this manifests in jinflow
Section titled “How this manifests in jinflow”The Simulation runs CLI-first today: jin scenario create branches the tenant AFS, applies one or more Interventions, and jin scenario build rebuilds the tenant against the modified framework. The resulting KLS is a true counter-factual — same engine, different input — and JinDesk can be pointed at it side by side with the baseline. The browser-side authoring surface for Suggestions and Interventions is the next layer; the substrate (AFS branching + scenario-aware make) is live.
- CLI:
jin scenario create <id> int_X [int_Y …](branches AFS + applies Interventions) ·jin scenario build <id>(rebuilds KLS on the scenario branch) ·jin scenario list - Reads from: the tenant’s AFS (baseline) + intervention YAMLs · the baseline KLS for comparison
- Writes to: scenario branch of tenant AFS · scenario KLS at
kls/<scenario_id>_kls.duckdb
Status: shipped — CLI substrate live. The browser-side Suggestion / Intervention authoring surface is forming; the Phase 5b incremental build path is the next implementation target.
Open Questions
Section titled “Open Questions”- Scope of Interventions: should Interventions only touch YAML (signals, theses, config), or also CSVs (seed data, reference tables)? Seed edits are powerful but harder to diff.
- Compound Scenarios: can a Scenario combine interventions from multiple Suggestions? (Yes, but the UX needs to handle conflicts.)
- Scenario persistence: scenarios are AFS branches — do they accumulate forever, or auto-prune after N days?
- Naming: “Simulation” implies continuous modeling. Is “Projection” better? Or “What-If Analysis”?
- Cost: a scenario build is a full
jin make. For a 60s inspire build that’s fine. For a 10-minute RMC build, do we need a “fast simulation” mode that only rebuilds affected layers? - Multi-tenant: can a scenario span multiple tenants? (Probably not — tenants are independent AFS instances.)
- Collaboration: can two users work on the same scenario? (AFS branches are git branches — standard git collaboration.)
Numerical neighbors: ← Sense 18: The Ledger — Computational Provenance as Narrative · Sense 19.1: The Simulation Prerequisites →