import subprocess, sys, shutil, os S="/tmp/dewey-chat02/scratch/packages/conversation" M=[ ("no O_NOFOLLOW + no lstat symlink","src/safe-fs.mjs",[("constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK","constants.O_RDONLY"),(' if (before.isSymbolicLink()) throw new Refusal("unsafe-path", "session file is a symlink");\n',''),(' if (!before.isFile()) throw',' if (false) throw'),("if (!st.isFile() || st.dev !== before.dev","if (st.dev !== before.dev")]), ("dir components unchecked","src/safe-fs.mjs",[(' if (st.isSymbolicLink()) throw new Refusal("unsafe-path", "session root contains a symlink");\n',''),(' if (!st.isDirectory()) throw',' if (false) throw')]), ("listing follows symlinks","src/safe-fs.mjs",[(' else if (dirent.isSymbolicLink()) refused.push({ name: dirent.name, code: "unsafe-path" });\n','')]), ("no prefix digest check","src/reader.mjs",[('if (pinned.digest !== state.digest) throw','if (false) throw')]), ("no dev/ino check","src/reader.mjs",[('if (pinned.file.dev !== state.dev || pinned.file.ino !== state.ino) throw','if (false) throw'),('if (fresh.file.dev !== state.dev || fresh.file.ino !== state.ino || fresh.length < state.length) throw','if (fresh.length < state.length) throw')]), ("no shorter check","src/reader.mjs",[('if (pinned.shorter) throw','if (false) throw')]), ("cwd always in project","src/reader.mjs",[(' if (typeof cwd !== "string" || !isAbsolute(cwd)) return false;',' return true;')]), ("relative cwd accepted","src/reader.mjs",[(' if (typeof cwd !== "string" || !isAbsolute(cwd)) return false;',' if (typeof cwd !== "string" || !cwd) return false;')]), ("no char cap","src/parts.mjs",[("chars + 1 > LIMITS.chars ||","false ||")]), ("no page byte cap","src/parts.mjs",[("if (bytes + add > LIMITS.pageBytes) break;","")]), ("no block cap","src/parts.mjs",[("current.length === LIMITS.blocks ||","false ||")]), ("no foreign check","src/reader.mjs",[("if (actor !== record.actor || purpose !== record.purpose || conversation !== record.conversation || branch !== record.branch) {","if (false) {")]), ("no branch binding","src/reader.mjs",[("|| branch !== record.branch) {",") {")]), ("no expiry","src/reader.mjs",[("if (Date.parse(record.expiresAt) <= now()) {","if (false) {")]), ("no parentSession notice","src/pi.mjs",[(" if (parsed.header.parentSession !== undefined && parsed.header.parentSession !== null) {\n units.push"," if (false) {\n units.push")]), ("branch param ignored","src/reader.mjs",[("const built = build(snap, found.root, branch ?? null, conversation);","const built = build(snap, found.root, null, conversation);")]), ("unknown branch served","src/reader.mjs",[("if (!parsed.branches.has(branch)) return null;","if (false) return null;")]), ("registration harness ignored","src/reader.mjs",[("unsupportedReason: harness !== null && harness !== HISTORY ? UNSUPPORTED_HARNESS : null,","unsupportedReason: null,")]), ("no placeholder roots","src/reader.mjs",[(" if (!reg || reg.layout !== \"repo\""," if (true || reg.layout !== \"repo\"")]), ("malformed notices dropped","src/pi.mjs",[('out.push({ notice: "malformed", lines: [pending[mi++].line] });','mi++;')]), ("bridge restored","src/pi.mjs",[(' path.push({ notice: "missing-parent", lines: lost });\n break;',' const prev = r.index > 0 ? parsed.byId.get(parsed.entries[r.index - 1].entry.id) : null;\n if (lost.length && prev) { path.push({ notice: "missing-parent", lines: lost }); r = prev; continue; }\n path.push({ notice: "missing-parent", lines: lost });\n break;')]), ("missing-parent lines not named","src/pi.mjs",[("const lost = parsed.malformed.filter((m) => m.after === r.index - 1).map((m) => m.line);","const lost = [];")]), ("trailing malformed only on default","src/pi.mjs",[(" flushBefore(Infinity);\n return out;"," if (leaf === parsed.defaultLeaf) flushBefore(Infinity);\n return out;")]), ("branch named by leaf","src/pi.mjs",[(" const branchOf = (leaf) => {"," const branchOf = (leaf) => branchName(leaf);\n const unused = (leaf) => {")]), ("later child continues branch","src/pi.mjs",[("if (children.get(p.entry.id)[0] !== r) return branchName(r);","if (children.get(p.entry.id).at(-1) !== r) return branchName(r);")]), ("first root not main","src/pi.mjs",[("return r === firstRoot ? MAIN : branchName(r);","return branchName(r);")]), ("no empty main","src/pi.mjs",[(" if (!branches.size) branches.set(MAIN, null);\n","")]), ("redacted thinking shown","src/pi.mjs",[('const t = b.redacted === true ? "" : typeof b.thinking','const t = typeof b.thinking')]), ("EACCES on a component rethrown","src/safe-fs.mjs",[('throw denied(err, "a session path component");','throw err;')]), ("incomplete never set","src/reader.mjs",[("incomplete: buf.length > length };","incomplete: false };")]), ("next re-reads fresh","src/reader.mjs",[("const pinned = snapshot(state.root, state.name, state.length);","const pinned = { ...snapshot(state.root, state.name), length: state.length };")]), ("follow skips history check","src/reader.mjs",[("if (!built || built.entries.length < state.offset || idsDigest(built.entries, state.offset) !== state.prefix) {","if (!built) {")]), ("follow skips the id digest","src/reader.mjs",[("|| idsDigest(built.entries, state.offset) !== state.prefix) {",") {")]), ("follow reads the default branch","src/reader.mjs",[("const built = build(fresh, state.root, state.branch, conversation);","const built = build(fresh, state.root, null, conversation);")]), ("catalogue writes a file","src/reader.mjs",[(" function catalogue() {"," function catalogue() {\n for (const r of listRoots()) { try { require_(r); } catch {} }")]), ("thinking visibility wrong","src/pi.mjs",[('visibility: t ? "permitted-visible" : "unavailable"','visibility: "permitted-visible"')]), ("raw tool ids","src/pi.mjs",[("call: safeId(b.id), name: safeId(b.name)","call: String(b.id), name: String(b.name)")]), ("id namespaces dropped","src/pi.mjs",[("id: `n.${e.id}`","id: e.id")]), ("surrogate split","src/parts.mjs",[("const width = cp > 0xffff ? 2 : 1;","const width = 1;")]), ] orig={} for f in ["src/safe-fs.mjs","src/reader.mjs","src/parts.mjs","src/pi.mjs"]: orig[f]=open(os.path.join(S,f)).read() for name,f,reps in M: src=orig[f] for a,b in reps: if a not in src: print("NOT APPLIED",name,repr(a[:60])); break src=src.replace(a,b) else: if name=="catalogue writes a file": src=src.replace("require_(r);",'(await_import => 0)(); (require_fs => 0)(); import_fs.writeFileSync(r.dir + "/x.tmp", "")').replace('import { createHash, randomBytes } from "node:crypto";','import { createHash, randomBytes } from "node:crypto";\nimport * as import_fs from "node:fs";') open(os.path.join(S,f),"w").write(src) r=subprocess.run(["node","--test","tests/"],cwd=S,capture_output=True,text=True,timeout=600) fails=sorted(set(l.strip()[2:].split(" (")[0] for l in r.stdout.splitlines() if l.lstrip().startswith("✖") and "failing tests" not in l)) print(("CAUGHT " if r.returncode else "MISSED ")+name+" -> "+"; ".join(x[:70] for x in fails)[:300]) open(os.path.join(S,f),"w").write(orig[f])