Files
evolver-publish 534ede263b Release v1.88.2
Co-authored-by: autogame-17 <autogame-17@users.noreply.github.com>
Co-authored-by: bjw9808 <bjw9808@gmail.com>
Co-authored-by: autogame-17 <166480271+autogame-17@users.noreply.github.com>
2026-06-05 09:29:13 +00:00

113 lines
4.6 KiB
JavaScript

const { describe, it, beforeEach, afterEach } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const os = require('os');
const path = require('path');
const { _buildGene, _buildCapsule } = require('../src/atp/atpExecute');
describe('atpExecute._buildGene', () => {
it('produces a valid Gene with deterministic asset_id for same caps', () => {
const a = _buildGene(['code_evolution', 'debugging'], ['log_error']);
const b = _buildGene(['debugging', 'code_evolution'], ['log_error']);
assert.equal(a.type, 'Gene');
assert.equal(typeof a.id, 'string');
assert.ok(Array.isArray(a.strategy) && a.strategy.length >= 2);
assert.ok(Array.isArray(a.validation) && a.validation.length >= 1);
assert.equal(typeof a.asset_id, 'string');
assert.ok(a.asset_id.startsWith('sha256:'));
// Capability order should not affect the gene id -- we sort caps before building the id.
assert.equal(a.asset_id, b.asset_id);
});
it('falls back to a default capability when none provided', () => {
const g = _buildGene([], []);
assert.equal(g.type, 'Gene');
assert.ok(g.id.length > 0);
});
it('clamps capability and signal arrays', () => {
const manyCaps = Array.from({ length: 30 }, function (_, i) { return 'cap_' + i; });
const manySigs = Array.from({ length: 30 }, function (_, i) { return 'sig_' + i; });
const g = _buildGene(manyCaps, manySigs);
assert.ok(g.signals_match.length <= 8, 'signals_match should be clamped');
});
});
describe('atpExecute._buildCapsule', () => {
it('produces a Capsule referencing its Gene and carrying the answer', () => {
const gene = _buildGene(['documentation'], ['user_feature_request']);
const capsule = _buildCapsule({
gene: gene,
answer: 'Here is a concrete outline: 1. install 2. configure 3. run',
summary: 'Answer for documentation question',
orderId: 'proof_abc123',
taskId: 'task_xyz789',
capabilities: ['documentation'],
signals: ['user_feature_request'],
});
assert.equal(capsule.type, 'Capsule');
assert.equal(capsule.gene, gene.id);
assert.equal(capsule.content.slice(0, 15), 'Here is a concr');
assert.equal(capsule.outcome.status, 'success');
// ATP provenance rides under `a2a` (Hub-allow-listed), not a top-level
// `atp` key (which the Hub payload sanitizer would strip on publish).
assert.equal(capsule.a2a.atp.order_id, 'proof_abc123');
assert.equal(capsule.a2a.atp.task_id, 'task_xyz789');
assert.equal(capsule.source_type, 'generated');
assert.equal(capsule.schema_version, '1.0.0');
assert.ok(capsule.asset_id.startsWith('sha256:'));
});
it('defaults capsule summary when caller does not provide one', () => {
const gene = _buildGene(['general'], []);
const capsule = _buildCapsule({
gene: gene,
answer: 'short answer',
orderId: 'proof_default',
});
assert.ok(capsule.summary.length > 0);
});
it('different answers yield different capsule asset_ids', () => {
const gene = _buildGene(['general'], []);
const c1 = _buildCapsule({ gene: gene, answer: 'answer one', orderId: 'p1' });
const c2 = _buildCapsule({ gene: gene, answer: 'answer two', orderId: 'p1' });
assert.notEqual(c1.asset_id, c2.asset_id);
});
});
describe('atpExecute CLI-shape invariants', () => {
// Smoke test for the input-validation branch -- does not require a live Hub.
it('rejects missing required params', async () => {
const { completeAtpTask } = require('../src/atp/atpExecute');
const r1 = await completeAtpTask({});
assert.equal(r1.ok, false);
assert.equal(r1.stage, 'input');
const r2 = await completeAtpTask({ taskId: 't', orderId: 'o' });
assert.equal(r2.ok, false);
assert.equal(r2.stage, 'input');
});
it('reports read_answer stage when answer file is missing', async () => {
const { completeAtpTask } = require('../src/atp/atpExecute');
const missing = path.join(os.tmpdir(), 'atp-missing-' + Date.now() + '.md');
const r = await completeAtpTask({
taskId: 't1', orderId: 'o1', answerFile: missing,
});
assert.equal(r.ok, false);
assert.equal(r.stage, 'read_answer');
});
it('reports read_answer stage when answer file is empty', async () => {
const { completeAtpTask } = require('../src/atp/atpExecute');
const emptyFile = fs.mkdtempSync(path.join(os.tmpdir(), 'atp-exec-')) + '/empty.md';
fs.writeFileSync(emptyFile, '');
const r = await completeAtpTask({
taskId: 't1', orderId: 'o1', answerFile: emptyFile,
});
assert.equal(r.ok, false);
assert.equal(r.stage, 'read_answer');
});
});