5.8 KiB
5.8 KiB
Tasks — Diff stringifyPatch human-readable patch formatter
Every checkbox MUST reflect work actually done in this change. Do not retroactively tick boxes for work that was already in main when this change opened.
0. Pre-flight (non-negotiable)
- 0.1 Confirm clean working tree (
git statusreports nothing) and no in-flight worktrees with uncommitted work (git worktree listthengit statusin each) - 0.2 If any worktrees exist under
.claude/worktrees/, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (git worktree remove) before opening a new one — code that has been lost twice on main is the failure mode this guards against. - 0.3 Confirm the package set in
MANIFEST.mdmatchesfind packages -maxdepth 3 -name package.jsoncount. Drift here means a prior change archived without regenerating the manifest.
Audit Note (2026-05-02)
Minimal progress — DEFERRED, do not archive.
- No
packages/data/diff/src/utils/stringify-patch/directory exists. grep -rln "stringifyPatch\|stringify-patch" packages/data/diff/src/returns zero hits.bunx turbo lint typecheck test --filter=@suaveplan/diffis GREEN — but the newstringifyPatchsurface is not implemented.- All 40 tasks remain to be done: error code
DIFF.INVALID_PATCH_OP,stringify-patch.tsfeature module,StringifyPatchOptions, OTel span event, subpath export, sibling.md, conformance + property tests.
1. Spec authoring
- 1.1 Read
../suaveplan/packages/universal/diff/src/utils/utils.ts(legacystringifyat L237-L240) - 1.2 Read RFC 6902 §4 for op grammar reference
- 1.3 Read
openspec/specs/diff/spec.mdandsrc/operations/to confirm the canonicalJsonPatchtype - 1.4 Read
openspec/AGENTS.mdSections 13 and 14 - 1.5 Draft
proposal.mdfromopenspec/templates/proposal.md - 1.6 Fill in
## Source mappingtable — every requirement cites a line range OR appears in the "no source line" table with justification - 1.7 Draft
specs/diff/spec.mdfromopenspec/templates/spec-delta.md - 1.8 Every requirement in the spec delta carries a
**Verified by:**line naming concreteit(...)titles
2. Implementation
- 2.1 Register error code
DIFF.INVALID_PATCH_OPinsrc/errors/diff-error.ts - 2.2 Create
src/utils/stringify-patch/feature module withstringify-patch.ts,stringify-patch.types.ts,stringify-patch.schemas.ts,stringify-patch.md,index.ts - 2.3 Define
StringifyPatchOptionsinstringify-patch.types.ts - 2.4 Implement
stringifyPatch(patch, options?)rendering one line per op:add /path -> <value>— value viavalueFormatterremove /pathreplace /path -> <value>move /from -> /pathcopy /from -> /pathtest /path -> <value>
- 2.5 Apply
options.indentprefix per line andoptions.uppercaseOpscasing transform - 2.6 Throw
DiffError(DIFF.INVALID_PATCH_OP)on unknown op (defensive) - 2.7 Wire OTel span event
diff.stringify-patchwithopCountattribute - 2.8 Add subpath export
./utils/stringify-patchtopackage.json::exports - 2.9 Re-export
stringifyPatchfrom the root barrelsrc/index.ts
3. Tests
- 3.1 Unit tests at
src/utils/stringify-patch/stringify-patch.test.ts— every operation type rendered; multi-op join with\n; empty patch returns empty string; default formatter usesJSON.stringify - 3.2 Spec-conformance tests at
src/utils/stringify-patch/stringify-patch.spec-conformance.test.ts—valueFormatterinvoked once per value-bearing op;uppercaseOpsflips case;indentprefix prepended per line;DIFF.INVALID_PATCH_OPthrown on unknown op; OTel span event emitted with correctopCount; subpath import resolves - 3.3 Property test (fast-check): for any well-formed
JsonPatch,stringifyPatch(patch).split('\n').length === patch.length - 3.4 Every
it(...)carries{ timeout: 5000 }
4. Documentation
- 4.1
src/utils/stringify-patch/stringify-patch.md— sibling doc (≥200 words, basic + advanced examples includingvalueFormatterredaction usage, full API reference) - 4.2 README links
./utils/stringify-patch/stringify-patch.mdunder## Modules - 4.3 Update
CLAUDE.md@suaveplan/diffentry to mentionstringifyPatch
5. Pre-archive verification (the 5-gate triple)
- 5.1
bun run check— Biome 0 errors / 0 warnings / 0 info across the whole monorepo - 5.2
bunx turbo lint typecheck test --filter=@suaveplan/diff— green - 5.3
bunx turbo test:coverage --filter=@suaveplan/diff— 100/100/100/100 - 5.4
bun scripts/openspec-conformance.ts @suaveplan/diff— exit 0, noerrorfindings - 5.5
bunx turbo build --filter=@suaveplan/diff— green - 5.6
bunx turbo test --filter=...@suaveplan/diff— every dependent (undo, event-sourcing, crdt) passes
6. Pre-archive 7-row checklist (AGENTS.md Section 13)
- 6.1 Generics threaded;
expectTypeOfconfirmsstringifyPatchreturnsstring(notstring | undefined) - 6.2 Zod schema wired at
StringifyPatchOptionsboundary - 6.3
DIFF.INVALID_PATCH_OPthrown by at least one production path - 6.4 Strict-mode behaviors tested (
uppercaseOps: falsevstrue; default vs customvalueFormatter) - 6.5 OTel span event emitted from production paths and asserted with a real in-memory
TracerProvider - 6.6 Lifecycle dedup — N/A (stateless function)
- 6.7 No retroactive tick — every box above reflects work done in this change
7. Archive
- 7.1 Fold spec delta into
openspec/specs/diff/spec.md - 7.2 Move
openspec/changes/diff-stringify/→openspec/archive/<yyyy-mm-dd>-diff-stringify/ - 7.3 Refresh
MANIFEST.mdif dep set changed (no expected change)