import assert from "node:assert/strict"; import { spawnSync } from "node:child_process"; import { fileURLToPath } from "node:url"; import test from "node:test"; import { parseOpenRectificationCaseRequest } from "../src/lib/rectification-agentic/v9/open-request.ts"; import { openRectificationRequestBody } from "../src/lib/rectification-entry.ts"; const sourceId = "11111111-1111-4111-8111-111111111111"; const requestId = "22222222-2222-4222-8222-222222222222"; test("handoff accepts only a source reference, never a browser domain or birth facts", () => { const body = openRectificationRequestBody("homepage", null, sourceId); assert.equal(body.sourceSessionId, sourceId); assert.ok(parseOpenRectificationCaseRequest(body)); for (const patch of [{ domain: "career" }, { productDomain: "marriage" }, { birth_date: "2000-06-14" }, { scores: [] }, { sourceSessionId: "not-a-uuid" }]) { assert.equal(parseOpenRectificationCaseRequest({ ...body, ...patch }), null); } assert.equal(parseOpenRectificationCaseRequest({ intent: "session", requestId, sessionId: sourceId, sourceSessionId: sourceId }), null); assert.equal(parseOpenRectificationCaseRequest({ intent: "new", requestId, sourceSessionId: sourceId }), null); assert.equal(openRectificationRequestBody("session", sourceId, sourceId).sourceSessionId, undefined); }); // Fictional owned-session/RPC controls exercising the actual POST and case service, // not a PostgreSQL or engine calibration claim. test("production open route reads owned consultation themes and fixes new-case targets without changing exact-session opens", () => { const script = String.raw` import assert from 'node:assert/strict'; import { mock } from 'node:test'; import { pathToFileURL } from 'node:url'; import { resolveActiveSkillPackage } from './src/lib/skill-package-registry.ts'; import { targetChartsForDomain } from './src/lib/rectification-agentic/core/segment-summary.ts'; const userId='11111111-1111-4111-8111-111111111111'; const sourceId='22222222-2222-4222-8222-222222222222'; const sessionId='33333333-3333-4333-8333-333333333333'; const caseId='44444444-4444-4444-8444-444444444444'; const skill=resolveActiveSkillPackage('jyotish-birth-time-rectification'); let source={id:sourceId,user_id:userId,session_type:'consultation',theme:'marriage'}; let persistedDomain=null; let sourceError=null; let queries=[]; let calls=[]; const response=()=>({case_id:caseId,session_id:sessionId,status:'draft',disposition:'created',should_start_opening:false,skill_version:skill.version}); const accounting={ from(table){assert.equal(table,'profiles'); return {select(){return this},eq(){return this},single:async()=>({error:null,data:{ birth_date:'2000-06-14',birth_place_label:'Synthetic Test City',reported_birth_time:'09:10',birth_time_source:'family_exact', latitude:40,longitude:-74,timezone_id:'America/New_York',timezone_offset:-4,ayanamsa:'raman' }})}}, rpc:async(fn,args)=>{ calls.push({fn,args}); if(fn==='get_agentic_rectification_skill_identity')return {error:null,data:{skill_name:skill.name,skill_version:skill.version,skill_sha256:skill.sha256,skill_source_commit:skill.sourceCommit}}; if(fn==='open_agentic_rectification_case')return {error:null,data:response()}; if(fn==='open_agentic_rectification_case_v2'){ if(args.p_intent==='session')assert.ok(!Object.hasOwn(args,'p_product_domain')); else if(persistedDomain===null)persistedDomain=args.p_product_domain; return {error:null,data:response()}; } throw new Error('unexpected RPC '+fn); } }; mock.module('server-only',{namedExports:{}}); mock.module('@/lib/supabase/server',{namedExports:{createServerSupabaseClient:async()=>({ auth:{getUser:async()=>({data:{user:{id:userId}},error:null})}, from(table){assert.equal(table,'chat_sessions'); const filters={}; return { select(columns){assert.equal(columns,'id,user_id,session_type,theme'); return this}, eq(key,value){filters[key]=value; return this}, maybeSingle:async()=>{queries.push(filters); assert.equal(filters.id,sourceId); assert.equal(filters.user_id,userId); return {data:source,error:sourceError}} }} })}}); mock.module('@/lib/supabase/admin',{namedExports:{createAdminSupabaseClient:()=>accounting}}); mock.module('@/lib/product-access',{namedExports:{isProductEnabled:async()=>true}}); // Account-deletion freeze (staging 96adbce3) has its own suite; here the account is not frozen. mock.module('@/lib/account-deletion-server',{namedExports:{refuseWhenAccountDeletionPending:async()=>null}}); const {POST}=await import(pathToFileURL(process.cwd()+'/src/app/api/rectification/cases/open/route.ts').href); const post=async(body)=>POST(new Request('https://example.invalid/api/rectification/cases/open',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify(body)})); const body={intent:'homepage',requestId:'55555555-5555-4555-8555-555555555555',sourceSessionId:sourceId}; for(const [theme,domain,targets] of [ ['marriage','marriage',['D1','D9']],['career','career',['D1','D10']],['general','general',['D1','D9','D10']], ['wealth','finance',['D1','D9','D10']],['migration','relocation',['D1','D9','D10']],['annual','general',['D1','D9','D10']], ['health','health',['D1','D9','D10']],['education','education',['D1','D9','D10']],['family','family',['D1','D9','D10']],['timing','general',['D1','D9','D10']] ]){ source.theme=theme; persistedDomain=null; calls=[]; const result=await post(body); assert.equal(result.status,200,await result.text()); assert.equal(persistedDomain,domain); assert.deepEqual(targetChartsForDomain(persistedDomain),targets); assert.equal(calls.filter(c=>c.fn==='open_agentic_rectification_case_v2').length,1); assert.ok(!calls.some(c=>/initialize_agentic_rectification_domain|focus|billing/.test(c.fn))); } source.theme='marriage'; persistedDomain=null; assert.equal((await post(body)).status,200); source.theme='career'; assert.equal((await post(body)).status,200); assert.equal(persistedDomain,'marriage','new source theme cannot rewrite persisted case domain'); for(const [replacement,status,code] of [ [null,404,'source_session_not_found'], [{...source,user_id:'66666666-6666-4666-8666-666666666666'},404,'source_session_not_found'], [{...source,session_type:'birth_time_rectification'},400,'source_session_not_consultation'], [{...source,theme:'relationship'},400,'source_session_invalid_theme'], [{...source,theme:'D1'},400,'source_session_invalid_theme'] ]){ source=replacement; calls=[]; const result=await post(body); assert.equal(result.status,status); assert.equal((await result.json()).code,code); assert.equal(calls.length,0,'invalid source must not read profile or open a case'); } sourceError={message:'synthetic unavailable'}; const unavailable=await post(body); assert.equal(unavailable.status,503); sourceError=null; calls=[]; queries=[]; persistedDomain=null; const general=await post({intent:'homepage',requestId:body.requestId}); assert.equal(general.status,200); assert.equal(persistedDomain,'general'); assert.equal(queries.length,0); calls=[]; queries=[]; const exact=await post({intent:'session',sessionId,requestId:body.requestId}); assert.equal(exact.status,200); assert.equal(queries.length,0); assert.ok(!Object.hasOwn(calls.find(c=>c.fn==='open_agentic_rectification_case_v2').args,'p_product_domain')); assert.equal((await post({...body,domain:'career'})).status,400); `; const result = spawnSync(process.execPath, ["--experimental-test-module-mocks", "--import", "tsx", "--input-type=module", "--eval", script], { cwd: fileURLToPath(new URL("../", import.meta.url)), encoding: "utf8", timeout: 60_000, }); assert.equal(result.status, 0, result.stderr + result.stdout); });