12 KiB
12 KiB
Tasks — Compress-SVG completion
Every checkbox MUST reflect work actually done in this change. Do not retroactively tick. The seven gaps closed here were never claimed by an earlier change; this is the first ticket that touches them.
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)
Status: DEFERRED. packages/docs/compress-svg/src/ only contains __benchmarks__, constants, core, parser, plugins, presets, types plus error-codes.ts. None of the seven gaps are filled: no optimizer/ (SvgOptimizer), no structural/, no deduplicator/, no path-tokenizer/, no archive/ (SvgPacker / SvgUnpacker / SvgArchiveBuilder), no browser/ unpacker, no cli.ts bin entry. This is a substantial migration estimated at ~6 000+ source lines verbatim; 0% is done.
1. Spec authoring
- 1.1 Read
../suaveplan/packages/universal/compress-svg/srcend-to-end (no dedicatedenterprise/compress-svg.mdexists) - 1.2 Read
openspec/specs/compress-svg/spec.md(does not exist yet — create on archive) - 1.3 Read
openspec/AGENTS.mdSections 0a (parity), 13 (verification), 14 (archival), 14a (affected dependents) - 1.4 Draft
proposal.mdfromopenspec/templates/proposal.md - 1.5 Fill in
## Source mappingtable — every requirement cites a line range OR appears in the "no source line" table with justification - 1.6 Draft
specs/compress-svg/spec.mdfromopenspec/templates/spec-delta.mdcovering all seven ADDED Requirements - 1.7 Every requirement in the spec delta carries a
**Verified by:**line naming concreteit(...)titles - 1.8
openspec change validate compress-svg-completionexits with no errors
2. SvgOptimizer façade
- 2.1 Port
optimizer/SvgOptimizer.ts(L1-L483) andoptimizer/SvgOptimizer.types.tsintopackages/docs/compress-svg/src/optimizer/svg-optimizer.ts - 2.2 Define
CompressorAdapterinterface and ship a Node adapter (bindszlib) and a browser adapter (bindsCompressionStream) - 2.3 Wire the optimizer to the existing plugin pipeline (
core/compress-svg); accept aSvgOptimizerConfigselecting plugins, presets, and the dictionary/structural/dedup pre-passes - 2.4 Emit OTel histogram
compress_svg.optimizer.duration_msand countercompress_svg.optimizer.bytes_saved - 2.5 Throw
COMPRESS_SVG.OPTIMIZER_PIPELINE_FAILEDwhen any selected plugin throws; chain the cause - 2.6 Sibling
.md(≥200 words, basic + advanced examples)
3. SvgStructuralOptimizer
- 3.1 Port
structural/SvgStructuralOptimizer.ts(L1-L458) and its.types.tsintopackages/docs/compress-svg/src/structural/svg-structural-optimizer.ts - 3.2 Implement four rules: flatten single-child
<g>; collapse identical attribute sets; hoist common attributes to a parent<g>; merge consecutive<path>elements with identicalfill/stroke/style - 3.3 Return a
StructuralOptimizationResultwith per-rule counts; expose each rule as a configurable boolean onStructuralOptimizerConfig - 3.4 Throw
COMPRESS_SVG.STRUCTURAL_INVALID_TREEon parser-rejectable input - 3.5 Sibling
.md
4. SvgDeduplicator
- 4.1 Port
deduplicator/SvgDeduplicator.ts(L1-L398) intopackages/docs/compress-svg/src/deduplicator/svg-deduplicator.ts - 4.2 Replace
node:crypto.createHash('sha256')with@suaveplan/crypto-hashsha256for browser/server parity - 4.3 Hoist a
<defs>block at the document root with<symbol id="dedup-{shortHash}">for each duplicate; replace duplicates with<use href="#dedup-{shortHash}"/> - 4.4 Return a
DeduplicationReport(candidatesScanned,duplicatesFound,bytesSaved,symbolMap) - 4.5 Throw
COMPRESS_SVG.DEDUPE_HASH_COLLISIONwhen two distinct subtrees produce the same short hash (extremely rare; guarded for safety) - 4.6 Sibling
.md
5. PathTokenizer
- 5.1 Port
PathTokenizer.ts(L1-L559) intopackages/docs/compress-svg/src/path-tokenizer/path-tokenizer.ts - 5.2 Export
tokenizePath(d): PathToken[]andformatTokens(tokens: PathToken[]): string; round-trip property test on 10 000 random valid paths - 5.3 Throw
COMPRESS_SVG.PATH_TOKEN_PARSE_FAILEDon malformeddstrings; carry the byte offset of the first invalid character - 5.4 Sibling
.md
6. Binary archive (SvgPacker / SvgUnpacker)
- 6.1 Port
SvgPacker.ts(L1-L2931) intopackages/docs/compress-svg/src/archive/svg-packer.ts - 6.2 Port
archive/SvgArchiveBuilder.ts(L1-L177) andarchive/SvgArchiveUnpacker.ts(L1-L182) intopackages/docs/compress-svg/src/archive/svg-archive-{builder,unpacker}.ts - 6.3 Preserve the legacy on-disk layout byte-for-byte (version header, manifest table, content-addressed payload table, checksum trailer)
- 6.4 Throw
COMPRESS_SVG.ARCHIVE_VERSION_MISMATCH,COMPRESS_SVG.ARCHIVE_CHECKSUM_FAILED,COMPRESS_SVG.ARCHIVE_PAYLOAD_NOT_FOUNDat the right call sites - 6.5 Round-trip property test: pack a directory of N SVGs → unpack → byte-equal originals
- 6.6 Sibling
.mdfor each implementation file
7. Browser unpacker
- 7.1 Port
browser/SvgArchiveUnpackerBrowser.ts(L1-L440) andbrowser/SvgUnpackerBrowser.ts(L1-L1152) intopackages/docs/compress-svg/src/browser/ - 7.2 Replace every
Buffer,node:fs,node:zlib,node:cryptoimport with Web-Streams /globalThis.cryptoequivalents - 7.3 Static import scan in test asserts no Node-only API on the
./browsersubpath - 7.4 Throw
COMPRESS_SVG.BROWSER_UNSUPPORTED_ENVIRONMENTwhenglobalThis.crypto?.subtleorCompressionStreamis missing - 7.5 Sibling
.mdfor each implementation file
8. CLI bin
- 8.1 Port
cli.ts(L1-L271) intopackages/docs/compress-svg/src/cli/cli.ts - 8.2 Wire
binfield inpackage.json:"suaveplan-svg-optimize": "./dist/cli/cli.js" - 8.3 Build the CLI atop
@suaveplan/cli(argument parser, command router, output formatter, spinner, JSON reporter) - 8.4 Flags:
--in <glob>,--out <dir>,--preset <name>,--archive <path>,--dedupe,--structural,--dry-run,--quiet,--json - 8.5 Throw
COMPRESS_SVG.CLI_INVALID_GLOBwhen no files match--in; exit code 2 (POSIX EX_USAGE) - 8.6 Sibling
.md
9. Error codes
- 9.1 Register
COMPRESS_SVG.*codes inerror-codes.ts:OPTIMIZER_PIPELINE_FAILED,STRUCTURAL_INVALID_TREE,DEDUPE_HASH_COLLISION,PATH_TOKEN_PARSE_FAILED,ARCHIVE_VERSION_MISMATCH,ARCHIVE_CHECKSUM_FAILED,ARCHIVE_PAYLOAD_NOT_FOUND,BROWSER_UNSUPPORTED_ENVIRONMENT,CLI_INVALID_GLOB - 9.2 Every code thrown by at least one production path; no orphan codes
10. Subpath exports
- 10.1
package.jsonexportsmap gains./optimizer,./structural,./deduplicator,./path-tokenizer,./archive,./browser,./cli - 10.2 Each subpath is tree-shakeable (
"sideEffects": falsealready set; verify by build artefact size) - 10.3
tests/dep-graph.test.tspins the subpath surface
11. Tests
- 11.1
src/optimizer/svg-optimizer.test.ts— pipeline orchestration, plugin selection,OptimizationResultshape, batch mode - 11.2
src/optimizer/svg-optimizer.spec-conformance.test.ts— injectableCompressorAdapterround-trip; pipeline-failed error code; OTel histogram emitted - 11.3
src/structural/svg-structural-optimizer.test.ts— every rule observable; per-rule counter accuracy - 11.4
src/structural/svg-structural-optimizer.spec-conformance.test.ts— invalid-tree error code - 11.5
src/deduplicator/svg-deduplicator.test.ts— cross-file dedup,<symbol>/<use>emission - 11.6
src/deduplicator/svg-deduplicator.spec-conformance.test.ts—DeduplicationReportshape; injected hash honoured; collision error code - 11.7
src/path-tokenizer/path-tokenizer.test.ts— every SVG path command; round-trip property test on 10 000 random paths - 11.8
src/path-tokenizer/path-tokenizer.spec-conformance.test.ts— malformed-path error code; absolute/relative flag preserved - 11.9
src/archive/svg-packer.test.ts— binary header, manifest, payload table, content-addressed dedup, version round-trip - 11.10
src/archive/svg-packer.spec-conformance.test.ts— version-mismatch / checksum-failed / payload-not-found error codes - 11.11
src/browser/svg-unpacker-browser.test.ts— browser unpacker round-trip with the same fixtures as the Node unpacker - 11.12
src/browser/svg-unpacker-browser.spec-conformance.test.ts— static-import scan asserts no Node API; missing-globalThis.cryptoerror path - 11.13
src/cli/cli.test.ts— argument parsing, glob expansion, in-place vs out-dir vs archive modes, dry-run, JSON reporter - 11.14
src/cli/cli.spec-conformance.test.ts— invalid-glob error code; POSIX exit codes - 11.15
tests/dep-graph.test.ts— subpath exports resolve, no Node API on./browser - 11.16 Every
it(...)carries{ timeout: 5000 }(or 30000 for archive round-trip tests)
12. Documentation
- 12.1 Sibling
.mdfor every implementation.ts(≥200 words, basic + advanced examples, full API reference) - 12.2 README links every co-located
.mdunder## Modules - 12.3 Update
CLAUDE.mdcompress-svgpackage listing to reflect the restored surface
13. Pre-archive verification (the 5-gate triple)
- 13.1
bun run check— Biome 0/0/0 across the monorepo - 13.2
bunx turbo lint typecheck test --filter=@suaveplan/compress-svg— green - 13.3
bunx turbo test:coverage --filter=@suaveplan/compress-svg— 100/100/100/100 - 13.4
bun scripts/openspec-conformance.ts @suaveplan/compress-svg— exit 0, noerrorfindings - 13.5
bunx turbo build --filter=@suaveplan/compress-svg— green
14. Pre-archive 7-row checklist (AGENTS.md Section 13)
- 14.1 Generics threaded;
expectTypeOfassertions onOptimizationResult,DeduplicationReport,StructuralOptimizationResult,PathToken[] - 14.2 Zod schemas wired at every declared boundary (
SvgOptimizerConfig,StructuralOptimizerConfig,DeduplicationConfig,SvgArchiveManifest, CLI args) - 14.3 Every
COMPRESS_SVG.*code thrown by at least one production path; no orphans - 14.4 Strict-mode behaviors tested both on and off (e.g.
dedupe: truevsfalse; archive with vs without checksum) - 14.5 OTel histograms / counters asserted with a real in-memory
MeterProvider - 14.6 Lifecycle dedup tested where claimed:
SvgDeduplicatoridempotent on identical input;SvgPackerarchive output stable byte-for-byte across runs (deterministic) - 14.7 No retroactive tick — every box above reflects work done in this change
15. Archive
- 15.1 Fold spec delta into
openspec/specs/compress-svg/spec.md(creating the file) - 15.2 Move
openspec/changes/compress-svg-completion/→openspec/archive/<yyyy-mm-dd>-compress-svg-completion/ - 15.3 Refresh
MANIFEST.mdif the package's exports list materially changed - 15.4 Update
STATUS.mdif the package was previously listed as Pending