diff --git a/.github/workflows/release-loop-gate.yml b/.github/workflows/release-loop-gate.yml new file mode 100644 index 00000000..a7dec67e --- /dev/null +++ b/.github/workflows/release-loop-gate.yml @@ -0,0 +1,63 @@ +name: Release loop-gate + +on: + push: + tags: + - 'loop-gate-v*' + workflow_dispatch: + inputs: + tag: + description: 'Tag to publish (e.g. loop-gate-v1.0.0)' + required: true + type: string + +permissions: + contents: read + id-token: write + +jobs: + test-and-publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + with: + ref: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/{0}', github.event.inputs.tag) || github.ref }} + + - uses: actions/setup-node@v7 + with: + node-version: '22' + registry-url: 'https://registry.npmjs.org' + cache: 'npm' + cache-dependency-path: tools/loop-gate/package-lock.json + + - name: Ensure npm supports trusted publishing (OIDC) + run: npm install -g npm@latest + + - name: Install, build, test + working-directory: tools/loop-gate + run: | + npm ci + npm run build + npm test + + - name: Skip if version already published + id: check + working-directory: tools/loop-gate + run: | + VERSION=$(node -p "require('./package.json').version") + if npm view "@cobusgreyling/loop-gate@${VERSION}" version 2>/dev/null; then + echo "Version ${VERSION} already on npm — skipping publish." + echo "skip=true" >> "$GITHUB_OUTPUT" + else + echo "Publishing @cobusgreyling/loop-gate@${VERSION}" + echo "skip=false" >> "$GITHUB_OUTPUT" + fi + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Publish to npm + if: steps.check.outputs.skip != 'true' + working-directory: tools/loop-gate + run: npm publish --access public --provenance + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} \ No newline at end of file diff --git a/STATE.md b/STATE.md index 6b7b6312..d6b79c90 100644 --- a/STATE.md +++ b/STATE.md @@ -1,22 +1,33 @@ # Loop State — loop-engineering reference -Last run: 2026-07-17T09:41:37Z (automated daily-triage workflow) +Last run: 2026-07-19T18:55:00Z (scheduled maintenance) ## High Priority (loop is acting or waiting on human) - Maintain loop readiness score ≥ 58 (current: **100**, level **L3**). -- Keep npm packages current after tool changes (tag `loop-audit-v*`, `loop-init-v*`, `loop-cost-v*` — see docs/RELEASE.md). - +- npm publish in flight after this run: `loop-gate` 1.0.0, `loop-audit` 1.6.1, `loop-mcp-server` 1.1.0 (tags after merge). +- Configure npm trusted publisher / `NPM_TOKEN` for `@cobusgreyling/loop-gate` if first publish fails. ## Watch List - Expand contributor failure stories (dependency sweeper, multi-loop). - Collect a production story for Post-Merge Cleanup. +- Remaining Cursor doc gaps: [#220](https://github.com/cobusgreyling/loop-engineering/issues/220), [#223](https://github.com/cobusgreyling/loop-engineering/issues/223), [#224](https://github.com/cobusgreyling/loop-engineering/issues/224). - Validate `loop-init` scaffolds on fresh projects across all patterns. +- Optional: StackMap outreach [#300](https://github.com/cobusgreyling/loop-engineering/issues/300). + +## Housekeeping (2026-07-19 maintenance) + +- Merged [#307](https://github.com/cobusgreyling/loop-engineering/pull/307) (Devin appendix → closes #200), [#302](https://github.com/cobusgreyling/loop-engineering/pull/302) (starter loop-gate), [#303](https://github.com/cobusgreyling/loop-engineering/pull/303) (MCP loop-gate), [#308](https://github.com/cobusgreyling/loop-engineering/pull/308) (audit/MCP cost fixes). +- Landed `release-loop-gate.yml` + RELEASE.md docs (supersedes conflicted [#305](https://github.com/cobusgreyling/loop-engineering/pull/305)). +- Landed loop-worktree week-two story from [#299](https://github.com/cobusgreyling/loop-engineering/pull/299) (story only; matrix noise dropped). +- Closed draft [#304](https://github.com/cobusgreyling/loop-engineering/pull/304) as superseded. +- Pruned automated star-history / daily-triage remote branches. ## Recent Noise (ignored this run) -— +- Star-history automation PRs (#309, #310) already merged. +- StackMap marketing issue #300. --- -Run log: Updated by `.github/workflows/daily-triage.yml`. See `LOOP.md` for cadence and gates. +Run log: Updated by `.github/workflows/daily-triage.yml`. See `LOOP.md` for cadence and gates. \ No newline at end of file diff --git a/docs/RELEASE.md b/docs/RELEASE.md index bd9c3db6..31acca7f 100644 --- a/docs/RELEASE.md +++ b/docs/RELEASE.md @@ -1,6 +1,6 @@ # Release playbook — npm packages -This repo ships eight public npm packages from `tools/`: +This repo ships nine public npm packages from `tools/`: | Package | Directory | Release tag | |---------|-----------|-------------| @@ -11,6 +11,7 @@ This repo ships eight public npm packages from `tools/`: | `@cobusgreyling/loop-context` | `tools/loop-context` | `loop-context-v*` | | `@cobusgreyling/loop-mcp-server` | `tools/mcp-server` | `loop-mcp-server-v*` | | `@cobusgreyling/loop-worktree` | `tools/loop-worktree` | `loop-worktree-v*` | +| `@cobusgreyling/loop-gate` | `tools/loop-gate` | `loop-gate-v*` | | `@cobusgreyling/goal-audit` | `tools/goal-audit` | `goal-audit-v*` | ## One-time setup (trusted publishing — recommended) @@ -26,6 +27,7 @@ Link npm to GitHub, then for **each package** on [npmjs.com](https://www.npmjs.c | `@cobusgreyling/loop-context` | `cobusgreyling/loop-engineering` | `release-loop-context.yml` | | `@cobusgreyling/loop-mcp-server` | `cobusgreyling/loop-engineering` | `release-loop-mcp-server.yml` | | `@cobusgreyling/loop-worktree` | `cobusgreyling/loop-engineering` | `release-loop-worktree.yml` | +| `@cobusgreyling/loop-gate` | `cobusgreyling/loop-engineering` | `release-loop-gate.yml` | | `@cobusgreyling/goal-audit` | `cobusgreyling/loop-engineering` | `release-goal-audit.yml` | Names must match **exactly** (case-sensitive). No `NPM_TOKEN` secret is required when trusted publishing is configured. @@ -73,12 +75,16 @@ git push origin loop-mcp-server-v1.0.0 git tag loop-worktree-v1.0.0 git push origin loop-worktree-v1.0.0 +# loop-gate (path denylist + auto-merge allowlist) +git tag loop-gate-v1.0.0 +git push origin loop-gate-v1.0.0 + # goal-audit (Goal Engineering readiness scorer — companion repo) git tag goal-audit-v1.0.2 git push origin goal-audit-v1.0.2 ``` -Workflows: `.github/workflows/release-loop-audit.yml`, `.github/workflows/release-loop-init.yml`, `.github/workflows/release-loop-cost.yml`, `.github/workflows/release-loop-sync.yml`, `.github/workflows/release-loop-context.yml`, `.github/workflows/release-loop-mcp-server.yml`, `.github/workflows/release-loop-worktree.yml`, `.github/workflows/release-goal-audit.yml`. +Workflows: `.github/workflows/release-loop-audit.yml`, `.github/workflows/release-loop-init.yml`, `.github/workflows/release-loop-cost.yml`, `.github/workflows/release-loop-sync.yml`, `.github/workflows/release-loop-context.yml`, `.github/workflows/release-loop-mcp-server.yml`, `.github/workflows/release-loop-worktree.yml`, `.github/workflows/release-loop-gate.yml`, `.github/workflows/release-goal-audit.yml`. ## Verify after publish diff --git a/stories/README.md b/stories/README.md index 6ae73e08..aa6b95a3 100644 --- a/stories/README.md +++ b/stories/README.md @@ -16,6 +16,7 @@ Real-world loop engineering — including failures. Contribute yours via [CONTRI | [quant-loop-the-verifier-problem.md](./quant-loop-the-verifier-problem.md) | Quant research (domain) | Numerical checker beats LLM-as-verifier for backtests | | [quant-loop-out-of-time.md](./quant-loop-out-of-time.md) | Quant research (domain) | Strategy passed research, failed out-of-time data | | [ky-cut-surface-generation-vs-consequence.md](./ky-cut-surface-generation-vs-consequence.md) | Philosophy → loop bridge | Generation ≠ consequence; preserve the cut surface | +| [loop-worktree-week-two.md](./loop-worktree-week-two.md) | PR Babysitter + loop-worktree | Pair worktrees with `loop-context --check`; exact `outcome: failure` enum | **Template for new stories:** diff --git a/stories/loop-worktree-week-two.md b/stories/loop-worktree-week-two.md new file mode 100644 index 00000000..cca63817 --- /dev/null +++ b/stories/loop-worktree-week-two.md @@ -0,0 +1,83 @@ +# Week Two with loop-worktree: PR Babysitter, one fix at a time + +**Pattern:** PR Babysitter +**Tool:** loop-worktree (paired with loop-context) + +## What I was doing + +I was running a small PR Babysitter loop: watch a PR, try a fix in isolation, +verify it, and only escalate to a human if the fix doesn't land. The part I +wanted to get right this week was making retries safe — if attempt #1 fails, +attempt #2 shouldn't be fighting attempt #1 for the same branch. + +## The workflow + +For each fix attempt, I create an isolated worktree keyed to the run: + +``` +npx @cobusgreyling/loop-worktree create --run-id pr-42-fix-1 --pattern pr-babysitter +``` + +That gives me a fresh checkout under `.loop-worktrees/pr-42-fix-1` on its own +branch (`loop/pr-42-fix-1`), tracked in `.loop-worktrees/manifest.json` — so +nothing touches the branch another attempt might still be using. + +Once the verifier rejects an attempt, I mark it rather than deleting it +immediately — that keeps the audit trail intact: + +``` +npx @cobusgreyling/loop-worktree mark --run-id pr-42-fix-1 --status rejected +``` + +`list` gives me a quick read on what's currently tracked: + +``` +npx @cobusgreyling/loop-worktree list +``` + +And periodically I sweep anything rejected or escalated: + +``` +npx @cobusgreyling/loop-worktree cleanup --status rejected --older-than 24h +``` + +## Pairing with loop-context --check + +Before letting the loop retry again, I run the ledger through +`loop-context --check` so a stuck fix doesn't just keep burning attempts: + +``` +npx @cobusgreyling/loop-context --check --ledger run.json --stagnation 3 --json +``` + +With three identical failures in a row it stayed green (`shouldContinue: true`), +but on the fourth repeat of the same error it correctly flipped to +`escalate: true` with exit code 2 — which is the signal I use to stop the loop +and hand the PR back to a human instead of trying a fifth time. + +## The surprise + +The gotcha that cost me the most time: `--check`'s stagnation trigger only +recognizes attempts with `"outcome": "failure"` exactly. I'd first logged +attempts as `"outcome": "fail"` — `--summary` and `--status` happily counted +those as failures and showed the repeated error, so everything *looked* +right, but `--check` never escalated no matter how many times the same error +repeated. Nothing errors out to tell you the value was wrong; the breaker +just quietly stays at "continue." Since the whole point of pairing +loop-worktree with loop-context is to stop a bad retry loop before it wastes +a worktree (and tokens) on a fix that isn't working, a silently-inert circuit +breaker is exactly the failure mode you don't want. + +Separately, a smaller but good surprise: `cleanup --older-than 24h` refused +to remove a worktree I'd just marked rejected seconds earlier — it only acts +once the attempt is actually old enough (or you pass `--force`). That's the +right default; I just didn't expect it on first try and thought the command +had silently no-op'd. + +## What I'd change + +I'd want `--check` to validate the `outcome` field against the documented +enum and fail loudly (or at least warn) on an unrecognized value, instead of +silently treating it as a no-op for the stagnation/no-progress triggers while +`--summary` keeps counting it as a failure. Right now the two commands can +disagree about the same ledger without telling you. \ No newline at end of file diff --git a/tools/loop-audit/package.json b/tools/loop-audit/package.json index b1b12800..5da74d3d 100644 --- a/tools/loop-audit/package.json +++ b/tools/loop-audit/package.json @@ -1,6 +1,6 @@ { "name": "@cobusgreyling/loop-audit", - "version": "1.6.0", + "version": "1.6.1", "description": "Loop engineering readiness auditor. Compute Loop Readiness Score (L0-L3), detect activity, and get actionable suggestions. npx @cobusgreyling/loop-audit . --suggest", "type": "module", "bin": { diff --git a/tools/mcp-server/package.json b/tools/mcp-server/package.json index 54e1b267..f4b948b2 100644 --- a/tools/mcp-server/package.json +++ b/tools/mcp-server/package.json @@ -1,6 +1,6 @@ { "name": "@cobusgreyling/loop-mcp-server", - "version": "1.0.0", + "version": "1.1.0", "description": "MCP server for loop-engineering — exposes patterns, skills, state, and audit tools as runtime-queryable resources for AI agents", "type": "module", "bin": {