harness-everything 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,7 +9,7 @@
9
9
  "name": "harness-everything",
10
10
  "source": "./",
11
11
  "description": "Harness OS: an orchestrated agent operating system — tier routing, circuit breaker guardrails, verification gates, WAL session memory, and self-evolving workspace rules.",
12
- "version": "0.4.0",
12
+ "version": "0.4.1",
13
13
  "author": {
14
14
  "name": "Miya Daniel"
15
15
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "harness-everything",
3
3
  "description": "Harness OS: an orchestrated agent operating system — tier routing, circuit breaker guardrails, verification gates, WAL session memory, and self-evolving workspace rules.",
4
- "version": "0.4.0",
4
+ "version": "0.4.1",
5
5
  "author": {
6
6
  "name": "Miya Daniel"
7
7
  },
@@ -9,10 +9,10 @@ jobs:
9
9
  validate:
10
10
  runs-on: ubuntu-latest
11
11
  steps:
12
- - uses: actions/checkout@v4
13
- - uses: actions/setup-node@v4
12
+ - uses: actions/checkout@v7
13
+ - uses: actions/setup-node@v7
14
14
  with:
15
- node-version: 20
15
+ node-version: 24
16
16
  - name: Validate eval case structure (free)
17
17
  run: node behavioral-evals/run.js validate
18
18
  - name: Install Harness for eval
@@ -16,12 +16,12 @@ jobs:
16
16
  os: [ubuntu-latest, windows-latest, macos-latest]
17
17
  runs-on: ${{ matrix.os }}
18
18
  steps:
19
- - uses: actions/checkout@v4
19
+ - uses: actions/checkout@v7
20
20
  with:
21
21
  fetch-depth: 0
22
- - uses: actions/setup-node@v4
22
+ - uses: actions/setup-node@v7
23
23
  with:
24
- node-version: 20
24
+ node-version: 24
25
25
  - name: Install dependencies for regression suite
26
26
  run: npm ci
27
27
  - name: Run hermetic self-regression suite
@@ -29,10 +29,26 @@ jobs:
29
29
  - name: Run focused mutation checks
30
30
  run: npm run test:mutations
31
31
 
32
+ runtime-floor:
33
+ runs-on: ubuntu-latest
34
+ steps:
35
+ - uses: actions/checkout@v7
36
+ with:
37
+ fetch-depth: 0
38
+ - uses: actions/setup-node@v7
39
+ with:
40
+ node-version: 22
41
+ - name: Install dependencies on minimum supported Node
42
+ run: npm ci
43
+ - name: Run representative regression suite on Node 22
44
+ run: npm test
45
+ - name: Verify installer contract on Node 22
46
+ run: node ci/installer-roundtrip.test.js
47
+
32
48
  skill-quality:
33
49
  runs-on: ubuntu-latest
34
50
  steps:
35
- - uses: actions/checkout@v4
51
+ - uses: actions/checkout@v7
36
52
  with:
37
53
  fetch-depth: 0
38
54
  - name: Install waza CLI
@@ -80,12 +96,12 @@ jobs:
80
96
  os: [ubuntu-latest, windows-latest, macos-latest]
81
97
  runs-on: ${{ matrix.os }}
82
98
  steps:
83
- - uses: actions/checkout@v4
99
+ - uses: actions/checkout@v7
84
100
  with:
85
101
  fetch-depth: 0
86
- - uses: actions/setup-node@v4
102
+ - uses: actions/setup-node@v7
87
103
  with:
88
- node-version: 20
104
+ node-version: 24
89
105
  - name: Install Node dependencies
90
106
  run: npm ci
91
107
  - name: Docs, manifest, and eval-coverage consistency
@@ -110,12 +126,12 @@ jobs:
110
126
  os: [ubuntu-latest, windows-latest, macos-latest]
111
127
  runs-on: ${{ matrix.os }}
112
128
  steps:
113
- - uses: actions/checkout@v4
129
+ - uses: actions/checkout@v7
114
130
  with:
115
131
  fetch-depth: 0
116
- - uses: actions/setup-node@v4
132
+ - uses: actions/setup-node@v7
117
133
  with:
118
- node-version: 20
134
+ node-version: 24
119
135
  - name: CLI --help works
120
136
  run: node bin/cli.js --help
121
137
  - name: Install, verify, uninstall, and restore seeded user files
@@ -28,14 +28,13 @@ jobs:
28
28
  runs-on: ubuntu-latest
29
29
  steps:
30
30
  - name: Checkout full release history
31
- uses: actions/checkout@v4
31
+ uses: actions/checkout@v7
32
32
  with:
33
33
  fetch-depth: 0
34
34
 
35
- # semantic-release 25 requires a newer Node runtime than the product's
36
- # normal Node 20 CI matrix. This only changes the release runner.
35
+ # Release tooling uses the repository's primary Node runtime.
37
36
  - name: Setup Node.js
38
- uses: actions/setup-node@v4
37
+ uses: actions/setup-node@v7
39
38
  with:
40
39
  node-version: 24
41
40
  cache: npm
package/.nvmrc ADDED
@@ -0,0 +1 @@
1
+ 24
package/AGENTS.md CHANGED
@@ -17,10 +17,12 @@ You are modifying **Harness**: an orchestrated agent operating system (skills +
17
17
  | `.agents/plugins/` + `plugins/harness-everything/` | Local OpenAI/Codex marketplace + `.codex-plugin` package with canonical skill copies and packaged session/prompt hooks. |
18
18
  | `submission/openai/` | Public OpenAI Skills-only listing/test inputs. The public artifact does not include local `.codex-plugin` lifecycle hooks. |
19
19
  | `evals/<skill>/` | Trigger/routing eval per skill (waza format). Required for every canonical routed skill. |
20
- | `behavioral-evals/` | LLM-behavior cases run via headless CLI sessions. On-demand only; costs tokens; never CI. |
20
+ | `behavioral-evals/` | LLM-behavior cases run via headless CLI sessions. They can be run on demand and are also structurally validated by the weekly `behavioral-evals.yml` workflow; live cases run there only when the Claude CLI is available. |
21
21
  | `benchmarks/` | BENCHMARK_SOP fixtures and recorded results. Evidence lives here or nowhere. |
22
22
  | `.claude-plugin/` | Claude Code plugin distribution manifests. Must list exactly the on-disk canonical skills. |
23
23
  | `docs/platform-capabilities.md` | Canonical current platform/install/enforcement/evidence matrix. |
24
+ | `docs/repository-contract.md` | Generated current-state Node/workflow/action/gate contract. Regenerate with `npm run docs:sync`; do not hand-edit. |
25
+ | `.nvmrc` | Primary development/CI Node runtime. `package.json#engines.node` remains the minimum supported runtime. |
24
26
  | `docs/`, `references/` | Philosophy, architecture, workflow documentation, shared checklists. |
25
27
 
26
28
  ## Non-Negotiable Change Rules
@@ -31,24 +33,28 @@ You are modifying **Harness**: an orchestrated agent operating system (skills +
31
33
  4. **Release version policy:** normal PRs do not manually bump package/plugin versions. `semantic-release` determines the next stable SemVer from Conventional Commits on `main`, and `scripts/sync-release-version.js` owns distribution-version synchronization. Skill frontmatter versions remain release metadata and must never exceed the package version's numeric base. Nested sub-skills (`<skill>/<sub>/SKILL.md`) inherit the parent skill's version and must always match it.
32
34
  5. **Distribution manifests are generated facts, not opinions:** if you add/remove/rename a canonical skill, update/sync every distribution that copies or lists it. Run `npm run plugin:sync`, `npm run test:consistency`, and `npm run test:plugin:openai` rather than updating only `.claude-plugin/plugin.json`.
33
35
  6. **Platform capability claims are tested contracts.** If host integration behavior changes, update `docs/platform-capabilities.md` and every affected current-state surface in the same change. Never turn package/mechanism evidence into a live-host claim, and never describe public Skills-only behavior as if it includes local lifecycle hooks.
34
- 7. **CHANGELOG.md keeps pending human-authored notes under `[Unreleased]`.** Do not create new alpha/beta/rc release headings; semantic-release owns stable release headings, tags, and release notes.
35
- 8. **Conventional Commit type is release input.** The final commit/squash title that lands on `main` must follow the convention. Breaking changes release major; `feat` releases minor; `fix`, `perf`, `refactor`, `build`, and `revert` release patch; `docs`, `test`, `ci`, `style`, and `chore` do not release by themselves.
36
+ 7. **Runtime/workflow claims are generated facts.** `package.json`, `.nvmrc`, `Dockerfile`, and active `.github/workflows/*.yml` are parsed by `scripts/repository-contract.js`. After changing them, run `npm run docs:sync`; `test:repo-contract` rejects stale generated docs, unsupported action majors, Node runtimes below the support floor, or loss of the Node 22 compatibility lane.
37
+ 8. **CHANGELOG.md keeps pending human-authored notes under `[Unreleased]`.** Do not create new alpha/beta/rc release headings; semantic-release owns stable release headings, tags, and release notes.
38
+ 9. **Conventional Commit type is release input.** The final commit/squash title that lands on `main` must follow the convention. Breaking changes release major; `feat` releases minor; `fix`, `perf`, `refactor`, `build`, and `revert` release patch; `docs`, `test`, `ci`, `style`, and `chore` do not release by themselves.
36
39
 
37
40
  ## Verification Before You Claim Done
38
41
 
39
- Run the local gates that mirror CI:
42
+ Run the local gates that cover the same contract categories as CI:
40
43
 
41
44
  ```bash
42
- npm test # self-regression: syntax, routing, mechanisms
43
- npm run test:mechanism # mechanism suites alone
44
- npm run test:consistency # manifests, versions, docs links, eval coverage + capability docs
45
- npm run test:docs:capabilities # platform documentation drift gate
46
- npm run test:references # executable/deep-dive references
47
- npm run test:release # release catalog + semantic-release/version-sync contract
48
- npm run test:collision # description collision detection
49
- npm run test:routing:skills # every positive skill route reaches its target
50
- npm run test:plugin:openai # local OpenAI/Codex plugin package
51
- npm run test:plugin:submission # public Skills-only submission inputs/bundle parity
45
+ npm test # self-regression: syntax, routing, mechanisms
46
+ npm run test:mutations # focused mutation checks
47
+ npm run test:mechanism # mechanism suites alone
48
+ npm run test:consistency # manifests, versions, docs links, eval coverage + repository contract
49
+ npm run test:repo-contract # runtime/workflow/action/schedule drift gate
50
+ npm run test:docs:capabilities # platform documentation drift gate
51
+ npm run test:references # executable/deep-dive references
52
+ npm run test:release # release catalog + semantic-release/version-sync contract
53
+ npm run test:collision # description collision detection
54
+ npm run test:routing:skills # every positive skill route reaches its target
55
+ npm run test:plugin:openai # local OpenAI/Codex plugin package
56
+ npm run test:plugin:submission # public Skills-only submission inputs/bundle parity
57
+ npm run test:platform:compatibility
52
58
  ```
53
59
 
54
60
  If waza is installed (`~/bin/waza`), also run what CI runs:
@@ -59,6 +65,8 @@ waza spec verify <skill> evals/<skill>/eval.yaml --fail --threshold 1
59
65
  waza tokens check
60
66
  ```
61
67
 
68
+ Node.js 24 is the primary CI runtime across Ubuntu, Windows, and macOS. A separate Ubuntu Node.js 22 lane protects the advertised minimum runtime. See [docs/repository-contract.md](docs/repository-contract.md) for the generated current state.
69
+
62
70
  Do not report "it works" from reading code. Record which evidence layer you actually proved: package, deterministic mechanism, live host, or behavior.
63
71
 
64
72
  ## Behavioral & Benchmark Evidence
@@ -66,6 +74,7 @@ Do not report "it works" from reading code. Record which evidence layer you actu
66
74
  Deterministic mechanism tests prove the tested hook/plugin contract; they do **not** prove a real host loaded it or that agents behave differently. For behavior:
67
75
 
68
76
  - `node behavioral-evals/run.js run --engine opencode` (or `--engine claude`) — on-demand, token-costing.
77
+ - The weekly `behavioral-evals.yml` workflow always validates case structure and runs live cases only when its runner has the Claude CLI.
69
78
  - `node benchmarks/run.js scaffold <scenario>` → run both variants → `record` with evidence logs.
70
79
 
71
80
  For a live-host enforcement claim, preserve a host/session artifact showing the mechanism was actually loaded and fired. Results are committed where the relevant evidence workflow requires it. A benchmark run without a recorded result is indistinguishable from one that never happened.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  All notable changes to this project are documented in this file.
4
4
 
5
+ ## [0.4.1](https://github.com/dyphn1/Harness-everything/compare/v0.4.0...v0.4.1) (2026-09-16)
6
+
5
7
  ## [0.4.0](https://github.com/dyphn1/Harness-everything/compare/v0.3.6...v0.4.0) (2026-09-16)
6
8
 
7
9
  ### Features
package/CONTRIBUTING.md CHANGED
@@ -4,24 +4,38 @@ Thanks for your interest in contributing.
4
4
 
5
5
  ## Development Setup
6
6
 
7
+ Harness supports **Node.js 22 or newer**. Node.js **24** is the primary development, CI, Docker, and release runtime; `.nvmrc` is the checked-in default. The generated current-state contract is [docs/repository-contract.md](docs/repository-contract.md).
8
+
7
9
  ```bash
8
10
  git clone https://github.com/dyphn1/Harness-everything.git
9
11
  cd Harness-everything
12
+ nvm use # uses Node 24 from .nvmrc when nvm is available
13
+ npm ci
10
14
  npm test
11
15
  ```
12
16
 
13
17
  ## Quality Gates
14
18
 
15
- All contributions must pass:
19
+ The reusable CI workflow runs the repository's deterministic gates across the supported operating-system matrix, with a separate Node 22 minimum-runtime lane. Before opening a PR, run the relevant local gates:
16
20
 
17
21
  ```bash
18
- npm test # self-regression
19
- npm run test:mechanism # hook mechanism checks
20
- npm run test:consistency # manifest, version, link checks
21
- npm run test:release # release catalog + version automation contract
22
- npm run test:collision # description collision detection
22
+ npm test # self-regression
23
+ npm run test:mutations # focused mutation checks
24
+ npm run test:mechanism # hook/plugin mechanism checks
25
+ npm run test:consistency # manifests, docs, eval coverage + repository contract
26
+ npm run test:repo-contract # Node/workflow/action/schedule drift gate
27
+ npm run test:references # executable/deep-dive references
28
+ npm run test:release # release catalog + version automation contract
29
+ npm run test:collision # description collision detection
30
+ npm run test:plugin:openai # local OpenAI/Codex plugin package
31
+ npm run test:plugin:submission # public Skills-only package reproducibility
32
+ npm run test:platform:compatibility
23
33
  ```
24
34
 
35
+ If `waza` is installed, CI also validates canonical skill readiness, routing evals, and token growth. See [AGENTS.md](AGENTS.md) for the repository operating rules.
36
+
37
+ When runtime or workflow configuration changes, run `npm run docs:sync` and commit the regenerated [docs/repository-contract.md](docs/repository-contract.md). CI rejects stale generated contract data.
38
+
25
39
  ## Skill Contributions
26
40
 
27
41
  Each skill lives in its own top-level directory with a `SKILL.md`. See [AGENTS.md](AGENTS.md) for full rules, but the non-negotiables:
@@ -46,10 +60,11 @@ If the repository uses squash merging, make the PR title a valid Conventional Co
46
60
  ## Pull Requests
47
61
 
48
62
  1. Fork and create a feature branch.
49
- 2. Make changes and ensure all gates pass.
50
- 3. Update `CHANGELOG.md` under `[Unreleased]` for user-visible changes.
51
- 4. Do not manually bump release versions; release automation owns them.
52
- 5. Open a PR with a Conventional Commit title that accurately represents its release impact.
63
+ 2. Make changes and ensure all relevant gates pass.
64
+ 3. Run `npm run docs:sync` after runtime/workflow changes and commit generated current-state documentation.
65
+ 4. Update `CHANGELOG.md` under `[Unreleased]` for user-visible changes.
66
+ 5. Do not manually bump release versions; release automation owns them.
67
+ 6. Open a PR with a Conventional Commit title that accurately represents its release impact.
53
68
 
54
69
  ## Reporting Issues
55
70
 
package/Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM node:20-alpine
1
+ FROM node:24-alpine
2
2
 
3
3
  # Install bash and git since the scripts depend on them
4
4
  RUN apk add --no-cache bash git
package/README.md CHANGED
@@ -48,6 +48,8 @@ The exact "Harness" behavior depends on the installation surface. Claude Code ha
48
48
 
49
49
  Harness integrates directly into your workspace. There is no heavy daemon, no paid external APIs, and zero configuration required.
50
50
 
51
+ **Runtime:** Harness supports **Node.js 22+**. Node.js **24** is the primary/recommended development and CI runtime (`.nvmrc`). The generated current-state runtime/workflow summary is [docs/repository-contract.md](docs/repository-contract.md).
52
+
51
53
  ```bash
52
54
  # Option A: Claude Code plugin (marketplace manifest included)
53
55
  # /plugin marketplace add dyphn1/Harness-everything
@@ -200,18 +202,18 @@ This repo uses a flat layout (waza/agentskills.io convention). The table below m
200
202
  |---|---|---|
201
203
  | `harness-everything` | **Core Runtime** | Bootstrap, kernel-router, tier-router, verify-gate, self-heal |
202
204
  | `hooks` | **Core Runtime** | Claude Code lifecycle hooks (prompt routing, circuit breaker, scope guard, stop gate, etc.) |
203
- | `scripts` | **Core Runtime** | Installer, manifest, prompts, workspace utilities |
205
+ | `scripts` | **Core Runtime** | Installer, manifest, prompts, workspace utilities, repository contract extraction/sync |
204
206
  | `bin` | **Core Runtime** | `harness` CLI entry point |
205
- | `ci` | **Quality Gates** | Consistency checks, description collision, mechanism tests, invariant-routing regression, documentation capability drift guard |
207
+ | `ci` | **Quality Gates** | Consistency checks, description collision, mechanism tests, invariant-routing regression, documentation/runtime contract drift guards |
206
208
  | `.github` | **CI/CD** | GitHub Actions workflows (ci.yml, release.yml, behavioral-evals.yml) |
207
209
  | `.claude-plugin` | **Distribution** | Plugin manifests for Claude Code marketplace |
208
210
  | `.agents/plugins` | **Distribution** | OpenAI/Codex repository marketplace metadata |
209
211
  | `plugins/harness-everything` | **Distribution** | Local OpenAI/Codex plugin package plus canonical skill copies |
210
212
  | `submission/openai` | **Distribution / Review** | Public OpenAI Skills-only listing/test inputs |
211
213
  | `evals` | **Routing Evals** | 26 trigger/routing eval suites (waza format) |
212
- | `behavioral-evals` | **Behavioral Evals** | LLM-level discipline cases (headless agent sessions) |
214
+ | `behavioral-evals` | **Behavioral Evals** | LLM-level discipline cases plus weekly structural validation workflow |
213
215
  | `benchmarks` | **Benchmarks** | BENCHMARK_SOP fixtures and recorded A/B results |
214
- | `docs` | **Documentation** | Philosophy, architecture, routing, reflection, platform capabilities, audit |
216
+ | `docs` | **Documentation** | Philosophy, architecture, routing, reflection, platform capabilities, generated repository contract, audit |
215
217
  | `references` | **Documentation** | Shared checklists (security, performance, definition-of-done) |
216
218
  | `multi-agent-workspace` | **Skill (Tier 3)** | Scaffold six zones, select agency specialists, and generate bounded launchers |
217
219
  | `environment-detection` | **Foundation** | Preflight: detect OS, shell, package manager |
@@ -249,6 +251,7 @@ For a deep dive into individual modules and the underlying philosophy, explore o
249
251
  * [Harness Philosophy](docs/philosophy.md): The core behavior-first, intervention-only design.
250
252
  * [Harness Architecture](docs/architecture.md): Lifecycle hooks, security model, and data locality.
251
253
  * [Platform Capability Matrix](docs/platform-capabilities.md): Canonical current enforcement/install/evidence boundary per surface.
254
+ * [Repository Runtime & Workflow Contract](docs/repository-contract.md): Generated Node/action/workflow/gate state used by consistency CI.
252
255
  * [OpenAI / ChatGPT Plugin Packaging](docs/openai-plugin.md): Local Codex/OpenAI plugin packaging plus public Skills-only submission boundary.
253
256
  * [Harness Routing & Triage](docs/routing.md): Detailed trigger criteria for Tiers 1, 2, and 3.
254
257
  * [Harness Reflection & Memory](docs/reflection.md): WAL session handoffs and workspace rules immunization.
@@ -264,7 +267,7 @@ Maintainers should follow [RELEASING.md](RELEASING.md) for tag-driven npm releas
264
267
 
265
268
  **If you are an agent asked to verify a Harness install, start at [VERIFICATION.md](VERIFICATION.md), not here.** It separates package/integrity checks, mechanism evidence, live-host evidence, and behavioral evidence so one kind of pass is not mistaken for another.
266
269
 
267
- `npm test` (`self-evolve/scripts/self-regression.js`) runs deterministic syntax, CLI, routing-matrix, positive skill-route coverage, **invariant-first routing regression**, reference, behavioral-case, Fable model-mode, and mechanism checks (`ci/mechanism-test.js`, `npm run test:mechanism` to run it alone). The suite checks real exit codes and stderr, not just "the code looks right." It runs in CI on Ubuntu, Windows, and macOS for every push and pull request (`.github/workflows/ci.yml`); live model evaluations remain explicitly on-demand.
270
+ `npm test` (`self-evolve/scripts/self-regression.js`) runs deterministic syntax, CLI, routing-matrix, positive skill-route coverage, **invariant-first routing regression**, reference, behavioral-case, Fable model-mode, and mechanism checks (`ci/mechanism-test.js`, `npm run test:mechanism` to run it alone). The suite checks real exit codes and stderr, not just "the code looks right." Primary CI runs on Node.js 24 across Ubuntu, Windows, and macOS for every push and pull request (`.github/workflows/ci.yml`), with a separate Node.js 22 compatibility lane for the advertised minimum runtime.
268
271
 
269
272
  For a fuller vanilla-vs-Harness behavioral comparison, see [Harness Skills Benchmark SOP](BENCHMARK_SOP.md) — standardized, reproducible scenarios:
270
273
  * **Test A:** Over-engineering defense (Tier 1 typo correction)
@@ -276,13 +279,13 @@ For a fuller vanilla-vs-Harness behavioral comparison, see [Harness Skills Bench
276
279
 
277
280
  Benchmark **results** are tracked in [benchmarks/](benchmarks/README.md) (`run.js scaffold` builds the fixture, `record` commits a schema-validated result bound to a session log). Until those cells are filled, effectiveness claims are unbacked by recorded evidence.
278
281
 
279
- ### Behavioral evals (LLM-level, on demand)
282
+ ### Behavioral evals (LLM-level, on demand + weekly structural validation)
280
283
 
281
- Mechanism tests prove individual packaged mechanisms; only real host/session evidence proves the host actually loaded and fired them. [behavioral-evals/](behavioral-evals/README.md) runs discipline cases (including pressure variants like "we ship in 5 minutes, skip checks") against headless agent sessions (`claude -p`, OpenCode) in throwaway workspaces: `npm run eval:behavioral`. Token-costing by design — never wired into CI.
284
+ Mechanism tests prove individual packaged mechanisms; only real host/session evidence proves the host actually loaded and fired them. [behavioral-evals/](behavioral-evals/README.md) runs discipline cases (including pressure variants like "we ship in 5 minutes, skip checks") against headless agent sessions (`claude -p`, OpenCode) in throwaway workspaces: `npm run eval:behavioral`. Live runs remain token-costing and can be invoked on demand. The weekly `behavioral-evals.yml` workflow always validates case structure and runs live cases only when the runner actually has the Claude CLI.
282
285
 
283
286
  ### Catalog hygiene
284
287
 
285
- `npm run test:consistency` keeps the distribution manifests, docs links, skill frontmatter, routing-eval coverage, and the cross-platform capability claims in lockstep with what is actually on disk; `npm run test:docs:capabilities` runs the platform-doc drift check directly. `npm run test:references` checks every executable/deep-dive path named by `SKILL.md`; `npm run test:release` compares release/catalog evidence; `npm run test:routing:skills` recursively classifies nested skills and executes the real router for every directly-routable skill's positive cases; `npm run test:routing:invariants` guards the invariant-first architecture; and `harness verify-install` detects stale installed versions or file trees. The installer E2E gate performs install → verify-install → uninstall against seeded user-owned files on Ubuntu, Windows, and macOS so path and ownership symmetry regressions fail CI. `npm run test:collision` fails CI when two skills' descriptions overlap enough to confuse the router.
288
+ `npm run test:consistency` keeps distribution manifests, docs links, skill frontmatter, routing-eval coverage, platform capability claims, and the generated repository runtime/workflow contract in lockstep with what is actually on disk. `npm run test:repo-contract` runs the runtime/workflow drift gate directly, while `npm run docs:sync` regenerates [docs/repository-contract.md](docs/repository-contract.md) after an intentional change. `npm run test:docs:capabilities` runs the platform-doc drift check directly. `npm run test:references` checks every executable/deep-dive path named by `SKILL.md`; `npm run test:release` compares release/catalog evidence; `npm run test:routing:skills` recursively classifies nested skills and executes the real router for every directly-routable skill's positive cases; `npm run test:routing:invariants` guards the invariant-first architecture; and `harness verify-install` detects stale installed versions or file trees. The installer E2E gate performs install → verify-install → uninstall against seeded user-owned files on Ubuntu, Windows, and macOS so path and ownership symmetry regressions fail CI. `npm run test:collision` fails CI when two skills' descriptions overlap enough to confuse the router.
286
289
 
287
290
  ---
288
291
 
@@ -303,8 +306,9 @@ To contribute to Harness or modify any Skill behavior, ensure you run the local
303
306
  ```bash
304
307
  npm run self-regression
305
308
  npm run test:consistency
309
+ npm run test:repo-contract
306
310
  npm run test:plugin:openai
307
311
  npm run test:plugin:submission
308
312
  ```
309
313
 
310
- All script modifications must pass 100% cleanly before pushing to keep the runtime immunized against behavioral regression.
314
+ After intentional runtime/workflow changes, run `npm run docs:sync` and commit the regenerated repository contract. All script modifications must pass 100% cleanly before pushing to keep the runtime immunized against behavioral regression.
package/RELEASING.md CHANGED
@@ -15,14 +15,25 @@ Harness releases are stable SemVer releases generated automatically from Convent
15
15
 
16
16
  There are no alpha, beta, or rc release channels. Historical prerelease tags remain history, but new releases come only from `main` and use `vX.Y.Z` tags.
17
17
 
18
- The migration baseline is the latest stable release tag, currently `v0.3.6`. Existing unreleased manifest strings do not determine the next version; Git history after that tag does.
18
+ Do not hard-code a "current release baseline" in this guide. `semantic-release` discovers the latest stable tag from Git history on each run, and release evidence belongs in [docs/release-evidence.md](docs/release-evidence.md).
19
+
20
+ ## Runtime contract
21
+
22
+ The release job uses the repository's primary Node runtime from the checked-in current-state policy: Node.js 24 today, with Node.js 22 retained as the minimum supported product runtime. The generated source-of-truth summary is [docs/repository-contract.md](docs/repository-contract.md).
23
+
24
+ When changing Node versions, GitHub Action majors, or workflow triggers, run:
25
+
26
+ ```bash
27
+ npm run docs:sync
28
+ npm run test:repo-contract
29
+ ```
19
30
 
20
31
  ## Release flow
21
32
 
22
33
  A push to `main` runs the full reusable CI gate and then semantic-release. A manual `workflow_dispatch` run is available for a safe retry.
23
34
 
24
35
  1. Check out full Git history and tags.
25
- 2. Run the same CI jobs used for pull requests.
36
+ 2. Run the same CI jobs used for pull requests, including the Node 22 minimum-runtime compatibility lane.
26
37
  3. Analyze Conventional Commits since the latest stable release.
27
38
  4. Exit without publishing when there is no releasable commit.
28
39
  5. Calculate the next stable SemVer.
package/VERIFICATION.md CHANGED
@@ -11,7 +11,7 @@ Harness verification separates four kinds of evidence that must not be conflated
11
11
 
12
12
  A mechanism test can pass while a live host never loads the plugin. A behavior test can pass on an advisory-only surface without proving any hard enforcement. Keep those claims separate.
13
13
 
14
- The authoritative current platform boundary is [docs/platform-capabilities.md](docs/platform-capabilities.md).
14
+ The authoritative current platform boundary is [docs/platform-capabilities.md](docs/platform-capabilities.md). The generated current runtime/workflow boundary is [docs/repository-contract.md](docs/repository-contract.md).
15
15
 
16
16
  ---
17
17
 
@@ -146,6 +146,21 @@ The capability test checks the current-state documentation surfaces for stale pl
146
146
 
147
147
  When changing platform integration behavior, update [docs/platform-capabilities.md](docs/platform-capabilities.md) and all affected current-state docs in the same PR.
148
148
 
149
+ ### 3a. Repository runtime/workflow contract
150
+
151
+ Runtime and workflow claims are extracted from `package.json`, `.nvmrc`, `Dockerfile`, and active `.github/workflows/*.yml` rather than being independently maintained in prose.
152
+
153
+ ```bash
154
+ npm run repo:contract # human-readable current state
155
+ npm run repo:contract -- --json
156
+ npm run docs:sync # regenerate docs/repository-contract.md
157
+ npm run test:repo-contract # fail on drift
158
+ ```
159
+
160
+ The contract gate requires Node.js 22 or newer as the supported floor, requires the primary `.nvmrc` runtime to match Docker and active primary workflows, keeps an explicit Node 22 CI compatibility lane, rejects GitHub Action majors below the supported floor, preserves the weekly behavioral-eval schedule, and checks that the generated contract document is current.
161
+
162
+ After intentionally changing runtime/workflow configuration, regenerate the document and commit it in the same PR. Historical audit/evidence snapshots are not rewritten merely because the current contract changed.
163
+
149
164
  ---
150
165
 
151
166
  ## 4. Behavioral test prompts
@@ -271,13 +286,17 @@ For a comprehensive audit:
271
286
 
272
287
  ```bash
273
288
  npm test
289
+ npm run test:mutations
274
290
  npm run test:consistency
291
+ npm run test:repo-contract
275
292
  npm run test:references
293
+ npm run test:release
276
294
  npm run test:routing:skills
277
295
  npm run test:routing:invariants
278
296
  npm run test:plugin:openai
279
297
  npm run test:plugin:submission
298
+ npm run test:platform:compatibility
280
299
  node ci/installer-roundtrip.test.js
281
300
  ```
282
301
 
283
- Do not accept "I read the code and it looks right" as evidence for a runtime or live-host claim.
302
+ Primary CI uses Node.js 24 across Ubuntu, Windows, and macOS; the dedicated Node.js 22 lane proves the advertised minimum remains viable. Do not accept "I read the code and it looks right" as evidence for a runtime or live-host claim.
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const assert = require('assert');
5
+ const { collectContract, renderContractMarkdown, validateContract } = require('../scripts/repository-contract');
6
+
7
+ const contract = collectContract();
8
+ const failures = validateContract(contract);
9
+ assert.deepStrictEqual(failures, [], `Repository contract drift:\n- ${failures.join('\n- ')}`);
10
+
11
+ const rendered = renderContractMarkdown(contract);
12
+ assert.match(rendered, /Minimum supported Node\.js/);
13
+ assert.match(rendered, /GitHub Actions runtime majors/);
14
+ assert.ok(contract.ci.qualityGates.includes('test:consistency'), 'CI contract must expose test:consistency');
15
+ assert.ok(contract.behavioralEvals.scheduled, 'Behavioral eval schedule must remain visible to the contract');
16
+
17
+ console.log('Repository contract verified: runtime, workflows, action majors, schedule, gates, and generated docs are synchronized.');
@@ -14,7 +14,9 @@ The source capture for this row is the local review artifact `.git/issue-review-
14
14
 
15
15
  ## Current review boundary
16
16
 
17
- No evidence in the source capture proves that `0.3.7-beta` was tagged, published to npm, or released on GitHub. The release preparation commit and changelog heading must therefore remain separate from a release claim until a maintainer records the post-tag observations above.
17
+ This file is an evidence ledger, not a source of truth for the current package version. Historical rows stay unchanged until all four observations for a newer release are deliberately collected. Current release/runtime configuration must be read from Git history, package metadata, the release workflow, and [repository-contract.md](repository-contract.md), rather than from prose such as the retired `0.3.7-beta` review note.
18
+
19
+ A GitHub tag or source version alone is not enough to add a completed row here; keep using `not observed` when registry, workflow, or publication evidence has not been checked.
18
20
 
19
21
  ## Evidence entry template
20
22
 
@@ -0,0 +1,27 @@
1
+ <!-- GENERATED by scripts/repository-contract.js. Run `npm run docs:sync` after workflow/runtime changes. -->
2
+ # Repository runtime and workflow contract
3
+
4
+ This page is generated from checked-in runtime and workflow sources. Do not edit it by hand. Historical audit/evidence documents are intentionally outside this current-state contract.
5
+
6
+ ## Runtime
7
+
8
+ - Minimum supported Node.js: **22** (from `package.json#engines.node`: `>=22`)
9
+ - Primary development/CI Node.js: **24** (from `.nvmrc`)
10
+ - Docker verification Node.js: **24** (from `Dockerfile`)
11
+
12
+ ## GitHub Actions runtime majors
13
+
14
+ - `actions/checkout`: v7
15
+ - `actions/setup-node`: v7
16
+
17
+ ## Active workflows
18
+
19
+ | Workflow | Node.js versions | Explicit triggers | npm quality gates |
20
+ | --- | --- | --- | --- |
21
+ | `behavioral-evals.yml` | 24 | schedule, workflow_dispatch | n/a |
22
+ | `ci.yml` | 22, 24 | workflow_call | `test`, `test:mutations`, `test:consistency`, `test:references`, `test:release`, `test:collision`, `test:plugin:openai`, `test:plugin:submission`, `test:platform:compatibility` |
23
+ | `release.yml` | 24 | workflow_dispatch | n/a |
24
+
25
+ ## Drift prevention
26
+
27
+ `npm run test:repo-contract` fails when runtime sources disagree, an active workflow reintroduces an unsupported Node version/action major, the Node 22 compatibility floor is no longer exercised, or this generated document is stale.
@@ -1,6 +1,6 @@
1
1
  # Harness OS Troubleshooting Guide
2
2
 
3
- This guide helps you resolve common issues with Harness OS installation and usage. Platform enforcement claims follow [platform-capabilities.md](platform-capabilities.md).
3
+ This guide helps you resolve common issues with Harness OS installation and usage. Platform enforcement claims follow [platform-capabilities.md](platform-capabilities.md). Current Node/workflow values are generated in [repository-contract.md](repository-contract.md).
4
4
 
5
5
  ## Installation Issues
6
6
 
@@ -31,14 +31,20 @@ export PATH=~/.npm-global/bin:$PATH
31
31
  # Check your Node.js version
32
32
  node --version
33
33
 
34
- # Harness requires Node.js 18 or higher
35
- # Update using nvm (recommended):
36
- nvm install 18
37
- nvm use 18
34
+ # Harness supports Node.js 22 or newer.
35
+ # Node.js 24 is the primary/recommended development runtime.
36
+ nvm install 24
37
+ nvm use 24
38
38
 
39
- # Or download from https://nodejs.org/
39
+ # To reproduce the minimum-runtime CI lane explicitly:
40
+ nvm install 22
41
+ nvm use 22
42
+
43
+ # Or download a supported release from https://nodejs.org/
40
44
  ```
41
45
 
46
+ The checked-in `.nvmrc` selects the primary runtime. If runtime/workflow files change, run `npm run docs:sync` followed by `npm run test:repo-contract` so generated current-state documentation cannot drift.
47
+
42
48
  ### Network Issues
43
49
 
44
50
  **Symptom:** `npm ERR! network` or timeout errors
@@ -264,6 +270,7 @@ For deterministic cross-platform mechanism checks, prefer:
264
270
  ```bash
265
271
  npm run test:mechanism
266
272
  npm run test:docs:capabilities
273
+ npm run test:repo-contract
267
274
  ```
268
275
 
269
276
  When isolating a specific Claude hook, use the Windows-safe `spawnSync` recipes in [../VERIFICATION.md](../VERIFICATION.md) rather than assuming a shell `echo | node` pipeline behaves the same on every OS.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "harness-enforcement",
3
3
  "description": "Repository inventory for the opencode enforcement plugin and its standalone helper",
4
- "version": "0.4.0",
4
+ "version": "0.4.1",
5
5
  "runtime": "index.mjs",
6
6
  "hooks": {
7
7
  "verify": "hooks/verify.js"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "harness-everything",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Harness OS: An Orchestrated Agent Operating System for AI-driven Development",
5
5
  "main": "harness-everything/scripts/bootstrap.js",
6
6
  "bin": {
@@ -13,7 +13,10 @@
13
13
  "test:mutations": "node ci/mutation-check.js",
14
14
  "test:tdd-quality": "node ci/mechanism-2s-tdd-quality.test.js",
15
15
  "tdd:quality": "node tdd/scripts/quality-gate.js",
16
- "test:consistency": "node ci/consistency-check.js && node ci/doc-capability-consistency.test.js",
16
+ "repo:contract": "node scripts/repository-contract.js",
17
+ "docs:sync": "node scripts/sync-current-docs.js",
18
+ "test:repo-contract": "node ci/repository-contract.test.js",
19
+ "test:consistency": "node ci/consistency-check.js && node ci/doc-capability-consistency.test.js && node ci/repository-contract.test.js",
17
20
  "test:docs:capabilities": "node ci/doc-capability-consistency.test.js",
18
21
  "test:references": "node ci/reference-check.js",
19
22
  "test:release": "node ci/release-consistency-check.js && node ci/mechanism-2x-release-automation.test.js && node ci/mechanism-2x-release-commit-message.test.js",
@@ -39,7 +42,7 @@
39
42
  "commitlint": "commitlint --edit"
40
43
  },
41
44
  "engines": {
42
- "node": ">=18"
45
+ "node": ">=22"
43
46
  },
44
47
  "author": "Miya Daniel",
45
48
  "license": "Apache-2.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "harness-everything",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Invariant-first engineering harness for routing, verification, and failure recovery while preserving agent autonomy.",
5
5
  "author": {
6
6
  "name": "Miya Daniel",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
3
  "name": "harness-everything",
4
- "version": "0.4.0",
4
+ "version": "0.4.1",
5
5
  "description": "Invariant-first engineering harness for routing, verification, and failure recovery while preserving agent autonomy.",
6
6
  "author": {
7
7
  "name": "Miya Daniel",
@@ -0,0 +1,213 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+
7
+ const ROOT = path.resolve(__dirname, '..');
8
+ const ACTION_MINIMUMS = Object.freeze({ checkout: 7, setupNode: 7 });
9
+ const MINIMUM_SUPPORTED_NODE_FLOOR = 22;
10
+
11
+ function read(root, rel) {
12
+ return fs.readFileSync(path.join(root, rel), 'utf8');
13
+ }
14
+
15
+ function readJson(root, rel) {
16
+ return JSON.parse(read(root, rel));
17
+ }
18
+
19
+ function parseMinimumNode(engine) {
20
+ const match = String(engine || '').match(/>=\s*v?(\d+)/);
21
+ return match ? Number(match[1]) : null;
22
+ }
23
+
24
+ function parseMajor(text) {
25
+ const match = String(text || '').trim().match(/^v?(\d+)/);
26
+ return match ? Number(match[1]) : null;
27
+ }
28
+
29
+ function uniqSorted(values) {
30
+ return [...new Set(values.filter(Number.isInteger))].sort((a, b) => a - b);
31
+ }
32
+
33
+ function extractMajors(text, action) {
34
+ const escaped = action.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
35
+ const re = new RegExp(`uses:\\s*${escaped}@v(\\d+)`, 'g');
36
+ const out = [];
37
+ let match;
38
+ while ((match = re.exec(text))) out.push(Number(match[1]));
39
+ return uniqSorted(out);
40
+ }
41
+
42
+ function extractNodeVersions(text) {
43
+ const out = [];
44
+ const re = /node-version:\s*["']?(\d+)(?:\.\d+)?["']?/g;
45
+ let match;
46
+ while ((match = re.exec(text))) out.push(Number(match[1]));
47
+ return uniqSorted(out);
48
+ }
49
+
50
+ function extractQualityGates(text) {
51
+ const gates = [];
52
+ if (/\bnpm\s+test\b/.test(text)) gates.push('test');
53
+ const re = /\bnpm\s+run\s+([A-Za-z0-9:_-]+)/g;
54
+ let match;
55
+ while ((match = re.exec(text))) gates.push(match[1]);
56
+ return [...new Set(gates)];
57
+ }
58
+
59
+ function listWorkflowFiles(root) {
60
+ const dir = path.join(root, '.github', 'workflows');
61
+ if (!fs.existsSync(dir)) return [];
62
+ return fs.readdirSync(dir)
63
+ .filter(name => /\.ya?ml$/i.test(name))
64
+ .sort();
65
+ }
66
+
67
+ function parseWorkflow(root, file) {
68
+ const rel = path.posix.join('.github/workflows', file);
69
+ const text = read(root, rel);
70
+ return {
71
+ file,
72
+ nodeVersions: extractNodeVersions(text),
73
+ checkoutMajors: extractMajors(text, 'actions/checkout'),
74
+ setupNodeMajors: extractMajors(text, 'actions/setup-node'),
75
+ scheduled: /^\s*schedule:\s*$/m.test(text),
76
+ workflowDispatch: /^\s*workflow_dispatch:\s*$/m.test(text),
77
+ workflowCall: /^\s*workflow_call:\s*$/m.test(text),
78
+ qualityGates: extractQualityGates(text),
79
+ };
80
+ }
81
+
82
+ function collectContract(root = ROOT) {
83
+ const pkg = readJson(root, 'package.json');
84
+ const nvmPath = path.join(root, '.nvmrc');
85
+ const primaryNode = fs.existsSync(nvmPath) ? parseMajor(read(root, '.nvmrc')) : null;
86
+ const dockerText = read(root, 'Dockerfile');
87
+ const dockerMatch = dockerText.match(/^FROM\s+node:(\d+)(?:[^\s]*)/m);
88
+ const workflows = listWorkflowFiles(root).map(file => parseWorkflow(root, file));
89
+ const ci = workflows.find(workflow => workflow.file === 'ci.yml' || workflow.file === 'ci.yaml');
90
+ const behavioral = workflows.find(workflow => /^behavioral-evals\.ya?ml$/.test(workflow.file));
91
+ const release = workflows.find(workflow => /^release\.ya?ml$/.test(workflow.file));
92
+
93
+ return {
94
+ runtime: {
95
+ packageEngine: pkg.engines?.node || null,
96
+ minimumNode: parseMinimumNode(pkg.engines?.node),
97
+ primaryNode,
98
+ dockerNode: dockerMatch ? Number(dockerMatch[1]) : null,
99
+ },
100
+ githubActions: {
101
+ checkoutMajors: uniqSorted(workflows.flatMap(workflow => workflow.checkoutMajors)),
102
+ setupNodeMajors: uniqSorted(workflows.flatMap(workflow => workflow.setupNodeMajors)),
103
+ },
104
+ workflows: Object.fromEntries(workflows.map(workflow => [workflow.file, workflow])),
105
+ ci: ci || null,
106
+ behavioralEvals: behavioral || null,
107
+ release: release || null,
108
+ };
109
+ }
110
+
111
+ function renderContractMarkdown(contract) {
112
+ const runtime = contract.runtime;
113
+ const actionList = values => values.length ? values.map(v => `v${v}`).join(', ') : 'not used';
114
+ const rows = Object.values(contract.workflows).map(workflow => {
115
+ const nodes = workflow.nodeVersions.length ? workflow.nodeVersions.map(String).join(', ') : 'n/a';
116
+ const trigger = [workflow.scheduled && 'schedule', workflow.workflowDispatch && 'workflow_dispatch', workflow.workflowCall && 'workflow_call'].filter(Boolean).join(', ') || 'push/pull request or other';
117
+ const gates = workflow.qualityGates.length ? workflow.qualityGates.map(g => `\`${g}\``).join(', ') : 'n/a';
118
+ return `| \`${workflow.file}\` | ${nodes} | ${trigger} | ${gates} |`;
119
+ }).join('\n');
120
+
121
+ return `<!-- GENERATED by scripts/repository-contract.js. Run \`npm run docs:sync\` after workflow/runtime changes. -->\n# Repository runtime and workflow contract\n\nThis page is generated from checked-in runtime and workflow sources. Do not edit it by hand. Historical audit/evidence documents are intentionally outside this current-state contract.\n\n## Runtime\n\n- Minimum supported Node.js: **${runtime.minimumNode}** (from \`package.json#engines.node\`: \`${runtime.packageEngine}\`)\n- Primary development/CI Node.js: **${runtime.primaryNode}** (from \`.nvmrc\`)\n- Docker verification Node.js: **${runtime.dockerNode}** (from \`Dockerfile\`)\n\n## GitHub Actions runtime majors\n\n- \`actions/checkout\`: ${actionList(contract.githubActions.checkoutMajors)}\n- \`actions/setup-node\`: ${actionList(contract.githubActions.setupNodeMajors)}\n\n## Active workflows\n\n| Workflow | Node.js versions | Explicit triggers | npm quality gates |\n| --- | --- | --- | --- |\n${rows}\n\n## Drift prevention\n\n\`npm run test:repo-contract\` fails when runtime sources disagree, an active workflow reintroduces an unsupported Node version/action major, the Node ${runtime.minimumNode} compatibility floor is no longer exercised, or this generated document is stale.\n`;
122
+ }
123
+
124
+ function validateContract(contract, root = ROOT) {
125
+ const failures = [];
126
+ const fail = message => failures.push(message);
127
+ const { runtime } = contract;
128
+
129
+ if (!Number.isInteger(runtime.minimumNode) || runtime.minimumNode < MINIMUM_SUPPORTED_NODE_FLOOR) {
130
+ fail(`package.json must declare Node >=${MINIMUM_SUPPORTED_NODE_FLOOR}; got ${runtime.packageEngine || 'missing'}`);
131
+ }
132
+ if (!Number.isInteger(runtime.primaryNode) || runtime.primaryNode < runtime.minimumNode) {
133
+ fail(`.nvmrc primary Node must be >= minimum Node ${runtime.minimumNode}; got ${runtime.primaryNode ?? 'missing'}`);
134
+ }
135
+ if (runtime.dockerNode !== runtime.primaryNode) {
136
+ fail(`Dockerfile Node ${runtime.dockerNode ?? 'missing'} must match .nvmrc Node ${runtime.primaryNode ?? 'missing'}`);
137
+ }
138
+
139
+ for (const major of contract.githubActions.checkoutMajors) {
140
+ if (major < ACTION_MINIMUMS.checkout) fail(`actions/checkout@v${major} is below supported floor v${ACTION_MINIMUMS.checkout}`);
141
+ }
142
+ for (const major of contract.githubActions.setupNodeMajors) {
143
+ if (major < ACTION_MINIMUMS.setupNode) fail(`actions/setup-node@v${major} is below supported floor v${ACTION_MINIMUMS.setupNode}`);
144
+ }
145
+ if (contract.githubActions.checkoutMajors.length !== 1) fail(`active workflows must use one checkout major; found ${contract.githubActions.checkoutMajors.join(', ') || 'none'}`);
146
+ if (contract.githubActions.setupNodeMajors.length !== 1) fail(`active workflows must use one setup-node major; found ${contract.githubActions.setupNodeMajors.join(', ') || 'none'}`);
147
+
148
+ for (const workflow of Object.values(contract.workflows)) {
149
+ for (const node of workflow.nodeVersions) {
150
+ if (node < runtime.minimumNode) fail(`${workflow.file} uses Node ${node}, below minimum ${runtime.minimumNode}`);
151
+ }
152
+ }
153
+
154
+ if (!contract.ci) fail('ci.yml is missing');
155
+ else {
156
+ if (!contract.ci.nodeVersions.includes(runtime.primaryNode)) fail(`ci.yml must exercise primary Node ${runtime.primaryNode}`);
157
+ if (!contract.ci.nodeVersions.includes(runtime.minimumNode)) fail(`ci.yml must exercise minimum supported Node ${runtime.minimumNode}`);
158
+ }
159
+ if (!contract.behavioralEvals) fail('behavioral-evals.yml is missing');
160
+ else {
161
+ if (!contract.behavioralEvals.scheduled) fail('behavioral-evals.yml must retain its scheduled trigger');
162
+ if (!contract.behavioralEvals.nodeVersions.includes(runtime.primaryNode)) fail(`behavioral-evals.yml must use primary Node ${runtime.primaryNode}`);
163
+ }
164
+ if (!contract.release) fail('release.yml is missing');
165
+ else if (!contract.release.nodeVersions.includes(runtime.primaryNode)) {
166
+ fail(`release.yml must use primary Node ${runtime.primaryNode}`);
167
+ }
168
+
169
+ const generatedPath = path.join(root, 'docs', 'repository-contract.md');
170
+ if (!fs.existsSync(generatedPath)) {
171
+ fail('docs/repository-contract.md is missing; run npm run docs:sync');
172
+ } else {
173
+ const actual = fs.readFileSync(generatedPath, 'utf8').replace(/\r\n/g, '\n');
174
+ const expected = renderContractMarkdown(contract).replace(/\r\n/g, '\n');
175
+ if (actual !== expected) fail('docs/repository-contract.md is stale; run npm run docs:sync');
176
+ }
177
+
178
+ return failures;
179
+ }
180
+
181
+ function printSummary(contract) {
182
+ console.log(`Node: >=${contract.runtime.minimumNode} supported; ${contract.runtime.primaryNode} primary; ${contract.runtime.dockerNode} Docker`);
183
+ console.log(`Actions: checkout ${contract.githubActions.checkoutMajors.map(v => `v${v}`).join(', ')}; setup-node ${contract.githubActions.setupNodeMajors.map(v => `v${v}`).join(', ')}`);
184
+ for (const workflow of Object.values(contract.workflows)) {
185
+ console.log(`${workflow.file}: Node ${workflow.nodeVersions.join(', ') || 'n/a'}; gates ${workflow.qualityGates.join(', ') || 'n/a'}`);
186
+ }
187
+ }
188
+
189
+ if (require.main === module) {
190
+ const args = new Set(process.argv.slice(2));
191
+ const contract = collectContract();
192
+ if (args.has('--json')) {
193
+ process.stdout.write(`${JSON.stringify(contract, null, 2)}\n`);
194
+ } else if (args.has('--check')) {
195
+ const failures = validateContract(contract);
196
+ if (failures.length) {
197
+ for (const failure of failures) console.error(`❌ ${failure}`);
198
+ process.exitCode = 1;
199
+ } else {
200
+ console.log('✅ Repository runtime/workflow contract is consistent.');
201
+ }
202
+ } else {
203
+ printSummary(contract);
204
+ }
205
+ }
206
+
207
+ module.exports = {
208
+ ACTION_MINIMUMS,
209
+ MINIMUM_SUPPORTED_NODE_FLOOR,
210
+ collectContract,
211
+ renderContractMarkdown,
212
+ validateContract,
213
+ };
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const { collectContract, renderContractMarkdown } = require('./repository-contract');
7
+
8
+ const ROOT = path.resolve(__dirname, '..');
9
+ const output = path.join(ROOT, 'docs', 'repository-contract.md');
10
+ fs.mkdirSync(path.dirname(output), { recursive: true });
11
+ fs.writeFileSync(output, renderContractMarkdown(collectContract(ROOT)), 'utf8');
12
+ console.log(`Updated ${path.relative(ROOT, output).replace(/\\/g, '/')}`);