Repository navigation
Lore CLI 0.8.0
Released as a pair with quest 0.9.0, and the mismatched numbers are the point. "The pair"
means released and qualified together, not numbered alike. Exact-version lockstep was retired by
decision: the two CLIs have independent change sets, and a matched version string that is not a
matched contract invites callers to use the number as a compatibility check. Detect a capability
by presence, never by comparing versions.
The theme: 0.8.0 makes lore's own type vocabulary reachable, and stops lore emitting things its
own validator rejects. Three of the fixes below are cases where the tool contradicted itself — a
scaffold its validator refused, a documented example its parser rejected, a type it suggested but
could not resolve.
Known incompatibility — added 2026-09-20, after release (LCLI-561)
This section was not in the original 0.8.0 notes. It is added here because the
incompatibility is real, already published, and a reader who hits it will look
at this release's entry first.
0.8.0 is the first version that writes the ADR-0021 relation qualifiers
(statement, version, relationOrdinal) into retained snapshot edges, in
commit dd0876dc (LCLI-540, #170). The schema they join is .strict(), so an
older lore rejects any snapshot file 0.8.0 wrote, with:
retained snapshot is malformed or unsupported
The failure is scope-wide, not per-file. One 0.8.0-written file makes
list, retain, load and delete all throw for the older binary in that
scope — including the drain path you would reach for to clear it.
The reverse direction is deliberately handled (ADR-0021 ruling 13,
isRetainedQualifierBackfill), so this is not a symmetric break. Upgrading
lore is the only complete remedy: the binary that rejects the file has already
shipped and cannot be patched retroactively.
The exposed configuration is narrower than it sounds. The store is
.lore/cache/snapshots/1, which is gitignored, so this does not travel through
your repository — it needs a store that outlives a version downgrade on one
filesystem, or a CI cache of .lore/ restored into a job with an older pin.
Full note, with the measurements and the containment steps:
Upgrade note: retained snapshots written by lore 0.8.0.
Provenance — read this before checking the packument
- 0.8.0 ships with NO provenance attestation, and neither did 0.7.0, 0.6.2 or 0.6.1. Expected,
not tampering. LCLI-482 remains open and unresolved: OIDC trusted publishing still cannot
authenticate for this repository. GitHub issues immutable-format subject claims
(repo:opum-ai@<id>/lore-cli@<id>:...) and npm's Trusted Publishing matches the classic
repo:opum-ai/lore-cli:...form, so the exchange is refused and npm returns E404 on PUT. There is
no repository-level opt-out — settinguse_immutable_subject: falseis accepted and has no
effect. 0.8.0 therefore goes out through the manualscripts/publish-release.shpath, which
cannot mint an attestation. Do not read this release as having fixed it.
Added
lore types— the type vocabulary, as data (LCLI-537). Prints the active profile, its OKF
version and casing convention, then every declared type with its slug, its required sections and
its full field table. The unknown-type warning now also names the valid set and offers a nearest
match, so a typo is answerable without openingprofile.toml.profile.strict_types(LCLI-538). Makes an unknown type an unconditional error rather
than a warning, for projects that do not want tolerated producer extensions. Off by default;
existing bundles are unaffected.
Changed
lore checknow detects committed-schema drift (LCLI-539). A.lore/schemas/*.jsonthat no
longer matches what the profile would generate is reported rather than silently trusted.- This can turn a previously-green
lore checkred on content you did not touch, which is
the intended behaviour: the drift was already there and unreported. Clear it with
lore schema export, then commit the regenerated.lore/schemas/*.json. Consuming
repositories that runlore checkas a required CI context pin lore by hand, so this reaches
them only when they bump that pin deliberately — and it fires on the FIRST such bump past
0.8.0, against schemas committed under an older lore, for every type at once (exit 6).
Measured by opum-marketplace on 2026-09-19: all 7 of its profile schemas failed on its first
0.8.0 CI run, andlore schema exportcleared it.
- This can turn a previously-green
Fixed
lore new <multi-word-type>is reachable from its own slug (LCLI-534).Attested Computationis the one multi-word built-in and it was unreachable fromattested-computation:
type resolution consulted only the lower-cased NAME, whose key contains a space — a spelling no
shell argument can carry.lore new attested-computation "X"therefore wrote
type: attested-computationverbatim, emitted no$schemamodeline, scaffolded noruntime
field, andlore validatedegraded to an unknown-type warning while suggesting the very type
it had failed to resolve. Type resolution now also consults each type's lower-kebab slug, in both
resolution sites, so a slug-named type is known to every consumer rather than only tolore new.lore newscaffolds a profile type's declared sections (LCLI-535). A type'ssectionsare
enforced bylore validatebut were never written bylore new, so the tool's own
scaffold produced a file the tool's own validator immediately rejected. Built-in types were
unaffected only because their hand-written templates already carry theirs. A user template that
overrides the body wholesale is deliberately outside the guarantee — removing a required heading
from your own template is your decision, andlore validatewill say so.lore new --template <name>.mdresolves the file you named (LCLI-536). The extension was
appended to a name that already had one, so lore looked forfeature.md.mdand failed even
though the exact file existed — and the not-found hint told you to create the doubled file,
advice that would have made the error permanent. Both template sources now normalize identically.lore export --helpadvertises a version the exporter accepts (LCLI-512). Help, the manifest
andcli-surface.mdall claimed--schema-version 1.0and shipped it as a worked example while
the exporter had moved to1.1, so running the tool's own documented example exited 2. Every
advertised value now derives from the constant rather than restating it, and two guards fail the
build if a literal is reintroduced anywhere — one of which runs each advertised example.lore link/lore unlinkno longer clobber a concurrent tracker edit (LCLI-522). Label edits
are read-modify-write: lore read a task's labels, decided what to remove, then wrote — and a
competing writer landing in between made that decision stale while the write applied anyway.
Against a tracker that supports an optimistic-concurrency precondition, lore now asserts the
revision it read and retries the whole read-decide-write cycle, bounded, when the record moved.- Support is detected by presence, never by a version comparison. Passing the flag
unconditionally would have raised lore's effective tracker floor and broken every version in
between — an external compatibility change wearing the costume of a bug fix. Trackers without
the concept are unaffected.
- Support is detected by presence, never by a version comparison. Passing the flag
- Retained snapshots now carry the ADR-0021 relation qualifiers (LCLI-540).
edgeValuedropped
statement,versionandrelationOrdinal— the three fieldsProjectionEdgeRecorddeclares
under the comment "carried verbatim so an indexed read is as precise as a direct one" — so the
projection carried them and the retained snapshot did not. The consequence was thatlore changed
could never report a relation re-pin, andlore provenancecould not recover which
claim_versionwas cited at a past snapshot, which is the question ADR-0021 exists to answer.
The three fields are now optional members of the retained edge value and the format version
stayslore-retained-snapshot/1: every snapshot written before this release still validates.
lore-retained-snapshot/2was considered and deliberately NOT taken, so that existing snapshots
keep validating; the qualifiers are additive and optional precisely to make that possible. lore snapshot retainno longer reports a corrupt cache when only Lore's serializer changed.
A snapshot key derives from the source projection stream rather than from the retained bytes, so
re-retaining a commit you had already retained before upgrading produced the same key over
different bytes and raised "retained snapshot key refers to different bytes". That was a false
report — nothing of yours had changed. The upgrade difference is now recognised and the retain
succeeds. It is recognised narrowly: a qualifier whose value changed, a qualifier that
disappeared, and any difference outside those three fields all still raise the original error.
Internal — the release's own gates
docker/e2e/selftest.shstays a gate as it grows (LCLI-533). A failing assertion appended
below its reporting line ran, printed, was never counted, and left the script exiting 0 — in a
required CI step whose entire purpose is that a gate must be observed failing rather than
assumed to work. The conditional-exit idiom at the tail is replaced by anexithandler, which
observes the true final state no matter where a future case is added. A trailing check would not
have been enough: it only ever sees cases inserted above itself, and appending at the end of the
file is exactly how this arrives.
Upgrade notes — things that will look like bugs and are not
Each has the same shape: you upgraded, and something looks broken.
lore checkmay go red on content you never edited. See LCLI-539 above. The drift was already
present and unreported; regenerating the committed schemas clears it.- A one-time wave of
changededges.lore changedcompares the retained value field by field,
so every edge that gains a qualifier compares unequal to its older retained self exactly once.
Comparing two snapshots both retained after this release shows nothing spurious. - A snapshot retained before this release never gains the qualifiers. The retained entry is left
exactly as it was retained rather than rewritten, because it is a record of what Lore held at that
time and back-dating it would claim Lore had recorded qualifiers when it had not. Re-retaining that
commit now reportsunchanged, which is honest — nothing changed. To get the qualifiers for a past
commit, delete that snapshot and retain it again. - Snapshots written by this release cannot be read by an older Lore. The retained edge schema
rejects unknown keys, so an older binary reading a newer snapshot fails validation — and because
the store parses every file in a scope to enumerate it, that fails the whole scope rather than the
one file. This only bites a deliberate downgrade: a pinned older Lore, a bisect, or a second
worktree. The store is the gitignored local cache under.lore/cache/snapshots/, so the remedy is
to remove the scope directory and re-retain. Nothing shared or committed is affected.