2026-09-10 18:27:41 -07:00
import test from "node:test" ;
import assert from "node:assert/strict" ;
import fs from "node:fs/promises" ;
import os from "node:os" ;
import path from "node:path" ;
import { promisify } from "node:util" ;
import { execFile as callback } from "node:child_process" ;
import { planStructure , applyStructure , resumeStructure , type StructuralRequest } from "../src/capability-language/structural-plan.js" ;
const execFile = promisify ( callback );
test ( "structural plans validate the graph, journal originals, and reject stale edits" , async ( context ) => {
const root = await fs . mkdtemp ( path . join ( os . tmpdir (), "qx-structural-test-" ));
context . after (() => fs . rm ( root , { recursive : true , force : true }));
await execFile ( "git" , [ "-C" , root , "init" ]);
await fs . writeFile ( path . join ( root , ".gitignore" ), ".quixos/\n" );
await fs . writeFile ( path . join ( root , "quixos.lock" ), `quixos-lock version 1 { quixos source { repository "https://example.test/quixos.git"; commit " ${ "a" . repeat ( 40 ) } "; } }` );
const before = `workspace Test id "workspace:test" revision "workspace:test@1" commit " ${ "b" . repeat ( 40 ) } " { atom Subject id "atom:subject"; }` ;
await fs . writeFile ( path . join ( root , "workspace.qx" ), before );
const request : StructuralRequest = { kind : "workspace" , files : [{ file : "workspace.qx" , edits : [{ operation : "append" , parent : { kind : "workspaceDecl" }, source : 'atom Game id "atom:game";' }]}]};
const plan = await planStructure ( root , request );
assert . equal ( await fs . readFile ( path . join ( root , "workspace.qx" ), "utf8" ), before );
await fs . writeFile ( path . join ( root , "workspace.qx" ), ` ${ before } \ n// newer edit` );
await assert . rejects (() => applyStructure ( plan ), /Stale scaffold/ );
await fs . writeFile ( path . join ( root , "workspace.qx" ), before );
const applied = await applyStructure ( plan );
assert . equal ( applied . phase , "complete" );
assert . ok (( await fs . readFile ( path . join ( root , "workspace.qx" ), "utf8" )). includes ( "atom Game" ));
const journal = JSON . parse ( await fs . readFile ( applied . journalPath , "utf8" ));
assert . equal ( journal . changes [ 0 ]. before , before );
assert . equal (( await resumeStructure ( root , applied . id )). phase , "complete" );
// Simulate a process interrupted after one file was written, before recording
// completion. Replay accepts the already-written exact after image.
journal . phase = "prepared" ;
await fs . writeFile ( applied . journalPath , JSON . stringify ( journal ));
assert . equal (( await resumeStructure ( root , applied . id )). phase , "complete" );
await assert . rejects (() => planStructure ( root , request ), /Duplicate|duplicate/ );
2026-09-14 10:26:11 -07:00
// Cross-repository edits may temporarily refer to an unfinished provider.
const provisional : StructuralRequest = { kind : "workspace" , validation : "syntax" , files : [{ file : "workspace.qx" , edits : [
{ operation : "import" , kind : "interface" , name : "NotImplementedYet" },
]}]};
const draft = await planStructure ( root , provisional );
assert . equal ( draft . validation , "syntax" );
await applyStructure ( draft );
assert . match ( await fs . readFile ( path . join ( root , "workspace.qx" ), "utf8" ), /import interface NotImplementedYet/ );
await assert . rejects (() => planStructure ( root , {... provisional , validation : "resource-graph" }));
2026-09-10 18:27:41 -07:00
});