## Summary Pure-function core logic: checklist building/parsing/diffing and HTML-comment metadata embedding. ## Tasks - [x] `src/core/checklist.ts` - `BODY_LIMIT = 65_000` - `buildChecklist(results)` → markdown checklist lines - `parseChecklist(body)` → `ChecklistItem[]` - `diffChecklist(old, new)` → `DiffResult` keyed on `repo:path:line:text` - `applyDiff(body, diff)` → updated body - `buildSummaryBlock` / `updateSummaryBlock` - `checkBodyLength` - [x] `src/core/metadata.ts` - `embedMetadata(body, meta)` — HTML comment at end of body - `extractMetadata(body)` → `EpicMetadata | null` - `updateMetadata(body, patch)` — partial update - `stripMetadata(body)` — remove for display ## Metadata format ```html <!-- github-issue-ops:metadata {"version":1,"replayCommand":"...","createdAt":"...","config":{...}} --> ``` ## Acceptance criteria - Unit tests in `src/core/checklist.test.ts` and `src/core/metadata.test.ts` pass - Round-trip: `extractMetadata(embedMetadata(body, meta))` equals `meta` - Diff is idempotent: re-applying the same results produces no new changes
Summary
Pure-function core logic: checklist building/parsing/diffing and HTML-comment metadata embedding.
Tasks
src/core/checklist.tsBODY_LIMIT = 65_000buildChecklist(results)→ markdown checklist linesparseChecklist(body)→ChecklistItem[]diffChecklist(old, new)→DiffResultkeyed onrepo:path:line:textapplyDiff(body, diff)→ updated bodybuildSummaryBlock/updateSummaryBlockcheckBodyLengthsrc/core/metadata.tsembedMetadata(body, meta)— HTML comment at end of bodyextractMetadata(body)→EpicMetadata | nullupdateMetadata(body, patch)— partial updatestripMetadata(body)— remove for displayMetadata format
Acceptance criteria
src/core/checklist.test.tsandsrc/core/metadata.test.tspassextractMetadata(embedMetadata(body, meta))equalsmeta