Archilyzer · Source

archilyzer

Archilyzer
git clone https://archilyzer.pages.dev/source/archilyzer.git
Log | Files | Refs | README | LICENSE

commit 6d34aa9d6ea97406c4e6f27af121a7a982315ea9
parent 4e9763e04c776c7841fe42abc2bbab08501a7a60
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Mon,  5 Oct 2026 03:35:25 -0400

common: tests for the converters' disk callbacks and the reports convert / to-manifest CLI

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

Diffstat:
Acommon/bin/reports-convert.test.ts | 212+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 212 insertions(+), 0 deletions(-)

diff --git a/common/bin/reports-convert.test.ts b/common/bin/reports-convert.test.ts @@ -0,0 +1,212 @@ +// The converters over files: the disk callbacks (cues behind the text guard, +// a post's channel and record off the posts archive) and the two CLI mains, +// on a temp channels tree. + +import { test } from "node:test"; +import assert from "node:assert/strict"; +import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import path from "node:path"; +import { convertMain, toManifestMain } from "./reports-convert"; +import { diskCuesOf, diskPostChannelOf, diskPostOf } from "../lib/report/convert-server"; +import { resolveCommand } from "./_cli"; +import { COMMANDS } from "./archilyzer"; + +const ORIGIN = "https://archive.example"; + +function tree() { + const root = mkdtempSync(path.join(tmpdir(), "reports-convert-")); + const channels = path.join(root, "channels"); + const rec = path.join(channels, "demo-channel", "data", "abc123"); + mkdirSync(rec, { recursive: true }); + writeFileSync( + path.join(rec, "transcript.cues.json"), + JSON.stringify({ + cues: [ + { start: 60.1, end: 62.0, text: "and then the host says" }, + { start: 58.2, end: 60.1, text: "This is where it starts." }, + { start: 62.4, end: 64.9, text: "we never said that." }, + ], + }), + ); + const social = path.join(channels, "demo-social"); + mkdirSync(path.join(social, "posts"), { recursive: true }); + writeFileSync(path.join(social, "posts-archive"), "twitter 987654321\n"); + writeFileSync( + path.join(social, "posts", "2024-05.jsonl"), + JSON.stringify({ + id: "987654321", + channelSlug: "demo-social", + author: "demo", + authorName: "Demo Account", + createdAt: "2024-05-01T12:00:00.000Z", + text: "a platform post", + url: "https://x.com/demo/status/987654321", + platform: "twitter", + }) + "\n", + ); + // A second channel holding the same post id: the handle picks. + const mirror = path.join(channels, "other-mirror"); + mkdirSync(mirror, { recursive: true }); + writeFileSync(path.join(mirror, "posts-archive"), "twitter 987654321\n"); + return { root, channels, done: () => rmSync(root, { recursive: true, force: true }) }; +} + +const quiet = () => { + const lines = { log: [] as string[], error: [] as string[] }; + return { lines, out: { log: (s: string) => lines.log.push(s), error: (s: string) => lines.error.push(s) } }; +}; + +test("diskCuesOf reads a record's cues sorted; a missing record or an unsafe id is null", async () => { + const t = tree(); + try { + const cuesOf = diskCuesOf(t.channels); + const cues = await cuesOf("demo-channel", "abc123"); + assert.deepEqual(cues?.map((c) => c.start), [58.2, 60.1, 62.4]); + assert.equal(await cuesOf("demo-channel", "nope"), null); + assert.equal(await cuesOf("demo-channel", ".."), null); + } finally { + t.done(); + } +}); + +test("diskCuesOf: a channel whose text is not readable is a warning, not a read", async () => { + const t = tree(); + try { + const legacy = path.join(t.channels, "legacy-channel"); + mkdirSync(legacy, { recursive: true }); + writeFileSync(path.join(legacy, "config.json"), JSON.stringify({ dataDir: "/elsewhere/legacy-channel/data" })); + const warnings: string[] = []; + assert.equal(await diskCuesOf(t.channels, warnings)("legacy-channel", "abc123"), null); + assert.equal(warnings.length, 1); + assert.match(warnings[0], /^legacy-channel: /); + } finally { + t.done(); + } +}); + +test("diskPostChannelOf finds the channel that keeps a post, the handle breaking a tie; diskPostOf reads its record", async () => { + const t = tree(); + try { + const channelOf = diskPostChannelOf(t.channels); + assert.equal(await channelOf({ platform: "x", id: "987654321", handle: "demo" }), "demo-social"); + assert.equal(await channelOf({ platform: "x", id: "987654321", handle: "other" }), "other-mirror"); + assert.equal(await channelOf({ platform: "x", id: "1" }), null); + const postOf = diskPostOf(t.channels); + assert.deepEqual(await postOf("demo-social", "987654321"), { + platform: "x", + url: "https://x.com/demo/status/987654321", + createdAt: "2024-05-01T12:00:00.000Z", + author: "demo", + authorName: "Demo Account", + }); + assert.equal(await postOf("demo-social", "2"), null); + } finally { + t.done(); + } +}); + +test("reports convert sweep: widened from the cues, the platform post found, written", async () => { + const t = tree(); + try { + const input = path.join(t.root, "sweep.md"); + writeFileSync( + input, + [ + "# A demo sweep", + "", + "## Findings", + "", + `- "we never said that" — [Demo @ 1:02](${ORIGIN}/?v=demo-channel%2Fabc123&t=62)`, + `- "a platform post" [post by demo](https://x.com/demo/status/987654321)`, + ].join("\n"), + ); + const out = path.join(t.root, "reports", "demo-sweep", "report.json"); + const { lines, out: o } = quiet(); + assert.equal(await convertMain({ from: "sweep", input, out, channelsDir: t.channels }, o), 0); + const report = JSON.parse(readFileSync(out, "utf8")); + assert.equal(report.id, "a-demo-sweep"); + assert.deepEqual([report.citations.c01.start, report.citations.c01.end], [60.1, 64.9]); + assert.equal(report.citations.p01.channel, "demo-social"); + assert.deepEqual(lines.error, []); + assert.match(lines.log[0], /report a-demo-sweep \(sweep\) — 1 section\(s\), 2 claim\(s\), 2 citation\(s\)/); + } finally { + t.done(); + } +}); + +test("reports convert refuses to write a report with problems; an unreadable input is exit 2", async () => { + const t = tree(); + try { + const input = path.join(t.root, "answer.json"); + writeFileSync(input, JSON.stringify({ answer: "Said [1 @ 0:05].", sources: [{ key: "demo-channel/abc123", snippets: [] }] })); + const out = path.join(t.root, "out.json"); + const { lines, out: o } = quiet(); + assert.equal(await convertMain({ from: "ask", input, out, id: "Not A Slug" }, o), 1); + assert.equal(existsSync(out), false); + assert.ok(lines.error.some((l) => l.startsWith(" id: must be a lowercase slug"))); + assert.equal(await convertMain({ from: "ask", input: path.join(t.root, "missing.json"), out }, quiet().out), 2); + writeFileSync(input, JSON.stringify({ unrelated: true })); + assert.equal(await convertMain({ from: "ask", input, out }, quiet().out), 2); + } finally { + t.done(); + } +}); + +test("reports to-manifest: a starter manifest, its posts read off the channels tree", async () => { + const t = tree(); + try { + const input = path.join(t.root, "report.json"); + writeFileSync( + input, + JSON.stringify({ + format: "archilyzer-report", + version: 1, + id: "demo-report", + kind: "sweep", + title: "A demo report", + citations: { + c01: { kind: "video", channel: "demo-channel", id: "abc123", start: 60.1, end: 64.9, quote: "we never said that." }, + p01: { kind: "post", channel: "demo-social", id: "987654321", quote: "a platform post" }, + }, + sections: [{ id: "s1", title: "Findings", claims: [{ id: "k1", text: "It was said.", citations: ["c01", "p01"] }] }], + }), + ); + const out = path.join(t.root, "video.manifest.json"); + const { lines, out: o } = quiet(); + assert.equal(await toManifestMain({ input, out, channelsDir: t.channels, siteOrigin: ORIGIN }, o), 0); + const m = JSON.parse(readFileSync(out, "utf8")); + assert.deepEqual( + m.timeline.map((e: { type: string; id: string }) => `${e.type}:${e.id}`), + ["card:title", "card:s1", "clip:c01"], + ); + assert.deepEqual(m.posts, [ + { + id: "p01", + platform: "x", + author: "Demo Account", + handle: "demo", + date: "2024-05-01T12:00:00.000Z", + text: "a platform post", + url: "https://x.com/demo/status/987654321", + attachTo: "c01", + siteChannel: "demo-social", + postId: "987654321", + }, + ]); + assert.equal(m.provenance.siteOrigin, ORIGIN); + assert.deepEqual(lines.error, []); + // An invalid report is refused, and nothing is written. + writeFileSync(input, JSON.stringify({ format: "archilyzer-report" })); + rmSync(out); + assert.equal(await toManifestMain({ input, out }, quiet().out), 1); + assert.equal(existsSync(out), false); + } finally { + t.done(); + } +}); + +test("the archilyzer table routes reports convert and reports to-manifest", () => { + assert.deepEqual(resolveCommand(COMMANDS, ["reports", "convert", "sweep", "in.md"])?.command.path, ["reports", "convert"]); + assert.deepEqual(resolveCommand(COMMANDS, ["reports", "to-manifest", "r.json"])?.command.path, ["reports", "to-manifest"]); +});