115 lines
6.2 KiB
JavaScript
115 lines
6.2 KiB
JavaScript
// CHAT-00 research checker only. No engine, filesystem mutation or network.
|
|
// These small models check proposed examples, not production authorization.
|
|
import assert from 'node:assert/strict';
|
|
import { readFileSync } from 'node:fs';
|
|
import { createHash } from 'node:crypto';
|
|
import { PassThrough } from 'node:stream';
|
|
import { fileURLToPath } from 'node:url';
|
|
import path from 'node:path';
|
|
|
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
const root = path.resolve(here, '../../..');
|
|
const sources = JSON.parse(readFileSync(path.join(here, 'sources.json'), 'utf8'));
|
|
const fixture = JSON.parse(readFileSync(path.join(here, 'fixtures.json'), 'utf8'));
|
|
let checks = 0;
|
|
const check = (name, fn) => { fn(); checks++; console.log(`PASS ${name}`); };
|
|
check('source IDs unique; provenance and inspected sections explicit', () => {
|
|
assert.equal(new Set(sources.sources.map(s => s.id)).size, sources.sources.length);
|
|
for (const s of sources.sources) {
|
|
assert.match(s.sha256, /^[a-f0-9]{64}$/);
|
|
assert.ok(s.locator && s.coverage && s.evidence);
|
|
}
|
|
});
|
|
for (const s of sources.sources.filter(s => s.repoPath)) {
|
|
check(`${s.id} installed/repository source hash`, () => {
|
|
const file = path.resolve(root, s.repoPath);
|
|
assert.ok(file.startsWith(root + path.sep));
|
|
const hash = createHash('sha256').update(readFileSync(file)).digest('hex');
|
|
assert.equal(hash, s.sha256, 'Source changed: re-investigate, do not refresh pin blindly');
|
|
});
|
|
}
|
|
// Public reference caches are deliberately not a required dependency. No fetch.
|
|
check('fixture provenance is synthetic, no runtime claim', () => {
|
|
assert.equal(fixture.evidence, 'synthetic-research-only');
|
|
assert.equal(fixture.runtimeEnforcementProven, false);
|
|
});
|
|
|
|
const context = fixture.binding;
|
|
const fields = ['actor', 'host', 'seat', 'project', 'workspace', 'conversation', 'branch', 'execution', 'controllerGeneration'];
|
|
const allowed = new Set(['prompt', 'approval', 'interrupt', 'force-stop', 'takeover']);
|
|
function admissible(request) {
|
|
return request.authenticated === true && request.accessGranted === true &&
|
|
fields.every(f => request[f] === context[f]) && allowed.has(request.operation) &&
|
|
request.source === 'broker' && request.role === 'controller' && request.claim === 'held' &&
|
|
(request.operation !== 'prompt' || (typeof request.message === 'string' && !request.message.startsWith('/')));
|
|
}
|
|
for (const c of fixture.admission) {
|
|
check(c.id, () => assert.equal(admissible({ ...fixture.request, ...c.patch }), c.expected));
|
|
}
|
|
|
|
function recoverQueue(queue) {
|
|
return queue.map(item => ({ ...item, state: item.state === 'queued' ? 'draft' : item.state }));
|
|
}
|
|
for (const operation of ['interrupt', 'force-stop', 'takeover']) {
|
|
check(`${operation}: only undispatched queue becomes draft, identity retained`, () => {
|
|
const result = recoverQueue(fixture.queue);
|
|
assert.deepEqual(result, fixture.recoveredQueue);
|
|
assert.equal(result[0].attachments[0], 'upload-1');
|
|
assert.equal(result[1].actor, 'old-controller');
|
|
});
|
|
}
|
|
for (const c of fixture.stopProof) {
|
|
check(c.id, () => {
|
|
const stopped = c.cohortVerified && c.liveMembers === 0 && c.effectsReconciled;
|
|
assert.equal(stopped, c.expectedStopped);
|
|
});
|
|
}
|
|
for (const c of fixture.uploads) {
|
|
check(c.id, () => {
|
|
const valid = c.sizes.length <= 10 && c.sizes.every(s => Number.isSafeInteger(s) && s > 0 && s <= 20 * 1024 * 1024) &&
|
|
c.sizes.reduce((a, b) => a + b, 0) <= 100 * 1024 * 1024;
|
|
assert.equal(valid, c.expected);
|
|
});
|
|
}
|
|
check('Claude documented interrupt cancellation is capability gated', () => {
|
|
const required = ['interrupt_receipt_v1', 'interrupt_cancel_queued_v1'];
|
|
assert.equal(required.every(x => fixture.claude.capabilities.includes(x)), true);
|
|
assert.equal(required.every(x => fixture.claude.oldCapabilities.includes(x)), false);
|
|
assert.deepEqual(fixture.claude.interrupt.request, { subtype: 'interrupt', cancel_queued: true });
|
|
assert.equal(fixture.claude.interrupt.type, 'control_request');
|
|
assert.equal(fixture.claude.response.response.request_id, fixture.claude.interrupt.request_id);
|
|
assert.deepEqual(fixture.claude.response.response.response.cancelled, ['message-1']);
|
|
// Empty lists are never treated as universal quiescence.
|
|
assert.equal(fixture.claude.emptyReceiptProvesCohortStopped, false);
|
|
});
|
|
check('Pi ordinary interrupt sequence fences first, clears before abort', () => {
|
|
assert.deepEqual(fixture.pi.interruptSequence, ['fence-dispatch', 'persist-draft-intent', 'clear_queue', 'abort', 'reconcile']);
|
|
assert.deepEqual(fixture.pi.clearResponse.data.followUp, ['next']);
|
|
assert.equal(fixture.pi.clearResponsePreservesAttachmentIds, false);
|
|
});
|
|
check('approval must match outstanding intent and cannot widen permissions', () => {
|
|
const pending = fixture.approval.pending;
|
|
const accept = response => response.id === pending.id && response.intent === pending.intent &&
|
|
response.execution === pending.execution && response.generation === pending.generation &&
|
|
pending.choices.includes(response.choice) && response.updatedPermissions === undefined;
|
|
for (const sample of fixture.approval.responses) assert.equal(accept(sample.value), sample.expected);
|
|
});
|
|
check('uncertain send is not safe replay, native success is not task completion', () => {
|
|
assert.equal(fixture.uncertain.allowBlindReplay, false);
|
|
assert.equal(fixture.uncertain.releaseWriterClaim, false);
|
|
assert.equal(fixture.uncertain.promptSuccessProvesAnswer, false);
|
|
});
|
|
|
|
// Import only the fully inspected pure framing helper, not the harness/SDK.
|
|
const { attachJsonlLineReader } = await import('../../../node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/jsonl.js');
|
|
check('installed Pi LF framing preserves UTF-8 chunk splits and Unicode separators', () => {
|
|
const stream = new PassThrough(); const lines = [];
|
|
const detach = attachJsonlLineReader(stream, line => lines.push(JSON.parse(line)));
|
|
const payload = { type: 'prompt', message: 'one\u2028two\u2029three 🦆' };
|
|
const bytes = Buffer.from(JSON.stringify(payload) + '\r\n');
|
|
for (const byte of bytes) stream.write(Buffer.from([byte]));
|
|
assert.deepEqual(lines, [payload]);
|
|
detach(); stream.destroy();
|
|
});
|
|
console.log(`CHAT-00 ${checks} checks passed. Synthetic/source checks only; engines, auth, live access and cutover NOT TESTED.`);
|