archived-agent-notes.spec.ts 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. import { describe, expect, it } from 'vitest'
  2. import {
  3. extendArchiveManifest,
  4. gitBlobHash,
  5. parseArchiveManifest,
  6. renderArchiveManifest,
  7. validateArchiveArtifacts,
  8. type ArchiveManifest,
  9. } from './archived-agent-notes.ts'
  10. function fixture(): Map<string, Buffer> {
  11. const base = '2026-07-26-example'
  12. const source = Buffer.from(`# Agent Note: Example\n\nStatus: implemented\nArchived: 2026-07-26\n\nEnglish | [中文](${base}.zh.md)\n\n## Problem\n\nExample.\n`)
  13. const zh = Buffer.from(`# Agent Note: 示例\n\nStatus: implemented\nArchived: 2026-07-26\n\n[English](${base}.md) | 中文\n\n## 问题\n\n示例。\n`)
  14. const meta = Buffer.from(`${base}.md: ${gitBlobHash(source)}\n${base}.zh.md: ${gitBlobHash(zh)}\n`)
  15. return new Map([
  16. [`process/${base}.md`, source],
  17. [`process/${base}.zh.md`, zh],
  18. [`process/${base}.i18n.yaml`, meta],
  19. ])
  20. }
  21. describe('archived Agent Notes', () => {
  22. it('accepts one complete implemented triplet with matching archive metadata', () => {
  23. expect(validateArchiveArtifacts(fixture())).toEqual([])
  24. })
  25. it('rejects incomplete triplets and invalid archive headers', () => {
  26. const artifacts = fixture()
  27. artifacts.delete('process/2026-07-26-example.i18n.yaml')
  28. artifacts.set(
  29. 'process/2026-07-26-example.md',
  30. Buffer.from('# Agent Note: Example\n\nStatus: proposed\nArchived: yesterday\n'),
  31. )
  32. expect(validateArchiveArtifacts(artifacts).join('\n')).toMatch(/incomplete archived triplet/)
  33. })
  34. it('extends the manifest without permitting a sealed change or removal', () => {
  35. const artifacts = fixture()
  36. const empty: ArchiveManifest = { version: 1, files: {} }
  37. const first = extendArchiveManifest(empty, artifacts)
  38. expect(first.errors).toEqual([])
  39. expect(first.added).toHaveLength(3)
  40. const sealed: ArchiveManifest = { version: 1, files: first.files }
  41. const changed = new Map(artifacts)
  42. changed.set('process/2026-07-26-example.md', Buffer.from('changed'))
  43. expect(extendArchiveManifest(sealed, changed).errors).toEqual([
  44. 'process/2026-07-26-example.md: sealed content hash changed',
  45. ])
  46. changed.delete('process/2026-07-26-example.zh.md')
  47. expect(extendArchiveManifest(sealed, changed).errors).toContain(
  48. 'process/2026-07-26-example.zh.md: sealed artifact is missing',
  49. )
  50. })
  51. it('round-trips the deterministic manifest schema', () => {
  52. const content = renderArchiveManifest({ 'process/z.md': `sha256:${'a'.repeat(64)}` })
  53. expect(parseArchiveManifest(content)).toEqual({
  54. version: 1,
  55. files: { 'process/z.md': `sha256:${'a'.repeat(64)}` },
  56. })
  57. })
  58. })