Aller au contenu

The Simulation — From Recommendation to Modeled Impact

Ce contenu n’est pas encore disponible dans votre langue.

Severity says how loud. Capability says who may act. Relevance says for whom this fires. Simulation answers what happens if.

The Simulation (Sense 19) is the last rung in the jinflow Experience: the path from noticing something is wrong (Signals → Theses → Verdicts → Observations) all the way through modeling the world that would result from acting on it (Suggestion → Intervention → Scenario → Simulation).

This page is the architectural companion to the Simulation guide. The guide walks a user through authoring + building + comparing; this page names the structural choices that make that work.


Most analytics tools collapse “what to do” and “how to do it” into a single recommendation field. That conflation breaks the moment you want to try the same change against last quarter’s data, or combine three independently-authored changes into one scenario, or have an analyst propose a recommendation that a pack author later realises in two different deterministic forms.

jinflow splits them four ways:

NounTierMutabilityShape
SuggestionA-tierfree-floating prosewhat to do (recommendation)
InterventionB-tierdeterministic edithow to do it (mechanism)
Scenariogit branchcomposedan analytical world
SimulationKLS filecomputedthe evidence

The Suggestion ↔ Intervention split mirrors Sense 15’s Observation ↔ Explanation split: prose layer (intent) above mechanism layer (execution), with a soft FK between them. The Scenario ↔ Simulation pair is reality vs. evidence — the branch declares the world, the KLS measures it.


A-tier vs B-tier — the structural choice

Section titled “A-tier vs B-tier — the structural choice”

This is the single most important architectural decision in Sense 19.

Suggestions are A-tier — they live on the suggestions orphan branch alongside notes, bookmarks, recents, and bell resolutions. That means they’re naturally shared across every scenario you create. The same Suggestion remains visible whether you’re on main, scenario/lower_thresholds, or scenario/zeta_onboarding — because the orphan branch sits outside the scenario DAG entirely.

Interventions are B-tier — they live on whatever branch you authored them on. main and each scenario carry their own intervention set. The same Suggestion can spawn different Interventions on different branches — that’s not a bug, it’s the mechanism by which scenarios are different.

If we’d made Interventions A-tier too, every scenario would inherit every Intervention ever authored — and you’d lose the ability to say “this scenario applies exactly these three interventions.” If we’d made Suggestions B-tier, you’d have to re-author the same recommendation on every branch you wanted it visible on. Splitting them was the move that made the whole chain compose cleanly.

tenant AFS git repo
├── main ← B-tier home (smebits, signals, interventions)
├── scenario/lower_thresholds ← B-tier alternative (different interventions applied)
├── scenario/zeta_onboarding ← another B-tier alternative
├── notes ← A-tier orphan
├── bookmarks ← A-tier orphan
├── recents ← A-tier orphan
├── bell ← A-tier orphan
└── suggestions ← A-tier orphan (joined the family 2026-05-22)

A scenario reads its B-tier from its own branch and its A-tier from the orphan branches. Compare against another scenario or production swaps the B-tier while the A-tier stays identical.


A built KLS — production or scenario — carries the artifacts of Sense 19 in four tables, all under the tenant’s meta schema (_<tenant>):

TableSourcePopulated when
suggestion_registryafs/suggestions/*.yamlAlways (orphan branch is pulled into the working tree at Phase 1c of jin make)
intervention_registryafs/interventions/*.yamlAlways (the file is on whatever branch is being built)
scenario_metadataThe scenario branch’s commit messageOnly when building from a scenario/<id> branch
notificationsThe Bell aggregator (Sense 33)Always

The asymmetry — scenario_metadata only on scenario builds — is the feature-detection mechanism the Compare UI uses to distinguish scenario KLSes from snapshot KLSes. A KLS that has scenario_metadata rows is a scenario; one that doesn’t isn’t.


The Phase 2 verb jin scenario create is mostly orchestration. The load-bearing piece is jinflow/scenarios/apply.py::apply_intervention() — the deterministic yaml_edit walker.

Three guarantees:

  1. Deterministic. Same intervention + same starting file → same output. No randomness, no network, no system clock.
  2. Drift-checked. Every change carries a from value the intervention expects to find at the path. Mismatch → refuse to apply. This is what makes interventions reliable across time: if reality drifted, you find out at apply, not at simulation.
  3. Format-preserving. Uses ruamel.yaml for round-trip read + write. Comments survive. Key order survives. The diff against base is exactly the bytes the intervention changes — reviewable as a one-line PR even when the target file has dense formatting.

The path syntax is dotted-with-bracket: thresholds.amount_chf for nested dicts, severity_rules[0].severity for list elements. The apply refuses to create missing keys — an intervention can’t invent a new top-level field. That’s an artifact_add-shape change, which Phase 2 doesn’t implement.

The apply refuses absolute target_file paths and any path containing .. segments — defense in depth before the load-bearing filesystem write. The Phase 1 checker (interventioncheck.py) catches these at author time; the apply re-verifies because defense in depth matters when the load-bearing operation is a file write.


A scenario is a git branch named scenario/<id> in the tenant AFS, nothing more. Its uniqueness is captured by:

  • The base — what it was forked from. Recorded in the structured commit message as Base: <branch>@<sha8>.
  • The interventions applied — listed in the same commit message under Interventions applied:.

create_scenario’s commit-message shape is the authoritative record of “this is what made the scenario.” It’s git’s canonical history of that act, and the Phase 4 metadata bake reads it back to populate _<tenant>.scenario_metadata.

Why commit-message-as-source-of-truth rather than a baked manifest file inside the AFS? Three reasons:

  • Git already records who, when, with what commit message — we’d be duplicating its job.
  • A manifest file would itself be a B-tier artifact that intervention-edits could accidentally modify.
  • Amending the commit (a normal git operation) needs zero bookkeeping — the bake reads whatever’s there at make time.

The trade-off: if someone amends the commit message into an unstructured shape, the bake silently no-ops rather than write a partial row. The check has explicit assertions; the contract is “the structured shape is required for the metadata to land.” A future verb that re-bakes metadata from a sidecar file could exist if the constraint ever bites; today it doesn’t.


A simulation is just jin make on a scenario branch. The existing --branch flag for jin make already does the heavy lifting:

  1. Creates a temporary git worktree at the requested branch
  2. Runs the full make pipeline against the worktree
  3. Writes the KLS to a branch-named path: <pack>_<tenant>_<safe_branch>_kls.duckdb

Where safe_branch is the branch name with / and \ replaced by _. For scenario/tighter, that’s scenario_tighter. The resulting KLS filename is <pack>_<tenant>_scenario_tighter_kls.duckdb.

jin scenario build <id> is a thin wrapper over jin make --branch scenario/<id> — it exists for ergonomics and to catch missing-branch errors earlier (clearer message than what jin make would surface).

The KLS-naming convention is pinned in two places:

  • make.py line ~2136 (the source of truth — where the build writes)
  • scenario.py::_scenario_kls_path() (where the list verb looks for build status)

The test test_scenario_kls_path_convention enforces both stay in sync. Drift would silently break “is this scenario built?” detection in the list verb.


JinDesk’s /[tenant]/compare route reads every *_kls.duckdb in the store. For each, it opens read-only, queries summary stats, and (Phase 4) queries _<tenant>.scenario_metadata to see if the KLS is a scenario.

KLSes with baked scenario metadata are routed to the “Scenarios” optgroup in the version-selector dropdowns; the rest land in “Production.” A scenario card renders an amber panel listing the interventions applied + a “Compare to production” shortcut that sets the other side to the working KLS.

No new infrastructure was needed in Compare — the snapshot- comparison machinery already supported arbitrary *_kls.duckdb files. The Phase 4 work was just teaching it to read one extra table and group the rows accordingly.


LayerPathRole
Contractscontracts/suggestion_contract.v1.json, contracts/intervention_contract.v1.jsonJSON-Schema declarations
Checkersscripts/suggestioncheck.py, scripts/interventioncheck.pyPre-bake validation, security checks on target_file
Apply mechanismjinflow/scenarios/apply.pyDeterministic yaml_edit, drift check, ruamel round-trip
Scenario creatorjinflow/scenarios/create.pyBranch + apply + commit with rollback
Bakersjinflow/cli/commands/baking.py::bake_suggestion_registry, bake_intervention_registry, bake_scenario_metadataSource YAMLs → KLS tables
CLIjinflow/cli/commands/scenario.pyjin scenario create / build / list
JinDeskexplorer/src/routes/[tenant]/compare/*Optgroup, scenario panel, Compare-to-production button
Sense docdocs/design/sense_19_the_simulation.mdCanonical specification, all four phases

  • Not a recommender system. Suggestions are authored by humans (analysts, pack authors, automated agents in the future). The Bell, the Atelier, and the Notebook surface suggestions; nothing invents them autonomously.
  • Not a database migration tool. Interventions are deterministic YAML edits. They don’t run SQL, don’t migrate schemas, don’t modify the KLS. The KLS is computed from the post-intervention AFS by jin make, the same way production builds from main.
  • Not a what-if calculator. Scenarios run the full analytical pipeline — the same compilers, the same validators, the same signal-finding emission. The simulation result is as trustworthy as production because it is production, just against different inputs.
  • Not a permissioning surface. Capability gating (Sense 25) and identity (Sense 18) compose orthogonally with this. Authoring a Suggestion requires the same write capability as authoring a note; creating a scenario requires the same as branching the AFS manually.

  • Sense 15 (Observation/Explanation) — the prose/mechanism split repeats one level up. Observation is to Explanation as Suggestion is to Intervention.
  • Sense 25 (Identity & Passes) — controls who can author + who can apply. The verb-level capability gate.
  • Sense 31 (The Inlet) — the source-data pipeline a scenario rebuilds with. Channel-level changes can themselves be an Intervention type (channel_change, not yet implemented).
  • Sense 33 (The Bell) — surfaces things the system noticed. A future verb jin bell acted-via sug_X closes the loop: acting on a ring by authoring a Suggestion.
  • Sense 37 (The Snapshot) — a scenario KLS is, conceptually, a snapshot of an alternative world. They share the _<tenant>.snapshot schema and the same Compare machinery.
  • Sense 38 (The Scribe) — when a viewer creates a scenario via a future cloud-JinDesk, the Scribe identity governs the commit attribution.

  1. Scenario lifecycle. Today scenarios are git branches with their own KLS files. Should they auto-prune after N days of inactivity? Get adopted into main with a verb? Versioning policy is not yet specified.
  2. Compound scenarios from multiple suggestions. A Suggestion can spawn multiple Interventions. A Scenario can apply multiple Interventions. But can a Suggestion be referenced from multiple Scenarios? Today yes (the Suggestion is orphan-branch, free-floating); the UX for “show me all Scenarios derived from sug_X” doesn’t exist yet.
  3. Non-yaml_edit Intervention types. The contract enumerates five (yaml_edit, artifact_add, artifact_remove, config_change, seed_edit); only the first is implemented. The others land when the use case arrives.
  4. Scenario sharing across machines. Scenarios are git branches — they push and pull like any other. But the scenario KLS is a build artifact; it doesn’t travel via git. Two analysts wanting to share a simulation need to either both build, or use the existing snapshot-sharing affordances.
  5. The “What if?” inline UX (Phase 5). A button on a Verdict detail page that flows through to scenario authoring + background build + notification + Simulation Results view. Substrate is ready; UI not built.

A jinflow analysis tells you what is happening. A thesis tells you why. A verdict tells you the root cause. A simulation tells you what would happen if you fixed it. The loop closes.

jazzisnow jinflow is a jazzisnow product
v0.64.7 · built 2026-09-20 19:48 UTC