// Sage, 2026-10-11: read-only, row 62 probes.md "Gate read". With the sync key: the project list // (status, page count, total, and parent and archived for #19 and its children 18, 20, 21), one // cross-project task read, and the four per-project open reads for comparison. GETs only; records // no titles; refuses to overwrite OUT; prints no secret. // Usage: node probe-62.mjs https://tasks.woltje.com SYNC_TOKEN_FILE OUT_JSON import { readFileSync, writeFileSync, existsSync } from "node:fs"; const [ORIGIN, KEY, OUT] = process.argv.slice(2); if (!/^https:\/\/tasks\.woltje\.com$/.test(ORIGIN)) throw new Error("tasks.woltje.com only"); if (!OUT || existsSync(OUT)) throw new Error("OUT_JSON missing or exists; refusing"); const BASE = ORIGIN + "/api/v2", TREE = [19, 18, 20, 21]; const key = readFileSync(KEY, "utf8").trim(); const get = async (path) => { const r = await fetch(BASE + path, { headers: { Authorization: `Bearer ${key}` }, redirect: "error" }); const t = await r.text(); let json = null; try { json = JSON.parse(t); } catch {} const items = json?.items ?? (Array.isArray(json) ? json : null); return { path, status: r.status, count: items ? items.length : null, total: json?.total ?? null, code: r.status === 200 ? null : json?.code ?? null, items }; }; const strip = ({ items, ...rest }) => rest; const rec = { at: new Date().toISOString(), key: "sync (key 9)", reads: [] }; const list = await get("/projects?per_page=50&page=1"); rec.reads.push(strip(list)); rec.tree = TREE.map((id) => { const p = (list.items ?? []).find((x) => x.id === id); return p ? { id, parent: p.parent_project_id, archived: p.is_archived } : { id, listed: false }; }); const filter = encodeURIComponent(`project in ${TREE.join(", ")}`); const cross = await get(`/tasks?filter=${filter}&sort_by=id&order_by=asc&per_page=50&page=1`); rec.reads.push({ ...strip(cross), projects: cross.items ? [...new Set(cross.items.map((t) => t.project_id))].sort((a, b) => a - b) : null }); for (const id of TREE) rec.reads.push(strip(await get(`/projects/${id}/tasks?filter=${encodeURIComponent("done = false")}&sort_by=id&order_by=asc&per_page=50&page=1`))); const out = JSON.stringify(rec, null, 1) + "\n"; if (out.includes(key)) throw new Error("secret in output; not written"); writeFileSync(OUT, out, { flag: "wx" }); process.stdout.write(out);