Parcourir la source

test: scope event snapshot normalization

Hypatia May il y a 2 mois
Parent
commit
f5fc7ac04a

+ 11 - 8
packages/support/acp-snapshot/src/normalize.ts

@@ -19,10 +19,10 @@ const EVENT_OMITTED_BYTES = '{{eventOmittedBytes}}'
 const CWD_ROOTED_PATH_RE = /\{\{cwd\}\}(?:[\\/][^\s<>"'`]+)+/g
 const PATH_TAG_RE = /(<path>)([^<]*)(<\/path>)/g
 const ADDITIONAL_INSTRUCTIONS_PATH_RE = /(Additional instructions from: )([^\r\n]+)/g
-const EMBEDDED_EVENT_TIME_RE = /("time": )\d+(?=,\r?\n)/g
+const EMBEDDED_EVENT_TIME_RE = /^(  "time": )\d+(?=,\r?$)/gm
 const EVENT_READ_OMITTED_BYTES_RE = /(\r?\n\r?\n\(Omitted )\d+( bytes\.)/g
-const EVENT_READ_RESULT_RE
-  = /^Session [^\r\n]+ — [^\r\n]+\r?\nTarget event seq \d+:\r?\n```json\r?\n\{\r?\n/
+const EVENT_READ_TARGET_REGION_RE
+  = /^Session [^\r\n]+ — [^\r\n]+\r?\nTarget event seq \d+:\r?\n```json\r?\n\{\r?\n[\s\S]*?(?=\r?\n```(?:\r?\n|$)|\r?\n\r?\n\(Omitted )/
 
 /** A UUID v4 string, the shape `randomUUID()` produces for session ids. */
 const UUID_RE = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi
@@ -78,11 +78,14 @@ function scrubString(value: string, ctx: NormalizeContext, cwdPathMode: CwdPathM
   }
   out = out.replace(LOCAL_SPILL_PATH_RE, (_match, name: string) => `{{spillLocator:${name}}}`)
   out = out.replace(SNAPSHOT_SPILL_PATH_RE, (_match, name: string) => `{{spillLocator:${name}}}`)
-  // Exact event-read results render pretty JSON inside a distinctive text
-  // envelope. Restrict time scrubbing to that envelope so JSON printed by
-  // models, bash, or unrelated tools remains regression-visible.
-  if (EVENT_READ_RESULT_RE.test(out)) {
-    out = out.replace(EMBEDDED_EVENT_TIME_RE, `$1${EVENT_TIME}`)
+  // Exact event-read results render the target as pretty JSON inside a
+  // distinctive envelope. Restrict time scrubbing to that fenced target so
+  // neighbor, model, bash, and unrelated tool text remains regression-visible.
+  if (EVENT_READ_TARGET_REGION_RE.test(out)) {
+    out = out.replace(
+      EVENT_READ_TARGET_REGION_RE,
+      target => target.replace(EMBEDDED_EVENT_TIME_RE, `$1${EVENT_TIME}`),
+    )
     out = out.replace(EVENT_READ_OMITTED_BYTES_RE, `$1${EVENT_OMITTED_BYTES}$2`)
   }
   for (const id of ctx.sessionIds) out = out.split(id).join(SESSION_ID)

+ 4 - 2
packages/support/acp-snapshot/tests/normalize.spec.ts

@@ -123,7 +123,7 @@ Additional instructions from: nested\AGENTS.md`,
     expect(out).not.toContain('2026-07-20T17:03:13.689Z')
   })
 
-  it('stabilizes a pretty-printed event timestamp embedded in tool-result text', () => {
+  it('stabilizes only the top-level event timestamp and spill byte count in event-read text', () => {
     const raw = JSON.stringify({
       jsonrpc: '2.0',
       method: 'session/update',
@@ -134,7 +134,7 @@ Additional instructions from: nested\AGENTS.md`,
             type: 'content',
             content: {
               type: 'text',
-              text: 'Session prior — title\nTarget event seq 4:\n```json\n{\n  "seq": 4,\n  "time": 1784876275593,\n  "data": {}\n}\n```\n\n(Omitted 39387 bytes. Full formatted result stored at: /tmp/result.txt.)',
+              text: 'Session prior — title\nTarget event seq 4:\n```json\n{\n  "seq": 4,\n  "time": 1784876275593,\n  "data": {\n    "time": 31337,\n    "note": "model-visible"\n  }\n}\n```\n\nAfter:\n  "time": 424242,\n  neighbor semantic text\n\n(Omitted 39387 bytes. Full formatted result stored at: /tmp/result.txt.)',
             },
           }],
         },
@@ -142,6 +142,8 @@ Additional instructions from: nested\AGENTS.md`,
     })
     const out = normalizeStdout(raw, ctx)
     expect(out).toContain('\\"time\\": {{eventTime}}')
+    expect(out).toContain('\\"time\\": 31337')
+    expect(out).toContain('\\"time\\": 424242')
     expect(out).toContain('Omitted {{eventOmittedBytes}} bytes')
     expect(out).not.toContain('1784876275593')
     expect(out).not.toContain('39387')