load(PR1): persist the interesting corpus as a campaign ConfigMap (DD-026) - #33
Conversation
…ap (DD-026) Producer half of load mode. An explore run's interesting inputs (the "replay corpus") are now persisted so they can be replayed under load (PR 2), viewed on the dashboard, and re-run for reproducibility. Transport: reuse the termination-message channel, NOT a sidecar (DD-026 §3 flagged the sidecar + a new driver-pod identity as the costly path). The driver splices a byte-capped (~3 KB, ≈top-N) replayCorpus array into the summary it already writes to /dev/termination-log; the operator — which now holds configmaps create;update — reads it back and materializes a campaign-owned <campaign>-corpus-out ConfigMap, setting status.corpusConfigMap. The driver stays credential-less. The cap is also the right load-replay semantics (hammer the best states); a bigger transport is a future extension. - runner: CoverageGuidedRun publishes its live corpus + splices replayCorpus into writeSummary; replayCorpusJson (dedup + JSON-escape + byte budget) unit tested. - operator: driverSummary.ReplayCorpus; emitCorpusConfigMap (create-or-update, owner-ref'd); status.corpusConfigMap; configmaps create;update;patch RBAC (regenerated role + synced chart RBAC/CRD). envtest spec added. - e2e: assert a completed campaign emits status.corpusConfigMap with route entries, owned by the campaign. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JuGqspSB9zpA5AyvHJBiDK
|
@claude please review this load-mode PR 1 (corpus producer). Focus: (1) the termination-message splice — replayCorpusJson byte cap (3 KB) vs the ~4 KiB termination-message limit INCLUDING the metrics JSON (safe headroom?), and malformed-JSON risk from the string splice into snapshotJson; (2) emitCorpusConfigMap create-or-update + owner ref + non-fatal error handling; (3) the lastCorpus static publish + shutdown-hook thread-safety; (4) RBAC scope (configmaps create;update;patch). runner + envtest green; in-cluster e2e running. |
|
Claude finished @ianp94's task in 4m 59s —— View job Review: load(PR1) — corpus producer (DD-026)Todo list
No repo-root 1. Termination-message splice (
|
…; trim RBAC (review #33) Four review fixes: - (race, blocking) The summary shutdown hook could iterate `corpus` while the main loop mutated it on an external SIGTERM — CME risk, and the broad catch in writeSummary would then drop the ENTIRE summary (metrics too). Synchronize the corpus add() sites, take a defensive copy under the same monitor, and split writeSummary's try/catch so a corpus failure never takes down the metrics. - (byte budget) Compute the corpus budget as (4 KiB − actual metrics size), not a fixed 3000, so a future metrics field can't push the merged write past the cap; count UTF-8 bytes, not UTF-16 chars. Added a combined-size test that writes a 500-entry corpus through the real snapshotJson and asserts < 4096. - (retryable) Emit the corpus BEFORE flipping to a terminal phase; on failure stay Running and retry (terminal campaigns never reconcile again, so the old path permanently forfeited the corpus on a transient error). - (RBAC) Drop the unused `patch` verb — emitCorpusConfigMap only Creates/Updates. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JuGqspSB9zpA5AyvHJBiDK
|
Great review — the shutdown-race catch (and that it could take down the metrics summary too, not just the new field) was the important one. All four fixed in `45deb1e`: #3 (race, was blocking): synchronized both #1 (byte budget): the corpus budget is now computed as #2 (non-retryable): emit now runs before the terminal-phase flip; on failure the campaign stays #4 (RBAC): dropped runner + envtest green; the producer happy path was already validated in-cluster (emitted a 24-route corpus ConfigMap) and these are edge-hardenings that don't touch it. Merging. |
Producer half of load/soak mode (DD-026). An explore run's interesting inputs (the replay corpus) are now persisted so they can be replayed under load (PR 2), rendered on the dashboard (the corpus-view you asked for), and re-run for reproducibility.
Transport: reuse the termination-message channel, not a sidecar
DD-026 §3 flagged the sidecar + a new driver-pod identity as the costly path. Instead — using the reviewer's own "reuse the termination-message" option + the top-N cap — the driver splices a byte-capped (~3 KB, ≈top-N)
replayCorpusarray into the summary it already writes to/dev/termination-log; the operator (which now holdsconfigmaps: create;update) reads it back and materializes a campaign-owned<campaign>-corpus-outConfigMap, settingstatus.corpusConfigMap. The driver stays credential-less — no new pod SA. The cap is also the right load-replay semantics (hammer the best states); a bigger transport (sidecar/PVC) is a documented future extension.Changes
CoverageGuidedRun): publishes its live corpus;writeSummarysplices inreplayCorpus;replayCorpusJson(dedup + JSON-escape + byte budget) with unit tests.driverSummary.ReplayCorpus;emitCorpusConfigMap(create-or-update, owner-ref'd);status.corpusConfigMap;configmaps create;update;patchRBAC (regenerated role + synced the chart's CRD + rbac.yaml). envtest spec asserts the emitted ConfigMap (content + owner ref).status.corpusConfigMapwith route entries, owned by the campaign.Scope
No
loadbehavior yet (that's PR 2); every completed explore campaign emits its corpus. Emission is non-fatal — a ConfigMap write failure logs but doesn't fail the (already Completed) run.Validation
runner
ReplayCorpusJsonTestgreen; operator envtest green (adds the emission spec). In-cluster e2e running (adds 3 corpus-emission checks).@claude please review — focus on: (1) the termination-message splice (
replayCorpusJsonbyte cap vs the ~4 KiB limit including the metrics JSON — is 3 KB safe headroom? malformed-JSON risk from the string splice?); (2)emitCorpusConfigMapcreate-or-update + owner ref + the non-fatal error handling; (3) thelastCorpusstatic publish (thread-safety at shutdown-hook time); (4) RBAC scope (configmaps create;update;patch— is patch needed?).🤖 Generated with Claude Code