Migrate launcher standards to DEED and update parser docs and contribution guidance - #39
coderabbitai[bot] wants to merge 6 commits into
Conversation
D73-C ruled that `launcher-standard` converts to `.deed`, so this crate
needs to read the estate's live format. This commit adds the reader and
the evidence that it reads it correctly; nothing consumes it yet, so the
existing `.a2ml` path is untouched and the crate still builds standalone.
`deed.rs` is a hand-rolled recursive-descent parser over the DEED v1.0.0
ABNF — no `nom`, no `pest`. The grammar has exactly one ambiguity worth
naming: after a keyword, `(` opens a list (value position), while in a
clause body the same `(` opens a clause. Position resolves it, so the
parser never backtracks. Two other rules are easy to get wrong in the
permissive direction and are asserted rather than assumed:
- `symbol = ALPHA *( ... "=" ... )` — `=` is a legal symbol CHARACTER,
never a field separator, but a symbol must still start with a letter.
A parser that splits on `=` is reading TOML.
- order is not semantic. Precedence is an explicit `:priority` INTEGER
and consumers MUST sort ascending, so `children_by_priority` sorts
and the corpus carries a deliberately scrambled fixture to prove it.
The `:schema-version` rule lives in `parse()` rather than in any schema
layer, because the ABNF states it as a side condition on `form`: exactly
one field, STRING-valued. It need not be a semver — the upstream corpus
carries `:schema-version "not-string-issue"` as a VALID fixture.
The 15-file corpus is vendored from `standards` at c60abfaa with a
`MANIFEST.sha256` recording its provenance and refresh procedure, so
drift is detected rather than inherited. The manifest test compares the
SET of names, not a count, so an added or removed fixture is visible.
`every_invalid_fixture_is_rejected_for_the_right_reason` panics when a
new fixture has no expected-reason entry — "10 files are rejected" is
not the same claim as "10 files are rejected for their 10 named
reasons", and only the second is worth having.
Four mutants were reintroduced and each killed exactly the right test:
file-order `children_by_priority`, an unstable reversed sort, the tab
check disabled, and a permissive escape table. Green was restored after
each.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WPSJ7fBhVAMcpSffCBWUDo
Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
Owner ruling D73-C converted `launcher-standard` to the estate's live
`.deed` format. The standards side merged as be6c9580, which opened a
silent-downgrade window: this crate still parsed the retired `.a2ml`,
so it could only ever see the baked copy. This closes it.
The vendored standard moves with the reader, and the retired
`launcher-standard.a2ml` is deleted in the same commit so no build can
resolve to it by accident.
Three defects are fixed rather than carried:
- `spec_version` now reads `:standard-version` ("0.4.0"). The document
also carries `:schema-version` ("1.0.0"), which is the version of
the DEED GRAMMAR. Reading it yields a confident wrong answer, and
because 1.0.0 sorts above 0.4.0 the mistake reads as an upgrade.
A test asserts the two are different values, so the trap cannot be
reintroduced silently.
- `resolve()` walked ONE hardcoded `/var/mnt/eclipse/...` path and
then fell through to the baked copy. On any host not using the
eclipse-mount layout that is a silent downgrade with no diagnostic.
It now walks the deed's own `(resolution)(standard-search)` ladder
in ascending `:priority`, and the baked fallback logs at `info!`
rather than `debug!` because it means the on-disk standard was not
found.
- An unset `$VAR` now SKIPS its rung. `unwrap_or_default()` would turn
`$HP_ESTATE_ROOT/standards/...` into `/standards/...` — a real
absolute path that could exist and is not what the standard named.
The single documented exception is `$XDG_DATA_HOME`, which the
deed's own `:note` says defaults to `$HOME/.local/share`; with
`$HOME` also unset that rung vanishes too.
`resolve()` delegates to `resolve_with(flag, env, exists)` so tests
inject closures. `std::env::set_var` is process-global while cargo runs
tests in parallel threads, so an env-mutating test corrupts its
neighbours instead of isolating itself.
A file that is still the old TOML is diagnosed by name and pointed at
standards#960, rather than reported as a deed syntax error — that would
send a reader hunting for a typo in a file that is simply the wrong
format. `include_str!` reaches outside this crate, so the vendored
standard is pinned by sha256; an edit in `standards/` would otherwise
change this binary with no diff here and no test naming it.
Three mutants were reintroduced and killed: reading `:schema-version`
(3 tests red), `unwrap_or_default()` on an unset var (1 test red), and
reading the ladder in file order (1 test red).
The third initially SURVIVED, and that is worth recording: the real
deed's rungs happen to be written 10, 20, 30, 40, 50, so sorting and
not-sorting are indistinguishable against it. The ordering test asserted
the right rule while being unable to detect its absence. The ladder
reader is now split out so the test can feed it a deliberately scrambled
document, and the test asserts the fixture is still scrambled so it
cannot lose its teeth to a later tidy-up.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WPSJ7fBhVAMcpSffCBWUDo
Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
Commits 65d6893 and 7ab9fc5 converted the launcher standard to a praxis DEED and taught launch-scaffolder to read it. The documentation surface still described the old arrangement, and in two places was actively wrong rather than merely stale: - EXPLAINME.adoc linked to standards/launcher-standard.a2ml, which 7ab9fc5 deleted. That was a broken link. - README.adoc and EXPLAINME.adoc documented resolution as a three-step chain ending at one hardcoded absolute path. The tool now walks the search ladder the standard declares for itself, sorted by :priority. - README.adoc's "Why A2ML for inputs" promised a v0.2 migration TO A2ML "once a2ml-rs reaches feature parity". A2ML is retired estate-wide, so that is a plan to build on a dead format. META.a2ml records the change as ADR-010 and marks ADR-003 superseded rather than rewriting it; ADR-003 is the historical record of what was decided on 2026-04-10 and its text is left intact. ADR-010 also records the two hazards that are not visible from the code: the deed carries two version numbers (:schema-version is the grammar, :standard-version is the document), and the real deed lists its rungs already in ascending :priority order, so a consumer that ignores :priority cannot be detected by testing against it. Deliberately NOT converted here, and named so they read as deferred rather than missed: - the per-app <app>.launcher.a2ml config format -> standards#960 - the emitted @a2ml-metadata launcher header, a wire format shared by mint and realign; changing it strands launchers already on disk - docs/ruleset-audit-2026-04-10/ and docs/compliance-audit-2026-04-10.adoc, which are dated audit records and should not be rewritten References to launcher-standard.adoc are untouched: that prose spec still exists in standards and is a different file from the .a2ml that was retired. No behaviour change. 56 tests green, clippy -D warnings clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WPSJ7fBhVAMcpSffCBWUDo Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
Add regression tests and align standard-loader guidance with ADR-010.
|
Important Review skippedThis PR was authored by the user configured for CodeRabbit reviews. CodeRabbit does not review PRs authored by this user. It's recommended to use a dedicated user account to post CodeRabbit review feedback. ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Essentials Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
Superseded — this content is already on
|
| file this PR adds | on main |
|---|---|
crates/launcher-common/src/deed.rs |
present, 39,081 B |
crates/launcher-common/tests/deed_corpus.rs |
present, and green — cargo test reports 5 passed |
standards/launcher-standard_praxis.deed |
present, 13,803 B |
standards/launcher-standard.a2ml (deleted here) |
already absent |
CONTRIBUTING.adoc |
present at root |
That is the whole of D73-C as this PR proposed it: the deed parser, the fixture
corpus, the standard converted from .a2ml to _praxis.deed, and the .a2ml
removed. All of it shipped.
It is load-bearing rather than incidental — the phase-2 emitter in #46 is written
directly against deed.rs's lex_string (its four legal escapes, its < 0x20
control-character rule, its whole-document tab rejection), and deed_corpus.rs
runs green alongside it. The work this PR contains is the foundation the current
branch builds on, which is the clearest evidence it landed.
The PR is CONFLICTING / DIRTY and cannot land in this state.
⚠ Stated honestly: this PR's deed.rs is +1050 lines against main's 39,081 B
and #38's +984, so the three are not byte-identical and this is not a
superset proof. Nothing is lost by closing — refs/pull/39/head is permanent and
the diff stays reachable. If something specific here is genuinely missing from
main, it should come back as a small focused PR against current main rather
than as this branch rebased.
🤖 Generated with Claude Code
The six commits go beyond the requested docstrings for PR #36: they introduce a DEED v1.0.0 parser and migrate the launcher standard from TOML/A2ML to praxis DEED 0.4.0.
Validation: commit history reports 56 passing tests, clean Clippy with warnings denied, and mutation checks. Validation was not rerun for this metadata preparation.
View coding task