Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
79 changes: 11 additions & 68 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,72 +31,14 @@ permissions:

jobs:
# ------------------------------------------------------------------
# Core-decoupling check (epic #470). The Dev Platform lives in its own
# repository; this fails if core re-acquires ANY reference to it.
#
# This was a ratchet — a committed count allowed to fall and never rise —
# for as long as the extraction was in flight. C13 finished the job and the
# floor is now hard zero: the script asserts 0 outright instead of reading
# a baseline, because a baseline is a number and numbers get edited. The
# job name is kept for continuity as a required check.
# The core-decoupling ratchet (epic #470) used to run here. It landed with
# the epic on 2026-07-30, peaked at 3,448 counted Dev Platform references,
# reached 0 at C13 and was removed at C14 on 2026-08-21. The extraction is
# finished — the Dev Platform lives in `byte5ai/omadia-dev-platform` — so
# the guard has done its job and a guard with nothing left to guard is
# maintenance, not safety. Reintroducing that coupling is now an ordinary
# architectural decision to argue for in review, not a number to edit.
# ------------------------------------------------------------------
decoupling:
name: core decoupling ratchet (#470)
runs-on: ubuntu-latest
# Was 5. `Ensure ripgrep` alone took 3:28 on a good run and 5:07 on a bad
# one, so this job routinely had ~90 seconds of headroom and intermittently
# blew the budget. A timed-out job reports as `cancelled`, and its remaining
# steps are `skipped` — so the ratchet was a REQUIRED check that silently
# did not run, which is the same failure family as a permanently-green
# guard-skip: not red, not passing, just absent.
timeout-minutes: 10
steps:
- uses: actions/checkout@v7

- uses: actions/setup-node@v7
with:
node-version: '22'

- name: Ensure ripgrep
# `apt-get update` is the expensive half — it refetches every package
# index to install one small binary. Try the cached indices first and
# only refresh when that actually fails. `rg` is genuinely needed:
# `check-core-decoupling.mjs` shells out to it (`execFileSync('rg', …)`).
run: |
if ! command -v rg >/dev/null; then
sudo apt-get install -y ripgrep \
|| (sudo apt-get update && sudo apt-get install -y ripgrep)
fi

- name: Assert core has ZERO Dev Platform references
# C13 pinned the count at 0 permanently. The script asserts that
# outright (`EXTRACTION_COMPLETE`) rather than comparing against
# `decoupling-baseline.json`, so a single reintroduced reference —
# code path, config key, i18n key, fixture string or comment — fails
# this job, and there is no number anyone can edit to make it pass.
#
# Belt and braces on top of the script's own exit code: assert the
# report literally says zero. If a future refactor ever made the
# script exit 0 while still counting hits (a `--report`-style path
# slipping into the default mode, an early `process.exit(0)`), this
# step still fails. A guard that can only fail loudly is the point.
run: |
node scripts/check-core-decoupling.mjs
node scripts/check-core-decoupling.mjs --report | tee /tmp/decoupling.txt
grep -qE '^ TOTAL 0( |$)' /tmp/decoupling.txt

- name: Test the detector itself
# The guard above only earns its required-check status if the detector
# it runs actually detects. `check-core-decoupling.test.mjs` plants a
# probe file under `middleware/src/` and asserts the checker goes red —
# it is the mutation test, committed.
#
# It is wired HERE deliberately. `scripts/` has no package.json and no
# other job globs `*.test.mjs`, so a test file sitting there would
# never execute: green because nothing ran it, which this job's own
# timeout comment above already names as the same failure family as a
# permanently-green guard-skip. A test nobody runs is not a test.
run: node --test scripts/check-core-decoupling.test.mjs

# ------------------------------------------------------------------
# Middleware: lint + typecheck + node:test against tsx
Expand Down Expand Up @@ -158,7 +100,8 @@ jobs:
# The root tsconfig only includes src/, so `typecheck` above never sees
# test/ or scripts/. This ratchet typechecks those trees against a
# committed baseline: it blocks NEW type errors while the pre-existing
# debt burns down (issue #573, same pattern as the decoupling ratchet).
# debt burns down (issue #573, same pattern the retired #470
# core-decoupling ratchet used).
- name: Typecheck (test + scripts trees, ratchet)
run: npm run typecheck:test

Expand Down Expand Up @@ -253,9 +196,9 @@ jobs:
# the count drops (broken DSN, a future suite reading an env var we
# don't set here, a cold-connection flake), a suite silently vanished —
# go red. Raise PG_TEST_FLOOR when you add Postgres tests, same
# baseline-ratchet convention as the core-decoupling job above.
# baseline-ratchet convention the retired #470 core-decoupling job used.
#
# NOTE — this floor is the INVERSE of the core-decoupling ratchet, and
# NOTE — this floor is the INVERSE of that ratchet, and
# the reflex from that one is wrong here. It is a MINIMUM on desirable
# coverage, so raising it as suites land is the intended move; there the
# counted thing is debt and the rule is reword-don't-raise. It had
Expand Down
17 changes: 17 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,23 @@ entry. See `CONTRIBUTING.md` § Releases & changelog.

## [Unreleased]

### Removed — the core-decoupling ratchet is retired (#470 C14)

- `scripts/check-core-decoupling.mjs`, its colocated detector test
`scripts/check-core-decoupling.test.mjs`, `specs/470-dev-platform-plugin/decoupling-baseline.json`
and the CI job `core decoupling ratchet (#470)` are removed. The guard ran from 2026-07-30
(#539) to 2026-08-21, peaked at **3,448** counted Dev Platform references in core, fell to
214 at C10 and reached **0** at C13, where the floor was pinned permanently.
- It was scaffolding for a migration in flight: it made a file inventory's staleness
survivable, because a checklist goes stale on contact and a count does not. The extraction
is finished and the Dev Platform lives in `byte5ai/omadia-dev-platform`, so the guard has
nothing left to guard — keeping it would cost a CI job and leave an editable number behind.
Reintroducing that coupling is now an ordinary architectural decision, argued for in review.
- No behaviour change: the job is not among `main`'s required status checks and no other job
declared `needs: decoupling`, so removing it cannot leave a branch waiting on a check that
will never report. (The job's own comment claimed required-check status; branch protection
says otherwise — worth knowing before trusting a comment about CI over the API.) The specs
under `specs/470-dev-platform-plugin/` keep a closing note in place of the live baseline rows.
### Added — runtime install of subscription CLIs from the admin UI (#309 extension, enabler for #294)

- **The Subscription-CLIs page can now install a missing vendor CLI in-app.**
Expand Down
3 changes: 2 additions & 1 deletion middleware/scripts/check-test-file-durations.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
*
* WHY A FRACTION AND NOT A COMMITTED BASELINE
* -------------------------------------------
* The repo's other ratchets (core-decoupling, test-typecheck, PG_TEST_FLOOR)
* The repo's other ratchets (test-typecheck, PG_TEST_FLOOR, and the #470
* core-decoupling ratchet until it was retired at C14)
* commit an absolute number, because they count things that do not vary by
* machine. Durations do: the same suite measured 36.5 s locally on 16 cores
* and 172 s on a 4-vCPU CI runner — a 4.7x spread. An absolute ms baseline
Expand Down
3 changes: 2 additions & 1 deletion middleware/scripts/check-test-typecheck.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
*
* The trees carry a large pre-existing type-error debt (intentional partial
* mocks, drifted fixtures, a few real bugs). Fixing all of it in one PR is a
* 130-file diff. So — exactly like `scripts/check-core-decoupling.mjs` — this
* 130-file diff. So — exactly like the #470 core-decoupling ratchet did, until
* it was retired at C14 — this
* counts errors per file against a committed baseline and refuses to let any
* file's count rise. New test type errors fail CI immediately; the debt burns
* down over time and the baseline only ever falls.
Expand Down
7 changes: 3 additions & 4 deletions middleware/scripts/plugin-ledger-handoff.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,9 @@
*
* DELIBERATELY GENERIC. It names no plugin and no table: the plan file
* supplies the plugin id, the ledger, the migrations directory and the
* entries, and core supplies the donor ledger. That is not tidiness — core's
* decoupling ratchet (`scripts/check-core-decoupling.mjs`) requires that no
* core file name the extracted plugin, and the next plugin to leave core will
* want this tool unchanged.
* entries, and core supplies the donor ledger. That is not tidiness — the
* extraction rule (epic #470) was that no core file names the extracted
* plugin, and the next plugin to leave core will want this tool unchanged.
*
* PLAN FILE
* ---------
Expand Down
4 changes: 2 additions & 2 deletions middleware/test/auth/staticPublicPathsClosedSet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ import { PUBLIC_MCP_PATH } from '../../src/mcp/publicMcpPath.js';
* WHY THIS SUITE DOES NOT NAME THE TWO DELETED PATHS
* -------------------------------------------------
* Naming them would write a plugin's wire paths back into core — the exact
* coupling this epic removes, and the thing `scripts/check-core-decoupling.mjs`
* counts on its way to a permanent zero. A test that hardcodes a plugin's URLs
* coupling this epic removed, and the thing the #470 decoupling ratchet counted
* on its way to zero before it was retired at C14. A test that hardcodes a plugin's URLs
* is a reference to that plugin whichever direction it asserts in, and it goes
* stale-but-green the day the plugin renames them.
*
Expand Down
6 changes: 3 additions & 3 deletions middleware/test/pluginMigrationHandoff.pg.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
* - `pg_advisory_xact_lock` really serialises two concurrent seeders.
* - `ROLLBACK` really un-does the dry run, including the ledger DDL.
*
* NAMES ARE DELIBERATELY NEUTRAL. This suite lives in core, and core's
* decoupling ratchet (`scripts/check-core-decoupling.mjs`) counts every one of
* the extracted plugin's identifiers in `middleware/test`. The mechanism is
* NAMES ARE DELIBERATELY NEUTRAL. This suite lives in core, and the epic #470
* extraction rule kept every one of the extracted plugin's identifiers out of
* `middleware/test` (the ratchet that enforced it was retired in C14). The mechanism is
* generic — any plugin adopting any core ledger — so the fixture is generic
* too. The nine REAL witnesses are documented in the epic README under
* `specs/470-dev-…-plugin/README.md` and shipped by the plugin repo, which
Expand Down
Loading
Loading