Releases: datumwise/columna
Release list
v0.14.0 — column identity is the canonical expression, not a mechanical default
WP-NAME-1 (ratified 2026-07-30). Retires the §4 pin-eliding mechanical default. An unaliased series is now keyed by its canonical expression, verbatim — no invented name, no mangle.
avg(revenue @ {day})→ keyed asavg(revenue @ {day})(the input anchor is now visible in the key)revenue→revenue;revenue.sum→revenue.sum(notrevenue_sum— the dot-to-underscore mangle retired with the default)- One rule: identity = canonical expression, or an
ASalias. Composite/nested/map/bracket expressions still take anAS.
WIRE CONTRACT BUMP: contract_version "1" → "2". No values, moods, disclosures, or reason codes change — only the default column key for the same utterance.
Migration — for consumers keying on column names
Unaliased column keys changed from mechanical defaults to canonical expressions (avg_revenue → avg(revenue), revenue_sum → revenue.sum). Key on AS aliases — an alias is author-owned and will never change under any future rule.
Triad: columna 0.14.0 · columna-core 0.14.0 · columna-server 0.8.2 (unchanged — the wire-schema text lives in core; the server re-exports it).
v0.13.4 — the composite input anchor: a product grain is a first-class pin
WP-GRAIN-1 (ratified 2026-07-29). An inline reduction's input anchor may now pin a product of levels — avg(revenue @ {store*product*cal.month}) — not just a single level. The engine's reduce_series_to_anchor was already composite-grain-native; this lifts the planner's single-level restriction and adjudicates the pin × output-anchor lattice.
- Law 1 —
pin_coarser_than_output(REFUSE, minted): a pin coarser than the output refuses with a pin-specific teaching message + two lawful edits. Its own dimension per OF-1. - Law 2 —
redundant_pin(CLARIFY, minted): two cross-comparable pin levels fix one axis, not two. - Law 4 — the two-stage-statistic disclosure, generalized: composite pin renders as a braced product; a same-case rider names the fixed axis and the reduced-over axes. Immaterial note ⇒ serve (an explicit pin is the asker's uttered denotation).
- F1 flip: the lawful-but-unfaithful two-stage statistic is now a well-formed ask that serves and agrees with its below-surface IR to float precision.
Wire contract unchanged — contract_version stays "1" (two reason codes added inside the existing vocabulary; the envelope shape is untouched).
Rowed future finding: the composite-input × faced-output corner meets the G4 chain guard and refuses chained_crossing — a named refusal, never a silent number.
Triad: columna 0.13.4 · columna-core 0.13.4 · columna-server 0.8.2 (unchanged — additive core feature, no wire change).
v0.13.3 — upstream mcp 2.0 broke fresh installs; capped, fixed, and guarded
If you installed Columna between 13:45 UTC on 2026-07-28 and now, and it failed on import — this is the fix. pip install --upgrade columna.
Nothing in this repository changed. The break arrived by resolver.
| when (UTC) | what |
|---|---|
| 2026-07-27 | 0.13.2 published; public launch. columna-server declared mcp>=1.0 — no ceiling. |
| 2026-07-28 13:41:40 | upstream publishes mcp 1.29.0, the last of the 1.x line. |
| 2026-07-28 13:45:28 | upstream publishes mcp 2.0.0, four minutes later. It moves/removes mcp.server.fastmcp. |
| 2026-07-28 ~13:45 → 2026-07-29 | every fresh pip install columna resolves to 2.0.0 and dies at import: ModuleNotFoundError: No module named 'mcp.server.fastmcp', exit 1, before a single mood prints. |
| 2026-07-29 03:47 | our CI goes red on main — on a specs-only merge. That red was the upstream break surfacing. |
| 2026-07-29 | 0.13.3 / columna-server 0.8.2. Fixed. |
Anyone who installed before 13:45 on the 28th is unaffected — their resolver already took a 1.x. The people this hit are exactly the ones the quickstart is written for: strangers, arriving after launch, typing the install-page command for the first time. We are sorry, and we would rather say what happened with timestamps than describe this release as "dependency maintenance".
What shipped
mcp>=1.0,<2.0— resolves to1.29.0. The door is named, not closed: the cap lifts to<3.0when the server is ported to the 2.x import path and the MCP stdio acceptance suite is green against it.- A repo-wide cap sweep — every dependency in every package now carries an upper bound: runtime, optional extras, and build backends.
- A guard that makes it permanent —
scripts/assert_dep_caps.pyruns in CI on every push and PR and fails, naming the offender, if any dependency lacks a ceiling. Twice is a class: an unboundedrequires-pythonon launch eve (0.13.2, found by a human on a Windows pass), an unboundedmcpthe day after (found by CI going red on a commit that touched no code). The third instance should be impossible by construction, not by vigilance. - CI now resolves the server's dependencies from its own package metadata, not from a hand-copied spec. The previous arrangement meant the shipped constraint was never the thing under test — which is how this stayed invisible.
An uncapped dependency is not permissiveness. It is an untested claim about versions that do not exist yet, and it breaks strangers' installs with nothing in the repo changing.
Versions
columna 0.13.3 · columna-core 0.13.3 · columna-server 0.8.2. The umbrella floor moves to columna-server>=0.8.2, so pip install columna cannot resolve to the broken build. No surface, wire, or behaviour change — contract_version stays "1".
Full detail: packages/columna-server/CHANGELOG.md (0.8.2) and packages/columna-core/CHANGELOG.md (0.13.3).
Columna 0.13.2 — the declared Python floor and ceiling: 3.10–3.13, 64-bit
Packaging release. No engine, wire, or contract change — contract_version stays "1".
columna 0.13.2 · columna-core 0.13.2 · columna-server 0.8.1
Why
A Windows fresh-venv pass found pip install columna on Python 3.14 not failing but building — a C++ source build of datasketches, which columna-core hard-depends on for HLL. datasketches 5.x publishes no cp314 wheels on any platform and no 32-bit Windows wheels at any version. With requires-python unbounded above, pip considered us a match, found no wheel, and fell through to a compiler.
Fail closed with a named reason beats rare success for whoever happens to own a compiler.
What changed
requires-python = ">=3.10,<3.14"on all three packages. pip now refuses cleanly —no matching distribution found— before dependency resolution ever reaches datasketches.- Classifiers name 3.13, which was supported and shipped but never advertised. CI's test matrix gains 3.13 in the same change.
- The supported line is written down — "Requires Python 3.10–3.13, 64-bit." — on the install page and both front-door READMEs, each with a troubleshooting line pointing the symptom at its cause.
demo --playno longer crashes on Windows. Piping or redirecting its output died withUnicodeEncodeError: 'charmap' codec can't encodeon the opening line, before a single mood printed: Python falls back to the locale encoding (cp1252) the moment stdout is not a console, and our output is legitimately non-ASCII.columna-servernow declares UTF-8 on stdout/stderr for every subcommand. This bug was found by the new Windows CI leg on its first run.
The guard
demo wheel install now runs windows-latest / py3.13 beside ubuntu / py3.10. The class — a dependency with platform or version wheel gaps — was invisible to a Linux-only CI, which is how this survived three releases. Both legs run the same assertion file so they cannot drift into proving different things. A second guard, test_demo_play_survives_a_cp1252_stdio_locale, reproduces the Windows failure on any platform via PYTHONIOENCODING=cp1252.
The door
Python 3.14 support arrives when datasketches ships cp314 wheels, or via the optional-extras split (datasketches/duckdb optional, with a polite refusal at point of use) scoped as WP-1.1 — rowed, not rushed.
Columna 0.13.1 - the reconciliation delta reports at the resolution its tolerance warrants
A recorded exhibit was changing by itself. This fixes it at the true cause and adds the structural guard so the class cannot recur silently.
The defect
The /case alloc reconciliation badge rendered delta 0.0000 on most runs and -0.0000 on ~20% — same package, same input, same machine. It reached a byte-preserved artifact, so an exhibit that may change only by re-recording was in fact changing on a coin flip, every deploy. The committed value was not correct; it was merely the side the coin had landed on in CI.
Misdiagnosed twice, then measured
Both first diagnoses said "signed zero." Both were wrong, and the fix derived from them provably does not work:
raw_delta= 4.656612873077393e-10 is_exactly_zero=False formats=0.0000
raw_delta=-4.656612873077393e-10 is_exactly_zero=False formats=-0.0000
raw_delta= 0.0 is_exactly_zero=True formats=0.0000
The value alternates between exactly 0.0 and ±2⁻³¹ — a sub-epsilon residue that flips sign. x if x != 0 else 0.0 therefore passes it through untouched. Implemented and measured: the flap survived at an unchanged rate (5 × -0.0000 of 20).
The epistemic failure is the point, and it ran in both directions: the builder reported a symptom name rather than a measured value, and the desk ruled on the report. Neither had looked at the number. Readings do not verify each other — and a symptom named in a report is still a reading.
The fix — at the cause, at the point of computation
def canonical_delta(delta: float, tol: float) -> float:
return 0.0 if abs(delta) <= tol else deltaabs(delta) <= tol is exactly the condition under which the engine has already ruled status: "reconciles".
The doctrine: a value below the system's declared tolerance is noise, not a finding — reporting it as a finding is false precision. Below its own declared resolution of meaning, the residual bits are non-reproducible summation noise (~2e-16 relative to a $2.2M total). Serving them as data is false precision, which is a species of confident wrong number — small, but the masthead does not say "no large wrong numbers."
Canonicalized where the delta is computed, not at the formatting boundary: the structured reconciliation.delta must be canonical too, or a consumer reading the number gets the artifact even when the prose does not.
No laundering — the load-bearing half: a delta OUTSIDE tolerance keeps its exact value and its sign, asserted by test. The guard must never quietly absorb a real shortfall.
Root cause, and what was rejected as a fix
Float summation order. Pinning threads was tried and rejected: it did not remove the flap and in fact inverted its distribution (9 × -0.0000 of 15). That is evidence of the cause — and its own argument against suppressing a symptom while leaving the class alive. We do not pin threading to hide a coin flip.
The structural guard
apps/website/scripts/check_generator_determinism.py — every committed-output generator runs twice and must be byte-identical. Non-determinism in a recorded artifact becomes a loud, named build failure instead of a 20%-of-deploys surprise. Wired into the deploy workflow. It fails closed and names its reason (proverb 5; AW-6's lesson) — never a sentinel, never a bare traceback.
Verified: STABLE gen_case.py (26312 bytes, 4 runs byte-identical).
Wire change, named not silent
Within-tolerance reconciliation deltas now canonicalize to 0.0, in both the prose and the structured field. In-tree consumers only. No contract_version bump — the envelope and the four moods are untouched. Named here per the standing rule: removal-and-change is always named, never silent.
Release
core 0.13.1 / 0.13.1-core · umbrella 0.13.1 pinning columna-core>=0.13.1 · columna-server 0.8.0 unchanged (its >=0.13.0 floor already admits the patch) · deploy pin moved to the 0.13.1 triad, publish-first-as-installable on the verbatim-pin gate.
Provenance — the honest history of a defect
Flagged at the #85 preview → ordered for the 0.12.1 cargo → never landed → resurfaced as a flap during the 0.13.0 confirmation re-record → misdiagnosed twice, once by the builder and once by the desk → measured → fixed at the true cause.
Verified: 20/20 runs now 0.0000; suite green.
Columna 0.13.0 — the ASSERT retirement
BREAKING. ASSERT (both forms) and standalone ATTR … ON <universe> are removed from the definition language.
Migration: delete those lines from your .cml. The parser's refusal names this note.
- The describe wire no longer emits
asserts, the universes'attributes, orpublished_scope.cut/cut_by. conflicting_datarefusals can no longer occur; the reason code is tombstoned, not reused.- Rationale — the admission test: everything a Manifold's trial proves is a precondition of something it serves, and a data contract licenses no serving behavior. Contracts belong to the attestation layer, upstream of the Manifold. (Ruling 2026-07-26.)
The triad: columna 0.13.0 (umbrella) · columna-core 0.13.0 · columna-server 0.8.0 — its own track, because the describe surface changed.
columna-server 0.8.0 requires columna-core>=0.13.0 as a FLOOR: its insulation tests assert a wire that only core 0.13.0 produces.
Multi-universe alignment (P1), previously 0.13, renumbers to 0.14 unchanged in scope — ruled, not drifted.
Columna 0.12.1 — category-driver descriptions (data-only)
Data-only patch: the two category-profile driver measures gain their describe descriptions.
priority and alloc_weight shipped 0.7.0 with empty descriptions — their folklore was written on the line after the MEASURE, which the parser (a DESCRIPTION lives on the header, before the FAMILY block) does not read. Moved inline and ratified:
priority— the category's assignment rank — 1 ranks first; drives the primary facealloc_weight— the category's relative allocation weight — normalized per product at the crossing; drives the split face
So describe_manifold, the Explorer, and the spec all carry them. No parser change (the placement was the defect); no wire-schema, no contract change.
Versions: columna-server 0.7.1, columna (metapackage) 0.12.1; columna-core unchanged (0.12.0). Requires columna-core>=0.12.0.
Columna 0.12.0 — the triad completes (assign · alloc faces + the anchor law + the third universe)
The RELATE face triad completes — assign and alloc join the shipped touch — and Cascadia gains its third universe.
columna-core 0.12.0
- Grammar.
FACE <name> = ASSIGN BY <measure-ref> ORDER MIN|MAXandALLOC BY <measure-ref>. ORDER is mandatory on ASSIGN, no default (a silent default would be an unrecorded resolution). The driver is a DECLARED measure, resolved at publish. - Engine.
ASSIGNrestricts the bridge to each member's top-ranked pair and single-counts (total reconciles to the grand total; the shadow of dropped memberships is disclosed).ALLOCsplits by the per-member-normalized driver (reconciles to the cent; the reconciliation badge is the commutation certificate).touchunchanged. - Adjudication (fail-closed, per scheme). assign — a unique top per member; alloc — non-negative driver, strictly-positive per-member sum; the driver must be a spine at the frontier grain; a face-driver dependency DAG.
- Anchor law (G5) — a distinct-class measure refuses at every face uniformly. Chain guard (G4) — a multi-hop face path refuses; one frontier at a time.
- Wire (additive;
contract_versionstays"1").relates[].faces[]gainsdriver; assign answers carrymemberships_unrepresented; alloc answers carryreconciliation {…}.
columna-server 0.7.0
- Third universe.
UNIVERSE category_profile = category BASIS spine(12-rowcategory_attributes, md5-deterministic) with two driver measures. The RELATE declaresprimary = ASSIGN BY priority ORDER MINandsplit = ALLOC BY alloc_weightbesidetouch. - Exhibits. E11 (
revenue AT {category.primary}) discloses the shadow (270 memberships; total ≡ the grand total $2,212,391.86); E12 (revenue AT {category.split}) serves with the reconciliation badge (total ≡ the grand total to the cent). - Site. Figure 1 draws the two universes it is taught and discloses the third on the figure itself (interim, fail-closed preserved); the /case chapter carries a lockstep forward-reference to
category_profile.
Requires columna-core>=0.12.0. Design history: docs/proposals/0.12-triad-PROPOSAL.md.
Columna 0.11.1 — warehouse coherence + the framework description
Columna 0.11.1 — release notes (RATIFIED, Huayin, 2026-07-19).
Warehouse coherence (columna-server 0.6.1, data-only)
A patch that makes the Cascadia demo warehouse cohere with its own transaction ground truth. A stranger-read of the generated exhibits (verified at the desk) found the reference and summary tables had drifted incoherent with the facts: customer FK coverage was 2,051/19,995, and the stale summaries ran 10–15× off base truth — which contradicted the burn story, where the summaries are meant to be plausibly wrong, the kind nobody notices, never wild.
The fix keeps the doctrine intact: transactions and eom_inventory are the ground truth and stay untouched — every recorded number delivers from them, and the E1–E10 seeds and both transcripts' figures are byte-stable across the regen. The reference and summary tables are regenerated derived-then-degraded: the warehouse now derives its lies from the truth — each summary computed from base fact, then wearing exactly the one story-sin it exists to teach (a customer base that covers the full id space — ~10,157; a daily-revenue summary true but for its 15 missing days; an "order value" that quietly divides by transactions; a visitor count double-counted per store; an inventory total that illegally sums a stock across time). A new permanent suite asserts the coherence — 100% FK coverage, each summary within its declared-sin tolerance of base truth — so the class can't recur.
Metapackage description (columna 0.11.1)
The positioning correction reaches the package index: the columna metapackage description moves from "honest metrics engine" to the ratified framework line — an honest data framework (Manifold, FrameQL, an honest engine).
columna-core is unchanged at 0.11.0.
Columna 0.11.0 — RELATE faces: the many-to-many crossing executes
body chars: 5633
�� release notes (RATIFIED, Huayin, 2026-07-19).*
Columna 0.11.0
The many-to-many crossing executes — the overlap counted, and stated.
0.11.0 is the release where the RELATE — the anti-edge, the relationship that declares "connected,
and no lawful rollup exists" — stops merely refusing a category rollup and starts answering one,
lawfully. A relationship may now declare faces: named crossing dispositions. The first,
touch, executes. columna-core reaches 0.11.0; columna-server reaches 0.6.0.
The crossing executes (columna-core 0.11.0)
RELATEdeclares FACES.RELATE a <-> b VIA t(fcol, tcol) FACES { touch = TOUCH -- "folklore" }.
A face names the value's disposition on the trip across a non-functional (M:N) edge — the
self-teaching verb triadtouch(the value reaches every match),assign(it goes to exactly
one),alloc(it splits across) — never the selection criterion, which lives in the declaration.
The bareVIA <table>form is unchanged, so existing manifolds parse byte-identically.touchexecutes;assign/allocare declared-but-deferred.SELECT revenue AT {category.touch}
join-multiplies the measure through the relationship's bridge to the crossed grain: the value reaches
every category a product sits in, deliberately multi-counted, served in disclose with the
over-count as a material caveat.assign/allocparse to an honest, fail-closed refusal — v1 executes
touchonly. The bare{category}stays barred and now clarifies with the face menu.- The two skews of a crossing, both disclosed. Over-count (per-bucket totals overlap; the sum
exceeds the grand total) and its mirror, coverage/shortfall (a fine entity in no bucket is excluded
from every cell, so the total can fall short). The crossing reports its coverage either way. - Crossed-grain absence is a lawful zero — events basis only. On an events population the expansion
is honest arithmetic; on a spine/grid, replication would corrupt the grid's own completeness claim, so
the crossing is refused there until that thinking lands. - Adjudicated at publish, under the polarity law. A face is closed by default; its license opens
the crossing, minted only by the adjudicator (never on parse).touch= VERIFIED — membership
expansion is exact arithmetic, no partition-of-unity to reconcile. - The
VIAbridge is map-layer. Engine-visible (the join-multiply needs it), describe-invisible — it
never ridesrelates[]or any wire; the insulation test asserts it.contract_versionstays"1".
The crossing goes visible (columna-server 0.6.0)
describe_manifold'srelates[]gainsfaces[]— each declared disposition rides describe as
data ({name, scheme, description}), so a consulting agent and the clarify-menu see it from the source
of truth. Additive;contract_versionstays"1".- Cascadia declares
FACE touch. The demo shows the crossing:SELECT revenue AT {category}
clarifies with the face menu;SELECT revenue AT {category.touch}executes — 12 categories, touch
total $3,182,555.97 against the single-count grand total of $2,212,391.86 — about 1.44×. That ratio
is not noise: it is the bridge's own fan-out, 870 memberships over 600 products, made arithmetic. The
over-count is the fan-out, and the answer says so — plus the coverage line, 600/600, no shortfall. - The recapture corpus grows to ten (E1–E10). E6 records the face menu (the ask, with its reason and
the way forward); E10 mints the executed crossing (the answer — disclose, over_count, coverage). Zero
drift flags.
The site, re-sequenced (reader-discipline applied to assembly)
The reader-discipline law — narrative order is epistemic order — now governs page assembly, not just
chapter prose. One role per surface, one introduction total, every exhibit seated where the reader has
earned it: the homepage reduces to a single line and a route (the recording is the case); /case
becomes the case study literally, its three chapters the page in order with every generated exhibit
moved into its story position (the fourteen tables where the data is met; the two artifacts where the
design is derived; and in the live chapter, build → inspect → use — the trials, then the Explorer
seated between the claims tried and the claims used, then the questions and the four moods as the
payoff); /explorer keeps its role as structure, never a second intro. The exhibits are re-seated by a
render-time split — the chapters stay byte-identical to the ratified charter across all three surfaces.
The honest ledger
The next faces are on the record, not promised: assign (the canonical pick) and alloc — the crown,
the partition-of-unity that makes per-bucket totals reconcile, with the shipped WITH allocation
grammar as its parameter. The spine-basis crossing (replication on a grid) waits on the spine-grid
domain source (OF-5). And the primary post-launch language road, carried forward from 0.10.0,
remains OF-13 — native coordinate-value predicates in WHERE (region = 'west'), the universal SQL
reflex the interim anchor-and-read prompt law stands in for and retires when the native filter lands.
Language-first: OF-13 fixes it for every consumer, not just our own agent (OF-15 is its secondary, agent-only, sibling).
The whole crossing — the declaration, the menu, the executed answer with its overlap stated — ships in
the Cascadia demo. pip install columna, and ask for revenue by category yourself.