Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
966e7c5
e2e: the package road, asserted — both directions
xormania Sep 1, 2026
98d14ec
e2e: serve recipes truly locally; apply the audit's workflow hardening
xormania Sep 1, 2026
fcdf683
Merge pull request #4 from minspec/e2e/package-loop
xor-machine Sep 1, 2026
34a0372
e2e: the org gate — one canonical road test, callable from every repo
xormania Sep 1, 2026
910d09c
Merge pull request #5 from minspec/e2e/org-gate
xor-machine Sep 1, 2026
7c85f20
ops: the review — Codex sweeps, Grok audits, the conductor applies
xormania Sep 1, 2026
7b25a71
Merge pull request #6 from minspec/ops/review-lane
xor-machine Sep 1, 2026
4d697c2
ops: the dev-lane — dispatch/task/harness/telemetry
xormania Sep 1, 2026
b80e036
ops: take the guards — hooks + workflow/checks
xormania Sep 1, 2026
9f5af68
ops: the local-CI infra — Gitea + act_runner + lane image
xormania Sep 1, 2026
0e34524
ops: the term wall — the lane refuses names this organisation does no…
xormania Sep 1, 2026
27a138d
ops: ignore every lever job root
xormania Sep 1, 2026
017f64b
ops: term wall tests, from the contract — 15 real executions
xormania Sep 1, 2026
4a54cba
ops: the term wall to its contract — pattern from configuration only
xormania Sep 1, 2026
80a0c82
ops: pin the term wall's hit format and refusal classes
xormania Sep 1, 2026
63f1408
ops: pin how CI hands the term wall its pattern
xormania Sep 1, 2026
e24bd27
ops: pin the workbench CI actions to release commits
Sep 1, 2026
f5b6035
ops: bring the lane term wall onto the pinned contract
Sep 1, 2026
9149aa7
ops: run the term wall in CI
Sep 1, 2026
a84bc55
Merge pull request #7 from minspec/ops/dev-lane
xor-machine Sep 1, 2026
2672aab
repo: move the wall to the object-store scan
Sep 2, 2026
7809ad9
Merge pull request #8 from minspec/repo/ci-pass
xor-machine Sep 2, 2026
a4e0273
ops: treat killed zombies as terminated in tests
xormania Sep 2, 2026
27af79f
Merge pull request #11 from minspec/codex/review-dev-lane-tools-for-i…
xormania Sep 2, 2026
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
10 changes: 10 additions & 0 deletions .claude/agents/test-author.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
name: test-author
description: Writes failing tests from a behavior contract without reading the implementation. Use for the red stage of a tdd work order when no second harness is available to author the tests.
---

Adopt the role card at `ops/process/roles/test-author.md` and follow it
exactly. Read the card first. You are the in-harness fallback for this role —
a second harness (Codex or Grok, per `ops/process/cross-review.md`) is
preferred when available, and the caller must say in the PR when the
fallback was used.
10 changes: 10 additions & 0 deletions .claude/agents/test-skeptic.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
name: test-skeptic
description: Adversarially reviews tests for shapes that pass over broken code. Use before recording green on a tdd work order when no third harness is available to judge the tests.
---

Adopt the role card at `ops/process/roles/test-skeptic.md` and follow it
exactly. Read the card first. You are the in-harness fallback for this role —
a harness that wrote neither the tests nor the implementation is preferred
(`ops/process/cross-review.md`), and the caller must say in the PR when the
fallback was used.
8 changes: 8 additions & 0 deletions .claude/skills/bdd/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
name: bdd
description: Given/When/Then behavior scenarios before tests or code, kept traceable to tests. Use at the spec stage of a work order, or when behavior needs agreeing on before implementation.
---

Read and follow `ops/process/bdd.md` — the canonical process document,
shared by every harness that works this repo. Scenarios land under
`.dev/design/features/`; when they are done, hand off per `ops/process/tdd.md`.
10 changes: 10 additions & 0 deletions .claude/skills/cross-review/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
name: cross-review
description: Have the other two harnesses (Codex, Grok — or Claude when another harness leads) review work against a detached snapshot. Use before merging test-bearing or evidence-bearing changes.
---

Read and follow `ops/process/cross-review.md` — the canonical process
document. The two rules that must survive any summary: reviewers get a
detached snapshot, never the live worktree; and only the owner triggers
`@codex review` on GitHub — the local `codex exec` reviewer is a different
thing and is yours to run.
38 changes: 38 additions & 0 deletions .claude/skills/dev-lane/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
name: dev-lane
description: The dev-lane pipeline — plan (Fable), tests (Grok), check the tests (Codex), code (Opus), review the code (Grok AND Codex, both). NO PRODUCER OWNS TWO CONSECUTIVE ARTIFACTS: whoever writes an implementation does not write or approve its tests. Scope is settled in session with the owner, then handed off. Load before starting any change under .dev/, and before dispatching any harness.
---

Read and follow `ops/process/pipeline.md` — the canonical sequence.
`ops/process/cross-review.md` covers review only; reading it alone gives
three roles where there are six.

Three rules that must survive any summary:

- **No producer owns two consecutive artifacts.** The specific models
matter less than that constraint. Measured twice on this repo: nine
defects past a green suite whose tests and code shared an author, and
eleven of fourteen review findings against two checkers being missing
test cases rather than coding errors.

- **The firewall is proved, not intended.** Withholding is invisible — a
snapshot that leaked the wrong file looks exactly like one that did
not. Prove both directions before dispatching: nothing matching a
withheld pattern present, *and* something matching every given pattern
present. An empty snapshot satisfies the first perfectly.

- **Contracts are extracted from an app's contract document, never from a
plan.** That is what keeps a plan disposable; the plan it was learned
from could not be retired because 1,236 citations under
`.dev/app/workflow/contracts/` point at it.

Scope is settled in session with the owner; the plan is not. State
*what* and the boundaries, and leave *how* to the planner. Review goes
to two harnesses, not one, so the rule holds whoever is driving — and a
CHANGES verdict is ruled on by a harness that produced neither the
artifact nor the finding, never by the producer, before any of it is
worked.

Reach: Claude loads this natively and Grok through claude-compat. **Codex
does not see repo skills** — its copy of these rules is `AGENTS.md`, which
every harness reads.
11 changes: 11 additions & 0 deletions .claude/skills/tdd/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
name: tdd
description: The wf-governed red→green loop — honest reds, sealed frozen sets, independent tests. Use when implementing anything under a tdd gate kind, or starting test-first work.
---

Read and follow `ops/process/tdd.md` — it is the canonical process document,
shared by every harness that works this repo (Claude, Codex, Grok), so it is
not duplicated here. When a step calls for the test-author or test-skeptic
role, prefer a different harness via `ops/process/cross-review.md`; the
`test-author` and `test-skeptic` subagents are the fallback when you must
fill a role in-harness.
2 changes: 1 addition & 1 deletion .env.dev
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

###> symfony/framework-bundle ###
APP_SECRET=bfba68e0d5a77f01269c924e502e3acf
APP_SECRET=NotASecretTestFixtureOnlyNeverDeploy0
###< symfony/framework-bundle ###
22 changes: 18 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,36 @@
name: ci
on:
pull_request:
types: [opened, synchronize, reopened, edited]
push:
branches: [dev, main]
permissions:
contents: read
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
persist-credentials: false
- name: term wall
uses: minspec/.github/.github/actions/term-wall@a5d88bb5b9bb744cf23c8829436e32f03d58c79d # minspec/.github#10
env:
TERM_WALL: ${{ vars.TERM_WALL }}
- uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # v2
with:
php-version: '8.4'
- run: composer validate --strict
- uses: actions/cache@v4
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ~/.cache/composer/files
key: composer-${{ hashFiles('composer.lock') }}
- run: composer install --prefer-dist --no-progress --no-interaction
- run: find src -name '*.php' -print0 | xargs -0 -r -n50 php -l
- run: php bin/console about
- run: vendor/bin/mate tools:list
- name: mate serves measured truth
run: |
vendor/bin/mate tools:call symfony-services --query=router --limit=10 --format=json \
| jq -e '.untrusted_data.services["router.default"]'
php bin/console fixture:hello 2>/dev/null && { echo "fixture must not be in the workbench app itself"; exit 1; } || true
vendor/bin/mate tools:list
114 changes: 114 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
name: e2e
# The org's one road test: package -> recipe -> endpoint -> app.
# Canonical here; every repo that can break the road calls this same
# workflow with its own PR slotted into the matching ref, siblings at
# dev. Never weaken it; extend it.
on:
pull_request:
push:
branches: [dev, main]
workflow_call:
inputs:
skeleton_ref:
type: string
default: dev
recipes_ref:
type: string
default: dev
fixtures_ref:
type: string
default: dev
workbench_ref:
type: string
default: ''
permissions:
contents: read
jobs:
e2e:
runs-on: ubuntu-latest
steps:
- name: checkout workbench (own run)
if: ${{ inputs.workbench_ref == '' }}
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
persist-credentials: false
path: wb
- name: checkout workbench (called)
if: ${{ inputs.workbench_ref != '' }}
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
repository: minspec/workbench
ref: ${{ inputs.workbench_ref }}
persist-credentials: false
path: wb
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
repository: minspec/skeleton
ref: ${{ inputs.skeleton_ref || 'dev' }}
persist-credentials: false
path: .e2e/skeleton
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
repository: minspec/workbench-fixtures
ref: ${{ inputs.fixtures_ref || 'dev' }}
persist-credentials: false
path: .e2e/fixtures
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
repository: minspec/recipes
ref: ${{ inputs.recipes_ref || 'dev' }}
persist-credentials: false
path: .e2e/recipes
- uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # v2
with:
php-version: '8.4'

- name: serve the recipes endpoint locally (clean arm)
run: |
cd .e2e/recipes
jq '._links.recipe_template = "http://127.0.0.1:8099/{package_dotted}.{version}.json" | .recipe_template = "http://127.0.0.1:8099/{package_dotted}.{version}.json"' index.json > index.tmp && mv index.tmp index.json
php -S 127.0.0.1:8099 &
sleep 1
curl -fsS http://127.0.0.1:8099/index.json | jq -e '.recipes["minspec/fixture-hello"]'

- name: compose the app from the skeleton
run: |
composer create-project minspec/skeleton .e2e/app --repository="{\"type\":\"path\",\"url\":\"$GITHUB_WORKSPACE/.e2e/skeleton\"}" --stability=dev --no-interaction

- name: require fixture-hello through the endpoint
run: |
cd .e2e/app
composer config secure-http false
composer config repositories.fixtures "{\"type\":\"path\",\"url\":\"$GITHUB_WORKSPACE/.e2e/fixtures/packages/fixture-hello\"}"
composer config extra.symfony.endpoint --json "[\"http://127.0.0.1:8099/index.json\",\"flex://defaults\"]"
composer require minspec/fixture-hello:1.0.0 --no-interaction

- name: assertions (independent test author)
run: bash wb/tests/e2e/assert.sh .e2e/app

- name: planted fault must fire
run: |
# Corrupt the served recipe (parameter renamed, ref changed so no
# cache can launder the plant), serve it on its own port, prove
# the plant landed and did not leak, then a fresh app build must
# fail. The clean arm above is the stay-quiet half.
mkdir -p .e2e/recipes-broken
cp .e2e/recipes/index.json .e2e/recipes-broken/
sed 's/fixture_hello.greeting/fixture_hello.wrong/' \
.e2e/recipes/minspec.fixture-hello.1.0.json > .e2e/recipes-broken/minspec.fixture-hello.1.0.json
sed -i 's/e2e-fixture-1.0/e2e-broken-1.0/' .e2e/recipes-broken/minspec.fixture-hello.1.0.json
grep -q 'fixture_hello.wrong' .e2e/recipes-broken/minspec.fixture-hello.1.0.json || { echo "plant did not land"; exit 1; }
! grep -q 'fixture_hello.wrong' .e2e/recipes/minspec.fixture-hello.1.0.json || { echo "plant leaked into clean fixture"; exit 1; }
jq '._links.recipe_template = "http://127.0.0.1:8098/{package_dotted}.{version}.json" | .recipe_template = "http://127.0.0.1:8098/{package_dotted}.{version}.json"' .e2e/recipes-broken/index.json > .e2e/recipes-broken/index.tmp && mv .e2e/recipes-broken/index.tmp .e2e/recipes-broken/index.json
(cd .e2e/recipes-broken && php -S 127.0.0.1:8098 &)
sleep 1
composer create-project minspec/skeleton .e2e/app-broken --repository="{\"type\":\"path\",\"url\":\"$GITHUB_WORKSPACE/.e2e/skeleton\"}" --stability=dev --no-interaction
cd .e2e/app-broken
composer config secure-http false
composer config repositories.fixtures "{\"type\":\"path\",\"url\":\"$GITHUB_WORKSPACE/.e2e/fixtures/packages/fixture-hello\"}"
composer config extra.symfony.endpoint --json "[\"http://127.0.0.1:8098/index.json\",\"flex://defaults\"]"
if composer require minspec/fixture-hello:1.0.0 --no-interaction >/dev/null 2>&1 && php bin/console list >/dev/null 2>&1; then
echo "planted fault did NOT fire — the oracle is blind"
exit 1
fi
echo "planted fault fired as required"
2 changes: 1 addition & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions ops/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,23 @@ maintainer installs it at `ops/bin/dispatch.sh` when wanted; its
staged text lives with the conductor session. Until then, delegation
runs through peer sessions and the House dispatch lane.

## The review

Big PRs to dev — substantive code, doctrine, or workflow changes, as
opposed to line fixes — take two independent passes before merge, each
from a different harness than the author:

- a **Codex security sweep**: supply chain, workflows, authority
boundaries, secrets
- a **Grok audit**: correctness, internal consistency, test quality

Both report on the wire (VERDICT / STAMP / FINDINGS with priorities;
anything unexamined marked UNCHECKED — silence is not a declaration).
The conductor dispatches both, applies findings through the lane
crediting the finder, and merges only on an APPROVE or on a CHANGES
whose P1/P2 findings are applied or explicitly ruled by the
maintainer. Ratification of stable remains the maintainer's.

## The rules the lane binds

- One line of work, one worktree (`../wt/<repo>/<slug>`); the main
Expand Down
3 changes: 3 additions & 0 deletions ops/bin/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Owner-owned, machine-specific — copy from dispatch.conf.example.
dispatch.conf
term-wall.conf
21 changes: 21 additions & 0 deletions ops/bin/dispatch.conf.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copy to dispatch.conf. The real dispatch.conf is gitignored: it is
# owner-owned, machine-specific config sourced by dispatch.sh, never a
# public artifact. A missing conf refuses loudly — it is not inferred.
#
# LAUNCHER_PIN is optional. Left empty, dispatch.sh finds the launcher next
# to itself (../devlane/dispatch/launch.py) — portable across worktrees and
# machines. Set it to an ABSOLUTE launch.py path only if you want the hard
# supply-chain lock (dispatch then runs exactly that launcher and no other).
#
# Owner allow rule (adding it is the owner's act):
# "Bash(bash /ABSOLUTE/PATH/TO/minspec/workbench/ops/bin/dispatch.sh:*)"
# Values may be overridden per call by an environment variable of the same
# name, then by the corresponding flag.

LAUNCHER_PIN=''
DEFAULT_TIMEOUT='300'
WF_AGENT_DEFAULT='GPT-5.6 Sol <noreply@openai.com>'
MODEL_GROK='grok-4.6'
MODEL_CODEX='gpt-5.6-sol'
MODEL_CLAUDE_READ='claude-opus-5'
MODEL_CLAUDE_PLAN='claude-fable-5'
Loading
Loading