Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 39 additions & 14 deletions 00-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,8 @@ explicitly opts into `enforce: write`.

When two edits to one record meet, for example an application update and an
edit made in a text editor, a tool that reconciles them uses the three-way
record merge of Chapter 12A. Different fields merge, timestamps take the
record merge of the
[concurrent edits profile](./concurrent-edits/0.1.md). Different fields merge, timestamps take the
later value, set-like lists take the union, appends to the body are both kept,
and only real disagreements are conflicts. How a tool surfaces a conflict, and
whether it replicates collections at all, is outside this specification.
Expand Down Expand Up @@ -310,18 +311,17 @@ keep those claims precise and independently testable.
| --- | --- |
| [01-concepts.md](./01-concepts.md) | Core terminology and data model |
| [02-collection-layout.md](./02-collection-layout.md) | Collection discovery, paths, and reserved state |
| [03-records-and-frontmatter.md](./03-records-and-frontmatter.md) | Markdown parsing and YAML value semantics |
| [03-records-and-frontmatter.md](./03-records-and-frontmatter.md) | Markdown parsing, record identity, and YAML value semantics |
| [04-configuration.md](./04-configuration.md) | The `mdbase.yaml` configuration file |
| [05-type-files.md](./05-type-files.md) | JSON Schema type wrappers and metadata |
| [05a-data-contracts.md](./05a-data-contracts.md) | versioned data contracts, type implementations, and transactional type packs |
| [05a-data-contracts.md](./05a-data-contracts.md) | versioned data contracts and type implementations |
| [06-json-schema-profile.md](./06-json-schema-profile.md) | Supported JSON Schema vocabulary and reference rules |
| [07-collection-semantics.md](./07-collection-semantics.md) | Matching, defaults, uniqueness, links, and paths |
| [08-links.md](./08-links.md) | Link syntax, resolution, traversal, and backlinks |
| [09-lifecycle.md](./09-lifecycle.md) | Managed values and mutation-time policy |
| [10-cel-profile.md](./10-cel-profile.md) | Portable expressions and host bindings |
| [11-querying.md](./11-querying.md) | Filters, ordering, projection, and result envelopes |
| [12-operations.md](./12-operations.md) | Read and write operations, concurrency, and diagnostics |
| [12a-concurrent-edits.md](./12a-concurrent-edits.md) | Record identity, move detection, three-way merge, and writer format fidelity |
| [12-operations.md](./12-operations.md) | Read and write operations, writer format fidelity, concurrency, and diagnostics |
| [13-migrations-and-compatibility.md](./13-migrations-and-compatibility.md) | Migration from earlier versions and compatibility |
| [14-conformance.md](./14-conformance.md) | Profiles, claims, fixtures, and runners |

Expand All @@ -330,6 +330,8 @@ chapters:

| Document | Description |
| --- | --- |
| [concurrent-edits/0.1.md](./concurrent-edits/0.1.md) | Concurrent edits profile 0.1: move detection and the three-way record merge |
| [type-packs/0.1.md](./type-packs/0.1.md) | Type packs profile 0.1: pack manifests, the lock file, assessment, and transactional apply |
| [interop/0.1.md](./interop/0.1.md) | Event and action interoperability profile 0.1 |
| [runtime/0.2.md](./runtime/0.2.md) | Durable runtime companion profile 0.2: standard pack, authorization, admission, execution, and recovery |
| [adapters/obsidian-bases.md](./adapters/obsidian-bases.md) | Obsidian Bases saved-view adapter |
Expand All @@ -342,17 +344,33 @@ directly comparable without making one product's internal API normative.
## Versioning

This specification uses semantic versioning. The current version is **0.3.0**,
in its fifth release candidate (`0.3.0-rc.5`); the sixth (`0.3.0-rc.6`) is
in draft. 0.3.0 is declared stable once
implementations pass the conformance suite.
in its sixth release candidate (`0.3.0-rc.6`), which is in draft.
Collections declare their specification version with `spec_version` in
`mdbase.yaml`. Tools declare the profiles and versions they implement.
`mdbase.yaml`, which is `0.3.0` for every release candidate. Tools declare
the profiles and versions they implement.

rc.6 is the last release candidate that adds or changes behavior. A later
release candidate only confirms or removes a provisional choice, corrects an
error, or adds tests. 0.3.0 is declared stable when both of these hold:

1. No paragraph marked **Provisional** remains in chapters 00 to 14. Each is
confirmed, by removing its marker, or removed together with the behavior
it describes.
2. The implementations named in the
[release contract](./release/v0.3.0.md) hold verified conformance claims
(Chapter 14) against that release candidate for the profiles of this
specification that the contract lists for them.

Companion profiles are not part of that gate. They keep their own versions
and can change after 0.3.0 is stable.

Companion profiles, artifacts, and schemas carry their own versions:

| Versioned thing | Declared by | Current | Format |
| --- | --- | --- | --- |
| collection specification | `spec_version` in `mdbase.yaml` | `0.3.0` | semantic version |
| concurrent edits profile | profile IDs `merge/0.1` and `move_detection/0.1` | `0.1` | major.minor |
| type packs profile | profile ID `type_packs/0.1` | `0.1` | major.minor |
| event/action interoperability profile | conformance claim `interop_profile_version` | `0.1` | major.minor |
| durable runtime profile | conformance claim `runtime_profile_version` | `0.2` | major.minor |
| interoperability testbed protocol | testbed evidence | `0.1` | major.minor |
Expand All @@ -371,11 +389,18 @@ The keywords `MUST`, `MUST NOT`, `SHOULD`, `SHOULD NOT`, and `MAY` are to be
interpreted as described in RFC 2119.

Draft notes use ordinary prose and are non-normative. A paragraph that begins
with **Provisional (rc.5).** or **Provisional (rc.6).** records a choice made where the design input
left a detail open. It is normative in the release candidate and may change
before 0.3.0 is declared stable. The
[0.3.0-rc.5 release notes](./docs/releases/0.3.0-rc.5.md) list every such
choice.
with **Provisional (rc.5).** or **Provisional (rc.6).** records a choice made
where the design input left a detail open. It is normative in the release
candidate, and it is confirmed or removed before 0.3.0 is declared stable
(see Versioning). The [release contract](./release/v0.3.0.md) lists every
such paragraph. A companion profile marks such a choice with its own version,
as in **Provisional (0.1).**, and may change it in a later version of the
profile.

A paragraph that begins with *Note (informative).* is not normative. Where
the specification names a library or an implementation, it does so only in
such a note: the text of the specification, not the behavior of any
implementation, defines conformance.

## License

Expand Down
7 changes: 4 additions & 3 deletions 01-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ may additionally include `collection.read_defaults`.
A record is identified by its path. A record carries no required mdbase
metadata: no ID, revision, or merge state is ever required in the file.
Implementations MAY keep internal record identities outside the collection's
records and follow a record across moves with the move detection of Chapter
12A.
records (Chapter 03) and follow a record across moves with the move
detection of the [concurrent edits profile](./concurrent-edits/0.1.md).

## Type

Expand Down Expand Up @@ -110,7 +110,8 @@ from type policy during the active mutation.
A merge combines two concurrent edits of one record against their common base
version. Each top-level frontmatter field has a merge strategy, declared in
`collection.merge` or derived from the type, and the body merges line by line.
Chapter 12A defines the merge function. When and where merges happen is an
The [concurrent edits profile](./concurrent-edits/0.1.md)
defines the merge function. When and where merges happen is an
implementation concern.

## Expression
Expand Down
11 changes: 7 additions & 4 deletions 02-collection-layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ record scan unless explicitly excluded.
The following paths are reserved by default:

- `mdbase.yaml`
- `mdbase.lock.yaml`, when managed type packs are installed
- `mdbase.lock.yaml`, when managed
[type packs](./type-packs/0.1.md) are installed
- the configured types folder, default `_types/`
- the configured contracts folder, default `_contracts/`
- `.mdbase/` for derived implementation state
Expand Down Expand Up @@ -224,9 +225,11 @@ collides, whatever file system it runs on:
`tasks/todo.md` to `tasks/Todo.md`, changes only the spelling of the path
and is not a collision.
- When record discovery finds several files with one path key, which can
happen on a case-sensitive file system, each file is still a record. Core
Read reports a `path_collision` warning on every record of the group, with
`details.paths` listing the group in code-point order.
happen on a case-sensitive file system, each file is still a record. A
tool that claims Collection Semantics reports a `path_collision` warning
on every record of the group, with `details.paths` listing the group in
code-point order. Core Read alone reads each file as written and computes
no path keys.

**Provisional (rc.5).** A tool that keeps records in a log or replicates
them across file systems cannot hold two records with one path key. It
Expand Down
47 changes: 41 additions & 6 deletions 03-records-and-frontmatter.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,27 @@ status: open
Body text.
```

If the first non-byte-order-mark bytes are not `---` followed by a line ending,
the file has no frontmatter and the full file is body text.

Whitespace or a blank line before the opening delimiter means there is no
frontmatter.
The **opening delimiter** is `---` followed by a line ending (`\n` or
`\r\n`), as the first bytes of the file after an optional byte-order mark.
The **closing delimiter** is the first later line that is exactly `---`,
ended by a line ending or by the end of the file. The frontmatter source is
the text between the two delimiter lines, and the body is everything after
the closing delimiter's line ending, so a blank line that follows the
delimiter is part of the body.

A file has no frontmatter, and the whole file is body text, when:

- it does not begin with the opening delimiter; whitespace or a blank line
before `---`, and `---` followed by a space or any other character, are
not an opening delimiter
- no later line is a closing delimiter; an opening delimiter that is never
closed does not make the rest of the file frontmatter

Only `---` closes frontmatter. The YAML document end marker `...`, a `---`
line with leading or trailing whitespace, and a longer run of dashes do not.
The first line that is exactly `---` closes it even when a YAML parser would
read that line as part of a block scalar, so every tool finds the same
frontmatter without parsing YAML.

## YAML Document Record Structure

Expand All @@ -60,6 +76,25 @@ application owns, such as Obsidian `.base` files (see the
[Obsidian Bases adapter](./adapters/obsidian-bases.md)), without a second
storage, discovery, or authorization model.

## Record Identity

A record is identified by its collection-relative path. Record files carry no
required mdbase metadata:

- An implementation MAY keep an internal identity for each record, for example
to follow it across moves or to key its history.
- Such identities, revisions, merge bases, and other bookkeeping MUST be kept
outside record files, for example in `.mdbase/` or the implementation's own
storage.
- An implementation MUST NOT write an identity into a record's frontmatter or
body, and MUST NOT require one to read, validate, query, or write a record.

A collection may still store its own identifiers in frontmatter, such as a
TaskNotes `id` field. When `settings.id_field` names such a field, it is used
for ID-based link resolution (Chapter 08) and as an identity hint for the move
detection of the [concurrent edits profile](./concurrent-edits/0.1.md). It
remains ordinary user data.

## Frontmatter Value

Frontmatter MUST parse to a YAML mapping. Empty frontmatter is an empty mapping.
Expand Down Expand Up @@ -183,7 +218,7 @@ update that supplies a non-empty body for a YAML document record fails with
(Chapter 12) is written exactly as supplied.

A write that changes some frontmatter keys of an existing record follows the
format fidelity rule of Chapter 12A: it re-emits only the changed top-level
writer format fidelity rule of Chapter 12: it re-emits only the changed top-level
entries, keeps every other entry byte-identical, including comments, quoting,
blank lines, and order, and keeps a changed entry's collection style. The rule
applies to Markdown records and YAML document records alike.
Expand Down
12 changes: 10 additions & 2 deletions 04-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ settings:
is the compatibility boundary. A v0.3 tool MUST reject v0.2 and v0.4
collections unless an explicit compatibility adapter is enabled.

Pre-1.0 draft versions MAY be accepted by explicit compatibility setting.
The value is exactly `"0.3.0"`, throughout the release-candidate series and
after it. A release candidate is a version of this specification, which a
tool names in its conformance claim (Chapter 14); it is never a version of a
collection, and a value such as `0.3.0-rc.5` is invalid.

## Settings

Expand Down Expand Up @@ -100,9 +103,14 @@ exception is a uniqueness rule that explicitly opts into `enforce: write`
single-record checks whose severity is always `warning`: they are reported at
levels `warn` and `error` and never reject a write.

`path_value_normalized` (Chapter 07) is not a validation issue. It is a
warning in the result of the write that normalized the value, at every
validation level, and it is not reported when the record is read later.

Writes that do not go through an engine's write operations are never rejected.
That includes edits made by other tools, files that appear through a file
system or synchronization tool, and the results of the merge in Chapter 12A.
system or synchronization tool, and the results of a merge
([concurrent edits profile](./concurrent-edits/0.1.md)).
Their issues are reported when the record is read or validated.

## Validation Levels
Expand Down
6 changes: 4 additions & 2 deletions 05-type-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ and collection rules.
Write operations use the same model around lifecycle processing: determine
membership from the requested draft, run the applicable lifecycle assignments,
then confirm membership once before final validation. The complete write order
is defined in Chapters 09 and 12.
is defined in Chapter 12.

## Required Frontmatter

Expand Down Expand Up @@ -196,7 +196,8 @@ implementing type matches `type: view` and maps every contract field to the
same-named frontmatter field.

A collection that stores portable view records SHOULD install that contract and
a type implementing it, normally through the `mdbase.view` type pack. A
a type implementing it, normally through the `mdbase.view`
[type pack](./type-packs/0.1.md). A
collection MAY instead implement the contract with its own type name, match
rule, and field mapping.

Expand Down Expand Up @@ -250,6 +251,7 @@ participates independently in each declaring type's uniqueness set.

Write operations determine membership from the requested draft and target path
before lifecycle runs. Explicit declarations use the same precedence as reads.
Chapter 12 defines which path a create uses when the request gives none.

After lifecycle has run, the implementation MUST evaluate membership once more.
If the final membership differs from the pre-lifecycle membership, the operation
Expand Down
Loading
Loading