Skip to content

Releases: borb-sh/quillmark

v0.95.1

Choose a tag to compare

@quillmark-tagger quillmark-tagger released this 19 Jul 13:15
5d9e988
Release v0.95.1

v0.95.0

Choose a tag to compare

@quillmark-tagger quillmark-tagger released this 19 Jul 13:08
8894866
  • release: re-cut to finish binding dists after the first publish run cancelled mid-flight
  • breaking typst: a present date / datetime field lowers to a click-to-edit value-object — (value: datetime(..), display: (..args) => text(value.display(..args))) — instead of a bare Typst datetime, so the rendered glyphs are born at a generated text(..) node carrying a region keyed on the field's schema path: a date placed by a vendored package, or a card's date riding a shared loop variable, is click-to-edit. A blank date stays none, so != none guards hold. Plates migrate two shapes: (data.f.display)("…") (paren form — the stored display is a closure on a dict, not a method) and data.f.value for anything native (comparison, .year()-family components, datetime-consuming packages). The tonguetoquill flagship quills' display-date dispatches on type(date), since their datetime.today() blank-date fallback stays a native datetime (#990)
  • breaking core,typst,pdfform: split the datetime field type into strict date and datetime (#717/#799 resolved) — date accepts a bare YYYY-MM-DD and rejects any time component; datetime accepts offset-less wall-clock YYYY-MM-DDThh:mm[:ss] (seconds zero-filled) and rejects timezone offsets, the space separator, fractional seconds, and bare dates. Offsets are rejected, never dropped (the engine does no zone math); storage stays verbatim; no truncation in either direction. A date lowers to the three-component Typst datetime(year:, month:, day:) (unchanged emission) and a datetime to the six-component constructor, carrying the wall-clock time. The transform schema marks date as format: "date" (keeping format: "date-time" for datetime), and the blueprint reads date<YYYY-MM-DD> / datetime<YYYY-MM-DDThh:mm[:ss]>. Most deployed datetime fields hold a bare date and migrate to type: date with byte-identical data; the fixtures (usaf_memo, cmu_letter) do so. No deprecation alias — datetime rejecting a bare date is the decided end-state (#991)
  • breaking python: the binding commits to the typed lanes — field I/O flows through quill.writer(doc) / quill.view(doc) exclusively and Document is quill-free data and structure. Removed (WASM-only by scope, not lag — their audience is not a Python audience): the opaque field store (store_field / store_fields / store_fill and card twins), the content lane (install / revise / apply_change), the quill-free field reads (get / get_card_field), and the module codec fns (import_markdown / export_markdown / rebase / map_pos). The composable $ext / field-remove card twins fold onto a trailing card=None selector and push_card folds into insert_card(card, at=None). Mirrored additions: writer.revise_field (the Delta receipt is not surfaced), writer.add_card(kind, fields=None, body=None, at=None), writer.card(i).kind, and the Writer / CardWriter / View / CardView handle classes exported from the package (#970)
  • breaking core,wasm,python: complete the RichTextContent residual sweep (#976 folds into #982) — retire the last informal-corpus / model-RichText identifiers the mechanical rename missed: CorpusHitContentHit, EditError::CorpusApplyEditError::ContentApply, RichtextDecodeError::NotCorpusNotContent (the codec-specific RichtextDecodeError type itself is kept), storage DTO CanonicalRichTextCanonicalContent (serde is unchanged — no wire migration), and the model-generic Typst emitter emit_richtext / emit_richtext_inlineemit_content / emit_content_inline (they lower any Content, richtext or plaintext). Also fixes the ParseError display strings richtext json …content json …, the doubled-word find-replace debris (content content modelcontent model), and stale prose/comments across canon and rustdoc. Schema/codec names are untouched — richtext / plaintext tokens, FieldType::{RichText,PlainText}, field_richtext / FieldRichtext* / apply_field_richtext_change, richtext(inline) — they name codecs, not the model. "corpus" is purged from the tree entirely, including the ordinary-English test-set names that meant a collection of fixtures (fixture_corpusfixtures, synthetic_corpussynthetic_inputs) (#982)
  • breaking core,wasm,python: a schema-bound read view — Quill::view(&doc) / quill.view(doc), the read twin of quill.writer(doc). view.get(addr) interprets each field by its declared type (a richtext field → markdown, a plaintext field → its literal text via the plaintext codec, every other type → its canonical value verbatim), returns absent as undefined / None, and — the authority the quill-free getMarkdown lacks — throws UnknownField for a name the schema does not declare and FieldRichtextDecode for a content field holding an undecodable value. Core TypedReader::get returns a ReadValue (Markdown/Plaintext/Value); view.card(i) is the card cursor; core adds Card::field_plaintext (the to_plaintext twin of field_markdown). getMarkdown's field half retires: getMarkdown / get_markdown / get_card_markdown are now body-only (WASM getMarkdown takes a CardAddr, a present field throws; Python drops the name parameter) — a field's markdown is read through view.get. The quill-free body projection stays on Document (#978)
  • breaking content: one delta-application contract — implicit trailing retain is try_apply's semantics (a short delta retains the untouched remainder; the error is over-consumption only), apply panics on an over-long delta instead of clamping (clamping is silent corruption), and extend_to_base is removed. split_line / join_line rebase marks through their one-char \n splice with map_pos — the same mapping the text-delta channel uses — so marks no longer drift across line ops and apply_field_change canonicalizes once (a single terminal normalize instead of one per stage); line sync rebuilds in one forward pass instead of per-\n Vec splices. Mark ops are specified in final-text coordinates (post-delta, post-line-op — the frame they validate against) (#926, #987)
  • breaking core: storage blobs tagged @0.81.0 / @0.82.0 fail as an unknown schema version — the read-only V0_81_0 / V0_82_0 DTO trees and their forward migrations are retired (nothing persisted on this lineage predates @0.92.0; 0.82.0 was yanked). V0_92_0 stays the oldest shape read, and its payload types back the current write path. DOCUMENT_STORAGE.md records variant retirement as the policy when no stored population remains (#929)
  • breaking core,wasm,python: the markdown projection stops appending a trailing newline — to_markdown projects a value, not a file, so field_markdown / body_markdown (WASM getMarkdown / exportMarkdown, Python export_markdown / get_markdown) no longer grow a \n; writer.set("subject", "Hello") reads back as "Hello", not "Hello\n". .qmd files still end in one newline (owned by Document::to_markdown, the file writer) and the content fixed point is unchanged (import is newline-insensitive) (#965)
  • breaking all: rename the content genus off its codec's name — crate quillmark-richtextquillmark-content, type RichTextContent (and RichTextLine/RichTextContainer/RichTextMark/RichTextIslandContentLine/…), const RICHTEXT_MEDIA_TYPECONTENT_MEDIA_TYPE and its wire string application/quillmark-richtext+jsonapplication/quillmark-content+json, #[serde(skip)] companion caches FieldSchema::{default,example}_corpus_content, SegmentMap.corpus: Range<usize>.content, Typst-emitter EmittedContentEmission (it is markup + source map, not a Typst content value). Schema tokens richtext / plaintext, FieldType::{RichText,PlainText} variants, and the codec-specific field_richtext / FieldRichtext* / apply_field_richtext_change / richtext(inline) surface are unchanged — those name codecs, not the model. Canonical body JSON is nameless, so stored documents don't migrate; contentMediaType consumers pin to the new spelling. Retires the informal "corpus" noun to end the code/prose split (#976)
  • breaking core,wasm,python: getMarkdown / get_markdown / get_card_markdown stop conflating an absent field with a present-but-not-richtext one — a present field that does not decode as richtext (a scalar/array/object a storeField wrote) now throws FieldRichtextDecode instead of reading back undefined / ""; absence still returns the absent shape. Core Card::field_markdown becomes Option<Result<String, RichtextDecodeError>> (the projection twin of field_richtext). Rule: absence returns, mismatch raises; read the raw value with get (#968)
  • feat(core,wasm): typed, anchor-preserving field revise — TypedWriter::revise_field / CardWriter::revise_field and writer.reviseField / writer.card(i).reviseField wrap core Card::revise_field_checked (diff-rebase surviving anchors, then schema-conform the result); the schema-bound verb lives on the writer, where the schema is (#957, #966)
  • breaking wasm: the quill-taking Document methods become the hidden ABI under the writer — commitField / commitFields / addCard_commitField / _commitFields / _addCard, dropped from the .d.ts; remove doc.reviseChecked (no runtime consumer — use writer.reviseField). The visible Document class then carries zero quill-taking methods (#966)
  • breaking core: rename EditError::BodyImportEditError::Import (message body import failed:markdown import failed:) — the variant also fires on field-path imports (revise_field), where "body" misnamed it (#966)
  • breaking wasm: fold pushCard into insertCard(card, at?) — one insertion verb per lane, absent at appends; insertCard's parameters reorder to (card, at?). Delete the deprecated...
Read more

v0.94.0

Choose a tag to compare

@quillmark-tagger quillmark-tagger released this 15 Jul 22:43
1afd871
  • Delete prose/plans directory
  • feat(wasm): promote the live-session/canvas surface to stable
  • docs(release): reconcile changelog and guides for 0.94.0 (skip 0.93)
  • test(core,quillmark): remove redundant and low-value tests
  • core: drop public→private rustdoc link in UiFieldSchema docs
  • core/seed: collapse merge-then-sort into one declaration-order pass
  • docs: declaration order is the field ordering contract; ui.order removed
  • core, bindings: update tests, golden, and doc surfaces for structural order
  • core: field declaration order becomes structural (IndexMap), ui.order retired
  • Simplify group-order sort key and ui.order stamping
  • Add card-level ui.groups registry for group identity and ordering
  • pdfform: place widget geometry once at bind, not per render
  • pdfform: gate form.json version before field-shape parse
  • pdfform: derive widget intrinsics from the quill schema (form@0.2.0, #940)
  • Reject nested ui.group; auto-order nested object properties
  • docs: densify the plaintext/enum section of the 0.93->0.94 guide
  • core, richtext: follow simplification cascades from plaintext
  • docs: extend canon (BLUEPRINT, PLATE_DATA) for plaintext and enum
  • docs: document plaintext and enum field types, narrow string
  • quillmark: end-to-end render test for plaintext through typst
  • core: test plaintext codec and enum promotion end-to-end
  • core: add plaintext and enum first-class field types
  • richtext: add from_plaintext literal codec and is_plain predicate
  • fix(typst/overlay): stop underline/strike decoration ink truncating $body regions
  • chore: migrate org references quillmark-org → borb-sh
  • docs: fix cross-tree link that broke mkdocs --strict
  • simplify: fix stale receiver refs and facade-prose misses after rename
  • rename typed-write facade editor→writer; unify on quill.writer(doc)
  • python: delete redundant commit_* verbs (subsumed by the editor)
  • docs: two-tier binding surface — parity table + strata/ephemerality (#932)
  • python: Document.editor(quill) front door + Editor/CardEditor + reads
  • wasm: quill.editor(doc) front door + tier-1 gap verbs + reads
  • wasm+python: delete addressed commit(addr) verb (subsumed by editor)
  • core: TypedEditor set_body + add_card (tier-1 mirror verbs)
  • simplify: follow the #925 cascades
  • docs: finish migration index entry; tidy wasm doc link
  • python: mirrored addressed write surface + corpus codec
  • wasm: addressed write surface (install/revise/applyChange/commit) + codec
  • richtext+core: pure Delta codec + install/revise body & field verbs
  • test(wasm): update runtime.test.js editor sugar to the strict contract
  • feat(core,wasm,python)!: typed field writes reject unknown names (#918)
  • wasm: split Card read type from CardInput write type (#917)
  • richtext: MarkOp::Remove subtracts the range instead of dropping the whole mark
  • fix(quillmark-pdf): dict/array depth walkers skip comments and strings
  • fix(richtext): markdown export never leaks a delimiter into the corpus
  • fix(richtext): saturate ordered-list marker; doc/hint cleanups from final review
  • #913: mirror the WASM typed batch on Python (commit_fields + set/commit reframe)
  • #911: finish exposing the typed editor in WASM (commitFields batch + JS editor sugar + reframe)
  • test(wasm): warm the lazy Typst backend load before timed Engine renders
  • test: consolidate generator-arm round-trips and costume proptests (tier 3-4)
  • test: remove orphan fixtures and redundant/low-value tests (tier 1-2)
  • docs: audit of legacy/redundant/low-value tests, fixtures, logic
  • richtext/core/bindings: address issues #902#906
  • richtext: escape image alt/URL and link URL on markdown export (#900)
  • richtext: strip \r and bidi controls from apply_text_delta inserts
  • Remove prose/proposals/: 893 proposal has landed
  • Unify binding write-verb grammar: mechanical card-write twins (#895)
  • Hard cutover to commit_field: remove legacy richtext writers
  • wip: bindings + tests + docs for typed writes (pre-cutover)
  • Typed field writes: conform dispatch, commit_field, TypedEditor (core)
  • Review typed-field-writes proposal against codebase; resolve open questions
  • Add proposal: typed field writes via schema-carried types (#893)
  • feat(wasm): setCardBody — corpus writer for a non-main card body (#892)
  • remove(core,richtext,wasm)!: delete the incremental-edit surface (#886)
  • test(wasm): fix two applyFieldDelta tests left stale by the #881 un-gate
  • feat(regions): field_boxes helper + CorpusHit granularity signal (#884)
  • fix(core,wasm): resolve lint CI failure + re-sync applyFieldDelta type after merge
  • wasm/canvas: report clamp on PaintResult; document paint compositing constraints
  • fix(wasm): make applyFieldDelta and supportsCanvas types honest about their domain
  • docs: migration guide for the richtext field write-surface unification (#881)
  • richtext: un-gate applyFieldDelta to richtext fields (step 6)
  • wasm: setRichtextField / updateCardRichtextField + per-field markdown getter (step 5)
  • richtext: emit projects corpus fields to markdown; wire/DTO lossless (steps 2-4)
  • richtext: Card::set_field_richtext writer + corpus read-back (step 1)
  • fixtures: table_demo Quill + end-to-end table render test; document pdfform limit
  • richtext: property-test structured tables through normalize + round-trip
  • richtext: in-cell images degrade honestly instead of silent-Lossless
  • richtext: canonical table shape — validate invariants, repair in normalize
  • test: drop two redundant inline tests; dense-prose the runtime edit-surface note
  • Prune landed simplification entries from the backlog
  • Silence clippy nits in span_scan walk refactor
  • test(wasm): keep runtime edit-surface guard focused on the #876 methods
  • docs: fix rustdoc intra-doc links to satisfy the -Dwarnings lint gate
  • Filter locate's glyph walk to the target segment
  • Share frame-walk geometry between region scan and corpus walk
  • feat(wasm): expose incremental editor edit surface through runtime (#876)
  • Skip props re-clone in normalize when already key-sorted; document R2 hazard
  • Carry the /Strong distinction instead of re-sniffing source
  • feat(typst): add plaintext(field) projection helper + document richtext migration hazard (#873)
  • Lift island mark-dispatch out of model into serial
  • Build canonical richtext tree once via move-based key sort
  • feat(wasm): add setBody(corpus) mutator on Document (#874)
  • Dedup emit_inline mark partition into wraps_and_codes
  • fix(typst): lower richtext(inline) fields to inline content (#872); fix wasm TS types (#875)
  • Remove unused ChangeLog/session forward surface
  • Cut over-engineered simplification findings; refresh drifted citations
  • docs(simplifications): remove the addressed findings
  • docs(simplifications): record the sync-twins deferral rationale
  • refactor(typst,richtext): dedup container dispatch and the #846 clip
  • refactor(core): one shared decoder for the dual-shape richtext seam
  • refactor(richtext): make apply_field_change all-or-nothing
  • refactor(core): single carrier for the richtext inline flag
  • refactor(richtext): drop unused usv UTF-16 helpers and content_key alias
  • refactor: apply low-risk simplifications from prose/simplifications
  • docs: record simplification-review findings in prose/simplifications/
  • fix(richtext): apply a short field delta leniently (auto-append remainder)
  • Trim unused test-only public methods from core
  • docs(core,typst): dense-prose pass on comments
  • docs(richtext): dense-prose pass on comments
  • docs(core): update QuillValue fill-setter reference after set_fill removal
  • Remove more dead/redundant logic
  • docs: remove stale info across canon, docs, and comments
  • test: remove redundant and low-value tests across the workspace
  • Remove dead and redundant logic
  • fix(docs): resolve broken intra-doc links (cargo doc -Dwarnings)
  • typst/richtext: address #855 cleanup findings
  • Fix #851 follow-up: transactional applyFieldDelta and fail-closed invalidation
  • richtext: fix issue #854 cleanup findings
  • fix(session): close the three delta-protocol lifecycle gaps (#851)
  • Fix low-risk API-surface findings from #856
  • fix(wasm): strip unreachable delta-API types from public runtime.d.ts (#850)
  • chore: ignore dist/, .vite/, test-results/ to prevent build-artifact commits
  • fix(richtext): cap single-line char diff to avoid quadratic blowup (#849)
  • fix(richtext): balance markdown export for overlap, escape & and trailing heading # (#848)
  • docs: fix richtext drift found in #853
  • fix(richtext): keep islands in sync on text-channel edits (#847)
  • fix(typst): balance markup for overlapping wrap+code marks (#846)
  • Render thematic breaks (---/***/___) instead of dropping them
  • fix(richtext): correct ChangeLog::map_pos staleness and future-revision handling
  • chore(richtext): drop richtext-spikes from integration branch
  • Move richtext inline shape to inline: true schema field.
  • feat(richtext): PR-H findings — fixture, runtime nav, docs (PR-H)
  • cargo fmt
  • feat(richtext): preview revision stamp + WASM session delta API (PR-F/PR-G)
  • feat(richtext): fallible document body mutators (PR-E)
  • docs(richtext): drop .qmd and Quill-Delta from phase-3 plan
  • docs(richtext): record PR-C/D landing in phase-3 plan
  • feat(richtext): add mark/line op channels and apply bundle (PR-D)
  • feat(richtext): add revision counter and bounded change log (PR-C)
  • feat(richtext): replace coarse delta::diff with Myers/LCS (PR-B)
  • Remove husky pre-commit hook
  • cargo fmt
  • docs(richtext): record phase-3 spike findings on integration branch
  • docs(richtext): align canon + code comments to PR-G, wrap up phase 2
  • fix(wasm): add span to canonical FieldRegion contract
  • richtext PR-G: richtext(inline), load-time example cache, alias cutover
  • Delete prose/review directory
  • docs(richtext): trim phase plans to landed reality, fold spike findings
  • test(richtext): wasm binding test for positionAt/locate round-trip (#829)
  • PR-F: regions + navigation — two-tier segment scan, position_at/locate (#829)
  • spike(rich...
Read more

v0.92.1

Choose a tag to compare

@quillmark-tagger quillmark-tagger released this 22 Jun 06:00
2b0ab3e
  • Accept uppercase field names; reserve only $-prefixed keys (#730)
  • docs: canonize $ext.editor.title as per-card display name slot (#729)

v0.92.0

Choose a tag to compare

@quillmark-tagger quillmark-tagger released this 22 Jun 02:48
9c1b915
  • 0.92 technical-debt sweep: correctness, $seed hardening, de-duplication (#727)
  • dotnet: add $seed namespace writers (parity with Python/WASM)
  • refactor(core): unify $ext/$seed into one out-of-band Meta concept
  • Cleanup: simplify QuillWorld::font to a single expression
  • Cleanup: de-narrate comments, sync canon binding tables with .NET
  • dotnet: fix stale schema version (CI) + review-flagged polish
  • docs(migration): cover the !fill → !must_fill rename in the 0.92 guide
  • dotnet: fix native-lib copy to test project + two correctness bugs
  • Remove Document.seed(kind) for strict ext/seed symmetry
  • dotnet: expose $seed on the Card DTO
  • refactor(dotnet): rename engine class Quillmark -> QuillmarkEngine
  • Reject !fill: treat as a noncanonical tag, not a fill alias
  • Fix binding build break + warn on unsupported fill positions
  • fix(dotnet): resolve engine type in test namespace (CS0426)
  • docs(dotnet): trim README to a dense, consumer-focused surface
  • Address review nits: loud divergence, docs, coverage
  • Add storage schema 0.92.0: persist nested !must_fill
  • docs(canon): consolidate binding overviews into BINDINGS.md
  • feat($seed): reject $seed on composable cards (root-only, like $quill)
  • docs: move dotnet binding into canon, delete DESIGN.md
  • docs: reframe QmBytes by-value return as a tested assumption, not a defect
  • Carry nested !must_fill across the live wire (CardWire)
  • Address review: trap FFI panics, fix depth-limit asymmetry, Equals contract
  • Detect nested !must_fill on sequence-item inline first key
  • docs($seed): correct two claims flagged in review
  • Fix invalid '--' inside XML comment in Quillmark.csproj
  • fix(docs): drop canon links that break mkdocs --strict
  • Promote .NET binding: CI test job, NuGet release, first-class docs
  • Spike: .NET binding symmetrical to the Python binding
  • Capture and round-trip nested !must_fill markers
  • Make QuillValue an annotated value tree (fill on nodes)
  • fix(bindings): bump currentSchemaVersion to 0.92.0; add $seed JS test
  • Rename !fill tag to !must_fill (accept !fill as deprecated alias)
  • docs($seed): document the per-kind seed-overlay key across canon and spec
  • test($seed): cover parse/emit/storage, overlay layering, advisory validation
  • feat(core): first-class $seed key for per-card-kind seed overlays
  • Remove RenderSession and canvas-preview APIs from Python binding (#722)

v0.91.0

Choose a tag to compare

@quillmark-tagger quillmark-tagger released this 17 Jun 21:59
1abbb65
  • Upgrade Typst backend to 0.15 (#720)
  • Security audit: resolve 10 findings, document 6 open issues (#719)
  • Hygiene pass: simplifications, dead code removal, and docs cleanup (#718)

v0.90.0

Choose a tag to compare

@quillmark-tagger quillmark-tagger released this 10 Jun 01:56
9a4fae8
Release v0.90.0

v0.89.1

Choose a tag to compare

@quillmark-tagger quillmark-tagger released this 10 Jun 01:47
22544f7
  • chore(release): v0.89.1-rc.1 (#714)

  • feat(wasm)!: 0.90 canonical API — engine-free Quill, single root export, typed errors; Python parity (#713)

  • Proposal: WASM bindings split (core + render) via backend-decoupled Quill (#710)

  • Add version selector matching and mismatch warnings (#708)

  • docs: density-optimization pass on user-facing docs (#703)

  • Remove role annotation from root block metadata header (#707)

  • canon: audit and correct all prose/canon/ docs (#704)

  • Fix makeCard fields/body typed as required in WASM .d.ts (#702)

  • Update CLAUDE.md

  • feat(wasm)!: 0.90 canonical API — engine-free Quill, single root export, typed errors; Python parity (#713)

  • Proposal: WASM bindings split (core + render) via backend-decoupled Quill (#710)

  • Add version selector matching and mismatch warnings (#708)

  • docs: density-optimization pass on user-facing docs (#703)

  • Remove role annotation from root block metadata header (#707)

  • canon: audit and correct all prose/canon/ docs (#704)

  • Fix makeCard fields/body typed as required in WASM .d.ts (#702)

  • Update CLAUDE.md

v0.89.1-rc.1

v0.89.1-rc.1 Pre-release
Pre-release

Choose a tag to compare

@quillmark-tagger quillmark-tagger released this 10 Jun 01:26
b472103
  • feat(wasm)!: 0.90 canonical API — engine-free Quill, single root export, typed errors; Python parity (#713)
  • Proposal: WASM bindings split (core + render) via backend-decoupled Quill (#710)
  • Add version selector matching and mismatch warnings (#708)
  • docs: density-optimization pass on user-facing docs (#703)
  • Remove role annotation from root block metadata header (#707)
  • canon: audit and correct all prose/canon/ docs (#704)
  • Fix makeCard fields/body typed as required in WASM .d.ts (#702)
  • Update CLAUDE.md

v0.88.0

Choose a tag to compare

@quillmark-tagger quillmark-tagger released this 05 Jun 13:36
1f398ab
  • Breaking (bindings + Rust API): a single canonical Card wire shape now
    flows in both directions. Core owns it as quillmark_core::CardWire (with
    From<&Card> / TryFrom<CardWire>); the WASM/Python bindings serialize and
    deserialize it instead of hand-rolling their own per-card translation. The
    flat CardInput { kind, fields?, body? } input type is removed:
    Document.pushCard / insertCard (push_card / insert_card) now accept the
    same Card shape they return ({ kind, payloadItems, … }), so a card from
    cards / removeCard / quill.seedCard feeds straight back in. Build a fresh
    card from a flat field map with the new Document.makeCard /
    Document.make_card helper. A stale { kind, fields } object is now a loud
    error (deny_unknown_fields), not a silently-empty card. The seeded per-card
    getters quill.seedMain / quill.seedCard (seed_main / seed_card) are
    exposed on both bindings, mirroring the Rust Quill::seed_main / seed_card.
  • Breaking (Rust API): Document::push_card now returns
    Result<(), EditError> and, with insert_card, validates that the card's
    $kind is a valid, non-reserved composable kind — the cards-list invariant is
    enforced at the edit op rather than incidentally at Card::new.
  • Breaking (bindings + Rust API): the schema-aware form view is removed.
    Quill::form / Quill::blank_main / Quill::blank_card (and the
    quill.form / blankMain / blankCard bindings) are gone, along with the
    Form / FormCard / FormFieldValue / FormFieldSource types. Validation
    diagnostics now flow through Quill::validate(&Document) -> Vec<Diagnostic>
    (quill.validate(doc) in WASM/Python), which forwards the canonical
    validation::* diagnostics and keeps the non-fatal validation::field_absent
    completeness signal that render demotes. Field values/defaults/order are a
    Document × quill.schema join the consumer performs directly. See
    docs/migrations/0.87-to-0.88.md.
  • Breaking (diagnostics): the validation code validation::must_fill_absent
    is renamed validation::field_absent. "Must-fill" is now scoped to the
    blueprint communication surface (the <must-fill> sentinel and the fatal
    validation::must_fill_sentinel); an absent field is a non-fatal
    completeness signal, not a fill requirement, since the render floor
    zero-fills it. The schema cell axis is renamed accordingly: the no-default:
    cell is Unendorsed (was "Must Fill"), the antonym of Endorsed
    consumers routing on the old code or label must update. Internally
    ValidationError::MustFillUnset { source } splits into FieldAbsent and
    MustFillSentinel and the MustFillSource enum is removed.
  • Breaking (bindings + Rust API): the example reference document is
    removed. QuillConfig::example() and the Quill.example (WASM) /
    Quill.example (Python) getters are gone. Its "show me a filled-out one"
    role is served by seeding — Quill::seed_document() / Quill.seedDocument()
    / Quill.seed_document() — which returns a committed Document rather than
    an annotated string. The CLI render with no input file now renders the
    seeded document. Nothing consumed the example document's annotations (the
    authoring surface is blueprint()), so the projection collapses into the
    seed: internally the FillSource fork in blueprint emission is gone and the
    blueprint always renders default: else the <must-fill> sentinel.
  • wasm: lower the npm package engines.node floor from >=24 to >=22.
    The runtime never required 24 — --weak-refs needs only Node 14.6+, and the
    using sugar that motivated the 24 floor is optional (a try / finally
    fallback covers Node 22). The aggressive floor hard-blocked installs on Node
    22 CI/dev images under engine-strict.
  • wasm: Document.makeCard(kind, fields?, body?) now types fields as
    optional in the generated .d.ts (was required, contradicting its docs);
    omitting it yields an empty field map, as before.
  • docs: fix the Quill.schema getter doc — the returned schema includes
    ui hints (it never stripped them); the stale "ui hints stripped" wording is
    corrected. The 0.87→0.88 migration guide now documents the fill flag's
    !fill-placeholder semantics and clarifies that seeding is example-filled,
    not a blank-form replacement.
  • blueprint: flatten group_fields and drop the unused group label (#697).
  • docs: document seeding (example → absent), fix a block-scalar prescan
    bug, and add commitment-ladder docs (#691).
  • docs(canon): dedup field-resolution semantics into SCHEMAS (#692); note
    that released migration guides are era-accurate and immutable (#695); prune
    evolutionary information from comments and canon docs (#700).