From e1428b7db924d3d93fd3ef690d7cce81cc7d0ca3 Mon Sep 17 00:00:00 2001 From: the Institute Date: Fri, 11 Sep 2026 09:36:01 -0400 Subject: [PATCH] Gate the document on the conformance suite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The suite has been the load-bearing rung since it was published, and nothing ran it. The repository carried no workflows at all; the checks reporting on a pull request were CodeQL and DCO, neither of which knows what the document is. That was survivable while amendments arrived as separate proposal files, which could not break the document by construction. Now that amendments edit the document itself, the suite is the only thing standing between a malformed edit and the standard, and it ran only when someone remembered to run it. Adds the Conformance workflow, which runs the suite on every pull request and on pushes to main. Deliberately no paths filter: this is meant to become a required status check, and a required check that never runs leaves a pull request blocked forever. The suite finishes in well under a second, so running it on every pull request costs nothing and always reports. Adds .githooks/pre-push for the same check locally, installed with git config core.hooksPath .githooks and says plainly in both the hook and CONTRIBUTING.md that this is a convenience rather than a gate — hooks are not distributed with a repository, and --no-verify skips them. The pull request check is what holds. Adds CONTRIBUTING.md, which the repository never had despite DCO being enforced on every commit. It records the sign-off requirement and the fact that DCO matches the trailer against the commit author exactly, which is the failure mode contributors actually hit. It also writes down what the suite constrains: the nine sections, no new third-level heading inside a layer, twelve lines, the twenty-five anchors, no product names, no addresses beyond the footer. .gitattributes pins the hook and the workflow to LF. Checked out with CRLF on a Linux runner the hook has a bad interpreter line and will not run. Co-Authored-By: Claude Opus 5 Signed-off-by: the Institute --- .gitattributes | 5 ++ .githooks/pre-push | 37 ++++++++++++++ .github/workflows/conformance.yml | 27 +++++++++++ CONTRIBUTING.md | 80 +++++++++++++++++++++++++++++++ 4 files changed, 149 insertions(+) create mode 100755 .githooks/pre-push create mode 100644 .github/workflows/conformance.yml create mode 100644 CONTRIBUTING.md diff --git a/.gitattributes b/.gitattributes index ca7d31a..fa67ffa 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,3 +5,8 @@ *.docx binary *.png binary *.md text eol=lf + +# The hook runs in a POSIX shell and the workflow on a Linux runner. CRLF +# would leave the hook with a bad interpreter line and unrunnable there. +.githooks/* text eol=lf +*.yml text eol=lf diff --git a/.githooks/pre-push b/.githooks/pre-push new file mode 100755 index 0000000..d9f92ff --- /dev/null +++ b/.githooks/pre-push @@ -0,0 +1,37 @@ +#!/bin/sh +# +# Run the JFA conformance suite before anything reaches the remote. +# +# Install once, in your clone: +# +# git config core.hooksPath .githooks +# +# This is a convenience, not a gate. Hooks live outside the repository's +# history unless you run that command, and `git push --no-verify` skips them. +# The gate is the Conformance check on the pull request. + +set -u + +for py in python3 python py; do + if command -v "$py" >/dev/null 2>&1; then + PY="$py" + break + fi +done + +if [ -z "${PY:-}" ]; then + echo "pre-push: no python interpreter found; skipping conformance suite" >&2 + exit 0 +fi + +if ! "$PY" jfa-conformance-suite.py; then + echo "" >&2 + echo "Push blocked: the conformance suite failed." >&2 + echo "" >&2 + echo "The document has drifted from the invariant registry. Fix it, or run" >&2 + echo " git push --no-verify" >&2 + echo "to push anyway — the pull request will fail the same check." >&2 + exit 1 +fi + +exit 0 diff --git a/.github/workflows/conformance.yml b/.github/workflows/conformance.yml new file mode 100644 index 0000000..11a19df --- /dev/null +++ b/.github/workflows/conformance.yml @@ -0,0 +1,27 @@ +name: Conformance + +# No paths filter, deliberately. This check is a required status check on main, +# and a required check that never runs leaves a pull request blocked forever. +# The suite takes well under a second, so running it on every pull request +# costs nothing and always reports. +on: + pull_request: + push: + branches: [main] + +permissions: + contents: read + +jobs: + conformance: + name: conformance + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: '3.x' + + - name: Run the JFA conformance suite + run: python jfa-conformance-suite.py diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..6e37016 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,80 @@ +# Contributing + +This repository carries the official JFA document, its translations, and the +conformance suite that binds the prose to the invariant registry. Two rules +govern every change: **sign your commits off**, and **keep the suite green**. + +## Amendments go into the document + +Propose a change by editing the document and opening a pull request. The diff +is the proposal, and the board approves or rejects it in review. Do not add +proposal files or version-documentation alongside the standard — git history is +the version record, and a parallel proposal document starts drifting from the +text it describes the moment it is merged. + +Text that is settled goes into the document. Anything still unsettled goes into +[OPEN-QUESTIONS.md](OPEN-QUESTIONS.md) as a numbered entry carrying a +`**Status:**` line and an `**Inherits:**` line, in the style of the entries +already there. Update the count in that file's opening paragraph when you add +one. This split is not cosmetic: merging a document edit makes the text +normative, so a question that is still open cannot ride in on it. + +## Sign-off (DCO) + +Every commit needs a `Signed-off-by` trailer. The DCO check requires the name +and email in that trailer to match the commit author exactly, so let git add it +rather than typing it by hand: + +``` +git commit -s +``` + +If the check fails on an existing branch, add the trailer to every commit and +force-push: + +``` +git rebase HEAD~ --signoff +git push --force-with-lease +``` + +## The conformance suite + +``` +python jfa-conformance-suite.py # check the document +python jfa-conformance-suite.py --list # print the invariant registry +``` + +Exit code 0 when every executed check passes, 1 otherwise. It runs on every +pull request as the **Conformance** check and takes well under a second. + +To catch failures before you push, install the hook once in your clone: + +``` +git config core.hooksPath .githooks +``` + +That is a convenience, not a gate — hooks are not distributed with the +repository, and `git push --no-verify` skips them. The pull request check is +what actually holds. + +### What the suite constrains + +Edits to the document fail the suite if they: + +- drop or reorder the nine `##` sections. Additional `##` sections are fine. +- add a `###` heading inside one of the five layer sections. Each must carry + exactly Protocol Tier, Orchestrator Tier and Frontend Tier, in that order. + Put new prose in the body of an existing tier. +- leave *The Lines That Cannot Be Crossed* with any count but twelve. +- remove or reword a registered anchor phrase. Twenty-five invariants are + anchored to the sections that carry them; run `--list` to see them, and + prefer appending to rewriting. +- name a product. The document is product-agnostic. +- introduce an email address other than the organizational footer's. + +## Translations + +The English document is authoritative; translations are for reach, not +interpretation. The suite checks the English document only. If you amend it, +say in the pull request whether the translations should be updated before the +change is adopted or after.