docs: add ubiquitous language, QFD design, and ADRs
This commit is contained in:
26
docs/adr/0001-detected-feedback-loops.md
Normal file
26
docs/adr/0001-detected-feedback-loops.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Feedback loops are detected from a polarity-annotated graph, not stored
|
||||
|
||||
A **Feedback Loop** in a **Model** is a cycle in the wiring (Stock → Information
|
||||
Link(s)/Flow → same Stock). We chose to **derive** loops by detecting cycles and
|
||||
classifying each as **Reinforcing** (even number of `−` polarities) or
|
||||
**Balancing** (odd), rather than storing them as first-class objects the user
|
||||
hand-labels. This makes loops *discovered insight* that can never disagree with
|
||||
the actual structure — the point of a systems-thinking tool.
|
||||
|
||||
## Considered Options
|
||||
|
||||
- **Hand-labeled annotation** — user drops a loop badge and tags it R/B. Simplest,
|
||||
but the label carries no structural truth and can contradict the wiring.
|
||||
- **Hybrid** — app detects the cycle exists; user assigns R/B. Removes the
|
||||
inconsistency risk only partially and makes the user do reasoning the app can do.
|
||||
- **Detected from structure (chosen)** — app finds cycles and classifies them.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Every **Information Link** must carry a **Polarity** (`+`/`−`); inflows/outflows
|
||||
carry inherent polarity. This is a required field from the diagram phase on.
|
||||
- There is **no `Loop` entity** in the data model — loops are computed, not
|
||||
persisted. A future reader seeing polarity on every link and no stored loop
|
||||
should look here.
|
||||
- Requires cycle-detection + sign-product logic. The same polarity data is
|
||||
reused when numeric simulation is added later.
|
||||
22
docs/adr/0002-vue-flow-substrate.md
Normal file
22
docs/adr/0002-vue-flow-substrate.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Vue Flow is the editor substrate; the domain Model is the source of truth
|
||||
|
||||
The editor is built on **Vue Flow** (`@vue-flow/core`) for pan/zoom, node
|
||||
dragging, handles, edge-drawing, and selection, with Stocks/Flows/Converters/
|
||||
Clouds as custom Vue node components. We rejected hand-rolling an SVG editor (too
|
||||
slow to the friction goals F1–F3) and heavier kits (AntV X6, mxGraph — not
|
||||
Vue-3-native).
|
||||
|
||||
The constraint that makes this safe: the **domain `Model` is the single source of
|
||||
truth; the Vue Flow graph is a derived projection of it, never the reverse.** All
|
||||
writes go through store actions that mutate the `Model`; the Vue Flow view is
|
||||
re-derived. The future simulator reads the `Model` and has no knowledge of Vue
|
||||
Flow.
|
||||
|
||||
## Consequences
|
||||
|
||||
- A **projection layer** (Model → Vue Flow nodes/edges, and Vue Flow events →
|
||||
store actions) must be built and kept thin. This is the price of the dependency.
|
||||
- Swapping the rendering substrate later means rewriting only the projection +
|
||||
node/edge components, not the domain model or the simulator.
|
||||
- A reader wondering "why is there a sync/projection layer instead of editing Vue
|
||||
Flow state directly?" should look here: it protects the simulate-later constraint.
|
||||
20
docs/adr/0003-flow-as-node-materialised-clouds.md
Normal file
20
docs/adr/0003-flow-as-node-materialised-clouds.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# A Flow is a node; Source/Sink clouds are materialised nodes
|
||||
|
||||
In the domain `Model`, a **Flow** is a *node* carrying `source` and `target`
|
||||
references (each to a Stock or Cloud), not an edge. The pipe you see is *rendered*
|
||||
from those references. The **Source/Sink** boundary is a **materialised Cloud
|
||||
node**, so every Flow connects node→node uniformly — no `null` ends.
|
||||
|
||||
We rejected modelling a Flow as an edge (it breaks "an Information Link targets a
|
||||
Flow," since edges can't be edge endpoints, and it muddies the simulator) and
|
||||
rejected `null`-ended flows (special-casing in every graph walk and in rendering).
|
||||
|
||||
## Consequences
|
||||
|
||||
- The only stored edge type is the **Information Link**. Flows and Clouds are
|
||||
nodes. A reader seeing a "node that renders as a pipe" and "phantom cloud nodes"
|
||||
should look here.
|
||||
- **Cloud lifecycle** must be auto-managed: spawn a Cloud when a Flow is left
|
||||
open-ended; remove it when the Flow attaches to a Stock; never leave orphans.
|
||||
- Loop detection and the future simulator both walk a uniform node graph
|
||||
(info-links + flow→stock edges), with no boundary special cases.
|
||||
Reference in New Issue
Block a user