106 lines
7.6 KiB
JavaScript
106 lines
7.6 KiB
JavaScript
const fs = require('node:fs')
|
|||
|
|
const path = require('node:path')
|
||
|
|
const crypto = require('node:crypto')
|
||
|
|
const { execFileSync } = require('node:child_process')
|
||
|
|
|
||
|
|
const schema = `persona_migration_test_${crypto.randomBytes(6).toString('hex')}`
|
||
|
|
const migration = fs.readFileSync(path.join(__dirname, '../migrations/versioned/000206_legacy_agent_persona.up.sql'), 'utf8')
|
||
|
|
const checks = []
|
||
|
|
function sql(query) {
|
||
|
|
return execFileSync('docker', ['--context', 'colima-yawan', 'exec', '-i', 'WeKnora-postgres',
|
||
|
|
'psql', '-X', '-U', 'postgres', '-d', 'yawan_native_acceptance_20260915', '-At', '-v', 'ON_ERROR_STOP=1'],
|
||
|
|
{ input: `SET search_path TO ${schema}, public;\n${query}`, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }).trim()
|
||
|
|
}
|
||
|
|
function check(name, condition) {
|
||
|
|
if (!condition) throw new Error(`Failed: ${name}`)
|
||
|
|
checks.push(name)
|
||
|
|
}
|
||
|
|
function assertion(condition, message) {
|
||
|
|
return `DO $$ BEGIN IF NOT (${condition}) THEN RAISE EXCEPTION '${message}'; END IF; END $$;`
|
||
|
|
}
|
||
|
|
const fixtureAgent = '5e807157-e1ae-4b6b-a770-e4d2b2d90001'
|
||
|
|
const boundAgent = '5e807157-e1ae-4b6b-a770-e4d2b2d90002'
|
||
|
|
const boundHuman = '5e807157-e1ae-4b6b-a770-e4d2b2d90003'
|
||
|
|
const copyAgent = (id, sourceID) => `
|
||
|
|
INSERT INTO custom_agents SELECT (jsonb_populate_record(NULL::custom_agents,
|
||
|
|
to_jsonb(a) || jsonb_build_object('id','${id}','name','Existing native name','config',
|
||
|
|
a.config || '{"system_prompt":"Existing edited task rules","custom_test_flag":true}'::jsonb))).*
|
||
|
|
FROM custom_agents a WHERE id=(SELECT target_id FROM yawan_legacy_asset_mappings WHERE source_id=2);
|
||
|
|
INSERT INTO yawan_legacy_asset_mappings SELECT (jsonb_populate_record(NULL::yawan_legacy_asset_mappings,
|
||
|
|
to_jsonb(m) || jsonb_build_object('source_id',${sourceID},'target_id','${id}'))).*
|
||
|
|
FROM yawan_legacy_asset_mappings m WHERE source_id=2;
|
||
|
|
`
|
||
|
|
try {
|
||
|
|
sql(`CREATE SCHEMA ${schema};
|
||
|
|
${['custom_agents', 'digital_humans', 'digital_human_versions', 'digital_human_bindings', 'digital_human_jobs',
|
||
|
|
'workbench_access_publications', 'workbench_access_grants', 'yawan_legacy_asset_mappings'].map(table =>
|
||
|
|
`CREATE TABLE ${schema}.${table} (LIKE public.${table} INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING INDEXES);`).join('\n')}
|
||
|
|
INSERT INTO yawan_legacy_asset_mappings SELECT * FROM public.yawan_legacy_asset_mappings
|
||
|
|
WHERE source_system='yawan-workbench' AND source_organization_id=1 AND source_kind='agent' AND source_id=2;
|
||
|
|
INSERT INTO custom_agents SELECT a.* FROM public.custom_agents a JOIN yawan_legacy_asset_mappings m
|
||
|
|
ON a.id=m.target_id AND a.tenant_id=m.target_tenant_id;
|
||
|
|
${copyAgent(fixtureAgent, 902)}
|
||
|
|
${copyAgent(boundAgent, 903)}
|
||
|
|
INSERT INTO workbench_access_publications VALUES (10059,'agents','${fixtureAgent}',false,now());
|
||
|
|
INSERT INTO workbench_access_grants VALUES (10059,'agents','${fixtureAgent}','test-grantee',now());
|
||
|
|
INSERT INTO digital_humans (id,tenant_id,owner_id,name,status,primary_agent_id)
|
||
|
|
SELECT '${boundHuman}',tenant_id,created_by,'Existing human','draft',id FROM custom_agents WHERE id='${boundAgent}';
|
||
|
|
INSERT INTO digital_human_bindings (id,tenant_id,owner_id,digital_human_id,agent_id)
|
||
|
|
SELECT '5e807157-e1ae-4b6b-a770-e4d2b2d90004',tenant_id,created_by,'${boundHuman}',id
|
||
|
|
FROM custom_agents WHERE id='${boundAgent}';`)
|
||
|
|
sql(`BEGIN; ${migration} COMMIT;`)
|
||
|
|
sql(assertion(`(SELECT count(*) FROM yawan_legacy_agent_persona_mappings)=2`, 'Expected only two unbound persona imports'))
|
||
|
|
checks.push('imports_nonempty_unbound_persona_only')
|
||
|
|
sql(assertion(`NOT EXISTS (SELECT 1 FROM yawan_legacy_agent_persona_mappings p
|
||
|
|
JOIN digital_human_versions v ON v.id=p.version_id
|
||
|
|
JOIN digital_humans h ON h.id=p.digital_human_id
|
||
|
|
JOIN digital_human_bindings b ON b.id=p.binding_id
|
||
|
|
JOIN custom_agents a ON a.id=p.agent_id AND a.tenant_id=p.tenant_id
|
||
|
|
WHERE v.persona<>p.source_persona OR v.status<>'imported' OR v.reviewed_at IS NOT NULL
|
||
|
|
OR v.review_note<>'' OR v.sources<>'[]'::jsonb OR h.active_version<>1 OR h.status<>'active'
|
||
|
|
OR b.applied_version<>1 OR h.owner_id<>a.created_by OR h.name<>a.name OR h.primary_agent_id<>a.id)
|
||
|
|
AND (SELECT count(*) FROM digital_human_jobs)=0`, 'Provenance and imported active semantics'))
|
||
|
|
checks.push('all_fields_owner_name_binding_preserved_without_fake_review_or_job')
|
||
|
|
sql(assertion(`(SELECT count(*) FROM custom_agents)=3 AND
|
||
|
|
(SELECT config->>'custom_test_flag' FROM custom_agents WHERE id='${fixtureAgent}')='true' AND
|
||
|
|
(SELECT config->>'system_prompt' FROM custom_agents WHERE id='${fixtureAgent}') LIKE 'Existing edited task rules%' AND
|
||
|
|
NOT EXISTS (SELECT 1 FROM yawan_legacy_agent_persona_mappings p
|
||
|
|
JOIN custom_agents a ON a.id=p.agent_id AND a.tenant_id=p.tenant_id,
|
||
|
|
jsonb_each_text(p.source_persona) f WHERE strpos(a.config->>'system_prompt',f.value)=0)`, 'Existing Agent configuration and all style values'))
|
||
|
|
checks.push('existing_agent_rules_and_all_style_values_in_runtime_prompt')
|
||
|
|
sql(assertion(`(SELECT global FROM workbench_access_publications WHERE kind='digital-humans' AND resource_id=
|
||
|
|
(SELECT digital_human_id FROM yawan_legacy_agent_persona_mappings WHERE source_id=2)) AND
|
||
|
|
NOT (SELECT global FROM workbench_access_publications WHERE kind='digital-humans' AND resource_id=
|
||
|
|
(SELECT digital_human_id FROM yawan_legacy_agent_persona_mappings WHERE source_id=902)) AND
|
||
|
|
EXISTS (SELECT 1 FROM workbench_access_grants WHERE kind='digital-humans' AND user_id='test-grantee')`, 'Visibility and explicit grants'))
|
||
|
|
checks.push('global_visibility_private_override_and_grants_preserved')
|
||
|
|
sql(assertion(`(SELECT count(*) FROM digital_humans WHERE id='${boundHuman}')=1 AND
|
||
|
|
(SELECT config->>'system_prompt' FROM custom_agents WHERE id='${boundAgent}')='Existing edited task rules'`, 'Existing digital human binding unchanged'))
|
||
|
|
checks.push('preexisting_human_binding_unchanged')
|
||
|
|
sql(`UPDATE digital_human_versions SET persona='{"tone":"native owner edit"}'
|
||
|
|
WHERE id=(SELECT version_id FROM yawan_legacy_agent_persona_mappings WHERE source_id=902);
|
||
|
|
UPDATE custom_agents SET config=jsonb_set(config,'{system_prompt}','"native prompt edit"') WHERE id='${fixtureAgent}';
|
||
|
|
UPDATE workbench_access_publications SET global=true WHERE kind='digital-humans' AND resource_id=
|
||
|
|
(SELECT digital_human_id FROM yawan_legacy_agent_persona_mappings WHERE source_id=902);
|
||
|
|
DELETE FROM digital_human_bindings WHERE id=(SELECT binding_id FROM yawan_legacy_agent_persona_mappings WHERE source_id=902);
|
||
|
|
BEGIN; ${migration} COMMIT;`)
|
||
|
|
sql(assertion(`(SELECT count(*) FROM yawan_legacy_agent_persona_mappings)=2 AND
|
||
|
|
(SELECT persona->>'tone' FROM digital_human_versions WHERE id=
|
||
|
|
(SELECT version_id FROM yawan_legacy_agent_persona_mappings WHERE source_id=902))='native owner edit' AND
|
||
|
|
(SELECT config->>'system_prompt' FROM custom_agents WHERE id='${fixtureAgent}')='native prompt edit' AND
|
||
|
|
NOT EXISTS (SELECT 1 FROM digital_human_bindings WHERE agent_id='${fixtureAgent}')`, 'Rerun preserves owner edits and intentional unbinding'))
|
||
|
|
checks.push('idempotency_preserves_later_native_edits_and_unbinding')
|
||
|
|
const invalidAgent = '5e807157-e1ae-4b6b-a770-e4d2b2d90005'
|
||
|
|
sql(copyAgent(invalidAgent, 904) + `UPDATE yawan_legacy_asset_mappings SET source_snapshot=
|
||
|
|
jsonb_set(source_snapshot,'{persona_json}','{"unknown_rule":"must review"}') WHERE source_id=904;`)
|
||
|
|
let rejected = false
|
||
|
|
try { sql(`BEGIN; ${migration} COMMIT;`) } catch (error) {
|
||
|
|
rejected = error.stderr?.toString().includes('requires explicit field review')
|
||
|
|
}
|
||
|
|
check('unknown_source_fields_rejected_atomically', rejected)
|
||
|
|
sql(assertion(`(SELECT count(*) FROM yawan_legacy_agent_persona_mappings)=2`, 'Invalid source cannot partly import'))
|
||
|
|
console.log(JSON.stringify({ ok: true, checks }, null, 2))
|
||
|
|
} finally {
|
||
|
|
sql(`DROP SCHEMA IF EXISTS ${schema} CASCADE;`)
|
||
|
|
}
|