Repository navigation
v0.2.1 — multi-resource filesystem sources + validated config
v0.2.1
Released: 2026-09-16
Headline: multi-resource filesystem sources + validated config.
A filesystem source used to mean one path, one glob, one table. It can now
declare several named resources and load them all in a single run, tycoon sources add walks you through them, and JSONL joins CSV and Parquet. Config
that was previously guessed at is validated instead — which is the one
change in this release that can break an existing project.
Almost everything here is on the ingestion side. The exception is tycoon city, which now lays the city out by pipeline depth, so a city rendered from
the same catalog looks different from 0.2.0. Details under Landed and
Upgrading from 0.2.0.
Landed
-
One source, many tables. A filesystem source can declare a
resources:list, each entry with its owntable_name,pathand
file_glob. A singletycoon data sources runloads all of them in one
dlt pipeline run, each landing in its own table:sources: arcade: type: filesystem schema: raw_arcade resources: - table_name: arcade_games path: data/input file_glob: games.csv - table_name: arcade_players path: data/input file_glob: players.csv
The older flat
path/file_globshape keeps working exactly as before. -
tycoon sources addprompts for resources. Adding a filesystem
source loops through resource entries instead of accepting a single
path. A table name that isn't a valid identifier, or that repeats one you
already entered, is refused with the reason and re-prompted — rather than
written totycoon.ymland failing later at load time. -
JSONL files are parsed into rows. A
*.jsonlglob pipes through
dlt'sread_jsonl(). Plain.jsonis deliberately excluded: a single
JSON document isn't the newline-delimited shaperead_jsonl()reads, and
falling back with a warning beats parsing it wrongly. -
A glob that matches nothing tells you. A typo'd glob and a source
with genuinely nothing new to load used to look identical — both loaded
zero rows in silence. Local globs that match no files now warn. Remote
buckets (s3://,gs://,az://) are skipped rather than guessed at. -
An unrecognized
file_globwarns instead of quietly loading
metadata. A glob that is neither CSV, Parquet nor JSONL still falls
back to the raw filesystem resource, but now says it is loading file
listings — path, size, modification time — not parsed rows. -
tycoon data analyze --rillworks on an already-scaffolded source.
The already-referenced check used to skip the entire command, so
analyze <source> --rillon a source that already had dbt staging models
produced no dashboards at all — and the only way past it,--force,
would have overwritten the existing dbt files. It now skips just the dbt
scaffolding step. -
The city is laid out by pipeline depth.
tycoon cityplaces gold and
mart schemas downtown and sources on the periphery, so the shape of the
city tells you where a table sits in your pipeline. Each schema is one
neighbourhood on a street lattice; within a ring, the kerb nearest
downtown goes to the schema feeding the most other schemas, then the
larger one, then by name. Streets are drawn where routes and doors need
them rather than everywhere, and every table now sits inside its own
schema's district. Median route length on the dogfood catalog fell from
229 tiles to 36.
Upgrading from 0.2.0
-
Breaking: a filesystem source must declare
pathorbucket_url.
With both missing, tycoon used to fall back to"."and silently scan
the working directory. It now fails with an error naming the source. If a
project relied on that default, make it explicit:sources: files: type: filesystem config: path: data/input # previously implicit file_glob: "*.csv"
-
Filesystem tables are named after the source, not after
read_csv/read_parquet. Two filesystem sources sharing a schema used
to collide into one table; each now lands in its own, named after the
tycoon source. A project with data already in the old generic table gets
a warning naming both tables on every run until the old one is gone. New
rows only go to the new table, so any dbt model still selecting
_read_csvor_read_parquetneeds updating by hand, then the old
table can be dropped. -
schema_versionstays at2— there is no migration to run. -
The city looks different. The ring layout reorders the whole city, so
a render of a catalog you looked at under 0.2.0 will not match your old
screenshots. Thecity.jsoncontract does not change: same top-level
keys, sameversion: 1. Anything reading the export keeps working. -
DATABASE_TYCOON_PLANNERdoes nothing now. It used to opt a run into
the ring planner; that planner is the only one, so the variable is read by
nothing. Leaving it set is harmless. -
Projects scaffolded from the
csv-importtemplate before 0.2.1 carry
a staging model that selects_read_csv. The template is fixed, but an
existing scaffolded project needs the same by-hand update as above.
Known limitations
- The legacy-table warning does not reach multi-resource sources. If
you migrate a flat filesystem source to theresources:shape, the old
generic table is left behind without the warning above — the one
migration most likely to strand a dbt model is the one that stays quiet
about it. Tracked for the next release. - A glob that matches nothing still truncates. The zero-match warning
is warn-and-continue, and the load then runs with
write_disposition="replace", so a previously loaded table is rewritten
to zero rows while every other signal stays green. Tracked in
#240, which
also proposes surfacing it in the run ledger and an opt-in
--fail-on-empty. - The city is a plan, not yet a simulation. The vehicle and guest
simulations run but nothing is drawn, as in 0.2.0. The fix is open as
#250 and lands in 0.2.2. - Coverage milestones are not surfaced yet. The exporter emits an
achievementsblock the renderer still does not read, so a milestone
shows as measured-zero rather than unknown. Fixed in #251, for 0.2.2. - The renderer's test suite is not CI-gated yet. That now includes the
new planner's own tests undertests/tycoon_city/sim, which pass locally
but are excluded from the defaultpytestrun until #256 and #253 land
the gate in 0.2.2. - Remote object storage is still unsupported.
s3://,gs://and
az://are recognized well enough to be skipped by the local-glob check,
but are not a supported source yet.
For contributors
- PR size and title checks run on every pull request, in warn-only
mode: at most 8 counted files, a 500-line cap on newly added
src/**/*.pyfiles, andtype(scope): descriptiontitles carrying a
gh-<N>orPTC-<N>scope. Release-promotion PRs from avX.Y.Zbranch
intomainare exempt. Both checks read their config and scripts from
the base ref, so a PR cannot raise its own limits. - A repository writing-style skill now documents the house style for
documentation, GitHub issues, PR descriptions, release notes and review
notes.
What's next
The rest of the city stream, already open as a stack of draft PRs (#248
through #256): the planner's tests joining the default pytest run, the
vehicle, guest and achievements fixes that 0.2.0 listed as known
limitations, and a CI gate for the web front end. After that, the
layer-aware data CLI (fire, repair, firehouse, data layers,
data health). The ingestion rewrite's M3 (#84) continues alongside.