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
40 changes: 40 additions & 0 deletions .github/workflows/deed-conformance.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# SPDX-License-Identifier: MPL-2.0
name: deed-conformance

# Conformance lane for the DEED grammar (standards#837). Three gates:
# validator self-test → fixture corpus → every committed *.deed file.

on:
push:
paths:
- '**.deed'
- '1-formats/deed/**'
- '.github/workflows/deed-conformance.yml'
pull_request:
paths:
- '**.deed'
- '1-formats/deed/**'
- '.github/workflows/deed-conformance.yml'

permissions: {}

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: validator self-test
run: python3 1-formats/deed/tools/deed_lint.py --self-test
- name: fixture corpus (valid must pass, invalid must fail)
run: python3 1-formats/deed/tools/deed_lint.py --fixtures 1-formats/deed/tools/fixtures
- name: lint every committed deed
run: |
set -e
FILES=$(find . -name '*.deed' -not -path './1-formats/deed/tools/fixtures/invalid/*' -print)
if [ -z "$FILES" ]; then
echo "no committed .deed files yet — fixtures carry the gate"
exit 0
fi
echo "$FILES" | xargs python3 1-formats/deed/tools/deed_lint.py
73 changes: 73 additions & 0 deletions 1-formats/deed/tools/README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// SPDX-License-Identifier: CC-BY-SA-4.0
= DEED conformance lane — tools
Campaign: standards#837 · Grammar: link:../spec/abnf/deed.anbf[spec/abnf/deed.anbf
(v1.0.0, current until the canonical-file ruling)]

== The lane's one property

*Nothing invalid ever lands.* Every emitted deed passes the validator before
it may be written; every `.deed` committed in this repo is linted in CI.

== `deed_lint.py` — the validator

Stdlib-only implementation of the normative grammar. Enforces:

* SPDX header required; one form; full input consumed
* doc-head whitelist (`estate-deed / repo-deed / estate-atlas-deed / praxis-deed`)
* `:schema-version` STRING exactly once (validator-level semantic, per grammar)
* filename ↔ doc-head dispatch with the exact-stem-first side condition
(`estate_chora.deed` can never be a repo-deed; stems may contain dots —
split on the final suffix only)
* booleans ONLY `#t`/`#f`; bare `true/false/yes/no` values rejected
* uuid5 literals `#u5"name"` — body is the RFC 4122 §4.3 name input, never hex
* strings: exactly four legal escapes (`\" \\ \n \t`); `\r`/`\uXXXX` are
parse errors; raw control bytes rejected; spaces INSIDE symbols impossible
* separators are SP / line-end / comment ONLY — tabs are invalid everywhere
(K9-consistent); bare CR rejected (CRLF or LF line-ends only)
* quoted values restricted to symbols and lists

Usage:

python3 deed_lint.py FILE.deed...
python3 deed_lint.py --self-test # 14-case embedded corpus
python3 deed_lint.py --fixtures fixtures/ # valid/ must pass, invalid/ must fail

== `a2ml_to_deed.py` — the translator

Implements ONE authoritative mapping: the specs in `../mappings/`. It is
deliberately unable to invent mappings — untabled fields fail closed:

* P-1 uuid: re-derived (RFC 4122 §4.3, URL namespace) and compared against
the instance; mismatch → no output. Never copied.
* `--beholding-chora NAME` required: refuse-to-emit otherwise (no invented
identifiers).
* Booleans `true/false → #t/#f`; enums → symbols against closed sets;
empty slots kept as greppable `""` / `()` per slot doctrine.
* SPDX headers pass through (translation changes grammar, not licence).
* POST-CONDITION: emitted text is linted; failure writes nothing.

a2ml_to_deed.py full <repo-root> --canonical-name NAME --beholding-chora C [--out F]
a2ml_to_deed.py clade|agentic|neurosym|playbook FILE.a2ml --canonical-name N --beholding-chora C
a2ml_to_deed.py state-scan FILE... # family-3 classification (no translation; ruling pending #843)
a2ml_to_deed.py scorecard-scan DIR # family-5 corpus census + absolute-path leak TSV

Reference translation of the estate's canonical template passes the lane
(six instance files → one deed, uuid oracle verified).

Working estate instances surfaced *live* during development and fixed by
table extension, exactly as the frame prescribes (fail → review → extend):
`[axis-3-audit-rules]`, `[methodology]`, `[rsr-repo-skeleton]`, plus one
genuine registry deficiency flagged, not patched (standards' own CLADE
lacks `primary-name` — CLADE-006 territory, reported on #837).

== Fixtures

`fixtures/valid/` and `fixtures/invalid/` mirror the embedded self-test
corpus plus one real translated deed (`valid/rsr-template-repo_chora.deed`).
Reload rule: fixtures are generated FROM the `_FIXTURES` table in
`deed_lint.py` — edit the table, regenerate the files, commit both.

== CI

`deed-conformance.yml` runs on any change touching `**.deed`, the grammar,
or these tools: self-test → fixtures → lint every committed `*.deed` file.
Loading
Loading