1d1af5c657
Seeds task outcomes, runs reflect(), and checks execution_pattern rows plus experience_saved product events for local acceptance. Co-authored-by: Cursor <cursoragent@cursor.com>
132 lines
4.3 KiB
JavaScript
132 lines
4.3 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Local acceptance: seed task_outcome rows, run reflect(), verify execution_pattern.
|
|
*
|
|
* Usage:
|
|
* node scripts/verify-experience-reflect-local.mjs
|
|
* node scripts/verify-experience-reflect-local.mjs --seed-only
|
|
* node scripts/verify-experience-reflect-local.mjs --reflect-only
|
|
*/
|
|
import { loadH5Environment } from './load-env.mjs';
|
|
import { createDbPool } from '../db.mjs';
|
|
import { createExperienceService } from '../experience-service.mjs';
|
|
|
|
const PROBLEM = 'Experience reflect local acceptance probe';
|
|
|
|
function parseArgs(argv) {
|
|
return {
|
|
seedOnly: argv.includes('--seed-only'),
|
|
reflectOnly: argv.includes('--reflect-only'),
|
|
};
|
|
}
|
|
|
|
async function countRows(pool, { kind = null, status = 'active' } = {}) {
|
|
const clauses = ['status = ?'];
|
|
const params = [status];
|
|
if (kind) {
|
|
clauses.push('kind = ?');
|
|
params.push(kind);
|
|
}
|
|
const [rows] = await pool.query(
|
|
`SELECT COUNT(*) AS count FROM h5_experience WHERE ${clauses.join(' AND ')}`,
|
|
params,
|
|
);
|
|
return Number(rows[0]?.count ?? 0);
|
|
}
|
|
|
|
async function seedTaskOutcomes(service, count = 3) {
|
|
const created = [];
|
|
for (let i = 0; i < count; i += 1) {
|
|
created.push(await service.record({
|
|
kind: 'task_outcome',
|
|
title: `Reflect probe ${i + 1}`,
|
|
body: `Local acceptance body ${i + 1}`,
|
|
problem: PROBLEM,
|
|
result: 'success',
|
|
confidence: 0.75 + i * 0.05,
|
|
environment: { runtime: 'local-dev', components: ['portal', 'goose'] },
|
|
action: { executor: 'goose', steps: [`step-${i + 1}`] },
|
|
tags: ['reflect-acceptance'],
|
|
}));
|
|
}
|
|
return created;
|
|
}
|
|
|
|
async function main() {
|
|
loadH5Environment(import.meta.dirname);
|
|
const options = parseArgs(process.argv.slice(2));
|
|
const pool = createDbPool();
|
|
const service = createExperienceService(pool, { productEventsPool: pool });
|
|
|
|
try {
|
|
const beforePatterns = await countRows(pool, { kind: 'execution_pattern' });
|
|
const beforeActiveOutcomes = await countRows(pool, { kind: 'task_outcome', status: 'active' });
|
|
|
|
if (!options.reflectOnly) {
|
|
const seeded = await seedTaskOutcomes(service, 3);
|
|
console.log(`[reflect-acceptance] seeded ${seeded.length} task_outcome rows`);
|
|
}
|
|
|
|
if (!options.seedOnly) {
|
|
const result = await service.reflect({ minGroupSize: 3 });
|
|
console.log('[reflect-acceptance] reflect result:', JSON.stringify({
|
|
ok: result.ok,
|
|
created: result.created,
|
|
archived: result.archived,
|
|
scope: result.scope,
|
|
}));
|
|
if (!result.created) {
|
|
console.log('[reflect-acceptance] note: no new pattern (group may already exist or below threshold)');
|
|
}
|
|
}
|
|
|
|
const afterPatterns = await countRows(pool, { kind: 'execution_pattern' });
|
|
const afterArchivedOutcomes = await countRows(pool, { kind: 'task_outcome', status: 'archived' });
|
|
const [patterns] = await pool.query(
|
|
`SELECT id, title, kind, result, confidence, created_at
|
|
FROM h5_experience
|
|
WHERE kind = 'execution_pattern' AND problem = ?
|
|
ORDER BY created_at DESC
|
|
LIMIT 3`,
|
|
[PROBLEM],
|
|
);
|
|
|
|
console.log('[reflect-acceptance] summary:', JSON.stringify({
|
|
executionPatternsBefore: beforePatterns,
|
|
executionPatternsAfter: afterPatterns,
|
|
activeTaskOutcomesBefore: beforeActiveOutcomes,
|
|
archivedTaskOutcomesAfter: afterArchivedOutcomes,
|
|
latestPatterns: patterns,
|
|
}, null, 2));
|
|
|
|
const [events] = await pool.query(
|
|
`SELECT event_type, data_json, created_at
|
|
FROM h5_memory_v2_product_events
|
|
WHERE event_type IN ('experience_saved', 'experience_recalled')
|
|
ORDER BY created_at DESC
|
|
LIMIT 5`,
|
|
).catch(() => [[]]);
|
|
|
|
if (events.length > 0) {
|
|
console.log('[reflect-acceptance] recent product events:', events);
|
|
} else {
|
|
console.log('[reflect-acceptance] product events table empty or unavailable (ok on fresh DB)');
|
|
}
|
|
|
|
const ok = afterPatterns >= beforePatterns && patterns.length > 0;
|
|
if (!ok && !options.seedOnly) {
|
|
process.exitCode = 1;
|
|
console.error('[reflect-acceptance] FAILED: expected at least one execution_pattern for probe problem');
|
|
} else {
|
|
console.log('[reflect-acceptance] OK');
|
|
}
|
|
} finally {
|
|
await pool.end();
|
|
}
|
|
}
|
|
|
|
main().catch((error) => {
|
|
console.error('[reflect-acceptance] error:', error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
});
|