Skip to content

Releases: iyulab/Formbase

Formbase 0.17.1

Choose a tag to compare

@github-actions github-actions released this 01 Oct 10:26

A patch. Pairs with MorphDB 0.14.x, unchanged from 0.17.0. No contract change.

Fixed

  • Packages carry the license text. Every package now ships LICENSE at its root beside the
    Apache-2.0 license expression, so redistributing a package carries the license copy the license
    requires and tooling that collects third-party notices finds the text.
  • WatermarkLagTrigger counts a form type's own documents. A lag threshold above one compared the
    watermark gap, but watermarks are shared by every form type, so other types' documents brought a
    projection due early. It now counts this type's documents after the projected watermark, reading no
    more than the threshold. The default threshold of one is unaffected.

Formbase 0.17.0

Choose a tag to compare

@github-actions github-actions released this 01 Oct 05:23

Pairs with MorphDB 0.14.x. A projection whose declaration has not changed reads only the documents
appended since its last run, with the result a rebuild would have, and a bound field names its value
column and, optionally, which record its value belongs to. Breaking for code that constructs or reads
EntityRef, for HTTP clients that send or read a bound field's target, and for implementers of
IProjectionStore and IProjectionState, which gain a member each.

Changed

  • A bound field's target names its value column as ValueField, not KeyField. The old name read
    as a lookup key, and declarations were written that way — KeyField was always the column the value
    comes from. EntityRef(entity, valueField, lookupKey, viaField); on the wire, target.valueField
    replaces target.keyField. Declarations already stored by an earlier release read back unchanged.
    RelationHint.KeyField (a relation's link field) is unaffected.

Added

  • A bound field can say which record its value belongs to. EntityRef.LookupKey (the field on the
    target that identifies a record) and EntityRef.ViaField (the field of this declaration carrying that
    key) — optional, and only as a pair. On the wire, target.lookupKey and target.viaField.
  • A target naming a field that does not exist is refused. Every declaration writer (in-memory,
    SQLite, PostgreSQL) refuses a ViaField that is not a field of the same declaration, and a
    ValueField or LookupKey that is not a field of the target form type when that form type is
    declared (DeclaredTargets); the host answers 400 /problems/invalid-declaration. An undeclared
    target is accepted unchecked.
  • A projection brings its table forward instead of rebuilding it when only documents were appended.
    When the declaration, table and recorded state are unchanged since the last projection, a run reads
    only the documents appended since its watermark: rows of records they correct or retire are removed,
    their own rows inserted, and the recorded skips updated in place. The table and GET …/projection/skips are what a rebuild would have produced; the cost of a run follows what was
    appended, not the size of the raw stream. A first run, a changed declaration or table, a table left
    in doubt by a failed run, and the first run after upgrading still rebuild. ProjectionResult.Mode
    (and mode on POST …/projection: rebuild or incremental) says which happened; on an
    incremental run the run's counts and skip lists cover the documents it read.
  • IProjectionStore.ReplaceRowsAsync (remove rows by record key or document, then insert — idempotent)
    and IProjectionState.ApplyProjectedDeltaAsync (compare-and-set on the recorded watermark, withdraw
    skips by record or document, append new ones). ProjectionSkip.Key and ProjectionFieldSkip.Key
    name the record a skipped document stood for; ProjectionStamp.SkipsKeyed says whether they do.
    SQLite and PostgreSQL state stores add the columns on first use.

Fixed

  • Two projections of one form type started at once in one process no longer race: they run one after
    the other. A run that finds the recorded projection moved under it marks it unverified, so the next
    run rebuilds rather than serving a table both runs wrote to.

Formbase 0.16.0

Choose a tag to compare

@github-actions github-actions released this 01 Oct 01:15

Pairs with MorphDB 0.14.x. An optional field whose value cannot be converted no longer drops its
document, and a timestamp without an offset reads the same on every host. Breaking for code that
implements IProjectionState.

Changed

  • An optional field whose value cannot be converted empties that field instead of dropping the
    document.
    A nullable column holding a value its type cannot take ("next week" in a Timestamp, an
    array in a Text) used to skip the whole document, so one bad value hid every other value it carried
    from every query. The row now lands with that column empty, and the emptied field is recorded (see
    Added). A required column that fails the same way still skips the document, as documented: the row
    cannot stand without it. Re-projecting an existing store can therefore insert rows that were skipped
    before.

Added

  • Emptied fields are recorded like skipped documents. ProjectionFieldSkip (document, field,
    reason) for each optional field a run emptied: in ProjectionResult.SkippedFields, recorded with the
    run by IProjectionState (GetFieldSkipsAsync, FormbaseEngine.GetProjectionFieldSkipsAsync) so it
    survives a restart, and replaced by the next run. They are counted neither in Skipped (the row
    landed) nor in AbsentFieldCounts (the document did carry a value). Host: skippedFields on the
    projection run response, skippedFields and fieldCount on GET /formtypes/{type}/projection/skips,
    and lastRun.skippedFieldCount on the projection status.
  • Breaking for IProjectionState implementers: SetProjectedAsync takes the field skips next to
    the skips, and GetFieldSkipsAsync is new. The SQLite and PostgreSQL adapters keep them in a table of
    their own (fb_projection_field_skips / projection_field_skips), created on first use in an
    existing store.

Fixed

  • A timestamp written without an offset is read as UTC, not in the host's zone. A date alone
    ("2026-01-15") or a date and time with no zone projected to a different instant on every machine
    that ran the projection — a date alone became the previous day east of Greenwich. Such a value is now
    that moment in UTC, so a date alone is its UTC midnight and reads back as the date written. Query
    filter values follow the same rule, so a filter written like the documents matches them. A value with
    an offset keeps it, as before.

Formbase 0.15.0

Choose a tag to compare

@github-actions github-actions released this 30 Sep 15:37

Pairs with MorphDB 0.14.x. A batch of documents is accepted in one durable write. Breaking for code
that implements IRawStore or IIntakeService.

Added

  • Accepting a batch in one durable write. FormbaseEngine.AcceptManyAsync(type, documents) takes
    documents and retirements of one form type (IntakeDocument.Accept, IntakeDocument.Retire) and stores
    them as one unit: when it returns all of them are durable, when it throws none is. Each accept on its own
    waits for its own commit — on SQLite, a sync to disk per document — so filling a store one document at a
    time is bound by that wait; a batch pays it once (10,000 documents into a SQLite file: about 13 times
    faster). On PostgreSQL a batch's inserts also travel together, a thousand to a round trip, so a database
    across a network is not waited on once per document. The batch's documents take consecutive watermarks in the order given. Idempotency keys work per
    document, so a batch cut off and sent again stores nothing twice; a key already holding another request
    refuses the whole batch with IdempotencyKeyReusedException, before anything is written.

Changed

  • Breaking: IRawStore.AppendManyAsync(type, appends) is new — a raw-store adapter implements it,
    and must store the batch atomically, which is why there is no default implementation that appends one
    at a time. RawAppend.Distinct and RawAppend.EnsureRepeats carry the idempotency rule an adapter
    checks before writing. IIntakeService.AcceptManyAsync is new as well.

Formbase 0.14.1

Choose a tag to compare

@github-actions github-actions released this 30 Sep 13:23

Pairs with MorphDB 0.14.x. Fixes for durable declarations: a declaration can no longer destroy the raw
documents of a single SQLite file, and the durable stores keep what a declaration says.

Added

  • DeclaredTableName — the rules every declaration writer applies before storing (IsReserved, Same,
    EnsureDeclarable, EnsureUnclaimed), and TableNameInUseException, raised when a declaration names a
    table another form type already projects into. Over HTTP it answers 409 /problems/table-name-in-use.

Fixed

  • A declaration can no longer name a table in the engine's fb_ namespace. On a single SQLite file, which
    keeps the raw documents, projection state and declarations beside the projected tables, a form type
    declared into fb_raw_documents replaced the raw table on its first projection — every document of
    every form type in the file was lost — and fb_field_hints or fb_projection_state broke the file the
    same way. InMemoryFieldHintSource.Declare, SqliteFieldHintSource.DeclareAsync and
    PostgresFieldHintSource.DeclareAsync now throw ArgumentException for a blank or fb_ table name, the
    host answers 400 /problems/invalid-declaration, and the SQLite projection store refuses to build or
    drop an fb_ table, so a declaration stored before this check still cannot reach one.

  • Two form types can no longer be declared into one table. Each rebuilt the table from its own documents,
    so a query of either read whichever projected last. The three declaration writers refuse the second
    (names compared ignoring case) with TableNameInUseException, atomically with the write; redeclaring a
    form type into its own table is unaffected. Declarations already stored that share a table keep
    projecting as before, but neither can be redeclared into that table until the other moves.

  • The durable declaration stores (SqliteFieldHintSource, PostgresFieldHintSource) kept only a
    declaration's table and fields: every declaration read back as version 1 with no relations. On the
    durable host the second replacement of a form type was therefore refused as a version conflict, and
    declared relations were gone after a restart — so a child relation declared through that host never
    reached MorphDB as a relation. Both stores now keep DeclarationVersion and
    Relations; a table written by an earlier version is upgraded in place on first use, and the
    declarations in it read back as version 1 with no relations — what they were stored as.
    Versions and relations declared before this release were never stored, so an upgraded store reads
    those declarations as version 1 with no relations until they are declared again (on the host, send
    expectedDeclarationVersion: 1 for that one replacement).

  • A form type stored as JSON — the target of a bound field inside a durable declaration — read back as
    the empty default, because FormTypeRef could be written but not read. On the SQLite and PostgreSQL
    stores a form type with a bound field (Snapshot or Reference with a Target) therefore could not be
    projected at all: resolving the target's table failed with "Value must be set" — and on the durable
    host, declaring one answered 500. It now reads back as
    the form type it was, including from declarations already on disk, so those form types project
    without being declared again.

Changed

  • FormTypeRef serializes as its identifier string ("work-order") rather than as an object
    ({"Value":"work-order"}); both forms are read.
  • A document skipped because an array arrived for a Text column is told both ways out: declare the column
    as Jsonb to keep the array as one value, or, when its items are rows of their own (a repeated section),
    append each item as a document of its own form type — projection does not split an array into rows.
    The skip used to name Jsonb only, which for a repeated section keeps every row in one column.

Formbase 0.14.0

Choose a tag to compare

@github-actions github-actions released this 29 Sep 06:27

Pairs with MorphDB 0.14.x. A correction is a new append — and now it can say which record it corrects. Breaking for code that
implements IRawStore or reads StoredDocument.Body, and for callers that passed a cancellation token
positionally to AcceptAsync/AppendAsync.

Added

  • Record identity. A document may name the record it belongs to with a RecordKey (an opaque
    string, compared exactly, scoped to the form type): FormbaseEngine.AcceptAsync(type, body, recordKey: key), over HTTP POST /formtypes/{type}/documents?recordKey=…. The projection shows each
    record once — the document with the latest watermark — so a corrected record is one row and a count
    counts it once. Documents without a key are records of their own, exactly as before.
  • Retiring a record. FormbaseEngine.RetireAsync(type, key), over HTTP
    DELETE /formtypes/{type}/records?recordKey=…, appends a retirement: a document with no body that
    takes the record out of the projection while its earlier documents stay in the raw stream. Appending
    under the key again brings the record back. Idempotency keys work for retirements as for intake.
  • Record keys are compared exactly and are not Unicode-normalized: the same text in two normalization
    forms (a file name from one system in NFC, from another in NFD) names two records. Normalize keys that
    come from file names or user input before sending them.
  • RecordFold.Latest — the fold the projector applies (latest per key, retired keys dropped), public so
    any reader of the raw stream can get records rather than appends.
  • Raw reads carry recordKey and retired (StoredDocument.Key, StoredDocument.IsRetirement). A
    retirement reads back with a null body; read retired rather than testing the body, since a document
    whose content is the JSON value null has a null body too.
  • Projected tables gain the fb_record_key bookkeeping column. Record reads still return the declared
    fields only.

Changed

  • A durable host refuses to start — exit code 78, naming the setting — when MorphDB answers that the
    configured Formbase:MorphDb:ProjectId does not exist. It used to report ready and fail its first
    projection with an unhandled error. A MorphDB that cannot be reached at startup does not stop the
    start, as before.
  • Breaking: IRawStore.AppendAsync(type, id, body, key = null, cancellationToken) takes the record key
    before the cancellation token, and IRawStore.RetireAsync is new — a raw-store adapter implements both.
    IIntakeService.AcceptAsync likewise takes recordKey before the token, and IIntakeService.RetireAsync
    is new. A call that passed the token positionally names it (cancellationToken: ct).
  • Breaking: StoredDocument.Body is nullable — null for a retirement. StoredDocumentResponse.Body
    is nullable over HTTP for the same reason, next to the new recordKey and retired.
  • An idempotency key reused under another record key, or for a retirement where it named a document (or
    the reverse), is refused like a key reused with a different body.
  • Schema intelligence skips retirements when sampling a form type's documents.
  • SQLite and PostgreSQL files and schemas from 0.13.x are upgraded in place on first use: the raw
    table gains its record-key column (and, on SQLite, a retirement column), and every document it holds
    reads back as a record of its own. On PostgreSQL the check runs before any change, so an up-to-date
    schema takes no table lock at startup. An existing projected table gains fb_record_key the next time
    it is rebuilt; until then nothing in it is keyed, because nothing appended before the upgrade was.
    The upgrade is one-way. Once a record has been retired, 0.13.x can no longer read the form type's
    raw stream (it answers 500), and a projection it runs leaves the table empty. Back up the database
    before upgrading if you may need to go back.
  • A bound field's target.keyField (EntityRef.KeyField) is documented for what it is: the field on
    the target form type whose value the bound field carries, not a key for finding the target record.
    The API reference had shown it one way and nothing said which; nothing about its behaviour changes.

Dependencies

  • Microsoft.Extensions.AI.Abstractions and Microsoft.Extensions.AI.OpenAI 10.10.1 (was 10.10.0), a patch.
  • Formbase.MorphDb depends on MorphDB.Client 0.14.0 (was 0.13.1), and the live tests and the compose file
    run the ghcr.io/iyulab/morphdb:0.14.0 image.

Formbase 0.13.0

Choose a tag to compare

@github-actions github-actions released this 28 Sep 13:52

Pairs with MorphDB 0.13.x, 0.13.1 or later. Record queries grow from equality to ranges, text
matching and empty-column tests, and the engine counts records per group. Formbase.Sqlite is new: the
whole engine's storage in one SQLite file, for a process with no database server. One breaking change
for code: QuerySpec.Filters is a list of FieldFilter (FieldFilter.Equal(column, value) is the old
entry), and an IProjectionStore adapter implements AggregateAsync. On the MorphDB store, a filter for
records whose column is empty used to miss them.

Added

  • Record queries filter with ranges and text matching, not only equality. A FieldFilter names a
    column, an operator and a value: Equal on any column; GreaterThan, GreaterThanOrEqual,
    LessThan and LessThanOrEqual on integer, decimal and timestamp columns; Contains and
    StartsWith, ignoring case, on text columns; IsNull and IsNotNull (FieldFilter.IsNull(column)),
    which take no value, on any column — "the records whose judgement is still blank". Filters all apply, and values are coerced to the
    column's declared type as equality values already were, so a date range can be written as text. An
    operator the column's type does not answer, a range or text match against null, or a value given to
    IsNull/IsNotNull, is refused with
    InvalidQueryException (its new InapplicableFilters names them) rather than answered with no rows.
    Text ranges are left out on purpose: backends order text differently, and the same query must return
    the same rows whichever store answers it.
  • Formbase.Sqlite: the raw store, projection store, projection state and field hints in one SQLite
    file (AddSqliteRawStore and AddSqliteProjection over one connection string — two different files
    are refused), for a process with no database server. Raw watermarks are never reused, so a restarted
    process finds its documents and its projections current. It passes the same contract tests as
    the in-memory and MorphDB stores: decimals compare numerically (kept as exact text under a numeric
    collation), instants compare as instants whatever their offset, and text matching ignores case beyond
    ASCII. Declared relations are not materialized.
  • FormbaseEngine.AggregateAsync counts projected records, optionally per group (AggregateSpec:
    GroupBy columns and the same filters). Groups come back ordered by their keys, nulls first, with key
    values as the declared column type, and the answer carries Stale and refuses exactly as a query
    does. Ungrouped, it is one count — zero when nothing matches.

Changed

  • Breaking: QuerySpec.Filters is a list of FieldFilter instead of a column-to-value dictionary;
    FieldFilter.Equal(column, value) is the old entry. IProjectionStore gains AggregateAsync, which
    an adapter implements by counting rows per group; the in-memory and MorphDB stores do, and both pass
    the same contract tests. The HTTP record endpoint still takes equality filters only.
  • Formbase.M3L depends on M3L.Native 0.17.0 (was 0.15.0), which targets .NET 10 like Formbase. The
    parsed declarations it reads are unchanged.

Fixed

  • On the MorphDB store, an equality filter with a null value — "the records whose column is empty" —
    was sent as a comparison with an empty string and missed the empty records. It is now sent as
    MorphDB's isnull, which needs MorphDB 0.13.1 or later; the in-memory store always answered it.
  • The compose bundle's PostgreSQL health check asks over TCP. Asked over the Unix socket, it reported
    the database healthy while the image was still running its init scripts on a socket-only server
    that restarts afterwards, so on a first docker compose up MorphDB could start against a server
    that was about to go away.

Formbase 0.12.0

Choose a tag to compare

@github-actions github-actions released this 27 Sep 04:48

Pairs with MorphDB 0.12.x, unchanged. A durable schema now records the namespace it holds and
refuses a host serving another name, an idempotency key belongs to one request, and a refused
configuration ends the process with exit code 78. Two changes are visible to existing deployments:
hosts that shared one schema under different namespaces no longer both start (see Upgrading under
the namespace section of the API reference), and a document naming a property twice is refused.

Added

  • GET /settings reports storage — the PostgreSQL schema and MorphDB project a durable host keeps
    its data in (null in-process). Two hosts reporting the same storage serve the same data, whatever
    namespace each answers to; the API reference and README now say that several namespaces sharing one
    PostgreSQL and one MorphDB need a schema and a project each.

Changed

  • A host that refuses its configuration — an unknown store profile, a durable profile missing a
    setting, half a model configuration, a schema holding another namespace — exits with code 78
    (EX_CONFIG) and says why once. It used to end on an unhandled exception: the runtime's crash exit
    code, and the message repeated under a stack trace.

  • A document whose JSON names a property twice in one object is refused with 400
    /problems/invalid-request (and DocumentBody.From/Parse throw). It used to be accepted, and
    the durable store kept only the last value while the in-process store kept both, so the body read
    back depended on the store.

  • A durable host's PostgreSQL schema records the namespace that first used it, and a host
    configured with another namespace over that schema refuses to start. Two names over one schema
    used to both start and serve each other's documents. A schema in use before this records the
    first namespace to start over it, so a deployment with one namespace per schema sees no change.
    A host whose database could not be reached at startup makes the check before its first request
    and answers 503 /problems/namespace-unverified until it passes; the readiness probe reports
    it too. The MorphDB project is not checked: namespaces sharing one replace each other's projected
    tables of the same name.

    If two namespaces already share one schema, decide which of them keeps it before upgrading, and
    start that host first and alone: whichever starts first claims the schema, so hosts started
    together are decided by which one got there first. Give every other namespace its own
    Formbase:Schema (and MorphDB project). The documents those hosts wrote while sharing stay in the
    claimed schema, under the namespace that claimed it — the raw stream does not record which host
    wrote a document, so Formbase cannot separate them.

Fixed

  • An Idempotency-Key sent again with a different request — another form type, or the same form
    type with a different body — is refused with 422 /problems/idempotency-key-reused. It used to
    answer 201 while storing nothing: the key's document stayed as it was and the new body was
    dropped. A retry of the accepted request still returns the same document; bodies are compared as
    JSON values, so property order and whitespace do not matter.

Formbase 0.11.1

Choose a tag to compare

@github-actions github-actions released this 24 Sep 23:27

Pairs with MorphDB 0.12.x. A patch: no surface moves. The packages carry their XML documentation,
the README quick start compiles as written, and the Docker release no longer republishes a version
already in the registry.

Added

  • The packages carry their XML documentation, so an IDE shows each member's comment from the package.

Fixed

  • The README quick start compiles as written. It builds a ServiceCollection, whose
    BuildServiceProvider lives in Microsoft.Extensions.DependencyInjection; Formbase.DependencyInjection
    depends only on the container abstractions, and the install list did not name the implementation, so
    a console app following the README failed with CS1061. The install list now names it (a host that
    already has a container skips it), and CI compiles the quick start against freshly packed packages
    and exactly the packages the README installs.

Changed

  • The Docker release no longer republishes a version that is already in the registry. A push that
    changed Directory.Build.props without changing <Version> used to rebuild that version from the
    pushed commit and move its image tags onto code never released under that number; the release now
    checks the registry first, publishes nothing when the tag exists, and fails rather than guesses when
    the registry cannot be asked. The NuGet release was already idempotent.

Dependencies

  • M3L.Native to 0.15.0. Its parse output lists metadata, custom-section and extension keys in
    sorted order rather than in an order that changed from run to run; its new lookup-path check
    (M3L-E022) is a validation diagnostic, and the hint adapter only parses, so a declaration it
    accepted before is accepted now.
  • MorphDB.Client to 0.12.3, and the MorphDB server image in docker-compose.yml, the README and
    the live fixtures to 0.12.3 (a patch: XML documentation and packaging). The live suite passes
    unchanged against the published 0.12.3 image.

Formbase 0.11.0

Choose a tag to compare

@github-actions github-actions released this 24 Sep 04:40

Pairs with MorphDB 0.12.x. A minor: a form type's raw stream is now readable over HTTP, page by
page, and a projection that builds nothing says why — which changes the public
NotProjectedException constructor in Formbase.Core. Everything on the wire is additive. The M3L
hint adapter maps and records more of what a declaration says, on M3L.Native 0.14.0.

Added

  • GET /formtypes/{type}/documents reads a form type's raw stream page by page, oldest first, after
    a watermark cursor (after, limit — default 100, at most 1000). Until now the only raw read was a
    single document by an id the caller had to already hold, and records carry only declared columns —
    so across the HTTP boundary, fields nothing had declared could not be read at all. Each page
    carries rawHead, read before the page and never passed, so a caller is caught up exactly when the
    last watermark it received equals it; limit=0 reads the head alone. An out-of-range limit or a
    negative after is refused with 400 rather than adjusted. In Formbase.Core,
    FormbaseEngine.ReadDocumentsAsync and DocumentPage are the same read for an embedding host.

Changed

  • The README's HTTP surface summary no longer says writing a declaration is not on the surface: PUT
    and DELETE /formtypes/{type}/declaration have been served since 0.8.0.

  • POST /formtypes/{type}/projection says why it built nothing. A run on a form type with no
    declaration answered 200 with projected: false and three empty diagnostic lists — and empty
    lists read as "nothing was lost", so the response looked like a successful run with nothing to
    do. It now carries notProjectedReason: noDeclaration when only a declaration can give the form
    type a shape, nothingToInfer when schema intelligence is installed but had no documents to infer
    from; null whenever projected is true. Additive on the wire.

  • The /problems/not-projected detail names the one remedy that applies instead of offering two.
    It used to say "declare field hints or trigger a projection" in every case, and with nothing
    declared the second remedy is a projection run that projects nothing — a loop the server never
    named. With nothing declared it now says to declare first; with a declared shape not yet built it
    says to trigger a projection. The problem type is unchanged. In Formbase.Core,
    NotProjectedException takes the state as a second constructor argument and exposes it as
    HasSchema.

  • The M3L hint adapter now maps the whole numeric catalog. byte, short and long join
    integer in the integer slot — that slot is emitted as a 64-bit column, so no rung of the ladder
    loses a value — and double and percentage join float, decimal and money in the decimal
    slot. Until now a field declared with any of those five names was reported as an unmapped type
    and degraded to a text column, which understated what the vocabulary can carry. binary is
    deliberately unchanged: it is the one catalog type with no slot to map to, so it still degrades
    to text with a recorded gap.

  • The M3L hint adapter counts two losses it used to let through unrecorded. A declared type
    parameter (string(50), decimal(10,2)) is recorded as a constraint gap, and an array field —
    which lands in a single JSONB column — is recorded with the element type and item nullability it
    cannot carry. Neither behaviour changes: the same columns come out. What changes is that the gap
    list, which exists to make the loss countable, no longer omits these two.

  • The M3L hint adapter records the three composition and ownership constructs M3L 0.13.0 makes
    structural. A model declared ::aspect(Base) or ::subtype(Base) is recorded with its base link,
    the same way an inherited model already is; a field contributed by ::extend keeps its column
    and is recorded with the owner it came from; and a model under a # Prefix: (or namespace) owner
    is recorded with that owner, since the form type is still identified by the bare model name. The
    hints themselves are unchanged — before 0.13.0 the base kinds were not models at all and were
    skipped without a trace, so this also stops an aspect or subtype from being silently emitted as a
    standalone table.

Documentation

  • The compose bundle is documented as needing --build, and its opening smoke check is now
    GET /health/ready rather than GET /settings. The host service is built from the tree, so
    docker compose up on its own brings back whatever image the last build left — a checkout that
    has moved on since then comes up serving the older one. /settings answers 200 from any
    build and so cannot tell the two apart; the readiness probe answers 404 on a build that
    predates the store health checks. The container health check already asked the same question
    from inside and a stale bundle never reported healthy, but nothing said to look there.

Dependencies

  • M3L.Native to 0.14.0. 0.11.0 adds a multi-file validation entry point (ValidateMulti and its
    typed and result-returning siblings) alongside the existing multi-file parse, and 0.12.0 widens
    the type catalog with byte, short and double and states float as 32-bit; the three new
    type names are mapped by the hint adapter in this same release. 0.13.0 adds the # Prefix: owner
    header, ::extend blocks (merged into their target's fields, each carrying its origin) and the
    ::aspect / ::subtype base kinds, which are now ordinary models with a base rather than untyped
    generic kinds — a document that used those three words as custom kinds changes meaning. The
    adapter's handling of them is described above. 0.14.0 resolves enum inheritance into an enum's
    values and tightens validation (a later hop of a lookup path without a reference, a value name
    repeated across inheritance, an argument on an extend header); the hint adapter parses without
    validating and maps enum types to text, so its output does not change.
  • MorphDB.Client to 0.12.2, and the MorphDB server image in docker-compose.yml, the README and
    the live fixtures to 0.12.2. The producer's releases since 0.12.0 are patches carrying dependency
    rounds and documentation corrections; no wire member moves. The suite with the live MorphDB tests
    passes unchanged against the published 0.12.2 image (330/330).
  • Microsoft.NET.Test.Sdk to 18.10.1 (tests only).