Week 11 / 2026 — Shippable
Dieser Inhalt ist noch nicht in deiner Sprache verfügbar.
9 March – 15 March 2026 · 232 commits · 0.4.0 → 0.7.9
This is the week jinflow became shippable. Not “feature complete” — those words don’t fit. Shippable: you could now download a binary on Windows, double-click it, and run a tenant build that produced a KLS without compiling Python, installing dbt, or knowing what a virtualenv is. The release pipeline shipped, the self-contained binary shipped, and Millésime — the second pack, a winery analytics framework with no relationship to hospitals — landed mid-week as proof that the pack architecture actually generalized.
Thirty-three releases in seven days. The version numbers don’t lie about the cadence.
The rename heard around the codebase
Section titled “The rename heard around the codebase”Monday morning opened with 974c3c17 — “Wire KLS to live root, rename NUMETRIX_ env vars to JINFLOW_, migrate system DB to DuckDB”. Three load-bearing changes in one commit:
- KLS files moved out of the engine repo into
<live_root>/<pack>/<tenant>/store/. NUMETRIX_DB_PATH,NUMETRIX_AFS_ROOT,NUMETRIX_TENANTS_DIRbecameJINFLOW_*— the pack-specific name was no longer the product name.- The system DB (operational state) migrated from SQLite to DuckDB. One database engine, not two.
Forty minutes later, 575db423 fixed the foundation flaw the migration surfaced: “Fix KLS naming: use underscore separator (dbt-duckdb splitext compatibility)”. Files named numetrix.<tenant>.duckdb were producing Catalog "x.y" does not exist errors because dbt-duckdb’s filename-to-catalog logic ran os.path.splitext. Underscore separator everywhere. The bug would resurface in memory for the next month, but the fix was here.
The self-contained binary
Section titled “The self-contained binary”By Tuesday afternoon, 16e3899f had shipped what the commit message describes as a “self-contained deployed binary: embedded Python, dbt, and script execution”. PyInstaller, embedded interpreter, all of it. The next sixty hours were a tour of every brittle thing about cross-platform Python:
- d8d0cd03: install full deps including dbt for PyInstaller
- 54e4af02: bundle the domain pack in the binary
- 8e8eb789: bundle
charset_normalizerto fix requests warnings - 326f7d49: bundle requests too (charset detection)
- 71e8f79e: bundle WeasyPrint with native lib discovery on macOS
- 3acf692e: bundle WeasyPrint dependencies, report templates in pack
- 6b9423b3: fix WeasyPrint fontTools bundling in spec
- 350e393a: bundle
anthropicso evolve works on the deployed binary - edaa8821 + deeb556a + 0399034a + 05d2bbb2: Windows cp1252 encoding errors. The whole week. Real ones.
Plus a thousand-pound footnote: 05d2bbb2 shrank the deploy binary by ~1.2 GB. Twelve hundred megabytes that did not need to be there.
By Saturday, 67d9087c had shipped scripts/release.sh — the full release pipeline — and 13afdf36 added the just release recipes with semver bump.
The numbers tell the story. From f7136b35 (0.4.0) on Wednesday to 42e09df9 (0.7.9) on Sunday night: thirty-three releases. Most of them fixing the previous one.
Millésime — the second pack
Section titled “Millésime — the second pack”Wednesday’s 1562eb07 added the Millésime domain pack — winery operations analytics. Three winery tenants, source data shaped completely differently from hospitals, the same signals/theses/dbt skeleton.
The followup commits show the architecture under pressure:
- d0c372d6: millesime gets its own source models directory (a Bronze that knows winery)
- 074dc4c7: millesime probe YAMLs conform to the DSL — same shape, different domain
- dd6596c5 + f5126059: the multi-pack support holes get fixed one by one
- 326365a1 — “Make all 8 YAML compilers pack-generic” — and the engine stops hardcoding
packs/numetrix/paths - b320aafc + 7fc4414d: synthetic data generation goes 8× for the reference winery, taxonomies for grape varietals and appellations
- 58a90317: millesime calibration — defect overlap, wine_id in lab CSVs, age-dependent sell patterns
The big test was Saturday: 08f79a89 added “four millesime reports: vintage quality, customer portfolio, cellar inventory, appellation performance”. The generic PDF report renderer landed the same day (ed794217) so they rendered without per-pack code. The proof: zero changes to the engine to ship reports for a domain it had never seen before.
The reports framework
Section titled “The reports framework”The reports work parallels the binary work. 42a400fa from W10 had committed the “report framework design: YAML-defined reports compiled to KLS”. W11 made it real:
- e9ae81a5 — “generic report framework: YAML-defined reports compiled to dbt SQL”
- 895f89a8 — Explorer generic report renderer for YAML-defined reports
- d98c93f5 — wire the build pipeline + fix io_coefficient probe SQL errors
- 6d1f7e22–6d1f6f22 — “Deprecate numetrix auditreport.py: migrate all 5 report types to YAML”. The hand-written PDF reports get replaced by declared ones.
By Sunday, 71e7b2ef fixed PDF report rendering: “flatten i18n labels, resolve field keys, add missing section titles”. The reports were now declared, compiled, and tri-lingual.
Calamine, atomic builds, three-way drift
Section titled “Calamine, atomic builds, three-way drift”Three engineering changes worth naming:
- Calamine for XLSX (77ca1c33) — Rust binding, ~5× faster than openpyxl. Extractor performance stopped being the bottleneck for any reasonable file size.
- Atomic KLS builds (0cad5ab9) — “Build KLS to temp file + atomic rename to avoid DuckDB lock conflicts.” The Explorer can be reading the file while make is writing the temp file. The atomic rename is the only safe handoff.
- Three-party drift detection (820f43fa) —
jinflow status --tenanttells you whether the pack, the tenant AFS, and the KLS are aligned. The earliest version of the AFS sync model that would later become Sense 21 (Heartbeat).
Two more concepts on paper
Section titled “Two more concepts on paper”- Cloud deployment Tier 0–5 (f2acf5d0) — five progression tiers from “single laptop demo” to “multi-tenant SaaS.” The deployment-mode vocabulary that becomes Sense 16 (P2P2P) and Sense 28 (The Direct Line).
- AFS/dbt separation (13507ea8) — “AFS/dbt separation for read-only AFS during build.” The principle that becomes the foundation of every later build-pipeline cleanup.
Quiet but consequential
Section titled “Quiet but consequential”- DuckDB-WASM mobile spike (0373df27) — Android feasibility test. Held but seeded.
- Cross-pack tenant discovery (b1a1c736) — Explorer finds tenants across packs, becomes contract-driven.
- Health endpoint + Dockerfile healthcheck + Fly.io config (1f1abcf0) — cloud deploy infrastructure pre-positioned.
jinflow resetandtenant/seeds/convention (480ea975)jinflow updateCLI (9b8ef595) + three-way sync (295c7300) — pack↔tenant conflict detection- CSV schema validation L0/L1/L2 (e9ade2f7)
- Declarative calibration system (e6ae1ce0) — all 3 phases at once
Numbers
Section titled “Numbers”- 232 commits, 7 days
- 33 releases (0.4.0 → 0.7.9). The minor bumps trace the shape: 0.4 (binary works), 0.5 (cross-pack), 0.6 (reports), 0.7 (release pipeline + drift)
- 1 new pack landed end-to-end with 4 reports
- 1.2 GB removed from the deploy binary in a single commit
- 1 system DB engine retired (SQLite → DuckDB)
- ~50 PyInstaller bundling fixes; the long tail of “it works on my machine”
- 1 release.sh from scratch
- 1 commit-msg semantic-prefix hook (W12 territory, but the seed is here)
What this week made possible
Section titled “What this week made possible”By Sunday night, jinflow was a thing you could distribute. The binary ran on Windows, macOS, and Linux. It included its own Python, its own dbt, its own pack, its own report renderer. The winery pack had a working analytics product two days after being added to the repo. The cloud story had a Dockerfile and a Fly.io config waiting.
A binary you can hand to someone is not the same as a binary worth handing to someone — but the latter requires the former to exist. This week the former existed.
Next week: the cloud deploy, identity, the proxy, the docs site, the second user.