The Typology · jinflow
A number stops being just a number. It becomes a typed stream the platform can reason about, refuse to misuse, and explain to a human — from the CSV it arrived in to the signal that reads it.
Almost every analytical tool strips a value's type at the CSV boundary and
asks the user to remember. A column arrives as text, gets cast
somewhere in the SQL, and its meaning — is this a
measurement? a currency? can I sum it? — lives only in the author's head.
When a bad value slips in, it surfaces three layers downstream as a
suspicious number with no explanation.
jinflow refuses that. The Typology restores what metrology has known for 150 years: a value is not a number — it is a number + kind + unit + uncertainty + reference standard, and a platform that calls itself transparent should not throw four of those five away. The gates make the restoration enforceable rather than aspirational — they turn "please type your data" into "the build will not proceed on a lie."
A semantic type is not a label at one place — it is the identity of a data stream, invariant under storage, carried through every stage, changing only under a declared conversion. So it is declared at two gates, with the river running between.
the type carried through the edges must equal the type declared at Gold — disagree, and the build stops and names the exact stage
Declaring the same value twice looks redundant — and in the best case it is. But the redundancy is a checksum, like double-entry bookkeeping: the value isn't that the two books agree by construction, it's that a mechanical reconciliation proves they agree.
Seven checks run inside jin make, each catching a distinct
class of untruth. Together they are a compiler for data semantics — every
declaration reaches DuckDB proven correct, or is refused first.
stream: — or a quantity resting on a string floorpassthrough: trueEach gate ships on a ramp: it warns while the discipline rolls out, and flips to stop only when a tenant opts in. A ramp gate can never abort a release on a data-quality finding — the fix for dirty data belongs upstream, and the gate's job is to point at it.
A synthetic tenant is a passthrough — the source column is the Gold column, unchanged. A real hospital feed is not: it renames, casts, aggregates to a new grain, and recodes on the way to Gold. So the reconciler grew a second model — it classifies each source→Gold edge and checks the transformation that edge kind is allowed to perform.
case_token: derived_from: { column: sejour_id, op: rename } cost_center_id: derived_from: { column: cc_demandeur, op: aggregate, agg: mode } start_time: derived_from: { column: prestation_date, op: aggregate, agg: min } case_type: derived_from: { column: admission_code, op: recode, mapping: opale_admission_map } billing_id: # minted surrogate — born, self-rooted, no cite
rollup, not equalityYou can't equate N source rows to one value — but you can check the aggregation is legal for the type. sum demands an additive quantity; mean an averageable one; min/max an orderable kind; mode a representative. This makes rollup load-bearing: declaring agg: sum on a concentration is now a build error.
A Codex standard or a pack-level mapping id. An unlicensed type change is refused — exactly as a passthrough that secretly transforms is refused.
A scaffolder parses the compiled dispatch, traces each column through the CTE chain to its source, and proposes the cite — turning 86 hand-declarations into a review. The same reader becomes the verifier: the declared op must match what the SQL does.
This is not theoretical. The first time the value gate ran on a real hospital's OPALE delivery, it found —
non-conforming boolean values. The Excel export ships French
Oui/Non and a coded G/O
where the type says boolean — values that would have
cast to silent NULLs three layers down and skewed every material-flow
number.
An invisible corruption, turned into a two-line fix — because the gate demanded the value be what it claimed to be, on the real rows, before anything downstream trusted it.
Not archaeology three layers down. A bad value is a warning on the row it arrived in, with the column named.
The reconciliation localizes a conversion bug to the exact stage where a type stopped matching. No more "somewhere in Gold."
Sum a concentration, average an ordinal, min a category — refused. The physics of extensive vs intensive quantities is encoded once and checked everywhere.
No column is typed because its name ends in _km2; no edge is guessed by matching names. Every assertion is a human's, and every assertion is verified against its source of truth.
Types travel with the AFS baked into every snapshot. The receiver needs no ambient knowledge to know what the values mean — the difference between shipping data and shipping science.
Two scaffolders propose the declarations from the source of truth; a human reviews and commits; the build reads literally. 145 columns, 86 columns — proposed, not transcribed.
The Column Passport surfaces the same declarations the gates enforce — kind, unit, standard, how it rolls up, and why the platform refuses to group it. Enforcement and explanation, one schema.
make, all on the ramp; 58 tests lock the contract.The extraordinary part isn't any single gate. It's that the whole path — CSV to signal — is now one continuous, enforced, human-legible chain of meaning. The data stopped being a pile of numbers we hope are right. It became a stream we can prove things about.