Skip to content

Week 18 / 2026 — Foundations week

27 April – 3 May 2026 · 130 commits · 0.46.3 → 0.47.3

Three foundations went in this week — units, diagnostics codes, and the Legend — each filling a hole the project had been working around for months. And while that was happening, the cli/init.py monolith dropped another thousand lines on the way to its eventual ~340-LOC final form. By Sunday night the engine was a different building.

It was a builder’s week. Loud only if you were paying attention.

The Legend (Sense 22) — labels that explain themselves

Section titled “The Legend (Sense 22) — labels that explain themselves”

The week opened with c422776d and 33aaa57e putting Sense 22 on the senses deck — “The Legend: labels that explain themselves.” Tuesday night brought the implementation kickoff in 2025a924: schema, legendcompile.py, tests, the shared normalizers in entitycompile.py. By Thursday Phase 4 was reading structured Legends end-to-end (dd6cad57, 5f8d6d17) and signal/verdict/smebit registries had a classifications_json column (51968f8c). Friday: severity badges on signal detail pages reading their own Legend (9c4c99a1).

What it does: a classification value (severity = “high”, category = “duplicate”, confidence = “medium”) stops being a string the UI has to guess at, and becomes an explained artifact. Icon, color, description, recommended action — all declared in the YAML, normalized through one shared helper, baked into the registry, read by the Explorer. The signal_revenue_leakage.yaml Legend block describes its three severity levels and what to do at each.

Six commits in six days, one phase per commit, each landing without breaking the others. This is what concept → implementation looks like when the concept paper was written before the code.

Wednesday evening, 5311cfd4 shipped what the commit message describes as “the dessert”:

Foundation for what every great compiler system has had for forty years: stable numbered codes, central registry, severity levels, runtime record buffer, numeric summary at end of run.

commands/diagnostics.py introduces Diag(code, severity, description) as a frozen dataclass, CODES as a central registry, and warn() / error() / note() as the new emission API. The naming convention is borrowed from gcc and rustc: E000-E099 fatal, E100+ recoverable, W000-W099 generic, W100+ domain, N000+ informational. The Diagnostics summary at the end of jin make shows numeric rollup + code frequency breakdown + per-code grouped detail.

The migration was incremental and bounded. Five demo callsites on Wednesday (5311cfd4). 45 more on Thursday (a98ac6ee). 19 more + 8 new codes Saturday (eb702c78). --allow=W003 / --deny=W014 / -Werror flags Wednesday night (c380b9b3). --json summary export on Friday (0553896a). By Sunday, jin make finished with a numeric diagnostics summary that a CI system could parse without grep.

The bridge in commands/steps.py_warn(text) → warn(W_UNTYPED, text) — let the ~80 untyped warn callsites keep working unchanged while the migration ran in the background. This is what no breaking changes looks like when the change underneath is fundamental.

Thursday morning, 3ff5767d shipped the UoM foundation — UCUM reference data, validator (uomcheck.py), engine module. Three layers, each owned by its rightful tier:

  • Engine owns universal truth — jinflow/uom/ucum_reference.yaml with 33 canonical units across counted things, mass, volume, length, amount, concentration, dimensionless.
  • Pack owns domain context — packs/<pack>/uoms/{aliases,starter_units}.yaml declares which UCUM units the domain uses and which labels map to which codes.
  • Tenant owns per-catalogue declarations — afs/tenant/seeds/manual_uoms.csv for the cases that pack-level can’t predict.

uomcheck validates all three layers including cross-references: pack starter units must exist in the engine reference; pack aliases must target engine codes; tenant CSV base units must be in the pack starter set. By Friday it was wired into the main pipeline (107993c2).

This is the architecture for a six-month problem the project had been deferring: how does “vials of substance billed in mg administered” become arithmetic the engine can do? The answer is the three-layer cascade. Phase 2 (drug strength conversion) is now a follow-on session, not a research question.

Two parallel renovation tracks ran all week. The first: the cli/__init__.py decomposition, which started life at 12,062 LOC and was below 2,000 by Wednesday. Friday night’s 4d632068“distribute stragglers — target resolvers, git query, SIS helpers” — read like an estate sale:

Twenty helpers move out of cli/init.py to three destination modules, each landing where its primary callers already live […] Monolith: 2,337 → 1,975 LOC (−362, ~83.6% drained from the 12,062 starting point).

By Tuesday morning of W19 it would be under 400. But within W18: Docker plumbing folded into commands/launch.py (a9ee0be1), R2 helpers into commands/r2.py (5eeba306), AFS-git infra into commands/afs.py (ea31f477, 1b299db6), us/ls helpers home (7d80bfd2), config + secrets (3efe0c25), KLS state + DLZ sync (f14b3398). Argparse wiring extracted into its own module (fdec552b). Each commit shrinks the monolith by 300-600 lines and lands without breaking tests.

The second track: cmd_make’s _cmd_make_inner — a ~1,400 LOC state machine — got cracked open into seven phase functions on Sunday. 1c1a89cb introduced MakeContext and extracted phase_0_extract. The five commits that followed (007a6bf3, 9a23939a, e606639b, b2aafed1, 0c92376e, 25341a20) carved Phases 0b → 4 in the same shape. Each phase has a minimal context, a tiny result struct, and a dedicated test file building synthetic AFS shapes on tmp_path. The pattern is the discipline: don’t predict what the next phase will need; let it tell you.

Sunday’s 3c86775f made jinflow afs update and jinflow afs promote separate commands. Pack-back is no longer a --pack flag on inbound sync. Five reasons in the commit message; the load-bearing one is the second: “Sense 20 names promotion as its own act — not afs update in reverse.”

The same operator-friendly impulse landed --pack dry-run support (bf0ccc79) and explicit Pack Scope honoring (a7ee95ed). Promote now reports 46 files (12 new + 34 updated) with 84 skipped by Pack Scope — the user can see what crosses the seam before it crosses.

Three senses got concept papers this week — none implemented, all dated, all sitting in docs/design/ waiting for the moment they’re needed:

  • Sense 21 — The Heartbeat (9a521907). Six beats, five operation modes. “Names the design gap surfaced by the six-day-stranded SIS cell incident.” Vocabulary: make, publish, sync, pulse, reconcile. The day pieces fit together across Local / P2P2P / Cloud / Semi-Cloud / Make-as-a-Service.
  • Sense 23 — The Engine’s Seam (488115eb). “Names the third party Sense 20 didn’t notice: the engine.” Pack and tenant know about each other; the engine has been evolving without asking either of them. Same four invariants from Sense 20, in engine-tenant language.
  • Sense 24 — The Steward (f3c1364b). “Analyst has the Canvas. CFO has Observations. The estate operator has been working in the hallway.” The Steward’s data layer is another tenant of jinflow — turned inward. Five views (Estate Map, Drift, History, Quarantine, Federation), four verbs (observe → understand → decide → act).

Three papers in three days. The Senses sequence is shaping up into a coherent architectural story rather than a backlog.

Playworks finally costs minutes, not hours

Section titled “Playworks finally costs minutes, not hours”

Saturday night’s 8c29f2d4 ended the “30 minutes per spec” era. The complaint, in the commit body: “every spec re-implemented the same boilerplate: seed localStorage so WelcomePrompt bows out, dismiss the PackSplash with Escape, override goto’s waitUntil because SvelteKit’s hot-reload websocket prevents ‘load’ from firing, work around Playwright’s auto-wait colliding with Chart.js’s perpetual ResizeObserver activity. None of that is about what the spec is actually testing.”

The structural fix: ?playworks=1 URL flag that suppresses WelcomePrompt, returns false from PackSplash, removes the early-boot loading splash on mount, sets body[data-playworks="1"] for fixture detection. Plus data-test attributes on the surfaces tests target. Plus a fixture that does the boilerplate once.

This is the kind of work that doesn’t show up in releases. It just makes the next 50 specs viable.

  • Notebook → note rename for the singular artifact (37db0b78). 73 YAMLs in the reference tenant, two in the pack; Explorer queries, dbt models, registries, CLI command, validator messages all flipped. The dir stays notebook/ (a notebook is full of notes). 307 tests pass.
  • Top-bar recents dropdown (42f4369a) — your last few visits, one click away.
  • --offline for jin make (5b1db657) — skip fetch + shared-branch ops when working without a network.
  • Adaptive precision bands for percent + ratio columns (0ba7a6b8). Numbers that read right.
  • Sense 22 search autocomplete from Legend values (13ea5369) — the moment the Legend exists, filtering knows what categories are.
  • [9b482686-from-W09 reprise]: this week’s equivalent was aa71b2a0“panel cell — handoff metadata lookup + preset tab persistence.” Notebook panel cells stopped losing their state on tab switch.
  • c5e66c93: “xlsx_to_csv — preserve row 0 of (N) continuation sheets.” The kind of fix that has a tenant’s quiet sigh of relief behind it.
  • e2478c45: “—skip-extract no longer suppresses canonicalise + enrich.” Misnamed flag, real bug.
  • f9a2479e: “jin afs pull — loop the auto-merge across all rebased commits.” One pull, many commits, all merged.
  • 3a9920e4: “jin make handles gen00→gen02 chain on freshness, regardless of input.” Incremental gating that doesn’t lie.
  • 130 commits, 7 days
  • 4 releases: 0.46.3 → 0.46.4 → … → 0.47.0 → 0.47.3 (the 0.47 minor on Sunday)
  • 3 foundations: Legend, Diagnostics, UoM
  • 3 new design papers: Heartbeat, Engine’s Seam, Steward
  • Monolith: ~3,500 → ~1,700 LOC across the week (still going)
  • cmd_make: 1 monolith → 7 phase functions + MakeContext
  • 24 typed diagnostic codes, 64 callsite migrations
  • 33 UCUM units in the engine reference
  • Tests: ~900 → ~932

The end-of-week shape of the engine is the shape that would carry the next two months. Diagnostics with codes (CI-readable). Units with grounding (drug strengths possible). Classifications with structure (Explorer reads YAML, doesn’t guess). A cli/init.py drained to the point where new commands stop hesitating before being added. A cmd_make that’s testable in slices. Three new senses on the board that name the next problems.

The week after this would be quieter on the commit graph and louder in conviction — Sense 25 (Pack-To-Go), the Funnel, Atelier. The 0.47 line is the line on which those rest.

Foundations, dispatched.

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