Files
2026-05-27 23:29:53 +01:00

6.6 KiB

Capability Spec: network-plugin-devtools

Capability: network-plugin-devtools Status: ACTIVE

Every requirement below carries a **Verified by:** line at authoring time. No exceptions. (See openspec/AGENTS.md §13.)


ADDED Requirements

Requirement: NET_DEV-01 — NetworkVisualizer produces a stable IR and supports three modes

The package SHALL export a NetworkVisualizer class whose start({ mode, refreshRate }) Zod-validates input (rejecting unknown modes with VISUALIZER_INVALID_MODE), whose render() produces a VisualizerScene IR carrying nodes, edges, heat, width, height, and an optional focus field, and whose three modes (hierarchy, flow, heat) drive distinct edge / heat collection paths from the injected TopologyAdapter and MessageStreamAdapter. render() SHALL surface VISUALIZER_EMPTY_TOPOLOGY when the active filter eliminates every node, and render() and mode() SHALL throw VISUALIZER_NOT_STARTED before start().

Verified by: src/visualizer/visualizer.spec-conformance.test.ts

Scenario: Mode switches the edge source

  • WHEN start({ mode: "flow", refreshRate: 30 }) is called and the stream returns three flow edges
  • THEN render().edges.length === 3

Requirement: NET_DEV-02 — Visualizer export delegates to the injected Renderer with format checking

NetworkVisualizer.export(format) SHALL accept only "svg" or "png", reject any other format with VISUALIZER_INVALID_MODE, surface renderer exceptions as VISUALIZER_RENDERER_FAILED (with the original error preserved as cause), and reject any renderer that returns an output whose format field does not match the requested format. The bundled SvgRenderer SHALL satisfy the Renderer contract and produce deterministic UTF-8 SVG bytes with mimeType === "image/svg+xml". PNG support SHALL be delivered via injected Renderer (no built-in encoder dependency).

Verified by: src/visualizer/visualizer.spec-conformance.test.ts

Scenario: Renderer format mismatch rejected

  • WHEN a renderer is injected that returns { format: "png" } while the consumer asked for "svg"
  • THEN export("svg") throws VISUALIZER_RENDERER_FAILED

Requirement: NET_DEV-03 — StateInspector records, inspects, scrubs, and diffs per path

The package SHALL export a StateInspector class with a configurable per-path ring buffer (default 256), record(StateSnapshot) Zod boundary surfacing INSPECTOR_DIFF_FAILED on invalid input, inspect(path) returning StateView (throws INSPECTOR_PATH_NOT_FOUND when absent), diff(path, fromVersion, toVersion) producing DiffView with added / removed / changed JSON Pointers and a numeric summary (throws INSPECTOR_INVALID_RANGE when versions match or are missing), scrub(path, atVersion) returning the latest snapshot ≤ atVersion (throws INSPECTOR_HISTORY_EMPTY when none satisfies the cap), and search(filter) AND-combining populated pathContains / peerId / sessionId / minVersion / maxVersion filters.

Verified by: src/inspector/inspector.spec-conformance.test.ts

Scenario: Diff classifies added / removed / changed paths

  • WHEN two snapshots are recorded with { a: 1 } and { b: 2 } at versions 1 and 2
  • THEN diff(path, 1, 2) reports removed: ["/a"] AND added: ["/b"]

Requirement: NET_DEV-04 — SimulationConfigTool builds, records, plays, and round-trips scenarios

The package SHALL export a SimulationConfigTool class with peer / link / condition / event editors, startRecording / stopRecording (throws SIMULATOR_RECORDING_INACTIVE on stop without start), loadPlayback enforcing scenario-id match (throws SIMULATOR_SCENARIO_INVALID on mismatch), playback() grouping events by atMs (throws SIMULATOR_PLAYBACK_INACTIVE before load), exportJson() / importJson(json) round-trip with full Zod validation (parse errors and schema errors both surface as SIMULATOR_SCENARIO_INVALID), addPeer rejecting duplicates with SIMULATOR_PEER_DUPLICATE, and addLink rejecting unknown endpoints with SIMULATOR_PEER_NOT_FOUND.

Verified by: src/simulator/simulator.spec-conformance.test.ts

Scenario: Playback groups concurrent events

  • WHEN three events at atMs: 100 and one at atMs: 200 are recorded and replayed
  • THEN playback() returns two ticks of length 3 and 1 in atMs order

Requirement: NET_DEV-05 — PerformanceProfiler distributes, baselines, regresses, and suggests

The package SHALL export a PerformanceProfiler class that records latency / throughput / plugin-overhead / memory samples into bounded rings, exposes p50 / p95 / p99 / min / max / mean / count distributions per path, supports named baselines (captureBaseline rejects duplicates with PROFILER_BASELINE_DUPLICATE), compare(baselineId) produces a Regression[] ranked by Z-score across p50 / p95 / p99 latency and message-throughput drops (throws PROFILER_NO_BASELINE when missing), and suggestions() emits category-tagged OptimizationSuggestions. Constructor SHALL throw PROFILER_INVALID_THRESHOLD on non-positive windowSize / regressionZScore / regressionWarnPct.

Verified by: src/profiler/profiler.spec-conformance.test.ts

Scenario: Tail-latency suggestion fires

  • WHEN latency samples produce p50 = 50 and p99 = 200
  • THEN suggestions() includes a category: "latency" entry whose subject is the path

Requirement: NET_DEV-06 — DevToolsPlugin facade exposes subsystems with a tier gate

DevToolsPlugin SHALL expose visualizer, inspector, simulator, profiler as public fields, evaluate the injected tierGate at install() time, record PLUGIN_TIER_GATE_REJECTED as tierRejection() when the gate returns false, expose requireActive() raising PLUGIN_DEV_DISABLED when the gate rejected activation, and expose idempotent stop() / dispose() lifecycles.

Verified by: src/plugin/devtools-plugin.spec-conformance.test.ts

Scenario: Production gate inert

  • WHEN tierGate: () => false is supplied and install then start are called
  • THEN isStarted() is true, isActive() is false, requireActive() throws PLUGIN_DEV_DISABLED

Requirement: NET_DEV-07 — Frozen NETWORK_DEV_CODES registry

NETWORK_DEV_CODES SHALL be frozen (Object.isFrozen() === true), every value SHALL be prefixed NET_DEV., and the registry SHALL include every code consumed by visualizer, inspector, simulator, profiler, and plugin facade modules. Removing a code is a major-version change.

Verified by: src/error-codes.spec-conformance.test.ts