6.9 KiB
6.9 KiB
Tasks: enterprise-profiler
Change ID: enterprise-profiler
Package: @suaveplan/profiler
Target path: universal/platform/profiler
Prerequisite packages on Verdaccio: @suaveplan/error, @suaveplan/types, @suaveplan/events, @suaveplan/logger
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.
1. Scaffold
- Create
universal/platform/profiler/withsrc/,tests/,src/__benchmarks__/, and all feature subdirectories per the layout inproposal.md. - Write
package.jsonat version0.1.0:"type": "module","sideEffects": falseexportsmap:"."barrel +"./core/profiler/profiler","./core/session/session","./sinks/console-sink/console-sink","./sinks/json-sink/json-sink","./utils/aggregate","./utils/flamegraph","./types/common"dependencies:@suaveplan/error workspace:^,@suaveplan/types workspace:^,@suaveplan/events workspace:^,@suaveplan/logger workspace:^,zod catalog:forms,@opentelemetry/api catalog:observability,tslib catalog:builddevDependencies:vitest catalog:testing,@vitest/coverage-istanbul catalog:testing,fast-check catalog:testing,mitata catalog:testing,@suaveplan/testing workspace:^
- Write
tsconfig.jsonextending@suaveplan/typescript-config/library.json. - Write
vitest.config.tsusingcreateTestConfig(). - Add
lint,typecheck,test,test:coverage,build,docs:check,benchscripts.
2. Types and error codes
- Define all public types in
src/types/common.ts:ProfileSample,StackFrame,ProfileSession,FlamegraphNode,ProfileAggregate,ProfilerOptions,SessionOptions,ProfilerSink,ConsoleSinkOptions,JsonSinkOptions. - Write
src/types/common.md(≥200 words, simple + advanced examples). - Define error codes in
src/error-codes.ts:ProfilerErrorCodeunion, metadata,registerProfilerErrorCodes(). - Write Zod schemas in
src/types/schemas.ts+src/types/schemas.md.
3. Aggregate utilities (src/utils/aggregate.ts)
- Implement
aggregateSamples(samples): compute count, totalCpuMs, avgCpuMs, p50/p95/p99 (insertion-sort on the cpu array), peakHeapMb, avgHeapMb. - Implement
formatDuration(ms): format asXms,Xs,Xm Xs. - Write
aggregate.test.ts(≤500 lines): empty array, single sample, percentile correctness for known data. - Write
aggregate.md(≥200 words).
4. Flamegraph utilities (src/utils/flamegraph.ts)
- Implement
buildFlamegraph(session): group samples by stack frame path, build tree by folding frames into children. - Each node's
value= number of samples that include this frame. - Produce sorted children (descending by value).
- Write
flamegraph.test.ts(≤500 lines): empty session, single frame, multi-frame stacks, shared frames merge correctly. - Write
flamegraph.md(≥200 words).
5. Profiler session (src/core/session/)
- Implement
ProfilerSession(internal class):sample()— capturesclock.now()+ heap stats viaprocess.memoryUsage()(guarded for non-Node runtimes); returnsProfileSample.stop()— setsendTime, returns immutableProfileSessionsnapshot.export('json', signal?)— JSON-serialises session.export('flamegraph', signal?)— callsbuildFlamegraph, JSON-serialises.toFlamegraph()— synchronousbuildFlamegraphcall.
- Write
session.test.ts(≤500 lines): sample, stop, export json, export flamegraph, abort on export. - Write
session.md(≥200 words).
6. Profiler (src/core/profiler/)
- Implement
createProfiler(options?): validates options with Zod; stores sessions inMap<string, ProfilerSession>. - Implement
profiler.startSession(name, options?)— generates UUID id, stores session, emits OTel spanprofiler.session.start. - Implement
profiler.getSession(id),listSessions(),clearSessions(). - Implement
profiler.use(sink)— registers sink; on session stop, callssink.onSessionEnd(session)asynchronously. - On session stop, emit OTel span
profiler.session.stop, histogramprofiler.session_duration_ms. - Write
profiler.test.ts(≤500 lines): session lifecycle, sink called on stop, multiple sessions. - Write
profiler.md(≥200 words).
7. Sinks (src/sinks/)
7a. Console sink
- Implement
createConsoleSink(options?)— on session end, prints a summary table viaconsole.logwith aggregate stats. - Write
console-sink.test.ts: output contains session name and p95 duration. - Write
console-sink.md.
7b. JSON sink
- Implement
createJsonSink(options: { path: string })— on session end, appends JSON line to file viaBun.write(orfs.appendFilefallback). - Write
json-sink.test.ts: file written, valid JSON, append-safe. - Write
json-sink.md.
8. Property-based tests (tests/property.test.ts)
aggregateSamplesinvariants: avg ≤ max, p50 ≤ p95 ≤ p99, count equals input length.buildFlamegraphnode value sum: root node value ≤ total samples.- Session stop idempotency: calling
stop()twice on a session should be a no-op after the first call (endTime does not change).
9. Benchmarks (src/__benchmarks__/profiler.bench.ts)
sample_hot: 1000session.sample()calls.buildFlamegraph_1k,buildFlamegraph_10k: flamegraph on 1k and 10k sample sessions.aggregateSamples_1k,aggregateSamples_10k: aggregate on 1k and 10k samples.
10. Docs
- All per-file
.mdfiles per layout inproposal.md. universal/platform/profiler/README.md: purpose, installation, quick-start, API section, dependency table, benchmarks table.
11. Verify and publish
bunx turbo lint --filter=@suaveplan/profiler— zero errors.bunx turbo typecheck --filter=@suaveplan/profiler— zero errors.bunx turbo test --filter=@suaveplan/profiler— all tests pass.bunx turbo test:coverage --filter=@suaveplan/profiler— 100% on all touched modules.bun run docs:check --filter=@suaveplan/profiler— zero errors.bun scripts/publish.ts --package @suaveplan/profiler.- Update
CLAUDE.mdpackage listing. - Archive: move
openspec/changes/enterprise-profiler/toopenspec/archive/2026-04-24-enterprise-profiler/.