@bongos/core 1.19.1033 → 1.19.1034
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.
- package/.bongos-core.json +186 -86
- package/.claude/skills/builder-start/SKILL.md +1 -1
- package/.claude/skills/grade-recover/SKILL.md +2 -1
- package/.claude/skills/grader-health/SKILL.md +4 -0
- package/.claude/skills/merge-mode/SKILL.md +1 -1
- package/docs/adr/0089-modular-multi-model-adversarial-grader.md +15 -0
- package/docs/adr/README.md +1 -1
- package/docs/api/openapi.json +1 -1
- package/docs/architecture.md +3 -2
- package/docs/canonical-permissions.md +2 -2
- package/docs/copy-inventory.md +34 -30
- package/docs/copy-registry.json +69 -33
- package/docs/module-api-changelog.md +3 -1
- package/docs/recipes/local-dev.md +45 -3
- package/docs/recipes/packaging-the-core.md +1 -1
- package/modules/autonomy/cadence.js +52 -0
- package/modules/government/protected-surfaces.json +1 -0
- package/modules/grading/grade-engine.js +267 -0
- package/modules/grading/grader-subagent.js +4 -3
- package/modules/grading/grader-workers/index.js +67 -11
- package/modules/grading/grader-workers/worker-verdict.js +32 -2
- package/modules/grading/grader.js +109 -88
- package/modules/hall-ui/public/deploy.js +35 -0
- package/modules/hall-ui/public/project-settings.css +7 -0
- package/modules/lifecycle/routes/tasks.js +19 -4
- package/modules/provisioning/control-plane-guard.js +14 -13
- package/modules/provisioning/core-upgrade.js +30 -17
- package/modules/provisioning/public-refusal.js +44 -0
- package/modules/provisioning/routes/disconnect.js +2 -1
- package/modules/provisioning/routes/env-manifest.js +5 -4
- package/modules/provisioning/routes/provisioning.js +16 -15
- package/modules/provisioning/routes/repo-private.js +2 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +70 -0
- package/scripts/gds/autobongos-run.js +10 -2
- package/scripts/gds/backfill-cost.js +20 -9
- package/scripts/gds/claim.js +2 -2
- package/scripts/gds/credential-presence.js +281 -0
- package/scripts/gds/deploy-main-audit-gate.sh +11 -4
- package/scripts/gds/dev-lib.js +212 -5
- package/scripts/gds/dev.js +102 -50
- package/scripts/gds/doctor.js +3 -2
- package/scripts/gds/grade-correlation-audit.js +280 -0
- package/scripts/gds/grade-replay.js +237 -0
- package/scripts/gds/hooks/pre-push.js +7 -3
- package/scripts/gds/main-audit.js +19 -10
- package/scripts/gds/memory-map.js +3 -1
- package/scripts/gds/onboarding-config.js +3 -2
- package/scripts/gds/plain-cards.js +4 -0
- package/scripts/gds/preflight.js +12 -4
- package/scripts/gds/provision-core-upgrade.js +155 -4
- package/scripts/gds/provision-repo-auth.js +15 -0
- package/scripts/gds/provision.js +1 -1
- package/scripts/gds/publish-credential-check.js +3 -0
- package/scripts/gds/push-main.js +14 -3
- package/scripts/gds/push-path-brief.js +3 -2
- package/scripts/gds/run-routine.js +18 -5
- package/scripts/gds/run-unit-tests.js +14 -3
- package/scripts/gds/session-cost.js +12 -3
- package/scripts/gds/ship-deploy-target.js +11 -6
- package/scripts/gds/ship-grade-steps.js +33 -0
- package/scripts/gds/ship-land.js +157 -11
- package/scripts/gds/ship-merge.js +3 -2
- package/scripts/gds/ship-preflight-steps.js +30 -8
- package/scripts/gds/ship.js +1 -1
- package/scripts/gds/upgrade.js +3 -3
- package/scripts/hall-preview/README.md +20 -3
- package/scripts/hall-preview/live-identity.js +1 -1
- package/scripts/hall-preview/refresh-fixtures.js +71 -11
- package/scripts/hall-preview/scrub-identity.js +296 -0
- package/src/bongos/routes/security.js +3 -3
- package/src/build-info.js +4 -2
- package/src/module-api.js +1 -1
- package/tests/adr_0089_scope.mjs +70 -0
- package/tests/autobongos_cadence.mjs +74 -0
- package/tests/consumer_layout_boot.mjs +363 -31
- package/tests/core_upgrade_door.mjs +40 -6
- package/tests/core_upgrade_runner.mjs +240 -4
- package/tests/credential_presence.mjs +153 -0
- package/tests/deploy_audit_gate.mjs +5 -2
- package/tests/deploy_page_projects.mjs +63 -2
- package/tests/dev_lib.mjs +2 -1
- package/tests/dev_windows.mjs +324 -0
- package/tests/env_knobs_neutral_prefix.mjs +203 -0
- package/tests/fixtures/grade-replay/recorded-panel-grades.json +27 -0
- package/tests/government_protected_surfaces.mjs +10 -0
- package/tests/grade_correlation_audit.mjs +159 -0
- package/tests/grade_engine.mjs +249 -0
- package/tests/grade_engine_replay.mjs +99 -0
- package/tests/grader_prompt_window_bound.mjs +132 -0
- package/tests/grader_unbacked_score.mjs +194 -0
- package/tests/hall_preview_scrub.mjs +214 -0
- package/tests/integration_parked_ratchet.mjs +24 -1
- package/tests/provisioning_public_refusal.mjs +195 -0
- package/tests/publish_status_branch.mjs +128 -0
- package/tests/ship_land_red_pr.mjs +236 -0
- package/tests/ship_preflight.mjs +67 -1
- package/tests/start_env_guard.mjs +16 -0
- package/tests/upgrade.mjs +20 -1
package/tests/ship_preflight.mjs
CHANGED
|
@@ -17,7 +17,7 @@ const {
|
|
|
17
17
|
untrackedPaths, untrackedLeftBehind, untrackedWarningLines,
|
|
18
18
|
} = require('../modules/lifecycle/ship-preflight.js');
|
|
19
19
|
// task 1001436: the preflight step itself + the ship-input resolver it is handed.
|
|
20
|
-
const { preflight, shipInputPaths } = require('../scripts/gds/ship-preflight-steps.js');
|
|
20
|
+
const { preflight, shipInputPaths, staleToolingFiles, TOOLING_PATHSPECS } = require('../scripts/gds/ship-preflight-steps.js');
|
|
21
21
|
|
|
22
22
|
const tests = [];
|
|
23
23
|
const test = (name, fn) => tests.push({ name, fn });
|
|
@@ -509,6 +509,72 @@ test('preflight (real git): nothing committed on the branch → no untracked war
|
|
|
509
509
|
});
|
|
510
510
|
});
|
|
511
511
|
|
|
512
|
+
// ---- stale ship-tooling guard (task 1004273) ----
|
|
513
|
+
// The guard named ship.js + grader.js only; two carves moved the logic into ship-*.js
|
|
514
|
+
// and grader-*.js / grader-workers/ / grade-engine.js, so a branch behind main on any
|
|
515
|
+
// of those shipped with a stale copy — the #662 shape the guard exists for.
|
|
516
|
+
|
|
517
|
+
test('stale-tooling guard: every tracked ship*.js and grader file is covered by TOOLING_PATHSPECS', () => {
|
|
518
|
+
const root = path.resolve(import.meta.dirname, '..');
|
|
519
|
+
const ls = (...spec) => execSync(`git ls-files -z -- ${spec.map((s) => `'${s}'`).join(' ')}`, { cwd: root, encoding: 'utf8' })
|
|
520
|
+
.split('\0').filter(Boolean);
|
|
521
|
+
// Chosen by an independent rule (the filename), then asked of git's own pathspec matcher.
|
|
522
|
+
const shipTooling = ls('scripts/gds', 'modules/grading').filter((f) =>
|
|
523
|
+
/^scripts\/gds\/ship[^/]*\.js$/.test(f) || /^modules\/grading\/(?:grader|grade-engine)/.test(f));
|
|
524
|
+
assert.ok(shipTooling.length >= 25, `only ${shipTooling.length} ship/grader file(s) found — the scan is reading the wrong tree`);
|
|
525
|
+
assert.ok(shipTooling.includes('scripts/gds/ship-land.js') && shipTooling.includes('modules/grading/grader-score.js'));
|
|
526
|
+
const covered = new Set(ls(...TOOLING_PATHSPECS));
|
|
527
|
+
const missed = shipTooling.filter((f) => !covered.has(f));
|
|
528
|
+
assert.deepEqual(missed, [], `ship/grade tooling the stale-tooling guard would not refuse: ${missed.join(', ')}`);
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
// Publish the throwaway repo's main to its local bare "origin".
|
|
532
|
+
const publishMain = (run) => run(['git', 'push', '-q', 'origin', 'main'].join(' '));
|
|
533
|
+
|
|
534
|
+
test('preflight (real git): main moved a carved ship-*.js and added a new grader file → refused stale-tooling', () => {
|
|
535
|
+
withPreflightRepo(({ work, run }) => {
|
|
536
|
+
fs.mkdirSync(path.join(work, 'scripts', 'gds'), { recursive: true });
|
|
537
|
+
fs.mkdirSync(path.join(work, 'modules', 'grading'), { recursive: true });
|
|
538
|
+
fs.writeFileSync(path.join(work, 'scripts', 'gds', 'ship-land.js'), '// v1\n');
|
|
539
|
+
fs.writeFileSync(path.join(work, 'modules', 'grading', 'grader-score.js'), '// v1\n');
|
|
540
|
+
run('git add -A && git commit -q -m tooling');
|
|
541
|
+
publishMain(run);
|
|
542
|
+
run('git checkout -q -b feature');
|
|
543
|
+
fs.writeFileSync(path.join(work, 'src.txt'), 'the branch\'s own work\n');
|
|
544
|
+
run('git add -A && git commit -q -m work');
|
|
545
|
+
// main moves: one carved file changes, one file appears that this checkout never had.
|
|
546
|
+
run('git checkout -q main');
|
|
547
|
+
fs.writeFileSync(path.join(work, 'scripts', 'gds', 'ship-land.js'), '// v2\n');
|
|
548
|
+
fs.writeFileSync(path.join(work, 'modules', 'grading', 'grader-new.js'), '// new carve\n');
|
|
549
|
+
run('git add -A && git commit -q -m "main moves the tooling"');
|
|
550
|
+
publishMain(run);
|
|
551
|
+
run('git checkout -q feature');
|
|
552
|
+
assert.ok(!fs.existsSync(path.join(work, 'modules', 'grading', 'grader-new.js')), 'the new file is on main only');
|
|
553
|
+
|
|
554
|
+
const { result, out } = capturePreflight({ task_id: 4244, head_sha: null }, {});
|
|
555
|
+
assert.equal(result.ok, false);
|
|
556
|
+
assert.equal(result.reason, 'stale-tooling');
|
|
557
|
+
assert.match(out, /- scripts\/gds\/ship-land\.js/, 'a carved ship-*.js is tooling');
|
|
558
|
+
assert.match(out, /- modules\/grading\/grader-new\.js/, 'a file only main has is still matched');
|
|
559
|
+
assert.deepEqual(staleToolingFiles({ cwd: work }).sort(), ['modules/grading/grader-new.js', 'scripts/gds/ship-land.js']);
|
|
560
|
+
});
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
test('preflight (real git): the branch\'s OWN edit to a ship-*.js is not stale tooling', () => {
|
|
564
|
+
withPreflightRepo(({ work, run }) => {
|
|
565
|
+
fs.mkdirSync(path.join(work, 'scripts', 'gds'), { recursive: true });
|
|
566
|
+
fs.writeFileSync(path.join(work, 'scripts', 'gds', 'ship-land.js'), '// v1\n');
|
|
567
|
+
run('git add -A && git commit -q -m tooling');
|
|
568
|
+
publishMain(run);
|
|
569
|
+
run('git checkout -q -b feature');
|
|
570
|
+
fs.writeFileSync(path.join(work, 'scripts', 'gds', 'ship-land.js'), '// the fix this task ships\n');
|
|
571
|
+
run('git add -A && git commit -q -m "fix the land"');
|
|
572
|
+
const { result } = capturePreflight({ task_id: 4245, head_sha: null }, {});
|
|
573
|
+
assert.equal(result.ok, true);
|
|
574
|
+
assert.deepEqual(staleToolingFiles({ cwd: work }), []);
|
|
575
|
+
});
|
|
576
|
+
});
|
|
577
|
+
|
|
512
578
|
// ---- runner ----
|
|
513
579
|
|
|
514
580
|
let pass = 0;
|
|
@@ -118,6 +118,22 @@ t('a hosted origin says the core installs with no token, and never re-offers the
|
|
|
118
118
|
assert.doesNotMatch(card, /\bprivate\b/i, 'must not call the package private');
|
|
119
119
|
});
|
|
120
120
|
|
|
121
|
+
// task 1004288: the card above was corrected when the core went public, but the SKILL that
|
|
122
|
+
// routes the same fresh-clone wall kept teaching the old posture — "a PRIVATE package", "404s
|
|
123
|
+
// on any machine with no NPM_TOKEN", "the expected tokenless outcome". An agent that believes
|
|
124
|
+
// that reads a real 404 (a version never published, a mistyped name) as normal and moves on.
|
|
125
|
+
t('the builder-start skill agrees with the card: the core is public, and a 404 is not normal', () => {
|
|
126
|
+
const { readFileSync } = require('node:fs');
|
|
127
|
+
const path = require('node:path');
|
|
128
|
+
const skill = readFileSync(path.join(import.meta.dirname, '..', '.claude', 'skills', 'builder-start', 'SKILL.md'), 'utf8');
|
|
129
|
+
assert.doesNotMatch(skill, /PRIVATE package|private package/i, 'must not call @bongos/core a private package (ADR 0283)');
|
|
130
|
+
assert.doesNotMatch(skill, /expected tokenless outcome/i, 'must not present a tokenless 404 as expected');
|
|
131
|
+
assert.doesNotMatch(skill, /404s on any machine with no `?NPM_TOKEN/i, 'must not tell the agent a tokenless install 404s');
|
|
132
|
+
assert.match(skill, /PUBLIC npm package/, 'names the core as public');
|
|
133
|
+
assert.match(skill, /ADR 0283/, 'cites the decision that made it public');
|
|
134
|
+
assert.match(skill, /404 on `@bongos\/core` is therefore \*\*not\*\* a normal outcome/, 'says a 404 now means something is wrong');
|
|
135
|
+
});
|
|
136
|
+
|
|
121
137
|
t('isLocalOrigin: loopback is local, everything else is remote', () => {
|
|
122
138
|
for (const o of ['http://localhost:3000', 'http://app.localhost:3000', 'http://127.0.0.1:3000', 'http://[::1]:3000']) {
|
|
123
139
|
assert.equal(isLocalOrigin(o), true, `${o} should be local`);
|
package/tests/upgrade.mjs
CHANGED
|
@@ -1543,7 +1543,7 @@ t('persistPin: a refused origin push on a WIRED private instance is loud — nam
|
|
|
1543
1543
|
assert.equal(r.refused, 'read-only-deploy-key');
|
|
1544
1544
|
// The tokenless refusal is a plain sentence, not the bare status line.
|
|
1545
1545
|
assert.match(r.error, /read-only deploy key at \/srv\/bongos\/acme\/\.git\/cloudbongos-deploy-key/, 'names the key');
|
|
1546
|
-
assert.match(r.error, /no owner GitHub token
|
|
1546
|
+
assert.match(r.error, /no owner GitHub token was available/, 'and why nothing else was tried');
|
|
1547
1547
|
assert.notEqual(r.error, 'git push failed');
|
|
1548
1548
|
const text = warnings.join('\n');
|
|
1549
1549
|
assert.match(text, /PIN NOT PUSHED/, 'shouts');
|
|
@@ -1655,6 +1655,25 @@ t('resolvePinPushAuth: the owner token is spent only when one is stored AND the
|
|
|
1655
1655
|
assert.equal(await u.resolvePinPushAuth(dir, { log: hush, instance: inst, getGithubToken: async () => { throw new Error('secret-box off'); } }, at('git@github.com:acme/widgets.git')), null);
|
|
1656
1656
|
});
|
|
1657
1657
|
|
|
1658
|
+
t('resolvePinPushAuth: on a hosted project\u2019s own box a missing row SAYS WHY, instead of falling back silently (task 1004065)', async () => {
|
|
1659
|
+
// The project's own database has no provisioning table (ADR 0281), so the lookup
|
|
1660
|
+
// answers null there — and on a checkout wired with the read-only deploy key that is
|
|
1661
|
+
// not "the origin path", it is a push that cannot succeed.
|
|
1662
|
+
const dir = { instanceDir: '/srv/bongos/acme' };
|
|
1663
|
+
const wired = { config: { status: 0, stdout: 'ssh -F /dev/null -i /srv/bongos/acme/.git/cloudbongos-deploy-key -o IdentitiesOnly=yes\n' }, remote: { status: 0, stdout: 'git@github.com:acme/widgets.git\n' } };
|
|
1664
|
+
const said = [];
|
|
1665
|
+
const r = await u.resolvePinPushAuth(dir, { log: (m) => said.push(m), getInstanceBySlug: async () => null }, pinRun(wired));
|
|
1666
|
+
assert.equal(r, null, 'still the remote path — there is no token to use');
|
|
1667
|
+
const line = said.join('\n');
|
|
1668
|
+
assert.match(line, /no provisioning row is readable from this database/, 'names what is missing');
|
|
1669
|
+
assert.match(line, /read-only deploy key at \/srv\/bongos\/acme\/\.git\/cloudbongos-deploy-key/, 'and why the fallback cannot work');
|
|
1670
|
+
assert.match(line, /pushes the pin from the hub/, 'and where the push actually happens');
|
|
1671
|
+
// An UNWIRED checkout with no row (a laptop, a public instance) is the real origin path: quiet.
|
|
1672
|
+
const quiet = [];
|
|
1673
|
+
await u.resolvePinPushAuth(dir, { log: (m) => quiet.push(m), getInstanceBySlug: async () => null }, pinRun({ remote: wired.remote }));
|
|
1674
|
+
assert.deepEqual(quiet, [], 'no noise where the fallback is correct');
|
|
1675
|
+
});
|
|
1676
|
+
|
|
1658
1677
|
t('runUpgrade --commit-pin: on a wired private instance the pin lands via the owner token, end to end', async () => {
|
|
1659
1678
|
const dir = scratchConsumer({ pinned: '1.14.1', installed: '1.14.1' });
|
|
1660
1679
|
const src = mkdtempSync(join(tmpdir(), 'otb-upgrade-src-'));
|