From ffabd7820e550aa495c5618de076cee346186786 Mon Sep 17 00:00:00 2001 From: Kjell Tore Guttormsen Date: Sun, 10 May 2026 21:48:21 +0200 Subject: [PATCH] test(voyage): Group C.8 SC6 round-trip via readAndUpdate (1bc37231) --- .../annotation-export-schema.test.mjs | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/plugins/voyage/tests/integration/annotation-export-schema.test.mjs b/plugins/voyage/tests/integration/annotation-export-schema.test.mjs index bafdb97..18eb28d 100644 --- a/plugins/voyage/tests/integration/annotation-export-schema.test.mjs +++ b/plugins/voyage/tests/integration/annotation-export-schema.test.mjs @@ -12,9 +12,12 @@ import { test } from 'node:test'; import { strict as assert } from 'node:assert'; -import { readFileSync } from 'node:fs'; +import { readFileSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; import { dirname, resolve, join } from 'node:path'; import { fileURLToPath } from 'node:url'; +import { readAndUpdate } from '../../lib/util/markdown-write.mjs'; +import { parseDocument } from '../../lib/util/frontmatter.mjs'; const __dirname = dirname(fileURLToPath(import.meta.url)); const ROOT = resolve(__dirname, '..', '..'); @@ -255,3 +258,34 @@ test('Group C.7 — fixture plan parses with anchors at block boundaries (v4.3 S assert.match(planText, //, 'ANN-0001 anchor required'); assert.match(planText, //, 'ANN-0002 anchor required'); }); + +// Group C.8 — SC6 round-trip: readAndUpdate raises revision to 1 + populates +// source_annotations + annotation_digest (finding 1bc37231). Verifies the +// trekrevise mutation contract end-to-end against a tmpdir copy of the +// pre-annotate plan fixture. +test('Group C.8 — SC6 round-trip: readAndUpdate raises revision to 1, source_annotations populated (1bc37231)', () => { + const tmpDir = mkdtempSync(join(tmpdir(), 'voyage-c8-')); + const tmpPath = join(tmpDir, 'plan.md'); + try { + writeFileSync(tmpPath, readFileSync(PLAN_FIXTURE, 'utf-8')); + const bundle = JSON.parse(readFileSync(BUNDLE, 'utf-8')); + + const result = readAndUpdate(tmpPath, ({ frontmatter, body }) => { + frontmatter.revision = (frontmatter.revision || 0) + 1; + frontmatter.source_annotations = bundle.annotations; + frontmatter.annotation_digest = computeAnnotationDigest(bundle.annotations); + return { frontmatter, body }; + }); + assert.equal(result.valid, true, `readAndUpdate must return valid: ${JSON.stringify(result.errors || [])}`); + + const parsed = parseDocument(readFileSync(tmpPath, 'utf-8')); + assert.equal(parsed.valid, true, `re-parsed file must be valid: ${JSON.stringify(parsed.errors || [])}`); + const fm = parsed.parsed.frontmatter; + assert.equal(fm.revision, 1, 'revision must be 1 after first round-trip'); + assert.equal(Array.isArray(fm.source_annotations), true, 'source_annotations must be array'); + assert.equal(fm.source_annotations.length, 2, 'source_annotations must have 2 entries from bundle fixture'); + assert.match(fm.annotation_digest, /^[0-9a-f]{16}$/, 'annotation_digest must be 16-hex-char SHA-256 prefix'); + } finally { + rmSync(tmpDir, { recursive: true, force: true }); + } +});