Migrating to Chatter 0.32.0
Last updated: 2026-10-27 (commit 5bfee2f9)
This pre-1.0 release changes CLI names, Rust APIs and selected JSON/RPC representations. Update dependent code and regenerate model JSON from its source where practical. Recovery-bearing JSON remains subject to validation; a successful deserialization does not establish valid CHAT.
CLI users and automation
Use the CLI migration table
for command-by-command replacements. Old names have no aliases. Frequent tasks
use validate, fix, format, convert, new, inspect and checks;
specialist operations live under experimental. commands list/show --format json describes the executable tree and its effects. --log-format controls
logging, not command-result encoding.
Repair, cache clearing and in-place transforms preview unless --apply is
specified. Semantic repair still needs explicit code selection. Validation
refresh uses --refresh-cache; directory export regeneration uses --rebuild.
Mapping, matching, replay and LLM suggestions have separate argument shapes.
Replay needs a recorded decision file and session identity; review needs an
operator identity. Scripted review refuses unused decisions. Speaker scans
require all selected transcripts and never treat missing input as an empty scan.
Output failures return nonzero through owned cleanup. Forced validation interruption returns 130. JSON validation writes no stderr on an output failure. Review produces files with no stdout result; scan summaries use stdout.
Source replacement (format --output over an existing regular destination,
fix --apply, and in-place transforms) uses explicit macOS/Linux/Windows
metadata policies. It refuses symlinks, read-only or multiply-linked files and
unsupported metadata, and checks the planned source before in-place publication.
Separate conversion/redaction/speaker artifacts and validation reports retain
source-alias checks and stage regular outputs. Their existing symlinks select
the target; hard-link siblings retain old bytes. Artifacts preserve ordinary
permissions, not the stricter source metadata contract. Streams cannot roll
back; a multi-file command is not a filesystem transaction. Audit publication
also requires complete run accounting. Directory conversion retains its
explicit stale-output and prune policies.
Windows replacement uses handle-based POSIX rename semantics so retained source identity handles remain valid while the new directory entry becomes visible. Filesystems or Windows versions that do not support that operation return an error without a delete/copy fallback. The staged file retains its admitted metadata; existing readers and other hard links retain the old bytes.
The following sections retain the detailed library/protocol migrations from the development changelog, grouped by consumer. Intermediate implementation states superseded before release are omitted.
Shared model and JSON consumers
-
Breaking (participant API/JSON): removed
ChatFile.participantsandwith_participants;with_line_mapnow takes only lines and the index. Participant accessors return borrowedParticipantViewvalues derived from current headers, so header edits and legacy JSON cannot restore stale ages, names or birth dates. Usecode(),id()andbirth_date()for view fields, orto_owned_participant()for a detached snapshot. The shared join retains its diagnostics; JSON and schema no longer contain the root metadata cache. -
Breaking (shared file API/JSON): removed the duplicated
ChatFile.optionsandChatFile.mediafields.option_flags()andmedia_header()borrow the current header lines, so edits and JSON import cannot leave pipeline policy or media readers using stale copies. JSON and schema contain only the header representations. Edit the typed header lines to change either value. -
Breaking (participant model and wire format):
ParticipantEntryandParticipantreplace independent name/role fields with taggedParticipantDetails::Complete { name, role }orMissingRole {}. Usename()/role()accessors; declared roles are optional. Both parsers retain role-less speaker declarations without borrowing ID roles, and E513 survives JSON import without false undeclared/orphan-speaker cascades. Contradictory or absent details are rejected during deserialization. LSP speaker name/role fields use null for absence. Merge role comparisons refuse missing roles. Native participant parsing now returns shared entries;ParticipantsHeaderParsedandParticipantEntryParsedare removed. Structurally damaged declarations retainUnparsedParticipantssource and cannot contribute fabricated identities or ID-join cascades. The sharedparticipant_declaration()API rejects absent, unparsed or repeated headers; accessors and metadata joins no longer select the first repeated declaration, and merge refuses unavailable declarations.apply_mapping_chatandrediarizenow return Results and refuse absent, rejected or repeated declarations before rewriting speakers. Pipeline/speaker-ID error types and recorded failure kinds distinguish declaration refusal. Sanitization refuses raw participant headers whose name boundaries are unknown. -
Breaking (validation context):
SharedValidationData::participant_idsis replaced by typedparticipant_rosterevidence. File validation derives speaker membership from declarations, independently of successful ID joins; missing metadata no longer makes a declared speaker appear undeclared. Unscoped and repeated declarations cannot establish negative membership. The shared participant join is now a borrowed plan: validation reports its diagnostics without rebuilding metadata, retaining missing-ID errors after JSON import. Birth-header membership uses declarations rather than ID joins. -
Breaking (model and language transforms): malformed
@Languagesheaders retainUnparsedLanguagessource through CHAT and JSON.ChatFile.languagesand its independently serialized cache are removed; uselanguage_declaration()to distinguish an admitted list from absent, empty, rejected or repeated declarations. Validation retains that distinction and withholds dependent membership/default conclusions.fix-sreturns a declaration error and retagging has a declaration-refusal variant; neither partially rewrites a file with an unavailable declaration. Validation context declaration data and its alternate/tertiary-language queries now return explicit declaration errors. Merge admission uses the same shared error type. Native file parsing carries admitted shared headers inHeaderParsed::Shared. -
Breaking (language declaration evidence): successful file/context declarations use
DeclaredLanguagesRef/DeclaredLanguages, whose primary code is structurally required. Empty builder input recordsEmptyrather than successful empty evidence. Declaration-aware resolution and extraction APIs consume the admitted view; raw-list convenience APIs admit at entry. Ordered code-array serialization and individual-code recovery are unchanged. -
Breaking (language resolution API):
LanguageResolutionandWordLanguagesmixed/ambiguous variants carry checkedMultipleLanguageCodesrather than a bare vector. UseTryFrom<Vec<LanguageCode>>andas_slice(). Resolved JSON rejects lists shorter than two codes; recovery markers still import them unchanged, report E212 and resolve toUnresolvedinstead of silently succeeding. -
Breaking: replace recovery-capable
NonEmptyStringmodel fields with explicitRecoveryText::{NonEmpty, Empty}.NonEmptyStringnow enforces non-emptiness through serde as well as constructors. JSON strings and contextual empty-text diagnostics are preserved; Rust consumers must distinguish recovery from admitted text. -
Breaking: remove
Word::simple,Word::new_unchecked,WordText::new_unchecked, andNonEmptyString::new_unchecked. Construct plain words withWord::new(location, WordText::new(text)?), or convertnon_empty_literal!output toWordText. Parse authored CHAT to retain its structure. JSON recovery admission is unchanged and still needs validation. -
Breaking:
Word::replace_simple_textnow requiresWordTextinstead of a raw string. Paired WOR redaction preserves admitted nonempty display text throughCountMatchedWorTimings::main_display_texts, removing unchecked replacement construction. JSON recovery remains subject to validation. -
Breaking: remove
WordPhonetic::new_uncheckedandWordShortening::new_unchecked. Use their checkednew/TryFromconstructors or conversion fromNonEmptyString. Lenient JSON admission remains subject to model validation. -
Breaking:
NonEmptyString::from_checked_literalrequires validatedNonEmptyLiteralevidence. Direct callers can no longer bypass the literal macro’s non-empty check by supplying a raw string. -
Add
Word::from_contentfor direct structured-word construction. Native lowering no longer computes a second cleaned-text projection or creates an unchecked temporary word before replacing its content. -
WOR display generation retains checked borrowed text from slot admission, removing unchecked word construction. Add
NonEmptyStrfor non-empty borrowed text and its allocation-only transition to owned text. -
Breaking: remove
MorWord::l2_placeholder(),MorWord::reset_to_l2_placeholder()andChatCleanedText::stanza_placeholder(). Unavailable analysis and provider transport substitutions must have explicit downstream states rather than fabricate morphology or cleaned source text. -
Breaking: remove
LanguageCode::empty(): absent source data must not manufacture the legitimate codeund. Explicitly suppliedundis retained. Native words now retain sharedWordLanguageMarkervalues, removingParsedLangSuffix, conversion-time language panics and the native word carrier’s emptyDefaultconstruction. -
Breaking (age admission):
AgeValueis opaque; construct it from text and read numeric values throughcomponents(). Callers can no longer pair unrelated numbers and serialized age text. Spelling validation consumes admitted shape evidence; string JSON/CHAT and recovery policy are unchanged. -
Breaking (MOR feature shape):
MorFeature::flatandMorFeature::with_key_valuereturnResult, refusing an equals sign in a flat value or key that would change the feature’s structure on JSON readback. Whole-text parsing still splits at the first equals sign and preserves empty fields and additional equals signs in values for ordinary validation. The string wire format and existing Debug representation are unchanged. -
Breaking (GRA label admission):
GrammaticalRelationType::newand string conversions are fallible; the interned payload is private. Labels require an initial ASCII letter followed by ASCII letters, digits or hyphens, preserving case, unknown heads and custom subtypes. Constructors, JSON and schema enforce this token boundary.GrammaticalRelation::newandAttachmentRelation::newtake checked labels;GrammaticalRelationType::rootconstructs the canonical root label. Vocabulary and graph validation remain separate from lexical admission. -
Breaking (Types field admission):
DesignType,ActivityType, andGroupTypeadmit nonempty ASCII alphanumeric atoms through falliblefrom_text/TryFromconstructors and JSON.TypesHeader::newtakes checked fields;TypesHeader::parseadmits three strings. Schemas enforce the same alphabet. The native parser rejects additional continued triples instead of silently keeping only the first one. -
Breaking (page-number admission):
PageNumber::newreturns a result; string conversions useTryFrom. Construction, JSON and schema require nonempty ASCII digits while preserving leading zeros and long identifiers. Native header parsing admits this shared type before lowering and refuses malformed page bodies instead of storing arbitrary text as a page number. -
Breaking (timed pause admission):
PauseDuration::TimedrequiresTimedPause::new(text)?, separating CHAT spelling from the optional numeric projection exposed byprojection(). The existing JSON shape is unchanged, but malformed spellings are rejected.PauseTimedDurationretains its standalone projection behavior. Large valid pauses remain syllable fillers and one-sided phonological alignment slots even without a numeric projection. Phon pause recognition now requires CHAT spelling too: integer-only or signed projection inputs no longer qualify as pause markers. -
Breaking (time-header API):
TimeDurationValueandTimeStartValueadmit text through their constructors and expose no mutable classification or components. Usesegments()andtime()to read parsed values. Empty headers have an absent state rather than fabricated midnight components; their pattern predicates return false. JSON strings and optional-empty validation are unchanged. -
Breaking (timing-tier API):
TimTierowns a private classification and derived time segments. Usefrom_text/emptyand the existing read accessors instead of constructing or mutating enum variants. Callers can no longer label unsupported text as parsed timing or edit its spelling independently of the segments. The JSON string representation is unchanged. -
Breaking (scoped marker labels):
LongFeatureLabelandNonvocalLabelnow require checked lexical admission;newandTryFromreturnInvalidScopedLabel. All five marker constructors require their admitted label type. JSON remains a string but rejects empty or malformed labels. The symbol registry owns the common alphabet used by both grammars, the model and generated schemas. Native structural marker carriers hold shared located models, removing raw-label reconstruction during conversion. -
Breaking (event admission):
EventType::newandTryFromadmit only nonempty descriptions in the registry-owned event character class and returnInvalidEventTypeon refusal.Event::newrequires this admitted type; unchecked string conversions are removed. JSON keeps its string shape but serde and generated schemas reject empty or delimited descriptions. Native event and annotation-chain carriers now contain the source-located sharedEvent. Sanitization admits its event replacement once before editing. -
Breaking (interposed speech):
OtherSpokenEventnow owns a structuredWordinstead of a public rawtextstring. Its constructor takes a word;word()andword_mut()expose that payload. JSON useswordand rejects the legacy raw-text shape. Both parsers use their ordinary word lowering, and model validation checks interposed words at every depth without adding them to the main speaker’s alignment sequence.LeafContent<'a>addsInterposed(&Word)and no longer implementsEq. Native token inspection exposesOtherSpokenPrefixfollowed by ordinary word tokens, and nativeContentItem::OtherSpokenEventcarries the shared model directly. -
Breaking (freecode model and lowering):
Freecode::text()exposes only admitted code text; the public mutabletextfield is removed. Both parsers preserve recognized blank freecodes as invalid source recovery. E316 replaces the primary parser’s unrelated E306 report, and model validation rejects the recovery after JSON import. Sanitization refuses it. ValidtextJSON remains unchanged; raw recovery usesunparsed.parse_freecodenow consumes a source-bound typed CST node. -
Breaking (postcode model):
Postcode::text()returns admitted payload text orNonefor recovery; the public mutabletextfield is removed. Both parsers preserve recognized empty postcodes as explicit source recovery. Validation rejects recovery and blank structured payloads after JSON import; sanitization refuses them. Valid{ "text": ... }JSON is unchanged, while retained source uses{ "unparsed": ... }. -
Breaking (structural view):
AngleRef::annotationsnow carriesAngleAnnotations::MissingorPresentwith admitted nonempty annotations. Useas_slice()for traversal. Model validation rejects retained bare angle groups at every depth, including after JSON readback; their CHAT spelling and existing wire shape remain unchanged. -
Breaking (content model):
OrphanAnnotationis a distinct variant ofUtteranceContent,BracketedItemand the borrowed content walker views. Native recovery no longer renders an unattached[/],[<]or replacement as an authored freecode. Original spelling and invalidity survive JSON; sanitization refuses this raw annotation source. -
Breaking (group locations and structural pauses):
PhoGroup::newandSinGroup::newtake a location first, andGroupRef::locationreturnsLocationdirectly. Native group carriers retain delimiters inEnclosedGroup; their serialized payload shape stays unchanged.LeafContent::Pausedistinguishes pauses from spoken events. E371 checks every nested phonological group and reports once at each offending group’s extent, including pauses nested inside other containers. JSON imports still report violations without inventing source positions. -
Breaking (structural overlap view):
LeafContent<'a>now carriesOverlapPoint(&OverlapPoint)separately from generic notation. Main-tier validation checks each retained point once, at its own location, including nested, word-internal, replacement and interposed points. The redundant alignment-region validation pass is removed; pairing no longer collapses diagnostics for standalone points or duplicates word-internal findings. -
Breaking (custom-tier model consolidation): Removed the unused
UserDefinedTierand suffix-onlyUserDefinedTierLabeltypes. ConstructDependentTier::UserDefined(UserDefinedDependentTier { .. })using a checked fullUserDefinedDependentTierLabel, such as"xgesture"rather than"gesture". Parser output and the CHAT/JSON document representation are unchanged. -
Breaking (custom-tier label admission):
UserDefinedDependentTier::labelnow requiresUserDefinedDependentTierLabel::new(text)?. Construction and JSON import reject malformed labels, built-in names and reserved structured extension names. Valid labels retain their string wire format.DependentTier::Unsupportednow carriesUnsupportedDependentTier, preserving unsupported input independently of custom-label admission. -
Breaking (dependent-tier model):
DependentTier::UnparsedTextpreserves a rejected text tier’s label and complete source. Native whole-file parsing no longer silently removes malformed bullet tokens from%com,%x*and other text tiers. Recovery remains invalid after JSON readback; redaction drops it, and tier replacement matches its original label. -
Add explicit
Header::UnparsedIDrecovery andRedactError::UnparsedID. Rejected ID fields retain source and invalidity through JSON. Missing-ID diagnostics require readable ID evidence; sanitization refuses rejected IDs. -
Main-tier terminal, inline and nested bullet positions now carry the shared
BulletStateenum. An occupied position holds parsedBullettiming or an explicitUnparsedBullet; missing terminal timing remainsNone. This changes the Rust payload types and requires explicit numeric projection. Parsed JSON keeps its existing shape; rejected JSON carries anunparsedpayload. Both parsers preserve rejected numeric source, model validation retains E360 after JSON import, and rejected terminal timing cannot promote an earlier inline bullet. Timing-dependent split/join/merge operations refuse recovery; rediarization flags rejected terminal timing without reassignment. -
BulletContentSegmentgains anUnparsedBulletvariant. Both parsers retain rejected numeric bullets in comment headers and structured text tiers instead of silently omitting them. Recovery retains the original spelling through CHAT and JSON serialization and remains invalid during model validation. Exhaustive matches over the public segment enum must handle this new state. -
Breaking:
DependentTier::UnparsedWorretains rejected word-timing source in both file parsers. It remains invalid and unusable for timing through JSON; replacement updates its slot, while redaction and splitting drop it. Native recovery no longer reconstructs and reparses failed WOR content. -
Breaking:
DependentTieraddsUnparsedPho,UnparsedModandUnparsedSin. Both parsers retain rejected phonology/sign source in its original slot. Recovery remains invalid and alignment-tainted after JSON import; redaction/splitting drop it and tier replacement updates its own slot. -
Breaking:
DependentTier::UnparsedGrapreserves the original rejected GRA tier in file parsing under both backends, including after JSON import. Recovery no longer exposes an empty or shortened dependency graph. It remains invalid, withdraws alignment trust, is replaced in its original regeneration slot, and causes redaction to returnRedactError::UnparsedGrammar. -
Breaking:
UnparsedMorTierbecomes the sharedUnparsedTierpayload;DependentTieraddsUnparsedPhoalnandUnparsedXphointvariants. MOR’s recovery variant and serialized fields retain their meanings. -
Breaking:
DependentTier::UnparsedMorexplicitly represents unparsed MOR source in the shared model and JSON schema. Exhaustive consumers must handle recovery. Sanitization refuses this state; regeneration replaces its slot. -
Breaking:
WriteChatimplementations now acceptW: ChatWriterand returnResult<(), W::Error>. Existingstd::fmt::Writedestinations remain supported. Owned-string helpers render through anInfallibledestination instead of discarding formatting failures; arbitraryDisplaycallbacks are excluded from the rendering interface. Phon tier content rendering is shared by itsDisplayand CHAT serializers. -
Breaking:
GraLowering::finish(location)returnsParseOutcome<GraTier>; a rejected relation cannot construct a serializable partial graph. RemoveGraCompletenessandGraLoweringReceipt. Source-bound Tree-sitter GRA parsing returnsResult<ParseOutcome<GraTier>, CstFailure>; re2c tier construction propagates rejection directly. File recovery continues to retain UnparsedGra. -
Breaking (diagnostic starting lines):
ErrorContext::line_offsetandwith_line_offsetnow useNonZeroUsize. JSON retains positive integer offsets and omitted offsets, but rejects zero instead of silently rendering it as line one. Source-backed contexts preserve the same nonzero proof through rendering; line-extent overflow remains an error.
Parser and transform consumers
-
Breaking (single-utterance admission):
SingleUtterance::admitconsumes aChatFileinstead of an utterance iterator, preserving document options. Single-utterance APIs in both backends retain a complete document’s@Options: CAsemantics. Callers no longer need to repeat those options in fragment context; bare shorthand still requires explicit CA context. -
Breaking: single-utterance parser APIs now reject input containing multiple utterances instead of silently returning the first. Both backends share cardinality admission; use whole-file parsing for multi-utterance inputs.
-
Breaking (fragment rebasing):
FragmentSource::rebaseandrebase_fromnow returnResult<T, FragmentRebaseError>, rejecting spans outside the admitted caller input instead of shifting or saturating them into document coordinates. Both parser backends propagate rejection.SpanShiftimplementations must provide the consumingtry_map_spansmethod; its derive generates it without requiringClone. The existing in-place text-edit shifting policy is unchanged. Unrepresentable diagnostic translations report an internal failure with the original message and snippet, without clamped labels. -
Breaking (parse-product fixture extraction): Removed the panicking
ParseProduct::expect_builtmethod from the production model API. Production callers matchBuiltandUnbuildable, retaining the model and diagnostics. Tests can explicitly importtalkbank_parser_tests::test_error::ParseProductTestExtfor the former fixture-only behavior. This does not change parsing or validity policy. -
Breaking (Tree-sitter bullet-text lowering API):
parse_bullet_contentand the nine low-level bullet-capable dependent-tier parsers returnResult<ParseOutcome<T>, CstFailure>. Missing content now rejects the enclosing body instead of inventing a continuation or an empty payload. Source-written continuations and absent optional dependent-tier bodies retain their existing meaning. The input-basedChatParserAPI is unchanged. -
Low-level Tree-sitter
parse_wor_tierreturnsResult<ParseOutcome<WorTier>, CstFailure>, distinguishing source rejection from producer failure. TheChatParserinterface is unchanged. -
Optional-validation and streaming-recovery APIs accept either parser through
ChatParser, including named transcript validation. Streaming products retain diagnostics independently of the caller’s sink. Parser rejection remains a parse failure and never becomes a parser-construction error or empty model. -
Checked source/model admission accepts either parser through
ChatParser.ParseProductnow belongs totalkbank-model; its old parser-crate export remains available. Both backends use one product-construction and admission path, preserving built models, diagnostics and explicit rejection. -
Breaking:
RoundtripFailure::Reparsedistinguishes rejected serialized output from serialization errors and text mismatches. -
Breaking (speaker mapping): mappings that give retained participants the same final code now refuse with
MappingAssignmentError::TargetCollision(CLI exit two), before CHAT output. Unmapped participants occupy their existing codes; swaps and reuse of dropped identities remain supported. -
Breaking (speaker mapping API):
apply_mapping_chatreturnsSpeakerIdError, preserving input-header refusals asSpeakerRewriteand reporting rejected replacement fields asInvalidAssignment. Speaker mapping now admits replacement speaker codes, canonical roles and nonblank names without comma/line delimiters before rendering. CLI refusal exits two. -
Breaking (pre-1.0):
DiarizationTurnnow requires its checkednewconstructor and exposes read-onlytrack()/span()accessors. Track labels must satisfy the same speaker-token constraints as speaker renames. Invalid turns-JSON tracks returnTurnsJsonError::InvalidTrack; the CLI exits with code 2 before opening CHAT or summary output destinations. -
Speaker mapping and rediarization now return
SpeakerRewriteError, distinguishing unavailable declarations from unparsed IDs. Merge reportsSpeakerHeaderswith input identity; pipeline and speaker-ID errors wrapSpeakerRewrite. These transforms refuse unreadable ID metadata before constructing output, including after JSON import. Recorded input failures addunparsed_id. -
Speaker-ID mapping now renames or drops
@Birth of,@Birthplace of, and@L1 ofreferences with their speaker assignment, preserving retained payloads. Header handling is exhaustive so new header kinds require review. -
Breaking (pre-1.0):
experimental review scriptedrefuses unused trailing decisions with exit 2 before writing either document.run_adjudicationnow consumes its prompter, andPrompterrequires a consumingfinishmethod.AdjudicationOutcomeexposes resolved sessions through read-only accessors. -
Breaking (pre-1.0): Sanitizer word and MOR lemma placeholders now use alphabetic suffixes (
worda,wordb, …,wordaa;lemmaa, …), removing numeric placeholders that introduced E220 errors in English output.PlaceholderIndex::first()and consumingsuccessor()replace numericnew(u32)/value(); the index is no longerCopyor ordered by Rust comparison traits. Its nonempty alphabetic representation has no zero index or fixed-width counter overflow. Timing correspondence and redaction policy are unchanged; sanitization still does not certify full output validity. -
Changed:
experimental transform redactrefuses partial source models whose unedited serialization drops or reorders non-whitespace source-line content, before opening output or writing stdout.ParsedSourceChat::sanitizeexposes this source-bound transition to library callers; model-onlysanitizedoes not establish source preservation. The shared loss check handles LF, CRLF and CR. -
Sanitization emits one placeholder per contiguous text or phonetic run, preserving structural markers and shortening boundaries. Escaped lexical segments no longer concatenate duplicate placeholders that change on a second pass.
Word::replace_contentapplies a completed rewrite and invalidates its derived text cache. -
Dependent-tier replacement uses one model-owned label identity for parsed and recovery payloads. Replacing text tiers such as
%comor%engupdates the first matching entry instead of appending a duplicate, while preserving its source separator and keeping distinct custom labels separate.
Experimental native parser consumers
-
Breaking (native grammar API):
parser::main_tier,parser::dependent_tiersandparser::headersare internal modules. UseRe2cParser’sChatParsermethods or the input-basedparser::parse_*helpers. Raw-token grammar composition could pair a token’s original spelling with foreign payloads before producing a source-bearing value. Public lexing and token inspection remain available; they do not grant parser admission. -
Breaking (native parser internals):
parser::classifyis crate-private. The obsolete subtoken word-start and unused pause classifiers are removed. Public source-input parsers and token inspection remain the supported routes. -
Breaking (native conversion API): raw
content_item_to_modelandtoken_to_terminatorhelpers are internal. Public lowering consumes parser-owned values through the existing word, tier, header and file converters. UseRe2cParser/ChatParseror input-based parser helpers to admit source text; a caller-built token or non-word item does not establish agreement between its payload and its source spelling. -
Breaking (native diagnostic API): removed the unused native
errormodule (ParseDiagnostic,ParseResult,Severity, and its span alias). Parser diagnostics usetalkbank_model::ErrorSink,ParseErrorandParseOutcome; no native entry point produced the removed types. The empty standalone binary is removed:talkbank-parser-re2cis a library crate. -
Breaking (pre-1.0): Removed the native parser’s
chat_lineslibrary module. The logical-line helper belongs to its fixture investigation tools and now lives in the integration-test target; production parsing is unchanged. -
Breaking (pre-1.0): Removed the documentation-hidden native parser
tests_supportmodule. Fixture loading now belongs solely to integration tests, whose nonempty fixture type removes empty-input skip paths. -
Breaking (pre-1.0): Native
SourceText::text_atis replaced by fallibleslice(range), returning aSourceSlicethat retains its source, text and span. Reversed, out-of-bounds and split-UTF-8 ranges are refused. Dependent-tier conversion now accepts that source-bound slice instead of separate extent and source arguments; file-region consumers reuse admitted bytes. -
Breaking: native lexer
LexResultretains its original source and exposes tokens throughtokens().error_report()no longer accepts a source argument, preventing mismatched sources or caller-edited ranges from panicking during reporting. -
Breaking (native lexer API):
Lexer::new,lex_lineand theCOND_*constants uselexer::StartConditioninstead of numeric DFA states. Lexer source, cursor, marker and tag fields are private. Callers choose a supported starting context; only the lexer may advance its internal state. -
Breaking (pre-1.0): Native lexer error records expose
token(),span()andcontext()accessors instead of mutable public fields. Error classification and report context now share one owner, removing an unknown-context fallback. -
Breaking (native header/file API):
Line::Headerholds aLocatedHeaderwith private syntax, source and separator fields.header_to_modeltakes that owner without a separate source;header_parsed_to_modelandHeaderProvenanceare removed. NativeChatFileexposeslines(),into_lines()andsource()instead of mutable fields. Native AST JSON retains its existing shape. -
Breaking (native utterance API): native
ast::Utterancefields are private. Read its main tier and dependent tiers throughmain_tier()anddependent_tiers(). The native parser owns their grouping through lowering; callers cannot assemble unrelated parsed tiers or erase observed tiers from a native parse result. Debug serialization and shared-model output are unchanged. -
Breaking (native word/dependent-tier API):
WordWithAnnotationsexposes borrowed accessors and retains its admitted source slice.word_from_parsedderives source and location; it no longer accepts a source argument. Rich word grammar entry points reject a foreign source buffer. Dependent-tier entries keep private payload/source fields, anddependent_tier_to_modelaccepts the entry without a separate source slice. Native JSON is unchanged. -
Breaking (native conversion API):
main_tier_to_modelandutterance_to_modelno longer accept a separate source argument. Located main tiers retain their original source;ParsedMainTierLine::source()derives it instead of exposing a replaceable source field. -
Breaking (native header tokens):
Token::HeaderPrefixcarriesHeaderPrefixToken, whosekind()retains the exact lexer-selected header identity. Unknown names such as@Commentaryand@OptionsExtraremain unknown headers and cannot acquire comment or option semantics. The shared model and serialized token payloads are unchanged. -
Breaking (native precode AST):
TierBody::langcodecontains the sharedLanguagePrecoderather than unchecked extracted text. Main and WOR grammars admit language values and source locations together; model lowering no longer silently discards a failed language conversion. The native AST serialization now emits the language string; shared CHAT/model serialization is unchanged. -
Breaking (native annotation carriers): word replacements occupy one optional field before scoped annotations;
annotations()now returns scoped annotations andreplacement()returns the optional replacement. Event carriers hold their scoped annotations directly, replacingAnnotatedEvent. Native parsing rejects misplaced tier codes, nonword replacements, repeated or reordered replacements, and annotations lacking required whitespace. The sharedChatParser::parse_wordboundary admits lexical words only; the native rich-word entry point still retains its attached syntax. -
Breaking (native tier carrier):
TierBody::linkerscontains located shared-modelLinkervalues instead of arbitrary lexer tokens. The grammar admits their kinds once; lowering cannot silently filter out an unmatched token. Native carrier JSON reflects the shared linker representation. -
Breaking (native dependent-tier API): text-backed parsed tiers carry an admitted
TextTierLabelinstead of a raw prefix token.dependent_tier_to_modelnow returnsDependentTierdirectly; every admitted entry retains a model tier, including explicit rejected-content variants. -
Breaking (native word-body API):
WordBodyErroraddsMalformedUnderline. Direct word-body scanning rejects an incomplete or malformed underline control sequence instead of returning it as lexical text. Exhaustive error matches must handle the new refusal. -
Breaking (native lexical API): embedded or trailing NUL bytes now produce lexical errors and scanning continues through the complete caller input.
Lexer,lexandlex_lineno longer accept explicit NUL padding as EOF. The generated DFA distinguishes source bytes from the bounded input’s end; parser-level control-character validation remains unchanged. -
Breaking (native lexer API):
DependentBodyKind::Trnis removed. The re2c parser preserves retired%trntiers as unsupported source text instead of promoting morphology-shaped content to%mor. E605 now reports the original unsupported label; malformed payloads remain opaque. -
Native re2c single-item retraces retain the admitted
ast::Chaininstead of unrestrictedContentItem.RetraceBody::Singlenow storesBox<Chain>;RetraceBody::itemsandContentItem::childrenyield borrowedContentRefiterators. Native AST serialization follows that shape. Marker ordering, shared-model output and source placement are preserved; unsupported single-retrace content is no longer representable. -
Native replacement annotations retain their complete source lexeme, preserving whitespace in
ParsedAnnotation::chat_textand orphan recovery. The serialized native carrier now exposeslexemeinstead of separatebegin/endfields (breaking, pre-1.0); shared CHAT model serialization is unchanged. -
Breaking (pre-1.0): Removed native
Token::Shortening,StressPrimaryandStressSecondaryvariants and their discriminants. The lexer already carries these constructs inside rich word bodies; their body/model support remains unchanged. Obsolete subtoken classification and admission paths have been removed. -
Breaking (pre-1.0): Removed
talkbank_parser_re2c::parser::classify::is_word_token. Subtoken assembly and annotation spacing now share one classified token owner; assembly consumes a nonempty sequence with its original source extent. -
Breaking: the native word-body scanner returns
WordBodyError, separating empty segments from unclosed shortenings. It no longer constructs a completed shortening when its closing parenthesis is absent. -
Breaking: native stress and overlap carriers use shared
WordStressMarkerTypeandOverlapPointKind. Remove duplicate enums and conversion matches; native debug kind names follow shared serialization. -
Breaking: native CA marker carriers use shared
CAElementTypeandCADelimiterType; remove duplicate native enums, character tables and lowering matches. Native debug AST serialization uses the shared snake-case kind names. -
Breaking: native word-body text and shortening variants carry shared
WordTextandWordShorteningvalues. Word-body scanning returnsResultand refuses empty lexical segments; lowering no longer constructs unchecked model text. Native AST string serialization is unchanged. -
Breaking: native word carriers use shared
WordCategory; remove the native duplicate enum and its lowering table. Native debug AST category serialization now uses shared-model names. Unknown rich-token prefixes are rejected. -
Breaking: native
ContentItem::Pausenow carries the shared locatedPause; removePauseKindParsedand its lowering. Grammar admission retains the lexer-issued full span and original timed-duration text. -
Breaking: remove native
TerminatorKindParsed; lexical classification and shared terminator construction now use one constructor table. Terminator conversion refuses tokens outside their supplied source instead of returning an unlocated value. -
Breaking: native
ContentItem::Separatorcarries the shared locatedSeparator; removeSeparatorKindParsedand its conversion/spelling tables. Main and WOR parsing share one separator grammar and reject missing source placement instead of substituting an unlocated value during conversion. -
Native media parsing constructs shared
MediaHeadervalues directly, preserving comma-whitespace provenance and explicit malformed-header recovery. Remove unused public nativeMediaHeaderParsedandTypesHeaderParsedstructs. -
Breaking: the native body-only
parse_id_headerandid_header_parserreturn sharedIDHeadervalues;IdHeaderParsedand its conversion are removed. Native file and fragment parsing use the same construction path. Empty elements inside nonempty ID language lists reject instead of being silently removed; file recovery retains the original header as unknown. -
Breaking (experimental native fragment API):
parse_languages_headerreturnsParseOutcome<LanguageCodes>;parse_languages_header_with_errorsalso reports input-relative diagnostics. Malformed lists reject instead of becoming empty successful lists.LanguagesHeaderParsedis removed. -
Breaking (experimental native AST):
ScopedAnnotationParsednow holds the sharedContentAnnotationplus the original lexeme. Inspectannotation()instead of matching a duplicate native enum. Public CHAT model and wire formats are unchanged; source spans and structural annotation policies remain. -
Native
ast::TierBody::terminatornow contains the sharedTerminatorinstead of a lexer token. Its experimental AST serialization follows the shared model representation. Main, MOR and WOR parsing admit located terminators through one grammar boundary;ChatParseris unchanged. -
Breaking: native WOR parsing constructs shared
WorItem/WorTierdirectly. RemovedWorItemParsed,WorTierParsedand their converter;wor_tier_parsernow takes the tier location. Unsupported word shapes and failed language/terminator admission reject instead of becoming placeholders or disappearing from successful tiers. -
Breaking: native PHO/SIN parsers construct shared model tiers directly. Removed the duplicate phonology/gesture ASTs (including
PhoWordParsed) and conversion helpers. The low-level PHO API returnsParseOutcome<PhoTier>instead of fabricating an empty tier on failure; the SIN body API now lives inparseralongside it. -
Breaking: native GRA APIs return shared model values in
ParseOutcome, with diagnostic variants ending in_with_errors. Remove nativeGraTier,GraRelationParsed,LoweredGraand their conversion APIs. GRA numeric rejection uses the shared all-or-rejected lowering transition directly. -
Breaking: native MOR combinators construct shared
MorWord,MorandMorTiervalues directly. Removed the duplicate native morphology types andmor_tier_to_modelconversion. Low-levelparse_mor_wordandparse_mor_tierreturnParseOutcomeof the shared types; diagnostic variants are available. -
Native text-tier helper APIs return
ParseOutcome<BulletContent>using the shared model directly. Grammar or lexical admission failure propagates rejection instead of a fabricated empty or silently shortened successful body. The duplicateTextTierParsedandTextTierSegmenttypes and their conversion functions are removed. Shared model and diagnostic wire formats are unchanged.
LSP clients and embedders
-
Breaking (pre-1.0): LSP execute-command failures now use JSON-RPC errors instead of successful string payloads. Malformed arguments and unknown command names return
-32602; admitted commands that fail return-32001. Successful transcript, header, graph and other command payloads keep their existing shapes. -
Breaking (pre-1.0):
talkbank/scopedFindresults replaceline,characterandlengthwith an LSPrange, preserving both endpoints of multiline matches. Matches that cannot project exactly, such as endpoints inside a CRLF pair, return an error instead of a rounded selection. -
Breaking (LSP speaker extraction):
talkbank/getSpeakersnow returns a JSON-RPC error when the current document has absent, unparsed or repeated participant declarations. It uses shared-model admission instead of returning an empty list or selecting the first competing header. Command failures are errors rather than strings inside successful responses. Missing roles in an admitted declaration remain explicit nulls. -
Speaker rename emits revision-bound document edits and is advertised only to clients supporting
workspace.workspaceEdit.documentChanges. Direct rename and prepare requests from unsupported clients return no result. Out-of-bounds cursor positions cannot be clamped onto a different rename target. -
LSP sessions that reject an edit now require newer full text or a reopen. Withhold source-dependent features, clear old diagnostics, and reject further incremental edits until synchronization is restored.
-
LSP document changes reject reversed ranges before position clamping; a rejected batch never commits partial text as a new revision.
-
Completion, on-type formatting and linked-editing responses now use the shared revision guard. Lost synchronization returns
ContentModifiedinstead of an apparently successful empty result. -
LSP formatting retains its producing open-document revision and refuses a response after that revision changes, closes, reopens or loses synchronization. Formatting, quick fixes and rename share document-owned revision admission.
-
Breaking (pre-1.0): Removed the public model/text-pair helpers
backend::features::document_symbol,backend::features::folding_rangeandbackend::features::code_lens::code_lens. Their server paths now consume source-bound analysis; code-lens anchors use parsed participant headers. -
Breaking (pre-1.0): Removed the public raw-text
backend::features::workspace_symbols_for_documenthelper. Workspace-symbol requests now use source-bound parsed analysis, omitting unparsed drafts while retaining navigation for recognized headers and utterances in the current buffer. Symbol response shapes are unchanged. -
The unversioned
backend::features::rename::renameedit builder is removed. Rename responses now pass through the server’s current-document admission.
Desktop integrations
-
Desktop validation binds events and cancellation to the issuing run. Pending startup can be disposed, and late callbacks, failures or cancellation from a replaced run cannot change the newer run. The internal IPC contract now requires a run identity in validation/cancellation requests and event envelopes.
-
Remove the dormant desktop
install_clicommand and its Rust protocol/error declarations. Desktop bundles do not contain a CLI; install it separately. The removed handler could delete an existing Unix CLI before replacement succeeded or overwrite a Windows executable during a failed copy.
Distribution and support boundaries
Upgrade the CLI, standalone LSP and desktop as coordinated products. Desktop
installers do not include a CLI-install action; install the CLI separately.
The package name is talkbank-chatter, while its executable is chatter.
Registry publication remains a separate maintainer action; source builds and
GitHub artifacts do not prove crates.io installation support.
The default parser is unchanged. Both backends share the model and recovery contracts; finite regression comparisons do not establish universal parser parity. This release is not a 1.0 completeness or platform-acceptance claim. Use the release procedure and publication contract for candidate qualification.
This page last changed: 2026-10-27 (commit 5bfee2f9). The whole book last changed: 2026-10-27 (commit 5bfee2f9).