Skip to content

Commit 9db4361

Browse files
committed
ci: track the ADR-0076 D7 engine repo-split trigger metric (#2462)
D7 (extracting the ObjectQL engine into its own repo) is gated on the cross-package commit ratio of engine.ts/registry.ts falling from ~88% to a low, stable level — but nothing measured it. Add scripts/check-engine-split-ratio.mjs (report-only by default; optional --threshold gate once OQ#5 is decided) and a weekly workflow that writes the ratio to the run's step summary. Current reading: 100% over the last 30 days — D7 stays firmly deferred. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu
1 parent 7f68068 commit 9db4361

2 files changed

Lines changed: 138 additions & 0 deletions

File tree

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Engine Split Metric (ADR-0076 D7)
2+
3+
# Tracks the D7 repo-split trigger metric (#2462): the cross-package commit
4+
# ratio of the ObjectQL engine core (engine.ts / registry.ts). The engine may
5+
# only be extracted into its own repo once this ratio is low and stable
6+
# (~88% at ADR time). Report-only — no gate until a threshold is agreed
7+
# (ADR-0076 OQ#5); the ratio lands in the run's step summary.
8+
9+
on:
10+
schedule:
11+
- cron: '17 3 * * 1' # weekly, Monday 03:17 UTC
12+
workflow_dispatch: {}
13+
pull_request:
14+
paths:
15+
- 'scripts/check-engine-split-ratio.mjs'
16+
- '.github/workflows/engine-split-metric.yml'
17+
18+
permissions:
19+
contents: read
20+
21+
jobs:
22+
ratio:
23+
name: Engine cross-package commit ratio
24+
runs-on: ubuntu-latest
25+
timeout-minutes: 10
26+
steps:
27+
- name: Checkout repository (full history)
28+
uses: actions/checkout@v7
29+
with:
30+
fetch-depth: 0
31+
32+
- name: Compute ratio (90-day window)
33+
run: node scripts/check-engine-split-ratio.mjs --days 90
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#!/usr/bin/env node
2+
/**
3+
* ADR-0076 D7 trigger metric (#2462): cross-package commit ratio of the
4+
* ObjectQL engine core (`engine.ts` / `registry.ts`).
5+
*
6+
* The engine repo-split (D7) is trigger-gated: it may only happen once the
7+
* share of engine-core commits that ALSO touch files outside
8+
* `packages/objectql/` falls to a low, stable level (it was ~88% when the
9+
* ADR was written — i.e. the engine still co-evolves with the rest of the
10+
* monorepo and is NOT separable). This script computes that ratio from git
11+
* history so CI can track it over time.
12+
*
13+
* Run: node scripts/check-engine-split-ratio.mjs [--days N] [--threshold PCT]
14+
*
15+
* --days N Look-back window in days (default 90).
16+
* --threshold PCT Optional gate: exit 1 if the ratio is ABOVE the given
17+
* percentage. By default the script is REPORT-ONLY (always
18+
* exits 0) — the split threshold is an open question
19+
* (ADR-0076 OQ#5) and is set deliberately, not by default.
20+
*
21+
* Output: a human-readable summary on stdout; when $GITHUB_STEP_SUMMARY is
22+
* set, a markdown section is appended for the Actions run summary.
23+
*
24+
* Requires full git history (in CI: actions/checkout with fetch-depth: 0).
25+
* Zero third-party dependencies.
26+
*/
27+
28+
import { execFileSync } from 'node:child_process';
29+
import { appendFileSync } from 'node:fs';
30+
import { dirname, resolve } from 'node:path';
31+
import { fileURLToPath } from 'node:url';
32+
33+
const __dirname = dirname(fileURLToPath(import.meta.url));
34+
const repoRoot = resolve(__dirname, '..');
35+
36+
const ENGINE_CORE = ['packages/objectql/src/engine.ts', 'packages/objectql/src/registry.ts'];
37+
const ENGINE_PACKAGE_PREFIX = 'packages/objectql/';
38+
39+
function arg(name, fallback) {
40+
const i = process.argv.indexOf(`--${name}`);
41+
if (i !== -1 && process.argv[i + 1] !== undefined) return process.argv[i + 1];
42+
return fallback;
43+
}
44+
45+
const days = Number(arg('days', '90'));
46+
const thresholdRaw = arg('threshold', '');
47+
const threshold = thresholdRaw === '' ? null : Number(thresholdRaw);
48+
if (!Number.isFinite(days) || days <= 0) {
49+
console.error(`Invalid --days value: ${arg('days', '90')}`);
50+
process.exit(2);
51+
}
52+
if (thresholdRaw !== '' && (!Number.isFinite(threshold) || threshold < 0 || threshold > 100)) {
53+
console.error(`Invalid --threshold value: ${thresholdRaw} (expected 0-100)`);
54+
process.exit(2);
55+
}
56+
57+
function git(...args) {
58+
return execFileSync('git', args, { cwd: repoRoot, encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 });
59+
}
60+
61+
// Commits in the window that touched the engine core.
62+
const shas = git(
63+
'log', `--since=${days} days ago`, '--format=%H', '--', ...ENGINE_CORE,
64+
).split('\n').filter(Boolean);
65+
66+
let crossPackage = 0;
67+
for (const sha of shas) {
68+
const files = git('show', '--name-only', '--format=', sha).split('\n').filter(Boolean);
69+
if (files.some((f) => !f.startsWith(ENGINE_PACKAGE_PREFIX))) crossPackage += 1;
70+
}
71+
72+
const total = shas.length;
73+
const ratio = total === 0 ? 0 : (crossPackage / total) * 100;
74+
const ratioStr = ratio.toFixed(1);
75+
76+
const lines = [
77+
`ADR-0076 D7 trigger metric — engine cross-package commit ratio`,
78+
` window: last ${days} days`,
79+
` engine-core commits: ${total} (${ENGINE_CORE.join(', ')})`,
80+
` also cross-package: ${crossPackage}`,
81+
` ratio: ${total === 0 ? 'n/a (no engine-core commits in window)' : `${ratioStr}%`}`,
82+
``,
83+
`Reference: ~88% at ADR time (2026-06) — the engine repo-split (D7) stays`,
84+
`deferred until this ratio is low and stable (threshold TBD, ADR-0076 OQ#5).`,
85+
];
86+
console.log(lines.join('\n'));
87+
88+
if (process.env.GITHUB_STEP_SUMMARY) {
89+
const md = [
90+
`### ADR-0076 D7 trigger metric — engine cross-package commit ratio`,
91+
``,
92+
`| Window | Engine-core commits | Cross-package | Ratio |`,
93+
`|---|---|---|---|`,
94+
`| last ${days} days | ${total} | ${crossPackage} | ${total === 0 ? 'n/a' : `${ratioStr}%`} |`,
95+
``,
96+
`Reference: ~88% at ADR time. D7 (engine repo-split) stays deferred until this is low and stable (OQ#5).`,
97+
``,
98+
].join('\n');
99+
appendFileSync(process.env.GITHUB_STEP_SUMMARY, md);
100+
}
101+
102+
if (threshold !== null && total > 0 && ratio > threshold) {
103+
console.error(`\nRatio ${ratioStr}% exceeds the configured threshold of ${threshold}% — engine is not separable.`);
104+
process.exit(1);
105+
}

0 commit comments

Comments
 (0)