mirror of
https://github.com/PR0M3TH3AN/TORCH.git
synced 2026-11-05 20:31:54 +00:00
Add reviewed fleet domain proposals
This commit is contained in:
1 parent
cce059fc3a
commit
b609ae44ce
9 files changed
+499
-17
No files matched your search
@@ -1,6 +1,6 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { execFileSync, spawnSync } from 'node:child_process';
|
||||
import { existsSync, mkdtempSync, writeFileSync } from 'node:fs';
|
||||
import { existsSync, mkdtempSync, readFileSync, writeFileSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import test from 'node:test';
|
||||
@@ -43,3 +43,26 @@ test('SCN-cli-install-approval: install requires an explicit reviewed approval f
|
||||
assert.equal(JSON.parse(result.stdout).error, 'APPROVAL_REQUIRED');
|
||||
assert.equal(existsSync(join(root, '.torch')), false);
|
||||
});
|
||||
|
||||
test('SCN-cli-domain-review: a generated proposal must be approved before install', () => {
|
||||
const root = repo();
|
||||
const proposalPath = join(root, 'fleet-proposal.json');
|
||||
const generated = run(root, ['domains', '--output', proposalPath, '--json']);
|
||||
assert.equal(generated.status, 0, generated.stderr || generated.stdout);
|
||||
const proposal = JSON.parse(readFileSync(proposalPath, 'utf8'));
|
||||
assert.equal(proposal.review.status, 'pending');
|
||||
assert.equal(proposal.domains.length > 0, true);
|
||||
|
||||
const rejected = run(root, ['install', '--proposal', proposalPath, '--yes', '--json']);
|
||||
assert.equal(rejected.status, 2);
|
||||
assert.equal(JSON.parse(rejected.stdout).error, 'PROPOSAL_NOT_APPROVED');
|
||||
assert.equal(existsSync(join(root, '.torch')), false);
|
||||
|
||||
proposal.review = {
|
||||
status: 'approved', reviewedAt: '2026-09-27T00:00:00Z', reviewedBy: 'fixture-owner', notes: [],
|
||||
};
|
||||
writeFileSync(proposalPath, `${JSON.stringify(proposal, null, 2)}\n`);
|
||||
const installed = run(root, ['install', '--proposal', proposalPath, '--yes', '--json']);
|
||||
assert.equal(installed.status, 0, installed.stderr || installed.stdout);
|
||||
assert.equal(existsSync(join(root, '.torch', 'domain-proposal.approved.json')), true);
|
||||
});
|
||||
@@ -0,0 +1,50 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { mkdirSync, mkdtempSync, writeFileSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import test from 'node:test';
|
||||
import { analyzeRepository } from '../../src/kernel/analyze.mjs';
|
||||
import { proposeDomains } from '../../src/kernel/domains.mjs';
|
||||
import { inspectRepository } from '../../src/kernel/git.mjs';
|
||||
|
||||
function architectureFixture() {
|
||||
const root = mkdtempSync(join(tmpdir(), 'torch-domains-'));
|
||||
for (const dir of ['src/client', 'src/server', 'src/shared', 'test']) mkdirSync(join(root, dir), { recursive: true });
|
||||
writeFileSync(join(root, 'src/shared/types.js'), 'export const protocol = 1;\n');
|
||||
writeFileSync(join(root, 'src/client/app.js'), "import { protocol } from '../shared/types.js';\nexport const client = protocol;\n");
|
||||
writeFileSync(join(root, 'src/client/view.js'), 'export const view = true;\n');
|
||||
writeFileSync(join(root, 'src/server/api.js'), "import { protocol } from '../shared/types.js';\nexport const api = protocol;\n");
|
||||
writeFileSync(join(root, 'src/server/store.js'), 'export const store = true;\n');
|
||||
writeFileSync(join(root, 'test/system.test.js'), 'export const scenario = true;\n');
|
||||
writeFileSync(join(root, 'test/contracts.test.js'), 'export const contracts = true;\n');
|
||||
writeFileSync(join(root, 'package.json'), JSON.stringify({ name: 'split-app', scripts: { test: 'node --test' } }));
|
||||
execFileSync('git', ['init', '-b', 'main', root]);
|
||||
execFileSync('git', ['-C', root, 'config', 'user.email', '[email protected]']);
|
||||
execFileSync('git', ['-C', root, 'config', 'user.name', 'TORCH Test']);
|
||||
execFileSync('git', ['-C', root, 'add', '.']);
|
||||
execFileSync('git', ['-C', root, 'commit', '-m', 'architecture fixture']);
|
||||
return root;
|
||||
}
|
||||
|
||||
test('SCN-domain-collision: shared contracts create evidence-linked neighboring domains', () => {
|
||||
const repository = inspectRepository(architectureFixture());
|
||||
const analysis = analyzeRepository(repository);
|
||||
const proposal = proposeDomains({ repository, analysis });
|
||||
const ids = proposal.domains.map((domain) => domain.id);
|
||||
|
||||
assert.deepEqual(ids, ['src-client', 'src-server', 'qa']);
|
||||
assert.equal(analysis.architecture.dependencies.some((edge) =>
|
||||
edge.from === 'src/client' && edge.to === 'src/shared' && edge.evidence === 'src/client/app.js'), true);
|
||||
assert.equal(analysis.architecture.dependencies.some((edge) =>
|
||||
edge.from === 'src/server' && edge.to === 'src/shared' && edge.evidence === 'src/server/api.js'), true);
|
||||
assert.equal(analysis.architecture.sharedSurfaces.includes('src/shared/types.js'), true);
|
||||
|
||||
const frontend = proposal.domains.find((domain) => domain.id === 'src-client');
|
||||
assert.deepEqual(frontend.neighbours, ['qa', 'src-server']);
|
||||
const collision = proposal.collisions.find((item) => item.domains.join(':') === 'src-client:src-server');
|
||||
assert.equal(collision.score >= 1, true);
|
||||
assert.equal(collision.reasons.some((reason) => reason.type === 'shared-dependency'), true);
|
||||
assert.equal(collision.resolution.strategy, 'session-manager-coordination');
|
||||
assert.equal(proposal.review.status, 'pending');
|
||||
});
|
||||
@@ -8,6 +8,7 @@ import { analyzeRepository } from '../../src/kernel/analyze.mjs';
|
||||
import { diagnoseProject } from '../../src/kernel/doctor.mjs';
|
||||
import { inspectRepository } from '../../src/kernel/git.mjs';
|
||||
import { installProject, planInstall, uninstallProject } from '../../src/kernel/install.mjs';
|
||||
import { proposeDomains, validateApprovedProposal } from '../../src/kernel/domains.mjs';
|
||||
|
||||
function fixture() {
|
||||
const root = mkdtempSync(join(tmpdir(), 'torch-kernel-'));
|
||||
@@ -24,12 +25,20 @@ function fixture() {
|
||||
return { root, env: { ...process.env, XDG_DATA_HOME: stateHome } };
|
||||
}
|
||||
|
||||
function approvedProposal(repository) {
|
||||
const proposal = proposeDomains({ repository, analysis: analyzeRepository(repository) });
|
||||
proposal.review = {
|
||||
status: 'approved', reviewedAt: '2026-09-27T00:00:00Z', reviewedBy: 'fixture-owner', notes: [],
|
||||
};
|
||||
return proposal;
|
||||
}
|
||||
|
||||
test('SCN-init-read-only: inspection and analysis do not mutate the project', () => {
|
||||
const { root, env } = fixture();
|
||||
const before = execFileSync('git', ['-C', root, 'status', '--porcelain'], { encoding: 'utf8' });
|
||||
const repository = inspectRepository(root);
|
||||
const analysis = analyzeRepository(repository);
|
||||
const plan = planInstall({ repository, env });
|
||||
const plan = planInstall({ repository, proposal: approvedProposal(repository), env });
|
||||
const after = execFileSync('git', ['-C', root, 'status', '--porcelain'], { encoding: 'utf8' });
|
||||
|
||||
assert.equal(analysis.mutationPerformed, false);
|
||||
@@ -43,8 +52,9 @@ test('SCN-init-read-only: inspection and analysis do not mutate the project', ()
|
||||
test('SCN-install-doctor-purge: a fresh install is healthy and exactly reversible', () => {
|
||||
const { root, env } = fixture();
|
||||
const repository = inspectRepository(root);
|
||||
const proposal = approvedProposal(repository);
|
||||
const installed = installProject({
|
||||
repository, env, projectId: 'fixture-project', now: () => new Date('2026-09-27T00:00:00Z'),
|
||||
repository, proposal, env, projectId: 'fixture-project', now: () => new Date('2026-09-27T00:00:00Z'),
|
||||
});
|
||||
|
||||
assert.equal(existsSync(join(root, '.torch', 'torch.yaml')), true);
|
||||
@@ -66,7 +76,7 @@ test('SCN-install-doctor-purge: a fresh install is healthy and exactly reversibl
|
||||
test('SCN-purge-protects-user-change: uninstall refuses to delete modified managed files', () => {
|
||||
const { root, env } = fixture();
|
||||
const repository = inspectRepository(root);
|
||||
installProject({ repository, env, projectId: 'modified-project' });
|
||||
installProject({ repository, proposal: approvedProposal(repository), env, projectId: 'modified-project' });
|
||||
const configPath = join(root, '.torch', 'torch.yaml');
|
||||
writeFileSync(configPath, `${readFileSync(configPath, 'utf8')}\n# owner change\n`);
|
||||
|
||||
@@ -77,3 +87,21 @@ test('SCN-purge-protects-user-change: uninstall refuses to delete modified manag
|
||||
);
|
||||
assert.equal(existsSync(configPath), true);
|
||||
});
|
||||
|
||||
test('SCN-domain-approval: installation rejects stale or unapproved organizational proposals', () => {
|
||||
const { root, env } = fixture();
|
||||
const repository = inspectRepository(root);
|
||||
const pending = proposeDomains({ repository, analysis: analyzeRepository(repository) });
|
||||
assert.throws(
|
||||
() => installProject({ repository, proposal: pending, env }),
|
||||
(error) => error.code === 'PROPOSAL_NOT_APPROVED'
|
||||
&& error.details.includes('proposal review status is not approved'),
|
||||
);
|
||||
pending.review.status = 'approved';
|
||||
pending.repository.head = '0000000000000000000000000000000000000000';
|
||||
assert.throws(
|
||||
() => validateApprovedProposal({ proposal: pending, repository }),
|
||||
(error) => error.details.includes('proposal is stale because HEAD changed'),
|
||||
);
|
||||
assert.equal(existsSync(join(root, '.torch')), false);
|
||||
});
|
||||
Reference in new issue
Block a user