Skip to content

spec: rewrite for 1.0 - #4

Open
gagarinlg wants to merge 1 commit into
mainfrom
spec/1.0-rewrite
Open

spec: rewrite for 1.0#4
gagarinlg wants to merge 1 commit into
mainfrom
spec/1.0-rewrite

Conversation

@gagarinlg

Copy link
Copy Markdown
Member

Update package spec

Rewrites the EdgeTX package specification to something an implementer can build
from. The previous draft could not be: it mandated POSIX APIs a browser cannot
call, guarded against symlinks FAT32 does not have, left the resolver and the
overwrite policy undefined, and had a normative state format with no schema and
no test coverage at all.

Thirteen rounds of adversarial review shaped this, each one building a throwaway
implementation from the prose and reporting where the prose failed. The last
three reviewers each answered that they could build a conforming implementation
from the normative documents alone — 65/65 manifest fixtures, 18/18 state
fixtures, 8/8 file lists, and a resolver with zero SAT/UNSAT disagreements
against a brute-force oracle over more than 100,000 fuzzed graphs.

WHAT THE FORMAT IS

Normative: docs/Manifest.md, docs/State.md and the two JSON Schemas. Everything
else is guidance and says so. Identity is location: a package id is its
repository URL, and there is no separate name registry.

- Ten content sections, source and destination paths, `exclude` patterns
- Hardware capabilities and firmware version bounds
- Variants: one package, many builds, selected by capabilities AND firmware
- Precompiled `.luac` packages, with one build per firmware generation
- Cross-package dependencies with semver ranges and a backtracking resolver
- Subpackages: several independent packages in one repository
- On-card state under `PKG/` that makes update and remove correct

SCOPED FOR WHAT THIS ACTUALLY IS

RC-controller firmware plus browser and desktop tooling writing to a FAT32 card,
at hobbyist scale. Requirements that no conforming browser implementation could
meet are gone. Four features were cut outright — a `depends` field for libraries
within one manifest, a flat-file spelling of subpackages, a `category` enum, and
the cached compatibility verdict in state. No packages exist yet, so nothing had
to be migrated and every feature was still speculative; each can return as a
MINOR addition when a real package needs it.

THE THINGS THAT WERE HARD

Most of the work was in cases where two conforming tools would otherwise do
different things, or where a package could reach a file it does not own:

- FAT32 case-insensitivity, applied to every destination comparison, so a
  package cannot take over another's files by changing one letter
- The `.lua`/`.luac` pair, where two distinct names are one executable — the
  source of three separate code-substitution holes, including one reachable by
  naming your victim as a dependency
- Marker ordering: nothing touches the card until every refusable check passes,
  so a refusal can never wedge a card into reporting an unfinished operation
- Cycle detection over the versions actually CHOSEN, not every version that
  exists, and reporting a range conflict rather than a cycle when both apply
- `**` in exclude patterns, ancestor destinations, and prerelease admissibility
  in version ranges, each of which two implementations read differently

CONFORMANCE

408 automated checks in 17 categories: manifest and state fixtures, file lists,
every example embedded in the documentation, cross-schema pattern agreement,
link and anchor resolution, table structure, Contents lists, retired wordings,
pseudocode helper contracts, and confinement of RFC 2119 language to the two
normative documents. CI runs exactly these.

83 fixtures. Every invalid one pins the specific rule it tests, so a fixture
cannot pass by being rejected for the wrong reason.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant