Archilyzer · Source

archilyzer

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

commit 3f74c143c755983276bda90c84da94c21a57152f
parent ce7eb8cf5c2614bafb9c062ee6bf2474d63bf9de
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Wed, 19 Aug 2026 00:04:26 -0400

umtool: the manifest writer refuses any non-clip, not just a card

Same family as the previous commit, found by auditing for it. updateClip()
guarded `type === "card"`, so a window could have been written onto the `scroll`
or `chart` entries one real manifest carries. It now refuses anything that is not
`type === "clip"` and names what it found.

Defence in depth rather than a live hole: /api/report/window resolves through
clipsOf(), which was already right. The CLI's `umtool window` reaches this
directly, though.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Diffstat:
Mumtool/lib/report/manifest.mjs | 5++++-
1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/umtool/lib/report/manifest.mjs b/umtool/lib/report/manifest.mjs @@ -131,7 +131,10 @@ export async function updateClip(dir, clipId, patch, { token = null } = {}) { const manifest = JSON.parse(raw); const entry = (manifest.timeline ?? []).find((e) => e.id === clipId); if (!entry) throw new Error(`no timeline entry with id ${clipId}`); - if (entry.type === "card") throw new Error(`${clipId} is a card, not a clip`); + // `!== "clip"`, not `=== "card"`. The timeline's vocabulary is open -- one + // real manifest carries `scroll` and `chart` entries -- and the card-only + // check would have let a window be written onto one of those. + if (entry.type !== "clip") throw new Error(`${clipId} is a ${entry.type ?? "non-clip"} entry, not a clip`); const before = { start: entry.start, end: entry.end }; for (const k of WINDOW_FIELDS) {