diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..018bcc1 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @DivyamTalwar diff --git a/README.md b/README.md index 4bd8d34..4318966 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![verify](https://github.com/divyamtalwar/fablewright/actions/workflows/ci.yml/badge.svg)](https://github.com/divyamtalwar/fablewright/actions/workflows/ci.yml) [![tests](https://img.shields.io/badge/tests-143%20offline-brightgreen.svg)](tests/run-tests.sh) -[![checks](https://img.shields.io/badge/verify-149%20checks-brightgreen.svg)](scripts/verify.sh) +[![verify](https://img.shields.io/badge/verify-fail--closed-brightgreen.svg)](scripts/verify.sh) [![hosts](https://img.shields.io/badge/hosts-Claude%20Code%20%C2%B7%20Codex-blue.svg)](#quickstart) [![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) @@ -19,7 +19,7 @@ have done. -![FABLEWRIGHT architecture](docs/images/architecture.png) +![One wright plans and accepts; four pinned lanes implement; a fresh read-only reader from a different model family returns ship, fix-first or rethink](docs/images/architecture.png) --- @@ -83,7 +83,7 @@ ERROR: lane luna was pinned to effort 'max' but thread bbbb... also ran at: low (across 3 turns). ``` -![Proven routing versus a refused lane](docs/images/proof.png) +![Two runs of the same command: one verified and exiting 0, one refused with exit 69 because the lane dropped below its pinned effort](docs/images/proof.png) --- @@ -165,7 +165,7 @@ anyone starts, a written integration step owned by the wright, one reader over t *combined* change set, and every lane from one model family — because a single reader cannot be cross-family with two families at once. -![The five routes and how the wright chooses between them](docs/images/routes.png) +![The five routes ordered cheapest-first, with who implements, who reviews, and the question that selects each](docs/images/routes.png) --- @@ -301,6 +301,44 @@ scripts/ ask-wright · cast-call · install-agents · inspect-age tests/ offline suite with synthetic rollout fixtures ``` +## Contributing + +Issues and pull requests are welcome, and the bar is the same one the project holds +itself to: evidence over description. + +`main` is protected. Every change arrives as a pull request, CI must be green on both +runners, and the maintainer merges. That is not ceremony — it is the same separation of +authorship and acceptance the tool itself enforces. + +```sh +git switch -c fix/short-scope +# change something +sh tests/run-tests.sh # 143 offline cases, no model calls +sh scripts/verify.sh # manifests, pins, wording, links, images, then the suite +shellcheck --severity=warning scripts/*.sh tests/*.sh +git push -u origin fix/short-scope +gh pr create +``` + +Both gates are offline: they call no model, spend no tokens, and write nothing outside a +temporary directory. A green `verify.sh` is the bar. + +Before proposing a change to the scripts, read +**[Traps this codebase has already hit](CONTRIBUTING.md#traps-this-codebase-has-already-hit)**. +The code carries no inline commentary, so that section is where the reasoning lives — +every entry is a real defect found in review, not a hypothetical. Changes that weaken +fail-closed behaviour will be declined however convenient they are; the rules are listed +in [CONTRIBUTING.md](CONTRIBUTING.md). + +Found something that behaves differently from what the docs promise? Open an issue with +the exact command and its exact output. If a lane was refused, that may be correct — this +tool stops a lane rather than returning work it could not verify — so paste the refusal +and let the evidence settle it. + +Security reports go through +[GitHub's private advisory flow](https://github.com/divyamtalwar/fablewright/security/advisories/new), +never a public issue. See [SECURITY.md](SECURITY.md). + ## Prior art The route-gating discipline — declare the route before the first task tool, default to diff --git a/docs/WALKTHROUGH.md b/docs/WALKTHROUGH.md index e153568..2dd9719 100644 --- a/docs/WALKTHROUGH.md +++ b/docs/WALKTHROUGH.md @@ -219,7 +219,7 @@ passed: 143 failed: 0 ALL TESTS PASSED $ sh scripts/verify.sh -verify 1.0.0: passed 149, failed 0 +verify 1.0.0: passed 155, failed 0 VERIFY PASSED ``` diff --git a/docs/images/architecture.png b/docs/images/architecture.png new file mode 100644 index 0000000..3665947 Binary files /dev/null and b/docs/images/architecture.png differ diff --git a/docs/images/proof.png b/docs/images/proof.png new file mode 100644 index 0000000..e54cb7f Binary files /dev/null and b/docs/images/proof.png differ diff --git a/docs/images/routes.png b/docs/images/routes.png new file mode 100644 index 0000000..90a4a06 Binary files /dev/null and b/docs/images/routes.png differ diff --git a/scripts/verify.sh b/scripts/verify.sh index 7ee4207..ac592d1 100755 --- a/scripts/verify.sh +++ b/scripts/verify.sh @@ -254,6 +254,26 @@ for cmd in hosts/claude-code/commands/*.md; do done [ "$bare_paths" -eq 0 ] && ok 'every command references repo files via ${CLAUDE_PLUGIN_ROOT}' +group 'every referenced image exists' +missing_images=0 +for image in $(grep -oE '!\[[^]]*\]\(([^)]+\.(png|jpg|jpeg|svg|gif))\)' README.md docs/*.md 2>/dev/null | + sed 's/.*(//; s/)$//' | sort -u); do + case "$image" in http*) continue ;; esac + if [ -f "$image" ]; then + ok "image exists: $image" + else + bad "image exists: $image" 'a README referencing a missing image renders a broken icon' + missing_images=$((missing_images + 1)) + fi +done +for image in docs/images/architecture.png docs/images/proof.png docs/images/routes.png; do + if grep -Fq "$image" README.md; then + ok "README uses the diagram: ${image##*/}" + else + bad "README uses the diagram: ${image##*/}" + fi +done + group 'every internal document link resolves' broken_links=0 link_report=${TMPDIR:-/tmp}/fablewright-links.$$