diff --git a/tests/oracle/golden/hook-audit-log.json b/tests/oracle/golden/hook-audit-log.json index eda8cce17..963285671 100644 --- a/tests/oracle/golden/hook-audit-log.json +++ b/tests/oracle/golden/hook-audit-log.json @@ -4,7 +4,7 @@ "exit": 0, "signal": null, "files": { - ".impeccable/audit.ndjson": "{\"ts\":\"\",\"event\":\"PostToolUse\",\"harness\":\"claude\",\"cwd\":\"\",\"session\":\"s1\",\"tool\":\"Edit\",\"file\":\"/src/components/Card.module.css\",\"ext\":\".css\",\"editCount\":1,\"findings\":2,\"freshFindings\":1,\"deferred\":1,\"emitted\":true,\"freshFiles\":1,\"chars\":1250,\"durationMs\": }\n", + ".impeccable/audit.ndjson": "{\"ts\":\"\",\"event\":\"PostToolUse\",\"harness\":\"claude\",\"cwd\":\"\",\"session\":\"s1\",\"tool\":\"Edit\",\"file\":\"/src/components/Card.module.css\",\"ext\":\".css\",\"editCount\":1,\"findings\":2,\"freshFindings\":1,\"deferred\":1,\"emitted\":true,\"freshFiles\":1,\"chars\": ,\"durationMs\": }\n", ".impeccable/hook.cache.json": "{\"version\":1,\"sessions\":{\"s1\":{\"updatedAt\": ,\"files\":{\"/src/components/Card.module.css\":{\"editCount\":1,\"findings\":[\"gradient-text:2\"]}},\"footerShown\":true}}}" } } diff --git a/tests/oracle/lib.mjs b/tests/oracle/lib.mjs index 2a8b8c670..ebcfbb5ab 100644 --- a/tests/oracle/lib.mjs +++ b/tests/oracle/lib.mjs @@ -90,7 +90,16 @@ export function stageWorkspace(name) { export function normalize(text, { ws, home = os.homedir() }) { if (typeof text !== 'string') return text; let out = text; - // The binary's own path first: it may sit under $HOME or the repo. + // The hook footer embeds the admin command: JS prints "node '/hook-admin.mjs'", + // the binary prints "'' hooks". Both collapse to . This must run + // before the generic binary-path mask below. + out = out.replace(/node '[^']*\/hook-admin\.mjs'/g, ''); + out = out.replace(/node "[^"]*\/hook-admin\.mjs"/g, ''); + out = out.replace(/'[^']*\/impeccable(?:\.exe)?' hooks/g, ''); + out = out.replace(/"[^"]*\\impeccable(?:\.exe)?" hooks/g, ''); + // Audit entries record the rendered message length, which includes that command's path. + out = out.replace(/"chars":\s*\d+/g, '"chars": '); + // The binary's own path: it may sit under $HOME or the repo. if (process.env.IMPECCABLE_BIN) { const bin = process.env.IMPECCABLE_BIN; for (const form of [`'${bin}'`, `"${bin}"`, bin]) out = out.split(form).join(''); @@ -102,10 +111,6 @@ export function normalize(text, { ws, home = os.homedir() }) { ]) { if (needle) out = out.split(needle).join(tag); } - // The hook footer embeds the admin command's own path; both runtimes name it differently. - out = out.replace(/node '[^']*\/hook-admin\.mjs'/g, ''); - out = out.replace(/node "[^"]*\/hook-admin\.mjs"/g, ''); - out = out.replace(/'[^']*\/impeccable(?:\.exe)?' hooks/g, ' hooks'); // Self-referential command lines: the JS prints "node /.mjs", the // binary prints " ". Both collapse to " ". out = out.replace(/node ['"]?\/skill\/scripts\/([a-z-]+)\.mjs['"]?/g, (m, v) => ` ${v === 'context-signals' ? 'signals' : v === 'hook-admin' ? 'hooks' : v}`);