Skip to content

Post-2.0 hardening & enhancement plan#5

Merged
ZelAnton merged 7 commits into
mainfrom
worktree-impl-post2
Jul 4, 2026
Merged

Post-2.0 hardening & enhancement plan#5
ZelAnton merged 7 commits into
mainfrom
worktree-impl-post2

Conversation

@ZelAnton

@ZelAnton ZelAnton commented Jul 4, 2026

Copy link
Copy Markdown
Owner

Implements docs/planning/post-2.0-plan.md — the post-2.0 hardening & enhancement plan — one item per stage. This PR accumulates the stages; each is independently green (build + tests + Fantomas), with the public-API snapshot, docs, and CHANGELOG.md updated in the same change set.

Progress

  • Item 5 — Record/replay enhancements — bytes capture (v2 base64), streaming replay, RecordReplayOptions (content-hash / normalizer / redaction), Auto record-on-miss, back-compat version policy.
  • Item 3 — ILogger observability — stable EventIds, LoggerMessage.Define, per-run RunId correlation, ActivitySource "ProcessKit" spans + Meter "ProcessKit" metrics (ProcessKitDiagnostics), secret-safe.
  • Item 4 — DI ExtensionsProcessKitOptions defaults (timeout / working dir, via Action/IConfiguration), keyed per-tool CliClients, container-managed shared ProcessGroup. (Separate Hosting package deferred, documented.)
  • Item 2 — Streaming backlog improvements
  • Item 1 — Async-I/O hardening

Order chosen to ship the additive, lower-risk items first and the highest-risk native item (async-I/O) last.

🤖 Generated with Claude Code

ZelAnton and others added 7 commits July 4, 2026 19:48
Detailed, code-grounded implementation plan for the five backlog items —
async-I/O hardening (overlapped Windows reads, POSIX pidfd/reaper exit-wait),
streaming backlog backpressure, ILogger observability enhancements (EventIds,
LoggerMessage.Define, correlation, Activity/Meter), DI Extensions enhancements
(options/keyed clients/group registration), and record/replay enhancements
(bytes + streaming replay, v2 schema). Each item states what/why/acceptance
criteria against the current implementation seams. Internal planning doc, kept
out of the consumer-facing docs index; no library change, so no CHANGELOG entry.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…s, auto)

RecordReplayRunner gains:
- Bytes capture record+replay via a v2 cassette schema (`StdoutBase64`,
  exact non-UTF-8 stdout bytes). A text/pre-v2 entry replayed through the
  bytes verb stays honestly `ProcessError.Unsupported` (no lossy re-encode).
- Streaming replay: `SpawnAsync` reconstructs a live `FakeProcess` handle from
  the recording; record-mode `SpawnAsync` stays `Unsupported`.
- `RecordReplayOptions`: opt-in file-stdin content hashing, an argument
  normalizer (tolerate volatile args), and a record-time redaction hook.
- `Auto(path, inner)`: replay-with-record-on-miss (VCR "new episodes").
- Version back-compat policy: accept 1..current, reject newer; v1 loads.

Public API snapshot, docs/testing.md, and CHANGELOG updated. +13 cassette
tests. Green on net10.0 (net8.0 via CI); Fantomas clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- testing.md: drop the now-stale "exactly what RecordReplayRunner does"
  attribution — RecordReplayRunner now serves SpawnAsync in replay/Auto
  mode (only record-mode SpawnAsync is Unsupported), which the rest of the
  doc already states.
- cookbook.md: point the record/replay recipe at the new bytes / streaming /
  Auto / RecordReplayOptions capabilities in testing.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…, metrics

- Log.fs: stable EventIds (name + number) per lifecycle event; cached
  LoggerMessage.Define delegates (no format/boxing when the level is off);
  a per-run RunId on every run-scoped event (spawn/exit/timeout/retry).
- RunId correlation: internal CommandConfig.RunId, stamped once at the verb
  layer (Runner.withRetry), so a run and all its retries share one id; a
  direct spawn gets a per-incarnation fallback.
- Diag.fs: an ActivitySource "ProcessKit" emitting a backdated span per
  completed run, and a Meter "ProcessKit" with runs started/completed/active,
  a duration histogram, retries, and supervisor restart/storm-pause counters —
  tagged only by program + outcome, never argv/env. Public ProcessKitDiagnostics
  exposes the source/meter names.
- RunningProcess: a single once-guarded conclude() (log + metrics + span) at
  every terminal verb (Output*/Wait/Finish/Profile/OutputEvents/ExitTask).

New docs/observability.md; API snapshot, cookbook, README, CHANGELOG updated.
+5 logging tests (EventIds, RunId correlation, level-gate, trace + metric
listeners with no-argv assertions). Green on net10.0; Fantomas clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…docs)

From the solution-level review:
- Expose the lifecycle EventIds publicly as ProcessKitDiagnostics.Events
  (new Diagnostics.fs, compiled before Log.fs), restoring symmetry with the
  public ActivitySource/Meter name constants — consumers filter/route by id
  without a magic number.
- Align metric units with OpenTelemetry/UCUM: dimensionless counts carry a
  {…} annotation, and the run-duration histogram is now in seconds (was ms),
  so OTel-calibrated dashboards aren't off by 1000×. The log line stays in ms.
- Docs: README Observability section + capability table now cover tracing/
  metrics and link the new guide; ROADMAP "What the library covers" lists them;
  observability.md gains the Events column and the corrected unit table.

API snapshot updated (additive: ProcessKitDiagnostics.Events). Green on
net10.0; Fantomas clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…shared group)

- ProcessKitOptions + AddProcessKit(Action<ProcessKitOptions>) / AddProcessKit(IConfiguration):
  default timeout / working directory applied to every DI-resolved run, only where the
  command sets none (per-command wins). Retry is intentionally NOT an option — the retry
  loop is a verb-layer policy that runs before a primitive IProcessRunner decorator can
  inject it, so it would silently no-op; set retry (and encoding/env) on a keyed CliClient
  instead, whose template precedes the verb.
- AddProcessKitClient(name, program, configure): a keyed per-tool CliClient, injected by
  role, running through the container's registered IProcessRunner.
- AddProcessKitGroup(): backs IProcessRunner with a shared, container-managed ProcessGroup
  (also registered directly); disposing the provider reaps the whole tree.
- Deferred: a separate ProcessKit.Extensions.Hosting package for a supervised IHostedService
  (documented) — kept out to keep the DI package hosting-free.

New docs/dependency-injection.md; DI API snapshot, cookbook, README index, CHANGELOG updated.
+4 DI tests. Green on net10.0; Fantomas clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
From the solution-level review:
- Add symmetric AddProcessKitGroup(Action<ProcessKitOptions>) /
  AddProcessKitGroup(IConfiguration) overloads, so a shared group can be
  configured with the same defaults as AddProcessKit in one call.
- dependency-injection.md: correct "Abstractions-light" -> "dependency-light"
  (Options/Options.ConfigurationExtensions are concrete packages), and warn
  about the AddProcessKit-vs-AddProcessKitGroup "first TryAdd wins" mis-wire.
- Cross-reference the DI guide from testing.md; list the new DI ergonomics in
  ROADMAP "What the library covers".

DI API snapshot + CHANGELOG updated. Green on net10.0; Fantomas clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ZelAnton ZelAnton merged commit 21245ea into main Jul 4, 2026
6 checks passed
@ZelAnton

ZelAnton commented Jul 4, 2026

Copy link
Copy Markdown
Owner Author

Merged into main directly (fast-forward 5455f7c..21245ea), per the repo's publish-directly-to-main workflow. All three stages (items 5, 3, 4) are on main and CI-green. Continuing Stages D–E directly on main.

@ZelAnton ZelAnton deleted the worktree-impl-post2 branch July 4, 2026 23:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant