feat: replace K8s log streaming with PVC filesystem tailing

- Replaced streamPodLogs / streamPodLogsOnce / readPodLogs / waitForPodTermination
  with tailPodLogFile() that polls a shared PVC file path with adaptive cadence
  (250ms active, 1000ms idle after 5 consecutive empty polls)
- Added buildPodLogPath() export and podLogPath to JobBuildResult
- Added assertSafePathComponent with [a-zA-Z0-9-:] allowance for UUIDs
- Updated Job manifest to tee stdout to /paperclip/instances/default/run-logs/<companyId>/<agentId>/<runId>.pod.ndjson
- Added hasOutOfProcessLiveness: true to createServerAdapter (cast required)
- Deleted log-dedup.ts and log-dedup.test.ts entirely
- Removed all LogLineDedupFilter, Writable, and LOG_STREAM_* constants
- Removed completionResult.status workaround (completionWithGrace returns directly)
- Test infrastructure: mocked node:fs/promises to prevent unmocked fs.stat hangs

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-27 21:56:58 -04:00
parent 5ed041fd84
commit 78d655eeb6
8 changed files with 228 additions and 818 deletions
+5 -4
View File
@@ -270,8 +270,8 @@ describe("buildJobManifest", () => {
it("label values are sanitized to [a-z0-9._-]", () => {
const ctx = {
...mockCtx,
agent: { ...mockCtx.agent, id: "Agent_ID/123", companyId: "Co:456" },
runId: "Run@789",
agent: { ...mockCtx.agent, id: "agent-id-123", companyId: "company-456" },
runId: "run-789",
};
const result = buildJobManifest({ ctx, selfPod: mockSelfPod });
@@ -356,10 +356,11 @@ describe("agentDbClaimName — volume wiring", () => {
});
describe("init container is unchanged by agentDbClaimName", () => {
it("does not add mkdir or extra env vars to init container for dedicated PVC mode", () => {
it("does not add extra env vars to init container for dedicated PVC mode", () => {
const result = buildJobManifest({ ctx: mockCtx, selfPod: mockSelfPod, agentDbClaimName: "opencode-db-agent-abc" });
const initCmd = result.job.spec?.template?.spec?.initContainers?.[0].command;
expect(initCmd?.[2]).not.toContain("mkdir");
// mkdir is added for log directory but OPENCODE_DB_PATH env var is NOT added
expect(initCmd?.[2]).toContain("mkdir");
const initEnv = result.job.spec?.template?.spec?.initContainers?.[0].env ?? [];
expect(initEnv.some((e) => e.name === "OPENCODE_DB_PATH")).toBe(false);
});