Skip to content

v0.14.0

Latest

Choose a tag to compare

@github-actions github-actions released this 06 Oct 16:24

Reach an enclosing level from inside each and flatten with ^. and $. (sl-8vqk, ADR-053)

Every path inside an each, flatten or nested-arrow block is relative to
the block, so there was no way to name a field from an enclosing level. The
"parent's field populates each child" case had to be written as a note,
which coverage and lineage cannot follow. Two prefixes now escape the rule:

  • ^.field goes up one level per ^.. Inside each lines inside
    each orders, ^.order_no is orders.order_no, and ^.^.id goes up two.
  • $.field starts from the schema root, whatever the depth.

A bare field or .field resolves exactly as before. Whether an escaped path
names a declared field is still checked by field-not-in-schema. The CLI,
coverage, the visualisation and the LSP all resolve escaped paths the same
way, and go-to-definition works on them. examples/ancestor-escape/ shows
both prefixes in a nested each.

A path that misses inside a block now says how to fix it, and the tutorials no longer teach the mistake (gh-525)

When an arrow inside a block fails field-not-in-schema and the path does
exist at an enclosing level, the message now names the block and suggests the
^. or $. spelling. The CLI and the language server share the message.

The BA tutorial and lessons 07 and 14 taught Order.OrderId -> order_id
inside flatten Order.LineItems, which resolves to
Order.LineItems.Order.OrderId and fails validation with a message that
looked like a tooling bug. They now use ^., and the prose explains why
paths in a block are relative. The spec, agent reference, language skill and
Excel prompt are corrected too. A new check, scripts/check-doc-snippets.mjs,
validates every each/flatten snippet in the tutorials, lessons and
nested-data guide through the CLI, so the docs cannot drift from the language
again.

A leading dot at mapping level now means the schema root (tced-ewd4)

satsuma coverage crashed with Schema-local path must not be empty on any
mapping containing a top-level each <list> -> .<target>. A leading dot at
mapping level now resolves against the schema root, as spec §4.6 says, so
each parties -> .rows and each parties -> rows are the same arrow.

This is a deliberate reversal: the dot used to be treated as a typo that
matched nothing. arrows, graph and field-lineage already resolved it to
the root, so coverage was the odd one out. The visualisation's coverage,
hover highlighting and overview edges follow the same rule.

The VS Code extension now needs VS Code 1.134 or later

The minimum supported VS Code is raised from 1.125 to 1.134, to match the
@types/vscode bump in #553. With the types ahead of the declared minimum,
vsce package refused to build the extension, so every Release run had failed
since 2026-09-29. A new unit test checks the two agree, so a future types bump
fails in its own pull request rather than at release.

//? questions are listed in VS Code's Problems panel again (sl-0j8b, gh-542)

The language server had been publishing //? comments as hints with the
"unnecessary" tag. VS Code leaves hints out of the Problems panel and greys
the comment out, so open questions were harder to see, not easier. They are
now Information diagnostics, worded Question: <text>.

Satsuma: Show Warnings now lists questions at Information too, rather
than as warnings, so questions in files nobody has open also reach the
panel. For a file that is open, the command leaves reporting to the language
server, so each comment appears once.

satsuma warnings --json gives every item a kind of "warning" or
"question". The default output has always mixed the two under a
"warning" envelope, and this is the only way to tell them apart.

Pan the visualiser by dragging empty space (sl-u3x8, gh-513)

The overview, mapping detail and chain views now pan the way Miro and Figma
do: drag empty space, or hold Space and drag from anywhere, including over a
card. The cursor shows grab where a drag will pan and grabbing during one.
A drag that starts on a card still leaves the card alone, Space+drag never
clicks the card underneath, and a pan keeps following the pointer outside
the canvas until release. Scrolling, middle-drag and Alt+drag pan as before.
This applies in the VS Code panel and the web playground, which share the
component.

Notes render as Markdown everywhere in the visualisation, and mapping notes are shown (vnm-kisd, vnm-bak4)

Notes promise Markdown, but field, fragment-card and metric-card notes showed
raw asterisks, and file-level notes lost their lists because note bodies keep
their source indentation. Every note is now dedented and rendered as
Markdown, with @ref highlighting inside it.

The mapping detail view never showed a mapping's note { } blocks at all.
They now appear in a collapsible section above the arrow table, expanded by
default, joined by any ( note "..." ) metadata. Arrow notes render as
Markdown too.

Overview cards show the whole mapping label and schema notes, and field comments get their badges (sl-q7pm)

A long mapping name such as CustomerRecordToMailingList pushed its "4 →s"
arrow count past the edge of its overview box. The box is now sized for the
count as well, and a name too long for the widest box is shortened with an
ellipsis instead. Overview schema cards now show the schema's note, as the
mapping view already did. And //! and //? comments on fields and mapping
arrows now reach the visualisation, so their warning and question badges
appear in both the overview and the mapping view. They had been silently
dropped, and a comment on a schema's last field was credited to the schema.

Smaller visualisation fixes

  • Enum badges collapse to a count (sl-2ne7). A multi-value enum used to
    print every value in one badge, the widest thing on the row. A click opens
    an overlay listing the values; a second click, a click elsewhere or Escape
    closes it.
  • The chain view tells an unknown field from one with no lineage
    (sv-embb). Focusing a field that is not declared now shows
    Field not found: <schema>.<field> instead of an empty chain.
  • @refs are highlighted in join and filter descriptions (sl-yhlj), as
    they already were in transforms and notes.
  • Empty arrow tables say so (sl-jetk, sl-k7i4). A report or model with
    no field arrows shows a stated empty state rather than column headers over
    nothing, and a target-only arrow's source cell reads derived rather than
    being blank.
  • Layout (sl-yedr, sl-6g23, sl-zsv6). Expanded namespaced cards keep
    their rounded corners, the field count joins the arrow as the expand
    target, and the toolbar wraps instead of pushing the file filter out of view.
  • Asterisks in notes survive Markdown (bsw-5b3m). Inline code such as
    SELECT * FROM t lost its asterisks to emphasis, and so did a lone * in
    a * b. Both now render as written.
  • Source filters appear in the mapping header (vsf-q7m2). A filter
    written on a source, such as source { customers (filter "...") }, was
    dropped before it reached the visualiser. Each one now shows as a filter
    chip under the sources.

A fragment spread inside a record no longer switches off validation (bsw-xivc, bsw-hbcb)

A schema whose only spreads sat inside a record, such as
addr record { ...address }, was treated as having an unresolved spread, so
satsuma validate checked none of its fields: an arrow to a misspelt field
in that schema passed silently, on the source and target sides alike. Nested
spreads now resolve exactly as top-level ones do, and an undefined nested
spread is reported like a top-level one. The unenumerated-record-target
lint rule, which skipped such schemas for the same reason, now fires on
them. The language server also reports undefined spreads, top-level and
nested, as you type rather than only on save.

Expect new warnings in workspaces that use this pattern: they were always
there, just not reported.

Language server: go-to-definition in three more places, and schema renames reach @refs (gpt-jwek, gpt-fjo7)

Go-to-definition now works on a metric's source value, on the schema part
of a qualified arrow path, and on a namespace's own name. These were already
reported by find-references, so the two now agree.

Renaming a schema now updates @refs in NL text that name a field of it,
such as @orders.total. Previously the rename left them dangling. Renaming
a field still does not reach @refs.

Three smaller editor fixes: the outline names each namespace instead of
showing (anonymous) (bsw-c7z2); the mapping code lens counts arrows inside
each and flatten blocks, so it agrees with satsuma summary (bsw-ks5q);
and Overview Visualization from the Explorer's right-click menu shows the
file you clicked rather than the one last open (bsw-a2zk).

CLI fixes for arrows, mapping and the unenumerated-record-target lint rule (gpt-qhfo, gpt-i1uv, sl-3fou, bsw-fbd8, bsw-an3y)

satsuma arrows <schema>.<nested.path> could return a shallower field's
arrow instead of the queried field's own. A fully qualified path now matches
exactly. An unqualified leaf name still shows every match.

The unenumerated-record-target rule went silent for any schema with a
fragment spread, even one that resolved. It now skips only unresolved
spreads. Its advice for a multi-source arrow also changed: the old remedies
do not parse there, so it now recommends one arrow per target leaf.

satsuma mapping dropped every source after the first in a multi-source
arrow, printing a -> c for a, b -> c in text, --arrows-only and
--json alike. It now shows them all. In --json, each arrow gains srcs,
listing every source in order; src still holds the first, so existing
readers keep working. The text output also lost each and flatten blocks
nested inside another one; they now print at any depth
(bsw-fbd8, bsw-an3y).

Rolling builds now identify the exact commit (sl-13p5)

CLI, standalone LSP, and VSIX artifacts built from main or a local untagged
revision now carry <VERSION>-dev.<short-sha>. satsuma --version, the LSP
initialize response, and VS Code's Extensions view all expose the same identity;
tagged releases remain clean X.Y.Z versions.

Clean-checkout lint now generates the ignored CLI/LSP build-version modules
before type-aware ESLint, so CI does not depend on artifacts left by a prior
local build (s1cl-gphp).

Release tags now point at the commit the release was built from, not at
whatever main had become by the time the release job ran (bsw-nx1l).

The VS Code extension is now packaged by a pinned @vscode/vsce from the
lockfile, not whichever version npx fetched on the day, so npm audit and
Dependabot cover the packager too (bsw-n4mm).

The site and docs lead with readability (sl-j7vt)

The site and main docs presented Satsuma's size advantage over YAML and JSON
as a token saving, and made unmeasured claims about better AI output. The old
"40–60% smaller than YAML" was wrong: measured across the specs in
examples/, Satsuma is a median 9% smaller than equivalent YAML. The copy
now describes Satsuma as a readable language for data mappings that people
and AI tools can both read and write, and the AI claims are gone.

The site now redeploys after every release (rv-tmb4). It had been left on
the previous version until someone deployed it by hand.