feat(#1433): capability trust gate + upgrade/compat (ADR-1244 Phase 4) (#1449)

ADR-1244 Phase 4 (D5 trust + D6 upgrade/compat). capability-trust.cjs (disclosure/consent, strict_known_registries, engines+compatVersions, reserved namespace) + capability-lifecycle.cjs (install/upgrade/remove/reconcile; ledger-as-commit-point _pending intent; atomic stage-then-swap; surgical marker-isolated shared-edit strip; owner-token lock) + capability-source promote/skipEnginesGate seams + loader pending-skip + config keys. No sandbox re-derived (consent+integrity+reversibility). 6 Codex adversarial rounds + /security-review (no HIGH) + /code-review; gsd-test green both platforms; CI green. Phase 5 (#1434) wires the CLI dispatch.

Closes #1433.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-06-18 21:40:37 -04:00
committed by GitHub
parent 1abb0d3427
commit 9219af3360
22 changed files with 2843 additions and 14 deletions

View File

@@ -112,6 +112,40 @@ describe('loadRegistry — accepting valid overlays', () => {
});
});
describe('loadRegistry — uncommitted (_pending) overlay is not activated (ADR-1244 Phase 4)', () => {
test('a capability dir whose ledger entry has a _pending intent is skipped with a warning', (t) => {
const home = makeOverlayHome([featureCap('pendingcap', { skills: ['pending-skill'] })]);
t.after(() => cleanup(home));
// Co-located ledger marks the cap as an in-flight (uncommitted) install.
fs.writeFileSync(
path.join(home, '.gsd-capabilities.json'),
JSON.stringify({
version: '1', updatedAt: '2026-01-01T00:00:00Z',
entries: { pendingcap: { id: 'pendingcap', version: '1.0.0', source: 's', integrity: '', files: [], sharedEdits: [], _pending: { kind: 'install', backupName: null, sharedFiles: [] } } },
}),
'utf8',
);
const reg = load(home);
assert.ok(!reg.capabilities['pendingcap'], 'uncommitted cap not activated');
assert.ok(reg._overlay.warnings.some((w) => w.id === 'pendingcap' && /in progress/.test(w.reason)), 'skip warning recorded');
});
test('once the ledger entry is committed (no _pending) the same dir activates normally', (t) => {
const home = makeOverlayHome([featureCap('committedcap', { skills: ['committed-skill'] })]);
t.after(() => cleanup(home));
fs.writeFileSync(
path.join(home, '.gsd-capabilities.json'),
JSON.stringify({
version: '1', updatedAt: '2026-01-01T00:00:00Z',
entries: { committedcap: { id: 'committedcap', version: '1.0.0', source: 's', integrity: '', files: [], sharedEdits: [] } },
}),
'utf8',
);
const reg = load(home);
assert.ok(reg.capabilities['committedcap'], 'committed cap activates');
});
});
describe('loadRegistry — first-party always wins', () => {
test('overlay whose id collides with a first-party id is rejected; first-party preserved', (t) => {
const home = makeOverlayHome([featureCap('ui', { skills: ['hijacked'] })]);