From e1b4155cd1d47fe05ac11fc0ef1e2105bbf45e59 Mon Sep 17 00:00:00 2001 From: Michael Heller <21163552+mdheller@users.noreply.github.com> Date: Wed, 29 Jul 2026 17:37:08 -0400 Subject: [PATCH 1/3] ci: run the TS suite in ts-ci (+ temporary failing test to prove teeth) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TypeScript suite was never executed by any workflow. ci.yml runs `cargo test --workspace` (Rust only); ts-ci ran typecheck, build and a dist staleness check. 401 tests existed and nothing invoked them, so a TS regression could merge with every required check green. This commit deliberately includes a failing test. CI must go RED. The next commit removes it and CI must go green — otherwise the step is decoration. --- .github/workflows/ts-ci.yml | 10 ++++++++++ ts/src/_ci-teeth.test.ts | 7 +++++++ 2 files changed, 17 insertions(+) create mode 100644 ts/src/_ci-teeth.test.ts diff --git a/.github/workflows/ts-ci.yml b/.github/workflows/ts-ci.yml index 585f0e8..3a25406 100644 --- a/.github/workflows/ts-ci.yml +++ b/.github/workflows/ts-ci.yml @@ -65,6 +65,16 @@ jobs: if: steps.changed.outputs.ts == 'true' run: npm run typecheck + # The TypeScript suite was never executed by ANY workflow: ci.yml runs + # `cargo test --workspace` (Rust only) and this job ran typecheck + build + a dist + # staleness check. 401 tests existed and nothing invoked them, so a TS regression + # could merge with every required check green — typecheck proves it COMPILES, not + # that it WORKS. Runs before the dist rebuild so a logic failure is reported as a + # test failure rather than surfacing later as a confusing dist diff. + - name: Test + if: steps.changed.outputs.ts == 'true' + run: npm test + - name: Rebuild dist if: steps.changed.outputs.ts == 'true' run: npm run build diff --git a/ts/src/_ci-teeth.test.ts b/ts/src/_ci-teeth.test.ts new file mode 100644 index 0000000..2075966 --- /dev/null +++ b/ts/src/_ci-teeth.test.ts @@ -0,0 +1,7 @@ +// TEMPORARY — proves the new CI `npm test` step actually fails the build. +// Removed in the following commit; if you are reading this on a branch, it should not be here. +import { test } from 'node:test' +import assert from 'node:assert/strict' +test('DELIBERATE FAILURE: proving ts-ci runs the suite', () => { + assert.equal(1, 2, 'if CI is green with this present, the test step is not wired') +}) From 84bede5cd408816937763ab5642ce15fa744b2c3 Mon Sep 17 00:00:00 2001 From: Michael Heller <21163552+mdheller@users.noreply.github.com> Date: Wed, 29 Jul 2026 17:48:17 -0400 Subject: [PATCH 2/3] =?UTF-8?q?ci:=20remove=20the=20deliberate=20failure?= =?UTF-8?q?=20=E2=80=94=20teeth=20proven?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous commit failed CI on purpose to prove the new `npm test` step is load-bearing rather than decoration. Removed; the suite is back to green. An unwired guard is worse than none: it gets cited as authority while never running. This repo already had 401 TS tests nothing executed. --- package-lock.json | 7 +++++-- ts/src/_ci-teeth.test.ts | 7 ------- 2 files changed, 5 insertions(+), 9 deletions(-) delete mode 100644 ts/src/_ci-teeth.test.ts diff --git a/package-lock.json b/package-lock.json index 6e16325..fc4f49e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,13 +1,16 @@ { "name": "@socioprophet/hellgraph", - "version": "0.4.2", + "version": "0.4.45", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@socioprophet/hellgraph", - "version": "0.4.2", + "version": "0.4.45", "license": "UNLICENSED", + "bin": { + "hellgraph-superpeer": "bin/hellgraph-superpeer.mjs" + }, "devDependencies": { "@types/node": "^20.0.0", "autobase": "7.28.1", diff --git a/ts/src/_ci-teeth.test.ts b/ts/src/_ci-teeth.test.ts deleted file mode 100644 index 2075966..0000000 --- a/ts/src/_ci-teeth.test.ts +++ /dev/null @@ -1,7 +0,0 @@ -// TEMPORARY — proves the new CI `npm test` step actually fails the build. -// Removed in the following commit; if you are reading this on a branch, it should not be here. -import { test } from 'node:test' -import assert from 'node:assert/strict' -test('DELIBERATE FAILURE: proving ts-ci runs the suite', () => { - assert.equal(1, 2, 'if CI is green with this present, the test step is not wired') -}) From 83fb5acb9b946271fae76b14ce93351abc60f2d0 Mon Sep 17 00:00:00 2001 From: Michael Heller <21163552+mdheller@users.noreply.github.com> Date: Wed, 29 Jul 2026 21:26:44 -0400 Subject: [PATCH 3/3] ci: run the tests on the change that edits the workflow, and on lockfile bumps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review finding on #36, and it is the same class of defect this PR exists to fix. The Test step was added to build-and-verify-dist correctly — that job is a REQUIRED check on main, so a failing suite genuinely blocks. But the step is gated on `steps.changed.outputs.ts`, and the detector grepped only `^(package\.json|ts/)`. This PR touches `.github/workflows/ts-ci.yml` and `package-lock.json`, neither of which matched, so on the head commit every step reported `skipped`: Detect TS/dist-relevant changes -> success Install / Typecheck / Test / Rebuild dist -> skipped No TS/dist changes — required check trivially satisfied -> success i.e. the commit that adds the test step had that step skipped, and the PR was green without ever running the 401 tests it wires up. Two real holes: - a dependency bump can land entirely in package-lock.json, and that is precisely the change most likely to break the suite; - a PR editing only ts-ci.yml skipped everything, so the workflow defining this gate was the one change the gate never ran on. Widened the detector to package(-lock)?.json, ts/, and ts-ci.yml itself. The escape hatch the file header describes is deliberately preserved — verified by truth table that Rust-only, README-only and ci.yml-only PRs still resolve to ts=false, so the required context still reports instead of hanging "expected". The proof that the step has teeth is already in this branch's history: 4ef89e35 added a deliberately failing test and build-and-verify-dist went red; 2afaeb17 removed it. Re-verified independently against the check-runs API. --- .github/workflows/ts-ci.yml | 12 ++++++++++-- package-lock.json | 4 ++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ts-ci.yml b/.github/workflows/ts-ci.yml index 3a25406..d31affe 100644 --- a/.github/workflows/ts-ci.yml +++ b/.github/workflows/ts-ci.yml @@ -46,7 +46,15 @@ jobs: fi base="${{ github.event.pull_request.base.sha }}" head="${{ github.event.pull_request.head.sha }}" - if git diff --name-only "$base" "$head" | grep -qE '^(package\.json|ts/)'; then + # Must include package-lock.json and THIS WORKFLOW, not just package.json and ts/**: + # - a dependency bump can land entirely in the lockfile, and that is exactly the + # change most likely to break the suite; + # - a PR editing only ts-ci.yml previously skipped every step, so the workflow that + # defines this gate was the one change the gate never ran on. This PR is that + # shape: before this line was widened, the commit adding the Test step below had + # it reported as `skipped`. + if git diff --name-only "$base" "$head" \ + | grep -qE '^(package(-lock)?\.json|ts/|\.github/workflows/ts-ci\.yml)'; then echo "ts=true" >> "$GITHUB_OUTPUT" else echo "ts=false" >> "$GITHUB_OUTPUT" @@ -91,7 +99,7 @@ jobs: - name: No TS/dist changes — required check trivially satisfied if: steps.changed.outputs.ts != 'true' - run: echo "This PR touches no package.json or ts/** files; build-and-verify-dist has nothing to verify." + run: echo "This PR touches no package.json, package-lock.json, ts/** or ts-ci.yml files; build-and-verify-dist has nothing to verify." # ── Vendored-ontology provenance (W12) ───────────────────────────────────────────── # ontology/kko/PROVENANCE.md recorded a sha256 that NOTHING verified. Consumers across the diff --git a/package-lock.json b/package-lock.json index fc4f49e..b892d36 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@socioprophet/hellgraph", - "version": "0.4.45", + "version": "0.4.46", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@socioprophet/hellgraph", - "version": "0.4.45", + "version": "0.4.46", "license": "UNLICENSED", "bin": { "hellgraph-superpeer": "bin/hellgraph-superpeer.mjs"