Files
TORCH/test/fleet/product-surface.test.mjs
T

106 lines
6.0 KiB
JavaScript

import assert from 'node:assert/strict';
import { execFileSync } from 'node:child_process';
import { existsSync, mkdtempSync, readFileSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import test from 'node:test';
import { createConsoleServer } from '../../src/console/server.mjs';
import { analyzeRepository } from '../../src/kernel/analyze.mjs';
import { proposeDomains } from '../../src/kernel/domains.mjs';
import { inspectRepository } from '../../src/kernel/git.mjs';
import { installProject } from '../../src/kernel/install.mjs';
import { createWorktrees } from '../../src/kernel/worktrees.mjs';
import { observeProject } from '../../src/observability/snapshot.mjs';
function fixture() {
const root = mkdtempSync(join(tmpdir(), 'torch-console-'));
execFileSync('git', ['init', '-b', 'main', root]);
execFileSync('git', ['-C', root, 'config', 'user.email', '[email protected]']);
execFileSync('git', ['-C', root, 'config', 'user.name', 'TORCH Test']);
writeFileSync(join(root, 'README.md'), '# Console fixture\n');
execFileSync('git', ['-C', root, 'add', '.']);
execFileSync('git', ['-C', root, 'commit', '-m', 'fixture']);
return root;
}
test('SCN-product-site: public surface explains the portable fleet and separates the local console', () => {
const html = readFileSync(new URL('../../site/index.html', import.meta.url), 'utf8');
const consoleHtml = readFileSync(new URL('../../site/console.html', import.meta.url), 'utf8');
assert.match(html, /One repository[\s\S]*coordinated AI engineering team/);
assert.match(html, /id="route-toggle"/);
assert.match(html, /Exact-commit checks/);
assert.match(html, /Live gate open/);
assert.match(html, /Context savings are a measured hypothesis/);
assert.match(html, /torch\.mjs bootstrap/);
assert.match(html, /manager can propose another specialist[\s\S]*owner approval/i);
assert.doesNotMatch(html, /nostr|relay coordination|task lock/i);
assert.match(consoleHtml, /Local Fleet Console/);
assert.match(consoleHtml, /noindex,nofollow/);
for (const label of ['Ownership', 'Worktrees', 'Delivery', 'Checks', 'Schedules', 'Providers', 'Decisions']) {
assert.match(consoleHtml, new RegExp(`>${label}<`));
}
});
test('SCN-architecture-decisions: every specification decision has an explicit accepted or gated boundary', () => {
const decisions = readFileSync(new URL('../../docs/ARCHITECTURE_DECISIONS.md', import.meta.url), 'utf8');
for (let number = 1; number <= 10; number += 1) {
assert.match(decisions, new RegExp(`ADR-${String(number).padStart(3, '0')}:`));
}
assert.match(decisions, /Multi-machine security[\s\S]*\*\*Status:\*\* gated/);
assert.match(decisions, /Distribution and update signing[\s\S]*\*\*Status:\*\* gated/);
assert.match(decisions, /MCP over\s+stdio/);
assert.match(decisions, /exact Git commit and the exact hash/);
});
test('SCN-console-readonly: HTTP console serves fixed assets and observes an installed fleet without mutation', async (context) => {
const root = fixture();
const env = { ...process.env, XDG_DATA_HOME: mkdtempSync(join(tmpdir(), 'torch-console-state-')) };
const repository = inspectRepository(root);
const proposal = proposeDomains({ repository, analysis: analyzeRepository(repository) });
proposal.review = {
status: 'approved', reviewedAt: '2026-09-27T00:00:00Z', reviewedBy: 'fixture-owner', notes: [],
};
installProject({ repository, proposal, env, projectId: 'console-fixture' });
execFileSync('git', ['-C', root, 'add', '.torch']);
execFileSync('git', ['-C', root, 'commit', '-m', 'install torch']);
createWorktrees({
repository: inspectRepository(root),
parentOverride: mkdtempSync(join(tmpdir(), 'torch-console-worktrees-')),
});
execFileSync('git', ['-C', root, 'add', '.torch/install-manifest.json']);
execFileSync('git', ['-C', root, 'commit', '-m', 'record worktrees']);
const databasePath = join(env.XDG_DATA_HOME, 'torch', 'projects', 'console-fixture', 'state.db');
assert.equal(existsSync(databasePath), false);
const before = execFileSync('git', ['-C', root, 'status', '--porcelain'], { encoding: 'utf8' });
const observed = observeProject({ repositoryRoot: root, env, now: () => new Date('2026-09-27T00:00:00Z') });
assert.equal(observed.mode, 'installed');
assert.equal(observed.mutationPerformed, false);
assert.equal(observed.agents.length, proposal.domains.length + 1);
assert.equal(observed.organization.domains.length, proposal.domains.length);
assert.equal(observed.worktrees.length, proposal.domains.length + 1);
assert.equal(observed.worktrees.every((worktree) => Number.isInteger(worktree.behind)), true);
assert.equal(observed.recoverability.level, 'ONE-DISK');
assert.match(observed.decisions.content, /TORCH decisions/);
assert.equal(observed.providers.forge.status, 'local-only');
assert.equal(observed.providers.delivery.release.provider, 'none');
assert.deepEqual(observed.deliveries, []);
assert.equal(observed.contextLocality.measured, false);
assert.deepEqual(observed.fleetChanges, []);
assert.equal(existsSync(databasePath), false);
assert.equal(execFileSync('git', ['-C', root, 'status', '--porcelain'], { encoding: 'utf8' }), before);
const server = createConsoleServer({ repositoryRoot: root, env });
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
context.after(() => server.close());
const origin = `http://127.0.0.1:${server.address().port}`;
const page = await fetch(`${origin}/`);
assert.equal(page.status, 200);
assert.match(page.headers.get('content-security-policy'), /default-src 'self'/);
assert.match(await page.text(), /coordinated AI engineering team/);
const snapshot = await fetch(`${origin}/api/snapshot`);
assert.equal(snapshot.status, 200);
assert.equal((await snapshot.json()).mutationPerformed, false);
assert.equal((await fetch(`${origin}/../package.json`)).status, 404);
assert.equal(execFileSync('git', ['-C', root, 'status', '--porcelain'], { encoding: 'utf8' }), before);
});