Skip to content

0.91.0 → 0.92.0 — $seed overlays and the !fill!must_fill rename

Two changes land together in 0.92.0:

  1. Additive: a new system-metadata key, $seed, lets a document carry the curated starting values that newly-added cards spawn with.
  2. Breaking (authored documents): the placeholder YAML tag !fill is renamed to !must_fill. There is no alias — a document still written with !fill parses but loses its placeholder status (see below).

Stored documents (the JSON storage DTO) written by 0.82.x0.91.x keep loading losslessly; the break is only in Markdown source that uses the old !fill tag.

What $seed is

$seed is a $-prefixed system key on the root block only — like $quill, a composable card carrying $seed is rejected at parse and on storage load. It is a mapping keyed by composable card-kind; each entry is a sparse overlay — the user fields (plus an optional reserved $body string) a freshly-added card of that kind should start with:

~~~
$quill: usaf_memo@0.2.0
$kind: main
$seed:
  indorsement:
    from: 49 FW/CC
    signature_block:
      - "JANE A. DOE, Col, USAF"
      - "Commander"
~~~

Adding a new indorsement now seeds from / signature_block from the overlay while every untouched field still flows from the quill's schema example: (overlay › example › absent). Like $ext, $seed round-trips through Markdown and storage and is stripped before backends — it never appears in rendered output. It is validated only advisorily (Quill::validate, warning severity) and never gates render. The model lives in the prose/canon/CARDS.md design doc.

seedCard takes an optional overlay

seedCard now accepts the per-kind overlay so a card added to a template-derived document inherits its curated values. Read the overlay from the document and hand it to the quill:

WASM / TypeScript

// before
const card = quill.seedCard(kind);
// after — pass the document's overlay (a read; it does not mutate the doc)
const card = quill.seedCard(kind, doc.main.seed?.[kind]);

quill.seedCard(kind) (omitting the overlay) still works and yields the bare schema seed, so unmodified call sites compile and behave as before.

Python

overlay = (doc.main["seed"] or {}).get(kind)   # None for the bare schema seed
card = quill.seed_card(kind, overlay)          # overlay defaults to None

Rust (core) — the one breaking signature: Quill::seed_card(&self, kind) becomes Quill::seed_card(&self, kind, overlay: Option<&SeedOverlay>). Pass None for the bare schema seed (the historical behavior), or layer a document's overlay by reading it off the main card's $seed map: doc.main().seed().and_then(|m| m.get(kind)).and_then(SeedOverlay::from_json). Making the overlay an explicit argument keeps it discoverable.

New accessors

  • The per-kind overlay is read off the main card's seed map — doc.main.seed?.[cardKind] (WASM) / doc.main["seed"][cardKind] (Python) / doc.main().seed() (Rust, then SeedOverlay::from_json); feed it straight to seedCard. There is no dedicated Document.seed accessor — $seed is read through the card, exactly like $ext.
  • Document.setSeedNamespace(cardKind, overlay) / removeSeedNamespace(cardKind) — write/clear one kind's overlay, preserving sibling kinds (the seed analogue of setExtNamespace). This is how a template author sets the values new cards spawn with.

The Card shape gains an optional seed field (hoisted from $seed, main card only), mirroring ext.

!fill!must_fill (breaking)

The placeholder tag that marks a field as a must-fill blank is renamed from !fill to !must_fill — more self-documenting (it conveys obligation) and aligned with the ⟨⟨…⟩⟩ blueprint sentinel.

~~~                          ~~~
$quill: usaf_memo@0.2.0      $quill: usaf_memo@0.2.0
$kind: main                  $kind: main
subject: !fill          →    subject: !must_fill
~~~                          ~~~

There is no !fill alias. !must_fill is the only recognized fill tag; every other custom tag — including a now-stale !fill — is treated as a noncanonical tag: it is dropped with a parse::unsupported_yaml_tag warning, the scalar value is kept, but the field is no longer marked as a placeholder. The document still parses, so this is a silent loss of placeholder status (a warning, not an error). Action: search your Markdown sources and quills for !fill and rewrite to !must_fill. (rg -l '!fill\b' finds them.)

This release also makes nested placeholders durable: a !must_fill marker on a value inside a field (an object leaf, a key in an array element) now survives a storage round-trip via the new per-field nested_fills list in the storage DTO.

Storage: schema quillmark/document@0.92.0

The StoredDocument wire format gains a seed payload-item variant and a per-field nested_fills list (carrying the paths of nested !must_fill markers), so newly serialized documents carry the tag quillmark/document@0.92.0. This is transparent: 0.81.x / 0.82.x0.91.x blobs migrate forward losslessly on read (V0_81_0 → V0_82_0 → V0_92_0, with seed absent and nested_fills empty), and re-serialization upgrades the tag. No action is required for persisted documents.