create-walle 0.10.0 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -41
- package/lib/owner-write-safety.js +135 -0
- package/lib/public-runtime.js +13 -5
- package/lib/release-schema.json +3 -2
- package/lib/runtime-closure-policy.json +7 -5
- package/package.json +10 -4
- package/template/bin/deps-doctor.js +1 -1
- package/template/bin/node-bin.sh +11 -0
- package/template/coding-task-manager/api-prompts.js +10 -22
- package/template/coding-task-manager/bin/capture-codex-rollout-records.js +417 -0
- package/template/coding-task-manager/bin/census-codex-lead-history.js +325 -0
- package/template/coding-task-manager/bin/claude-hook.js +7 -3
- package/template/coding-task-manager/bin/claude-table-parity.js +307 -0
- package/template/coding-task-manager/bin/conversation-storage-auto-migration-lib.js +16 -1
- package/template/coding-task-manager/bin/conversation-storage-generation-evidence.js +9 -2
- package/template/coding-task-manager/bin/conversation-storage-service-entry-lib.js +16 -1
- package/template/coding-task-manager/bin/conversation-storage-walle-owner.js +247 -0
- package/template/coding-task-manager/bin/ctm-machine-pair.js +160 -0
- package/template/coding-task-manager/bin/lead-wait-census.js +1348 -0
- package/template/coding-task-manager/bin/repair-foreign-clone.js +564 -0
- package/template/coding-task-manager/bin/repair-resume-echo-titles.js +248 -0
- package/template/coding-task-manager/bin/seam-replay-codex.js +301 -0
- package/template/coding-task-manager/bin/write-lock-bench.js +111 -0
- package/template/coding-task-manager/db.js +705 -286
- package/template/coding-task-manager/git-utils.js +44 -0
- package/template/coding-task-manager/lib/adopted-host-redial.js +4 -0
- package/template/coding-task-manager/lib/agent-presets.js +15 -0
- package/template/coding-task-manager/lib/agent-title-apply.js +88 -0
- package/template/coding-task-manager/lib/agent-title-backfill-read.js +92 -0
- package/template/coding-task-manager/lib/api/host-stats.js +98 -0
- package/template/coding-task-manager/lib/api/ingress.js +35 -12
- package/template/coding-task-manager/lib/api/machine-pairing.js +285 -0
- package/template/coding-task-manager/lib/api/machine-pool.js +307 -0
- package/template/coding-task-manager/lib/api/machines.js +461 -0
- package/template/coding-task-manager/lib/api/misc-ops.js +20 -5
- package/template/coding-task-manager/lib/api/providers.js +53 -6
- package/template/coding-task-manager/lib/api/resume-from-store.js +25 -0
- package/template/coding-task-manager/lib/api/sessions.js +160 -8
- package/template/coding-task-manager/lib/api/transcript-history.js +17 -4
- package/template/coding-task-manager/lib/api/worktrees.js +38 -37
- package/template/coding-task-manager/lib/approval-drift.js +16 -1
- package/template/coding-task-manager/lib/approval-logical-frame.js +5 -1
- package/template/coding-task-manager/lib/approval-scope.js +68 -4
- package/template/coding-task-manager/lib/auth-context.js +32 -2
- package/template/coding-task-manager/lib/auth-rate-limit.js +41 -1
- package/template/coding-task-manager/lib/auth-rules.js +186 -45
- package/template/coding-task-manager/lib/broadcast-serialize.js +2 -1
- package/template/coding-task-manager/lib/browser-session-broker.js +9 -1
- package/template/coding-task-manager/lib/browser-use-adapter.js +33 -2
- package/template/coding-task-manager/lib/claude-markdown-ansi.js +27 -85
- package/template/coding-task-manager/lib/claude-session-title.js +6 -30
- package/template/coding-task-manager/lib/claude-table-layout.js +322 -0
- package/template/coding-task-manager/lib/client-diag-handler.js +25 -0
- package/template/coding-task-manager/lib/codex-config-guard.js +33 -3
- package/template/coding-task-manager/lib/codex-harness-qualification.js +12 -0
- package/template/coding-task-manager/lib/codex-history-terminal-renderer.js +33 -33
- package/template/coding-task-manager/lib/codex-launch-health.js +29 -2
- package/template/coding-task-manager/lib/codex-link-preparation.js +9 -8
- package/template/coding-task-manager/lib/codex-local-links.js +267 -0
- package/template/coding-task-manager/lib/codex-markdown-lists.js +160 -0
- package/template/coding-task-manager/lib/codex-native-history-prefix.js +4 -0
- package/template/coding-task-manager/lib/codex-paths.js +2 -1
- package/template/coding-task-manager/lib/codex-source-handoff.js +186 -0
- package/template/coding-task-manager/lib/coding-agent-models.js +21 -30
- package/template/coding-task-manager/lib/coding-session-model-adapters.js +27 -2
- package/template/coding-task-manager/lib/coding-session-model-projection.js +5 -0
- package/template/coding-task-manager/lib/coding-session-model-runtime.js +1 -2
- package/template/coding-task-manager/lib/coding-session-model-state.js +10 -0
- package/template/coding-task-manager/lib/coding-session-model-sync-state.js +0 -1
- package/template/coding-task-manager/lib/conversation-import/cursor-guard-owner.js +10 -0
- package/template/coding-task-manager/lib/create/resolve-launch-params.js +8 -1
- package/template/coding-task-manager/lib/ctm-boot-lifecycle.js +17 -1
- package/template/coding-task-manager/lib/db-domain-tables.js +7 -0
- package/template/coding-task-manager/lib/db-domains.js +21 -2
- package/template/coding-task-manager/lib/db-owner-op-registry.js +7 -0
- package/template/coding-task-manager/lib/db-owner-worker-client.js +22 -0
- package/template/coding-task-manager/lib/db-schema-source-files.js +1 -0
- package/template/coding-task-manager/lib/feature-manifest.js +1 -3
- package/template/coding-task-manager/lib/fs-watcher.js +3 -2
- package/template/coding-task-manager/lib/harness-history-transition.js +41 -14
- package/template/coding-task-manager/lib/headless-inflight-ops.js +203 -0
- package/template/coding-task-manager/lib/headless-missing-reply.js +42 -0
- package/template/coding-task-manager/lib/headless-term-service.js +60 -23
- package/template/coding-task-manager/lib/history-transition-read-op.js +179 -23
- package/template/coding-task-manager/lib/host-control-dial.js +167 -0
- package/template/coding-task-manager/lib/host-handoff-orchestrator.js +16 -2
- package/template/coding-task-manager/lib/host-handoff.js +51 -13
- package/template/coding-task-manager/lib/host-health-ledger.js +164 -12
- package/template/coding-task-manager/lib/host-self-truth-watchdog.js +4 -0
- package/template/coding-task-manager/lib/host-stats.js +328 -0
- package/template/coding-task-manager/lib/host-threadpool-evacuation.js +160 -0
- package/template/coding-task-manager/lib/host-threadpool-monitor.js +14 -1
- package/template/coding-task-manager/lib/hosted-input-dispatch.js +203 -0
- package/template/coding-task-manager/lib/hosted-sync-worker.js +113 -5
- package/template/coding-task-manager/lib/instance-id-ownership-manifest.js +4 -0
- package/template/coding-task-manager/lib/instance-manifest-runtime.js +3 -0
- package/template/coding-task-manager/lib/instance-manifest.js +13 -1
- package/template/coding-task-manager/lib/instance-sync-status.js +15 -0
- package/template/coding-task-manager/lib/kernel/diag-log.js +12 -0
- package/template/coding-task-manager/lib/launch-model-override.js +160 -1
- package/template/coding-task-manager/lib/launch-plan-worker.js +59 -2
- package/template/coding-task-manager/lib/lead-model-observer.js +17 -2
- package/template/coding-task-manager/lib/lead-model-switch-runtime.js +57 -4
- package/template/coding-task-manager/lib/lead-model-switch.js +11 -2
- package/template/coding-task-manager/lib/lead-model-transition-runtime.js +42 -4
- package/template/coding-task-manager/lib/lead-model-transition-store.js +61 -3
- package/template/coding-task-manager/lib/legacy-draft-cancellation-recovery.js +111 -0
- package/template/coding-task-manager/lib/login-tripwire.js +18 -0
- package/template/coding-task-manager/lib/machine-pairing.js +238 -0
- package/template/coding-task-manager/lib/machine-pool.js +409 -0
- package/template/coding-task-manager/lib/machine-registry.js +749 -0
- package/template/coding-task-manager/lib/machine-self.js +66 -0
- package/template/coding-task-manager/lib/main-thread-lint-exemptions.json +56 -4
- package/template/coding-task-manager/lib/media-journal-control-reader.js +473 -0
- package/template/coding-task-manager/lib/media-journal.js +84 -27
- package/template/coding-task-manager/lib/media-store-options.js +43 -15
- package/template/coding-task-manager/lib/migrations/v56-host-samples-and-machine-pool.js +76 -0
- package/template/coding-task-manager/lib/mirror-feed-sanitize.js +12 -3
- package/template/coding-task-manager/lib/model-execution-recipe-metadata.js +16 -3
- package/template/coding-task-manager/lib/model-proxy/anthropic-face.js +4 -0
- package/template/coding-task-manager/lib/model-proxy/chat-response-translators.js +3 -0
- package/template/coding-task-manager/lib/model-proxy/collaboration-codec.js +94 -0
- package/template/coding-task-manager/lib/model-proxy/handoff.js +494 -0
- package/template/coding-task-manager/lib/model-proxy/lead-worker-picks.js +25 -0
- package/template/coding-task-manager/lib/model-proxy/native-lead-listener.js +61 -7
- package/template/coding-task-manager/lib/model-proxy/proxy-cli.js +200 -0
- package/template/coding-task-manager/lib/model-proxy/proxy-instance-record.js +257 -0
- package/template/coding-task-manager/lib/model-proxy/responses-face.js +24 -2
- package/template/coding-task-manager/lib/model-proxy/stream-accounting.js +205 -0
- package/template/coding-task-manager/lib/model-proxy/tokens.js +78 -0
- package/template/coding-task-manager/lib/model-proxy/upstream-outcome.js +9 -0
- package/template/coding-task-manager/lib/native-history-control.js +62 -14
- package/template/coding-task-manager/lib/native-lead-settings-client.js +2 -1
- package/template/coding-task-manager/lib/native-lead-tls.js +18 -4
- package/template/coding-task-manager/lib/oauth-proxy-supervisor.js +628 -64
- package/template/coding-task-manager/lib/owner-action-manifest-data.json +14 -0
- package/template/coding-task-manager/lib/painted-row-recorder.js +9 -1
- package/template/coding-task-manager/lib/prompt-admission-trace.js +69 -0
- package/template/coding-task-manager/lib/prompt-submission-contract.js +21 -1
- package/template/coding-task-manager/lib/provider-login-broker.js +192 -9
- package/template/coding-task-manager/lib/provider-login-capture.js +153 -0
- package/template/coding-task-manager/lib/queue-draft-status-overlay.js +36 -0
- package/template/coding-task-manager/lib/raw-codex-history-window.js +5 -3
- package/template/coding-task-manager/lib/raw-history-block.js +3 -1
- package/template/coding-task-manager/lib/read-pool-client.js +36 -24
- package/template/coding-task-manager/lib/read-pool-op-registry.js +10 -1
- package/template/coding-task-manager/lib/read-pool-telemetry.js +14 -5
- package/template/coding-task-manager/lib/recent-catalog-query.js +26 -0
- package/template/coding-task-manager/lib/recent-session-catalog-response.js +9 -0
- package/template/coding-task-manager/lib/remote-command-context.js +12 -0
- package/template/coding-task-manager/lib/remote-command-runtime.js +18 -5
- package/template/coding-task-manager/lib/remote-machine-catalog.js +1062 -0
- package/template/coding-task-manager/lib/remote-machine-create.js +693 -0
- package/template/coding-task-manager/lib/remote-machine-link.js +939 -0
- package/template/coding-task-manager/lib/remote-machine-proxy.js +520 -0
- package/template/coding-task-manager/lib/remote-session-forward.js +306 -0
- package/template/coding-task-manager/lib/remote-submission-status.js +6 -0
- package/template/coding-task-manager/lib/restart-outcome-truth.js +20 -3
- package/template/coding-task-manager/lib/restart-preflight.js +9 -2
- package/template/coding-task-manager/lib/restore-backoff-gate.js +10 -2
- package/template/coding-task-manager/lib/restore-prepare-retry.js +12 -5
- package/template/coding-task-manager/lib/restore-resume-batch.js +22 -1
- package/template/coding-task-manager/lib/resume-blocked-wire.js +62 -1
- package/template/coding-task-manager/lib/resume-cwd.js +13 -0
- package/template/coding-task-manager/lib/resume-from-store.js +12 -1
- package/template/coding-task-manager/lib/resume-origin-facts.js +38 -1
- package/template/coding-task-manager/lib/resume-preflight.js +21 -16
- package/template/coding-task-manager/lib/review-repo-admission.js +39 -6
- package/template/coding-task-manager/lib/review-repo-registry.js +17 -0
- package/template/coding-task-manager/lib/root-delivery-runtime.js +72 -15
- package/template/coding-task-manager/lib/root-delivery-selection.js +37 -1
- package/template/coding-task-manager/lib/root-prompt-admission.js +43 -11
- package/template/coding-task-manager/lib/root-prompt-flow.js +175 -38
- package/template/coding-task-manager/lib/scrollback-archive-store.js +7 -4
- package/template/coding-task-manager/lib/server-memory-sampler-runtime.js +10 -0
- package/template/coding-task-manager/lib/server-memory-sampler.js +41 -2
- package/template/coding-task-manager/lib/session-analysis-memory.js +2 -0
- package/template/coding-task-manager/lib/session-create/codex-native-provider-gate.js +218 -0
- package/template/coding-task-manager/lib/session-create/codex-resume-exit-classify.js +52 -0
- package/template/coding-task-manager/lib/session-create/delegate-worker.js +95 -6
- package/template/coding-task-manager/lib/session-create/identity.js +20 -1
- package/template/coding-task-manager/lib/session-create/prepared.js +69 -1
- package/template/coding-task-manager/lib/session-create/provider-launch-context.js +77 -0
- package/template/coding-task-manager/lib/session-create/provider-process.js +38 -39
- package/template/coding-task-manager/lib/session-create/response.js +30 -12
- package/template/coding-task-manager/lib/session-create/transcript.js +13 -4
- package/template/coding-task-manager/lib/session-create/worker-continuation.js +43 -1
- package/template/coding-task-manager/lib/session-create/worker-notices.js +94 -5
- package/template/coding-task-manager/lib/session-create/worker-observability.js +99 -7
- package/template/coding-task-manager/lib/session-create/worker-stop.js +11 -3
- package/template/coding-task-manager/lib/session-create/worker-wait-watcher.js +315 -0
- package/template/coding-task-manager/lib/session-geometry-authority-handler.js +10 -1
- package/template/coding-task-manager/lib/session-host-manager.js +152 -206
- package/template/coding-task-manager/lib/session-jobs.js +17 -9
- package/template/coding-task-manager/lib/session-lifecycle.js +20 -50
- package/template/coding-task-manager/lib/session-model-action-preconditions.js +68 -3
- package/template/coding-task-manager/lib/session-resource-sampler.js +67 -9
- package/template/coding-task-manager/lib/session-standup.js +67 -4
- package/template/coding-task-manager/lib/session-status-ledger.js +42 -3
- package/template/coding-task-manager/lib/session-status-runtime.js +45 -1
- package/template/coding-task-manager/lib/session-status.js +2 -2
- package/template/coding-task-manager/lib/session-title-mirror.js +25 -57
- package/template/coding-task-manager/lib/session-transcript-trash.js +8 -1
- package/template/coding-task-manager/lib/startup-pointer-write.js +57 -0
- package/template/coding-task-manager/lib/state-sync/painted-frame-field.js +11 -0
- package/template/coding-task-manager/lib/storage/coding-session-model-store.js +21 -22
- package/template/coding-task-manager/lib/surviving-owner-bootstrap.js +7 -2
- package/template/coding-task-manager/lib/surviving-owner-recovery.js +2 -1
- package/template/coding-task-manager/lib/terminal-draft-http-status.js +25 -0
- package/template/coding-task-manager/lib/transcript-archiver.js +229 -229
- package/template/coding-task-manager/lib/transcript-frame-cache.js +12 -2
- package/template/coding-task-manager/lib/transcript-guard-job.js +55 -4
- package/template/coding-task-manager/lib/transcript-link.js +77 -0
- package/template/coding-task-manager/lib/transcript-manifest-store.js +8 -4
- package/template/coding-task-manager/lib/transcript-source.js +8 -3
- package/template/coding-task-manager/lib/transcript-store.js +40 -0
- package/template/coding-task-manager/lib/tunnel-lane-governor.js +6 -3
- package/template/coding-task-manager/lib/typing-interaction-trace.js +136 -2
- package/template/coding-task-manager/lib/typing-worker-stages.js +208 -1
- package/template/coding-task-manager/lib/usage-ledger/claude-parse.js +53 -2
- package/template/coding-task-manager/lib/usage-ledger/ingest.js +13 -4
- package/template/coding-task-manager/lib/usage-ledger/read.js +14 -0
- package/template/coding-task-manager/lib/usage-ledger/schema.js +49 -1
- package/template/coding-task-manager/lib/usage-ledger/store.js +337 -6
- package/template/coding-task-manager/lib/usage-ledger/task-read.js +123 -5
- package/template/coding-task-manager/lib/visible-revision-watchdog.js +8 -12
- package/template/coding-task-manager/lib/wake-skip-reasons.js +46 -0
- package/template/coding-task-manager/lib/walle-supervisor.js +98 -14
- package/template/coding-task-manager/lib/worker-failure-classify.js +13 -1
- package/template/coding-task-manager/lib/ws/input.js +1 -0
- package/template/coding-task-manager/lib/ws/state-sync.js +19 -2
- package/template/coding-task-manager/lib/ws/terminal-attach.js +32 -1
- package/template/coding-task-manager/lib/ws-router.js +68 -1
- package/template/coding-task-manager/lib/ws-send-admission.js +22 -4
- package/template/coding-task-manager/oauth-proxy.js +99 -55
- package/template/coding-task-manager/package-lock.json +24 -0
- package/template/coding-task-manager/package.json +3 -0
- package/template/coding-task-manager/protocol/message-table.json +0 -10
- package/template/coding-task-manager/protocol/messages.js +0 -10
- package/template/coding-task-manager/protocol/ws-schema.json +0 -20
- package/template/coding-task-manager/protocol/ws-schema.md +0 -2
- package/template/coding-task-manager/providers/codex-mcp-extract.js +121 -19
- package/template/coding-task-manager/providers/codex-mcp.js +14 -5
- package/template/coding-task-manager/public/css/app.css +279 -2
- package/template/coding-task-manager/public/css/reviews.css +4 -0
- package/template/coding-task-manager/public/index.html +297 -240
- package/template/coding-task-manager/public/js/app/machines-page.js +1252 -0
- package/template/coding-task-manager/public/js/app/models-tab.js +546 -36
- package/template/coding-task-manager/public/js/app/worktrees-panel.js +7 -5
- package/template/coding-task-manager/public/js/background-work.js +13 -7
- package/template/coding-task-manager/public/js/client-health-core.js +81 -0
- package/template/coding-task-manager/public/js/client-health-main.js +61 -0
- package/template/coding-task-manager/public/js/coding-session-model-presentation.js +44 -4
- package/template/coding-task-manager/public/js/core/session-commands.js +676 -0
- package/template/coding-task-manager/public/js/core/session-selectors.js +5 -1
- package/template/coding-task-manager/public/js/history-app-seam.js +26 -2
- package/template/coding-task-manager/public/js/history-painted-rows.js +17 -2
- package/template/coding-task-manager/public/js/history-reader-park.js +13 -1
- package/template/coding-task-manager/public/js/history-scroller.js +187 -9
- package/template/coding-task-manager/public/js/history-transcript-pages.js +5 -5
- package/template/coding-task-manager/public/js/machine-pool-shared.js +436 -0
- package/template/coding-task-manager/public/js/private-state-scope.js +31 -3
- package/template/coding-task-manager/public/js/prompt-submission-client.js +173 -4
- package/template/coding-task-manager/public/js/prompt-submission-tray.js +281 -0
- package/template/coding-task-manager/public/js/protocol.js +0 -10
- package/template/coding-task-manager/public/js/queue-panel-submission-reconcile.js +174 -1
- package/template/coding-task-manager/public/js/reviews.js +7 -3
- package/template/coding-task-manager/public/js/root-draft-lifetime.js +139 -2
- package/template/coding-task-manager/public/js/root-queue-builder-lifetime.js +16 -0
- package/template/coding-task-manager/public/js/row-join.js +18 -3
- package/template/coding-task-manager/public/js/session-model-picker.js +1 -1
- package/template/coding-task-manager/public/js/session-search-utils.js +46 -19
- package/template/coding-task-manager/public/js/session-usage-view.js +1 -0
- package/template/coding-task-manager/public/js/state-sync-client.js +4 -0
- package/template/coding-task-manager/public/js/terminal/runtime-02.js +16 -7
- package/template/coding-task-manager/public/js/terminal/runtime-03.js +41 -0
- package/template/coding-task-manager/public/js/terminal/runtime-04.js +41 -4
- package/template/coding-task-manager/public/js/terminal/runtime-12.js +52 -2
- package/template/coding-task-manager/public/js/terminal/runtime-16.js +12 -12
- package/template/coding-task-manager/public/js/terminal/runtime-18.js +14 -0
- package/template/coding-task-manager/public/js/terminal/runtime-19.js +8 -4
- package/template/coding-task-manager/public/js/terminal/runtime-20.js +210 -73
- package/template/coding-task-manager/public/js/terminal/runtime-21.js +19 -6
- package/template/coding-task-manager/public/js/terminal/runtime-22.js +86 -0
- package/template/coding-task-manager/public/js/terminal-history-viewport.js +1 -3
- package/template/coding-task-manager/public/js/terminal-wheel.js +39 -2
- package/template/coding-task-manager/public/js/walle/chat-conversation.js +11 -3
- package/template/coding-task-manager/public/js/walle-session.js +30 -7
- package/template/coding-task-manager/public/m/app.css +226 -8
- package/template/coding-task-manager/public/m/app.js +502 -9
- package/template/coding-task-manager/public/m/index.html +38 -1
- package/template/coding-task-manager/public/m/machines.js +1313 -0
- package/template/coding-task-manager/public/m/pool-failover.js +391 -0
- package/template/coding-task-manager/public/m/private-queue-actions.js +26 -7
- package/template/coding-task-manager/public/m/sw.js +5 -0
- package/template/coding-task-manager/queue-engine.js +13 -0
- package/template/coding-task-manager/server/approvals.js +5 -6
- package/template/coding-task-manager/server/boot.js +136 -17
- package/template/coding-task-manager/server.js +964 -425
- package/template/coding-task-manager/session-integrity.js +7 -9
- package/template/coding-task-manager/workers/db-owner-worker.js +53 -7
- package/template/coding-task-manager/workers/read-pool-worker.js +17 -6
- package/template/coding-task-manager/workers/session-host-pool-process.js +18 -4
- package/template/coding-task-manager/workers/session-host-process.js +14 -3
- package/template/coding-task-manager/workers/transcript-archive-worker.js +1 -1
- package/template/coding-task-manager/workers/worktree-worker.js +34 -0
- package/template/package-lock.json +2 -2
- package/template/package.json +1 -1
- package/template/scripts/conversation-storage-v2-migration.js +78 -11
- package/template/shared/conversation-storage-v2-contract.js +42 -6
- package/template/shared/fixtures/worker-status-payloads.json +392 -0
- package/template/shared/git-remote-key.js +83 -0
- package/template/shared/host-identity.js +98 -2
- package/template/shared/owner-write-safety.js +135 -0
- package/template/shared/public-runtime.js +13 -5
- package/template/shared/release-schema.json +3 -2
- package/template/shared/report-citations.js +14 -0
- package/template/shared/sqlite-write-lock.js +361 -223
- package/template/shared/storage/contract.js +35 -3
- package/template/wall-e/agent.js +21 -0
- package/template/wall-e/api-walle.js +5 -0
- package/template/wall-e/bin/brain-purge-legacy-ctm.js +3 -2
- package/template/wall-e/bin/walle-mcp-stdio.js +12 -6
- package/template/wall-e/brain/helper-rules-schema.js +129 -0
- package/template/wall-e/brain/migrations.js +51 -22
- package/template/wall-e/brain/model-deployment-facts.js +31 -1
- package/template/wall-e/brain/owner-call-whitelist.js +16 -0
- package/template/wall-e/brain/schema-ensures.js +22 -0
- package/template/wall-e/brain.js +1 -1
- package/template/wall-e/coding/host-capabilities.js +2 -2
- package/template/wall-e/coding/journal-dispatcher.js +51 -0
- package/template/wall-e/coding/session-journal.js +28 -40
- package/template/wall-e/coding-orchestrator.js +23 -26
- package/template/wall-e/fly.toml +1 -1
- package/template/wall-e/http/auth.js +18 -1
- package/template/wall-e/http/blog-views-api.js +318 -0
- package/template/wall-e/http/helper-rules-api.js +321 -0
- package/template/wall-e/http/model-proxy-providers.js +3 -1
- package/template/wall-e/http/telemetry-api.js +12 -0
- package/template/wall-e/lib/blog-view-policy.js +88 -0
- package/template/wall-e/lib/blog-view-store.js +169 -0
- package/template/wall-e/lib/client-config-lock.js +2 -1
- package/template/wall-e/lib/coding-journal-writer-child-client.js +67 -18
- package/template/wall-e/lib/error-kinds.js +10 -1
- package/template/wall-e/lib/feature-manifest.js +1 -1
- package/template/wall-e/lib/helper-rules/cell-state.js +123 -0
- package/template/wall-e/lib/helper-rules/evaluate.js +357 -0
- package/template/wall-e/lib/helper-rules/explore-rubric.md +12 -0
- package/template/wall-e/lib/helper-rules/grade.js +277 -0
- package/template/wall-e/lib/helper-rules/label.js +247 -0
- package/template/wall-e/lib/helper-rules/lead-call-hook.js +522 -0
- package/template/wall-e/lib/helper-rules/store.js +667 -0
- package/template/wall-e/lib/mcp-integration.js +5 -6
- package/template/wall-e/lib/runtime-worker-pool.js +1 -0
- package/template/wall-e/lib/scheduler-worker-jobs.js +6 -0
- package/template/wall-e/lib/telemetry-db-schema.js +37 -0
- package/template/wall-e/lib/telemetry-process-client.js +76 -1
- package/template/wall-e/llm/default-fallback.js +4 -0
- package/template/wall-e/llm/model-catalog.js +13 -4
- package/template/wall-e/llm/model-roles.js +6 -0
- package/template/wall-e/llm/portkey-http.js +150 -0
- package/template/wall-e/llm/portkey-sync.js +15 -145
- package/template/wall-e/llm/worker-mcp-routing.js +61 -0
- package/template/wall-e/llm/worker-route.js +43 -1
- package/template/wall-e/loops/brain-custom-writes.js +45 -0
- package/template/wall-e/mcp-protocol-contract.js +41 -1
- package/template/wall-e/mcp-server.js +13 -2
- package/template/wall-e/mcp-worker-schemas.js +20 -2
- package/template/wall-e/memory/ctm-context-client.js +25 -5
- package/template/wall-e/shared/release-schema.json +3 -2
- package/template/wall-e/shared/sqlite-write-lock.js +361 -223
- package/template/wall-e/shared/storage/contract.js +35 -3
- package/template/wall-e/skills/_templates/delegate-worker/VERSION +1 -1
- package/template/wall-e/skills/_templates/delegate-worker/released-sha256.json +6 -0
- package/template/wall-e/skills/_templates/delegate-worker/templates/claude/SKILL.md +7 -2
- package/template/wall-e/skills/_templates/delegate-worker/templates/codex/SKILL.md +7 -2
- package/template/wall-e/tools/local-tools.js +12 -5
- package/template/wall-e/workers/brain-owner-worker.js +9 -0
- package/template/wall-e/workers/coding-journal-writer-child.js +8 -1
- package/template/wall-e/workers/telemetry-worker.js +8 -0
- package/template/coding-task-manager/lib/giant-freeze-park.js +0 -31
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
const fs = require('fs');
|
|
17
17
|
const path = require('path');
|
|
18
|
+
const { writeStartupPointerGuarded, readStartupTaskProjectDir } = require('./lib/startup-pointer-write');
|
|
18
19
|
const crypto = require('crypto');
|
|
19
20
|
const claudeDesktopSessions = require('./lib/claude-desktop-sessions');
|
|
20
21
|
const { agentRowGhostVerdict } = require('./lib/session-identity-guard');
|
|
@@ -909,13 +910,8 @@ function recoverMismatches(db, issues, getAllSessionFiles, opts = {}) {
|
|
|
909
910
|
if (!issue.sessionId || !agentId || !resumeId) { result.skipped++; break; }
|
|
910
911
|
try {
|
|
911
912
|
const projectDir = issue.details?.jsonl_path ? path.dirname(issue.details.jsonl_path) : '';
|
|
912
|
-
|
|
913
|
-
const
|
|
914
|
-
const vals = [JSON.stringify(['resume', resumeId])];
|
|
915
|
-
if (cols.has('agent_project_dir')) { sets.push('agent_project_dir = ?'); vals.push(projectDir || null); }
|
|
916
|
-
if (cols.has('claude_project_dir')) { sets.push('claude_project_dir = ?'); vals.push(projectDir || null); }
|
|
917
|
-
vals.push(issue.sessionId);
|
|
918
|
-
const fixed = db.prepare(`UPDATE startup_tasks SET ${sets.join(', ')} WHERE ctm_session_id = ?`).run(...vals).changes || 0;
|
|
913
|
+
// WP-3: guarded writer (lib/startup-pointer-write.js) — an active transition's candidate fork is refused.
|
|
914
|
+
const fixed = writeStartupPointerGuarded(db, issue.sessionId, ['resume', resumeId], projectDir);
|
|
919
915
|
let removedSelfRows = 0;
|
|
920
916
|
if (issue.details?.has_empty_self_row) {
|
|
921
917
|
removedSelfRows = db.prepare(`
|
|
@@ -968,8 +964,10 @@ function recoverMismatches(db, issues, getAllSessionFiles, opts = {}) {
|
|
|
968
964
|
return arg;
|
|
969
965
|
});
|
|
970
966
|
if (changed) {
|
|
971
|
-
|
|
972
|
-
|
|
967
|
+
// WP-3: guarded writer; the stored dir columns are handed back so the alias heal never clears them.
|
|
968
|
+
fixed += writeStartupPointerGuarded(
|
|
969
|
+
db, issue.sessionId, healedArgs, readStartupTaskProjectDir(db, issue.sessionId),
|
|
970
|
+
);
|
|
973
971
|
}
|
|
974
972
|
}
|
|
975
973
|
}
|
|
@@ -48,6 +48,11 @@ const {
|
|
|
48
48
|
|
|
49
49
|
const db = require('../db');
|
|
50
50
|
const walleTranscript = require('../lib/walle-transcript');
|
|
51
|
+
// WP-3 (worker-transcript-link-derived-not-discovered-2026-10-25.html §5 D-5): the boot backfill
|
|
52
|
+
// predicts a transcript path from (cwd, agent_session_id) and VERIFIES it before linking
|
|
53
|
+
// (lib/transcript-link.js) -- the same derived-not-discovered pair WP-2's resume preflight uses.
|
|
54
|
+
const { deriveClaudeTranscriptPath } = require('../lib/resume-cwd');
|
|
55
|
+
const { verifyClaudeTranscriptAt } = require('../lib/transcript-link');
|
|
51
56
|
// WP-0a: the coding-session model-owner batch body (see the store's module doc). Required
|
|
52
57
|
// here (not lazily) because this worker is the only caller, and the store has no db.js edge.
|
|
53
58
|
const { persistModelSelectionBatch } = require('../lib/storage/coding-session-model-store');
|
|
@@ -673,7 +678,6 @@ async function _runOp(op, payload = {}, task = null) {
|
|
|
673
678
|
return { heldMs: durationMs };
|
|
674
679
|
}
|
|
675
680
|
case 'runBootRepairs': {
|
|
676
|
-
const titleRepair = db.repairSessionTitlesFromStartupTasks?.({ limit: 2000 }) || null;
|
|
677
681
|
const rolloutIdentityRepair = db.repairCodexRolloutAgentIdentities?.() || null;
|
|
678
682
|
const metadataRepair = db.repairCodexSessionMetadataFromConversations?.() || null;
|
|
679
683
|
const walleIdentity = require('../lib/migrations/dc-walle-identity-rekey');
|
|
@@ -685,7 +689,7 @@ async function _runOp(op, payload = {}, task = null) {
|
|
|
685
689
|
coreDb: db.getDomainDb('core'),
|
|
686
690
|
});
|
|
687
691
|
return {
|
|
688
|
-
|
|
692
|
+
rolloutIdentityRepair, metadataRepair,
|
|
689
693
|
walleIdentityRekey, walleIdentityAudit,
|
|
690
694
|
};
|
|
691
695
|
}
|
|
@@ -998,12 +1002,15 @@ async function _runOp(op, payload = {}, task = null) {
|
|
|
998
1002
|
// agent_sessions is CORE; this op runs on the base worker, so route the write to the
|
|
999
1003
|
// core handle (pre-flip/flag-off === getDb(); post-flip === core.db). The SQLite write
|
|
1000
1004
|
// lock serializes it against the core worker's own agent_sessions writes.
|
|
1005
|
+
// jsonl_path is an optional guarded link (WP-1/D-7): an empty payload value never blanks
|
|
1006
|
+
// an existing link, so a caller that only carries file metadata cannot unlink the row.
|
|
1001
1007
|
const result = db.getDomainDb('core').prepare(
|
|
1002
|
-
"UPDATE agent_sessions SET file_size = ?, compact_bak_size = ?, modified_at = ?, updated_at = datetime('now') WHERE agent_session_id = ?",
|
|
1008
|
+
"UPDATE agent_sessions SET file_size = ?, compact_bak_size = ?, modified_at = ?, jsonl_path = COALESCE(NULLIF(?, ''), jsonl_path), updated_at = datetime('now') WHERE agent_session_id = ?",
|
|
1003
1009
|
).run(
|
|
1004
1010
|
Number(payload.fileSize || 0),
|
|
1005
1011
|
Number(payload.compactBakSize || 0),
|
|
1006
1012
|
String(payload.modifiedAt || ''),
|
|
1013
|
+
String(payload.jsonlPath || ''),
|
|
1007
1014
|
sessionId,
|
|
1008
1015
|
);
|
|
1009
1016
|
return { updated: result.changes > 0 };
|
|
@@ -1163,8 +1170,8 @@ async function _runOp(op, payload = {}, task = null) {
|
|
|
1163
1170
|
case 'flushSessionDiagnostics': {
|
|
1164
1171
|
// Durable session-diagnostics batch write (INSERT + per-session retention sweep, one txn).
|
|
1165
1172
|
// Runs on THIS worker — the designated serial writer — so the cross-process SQLite
|
|
1166
|
-
// write
|
|
1167
|
-
//
|
|
1173
|
+
// write lock (and any wait for it) never blocks the main event loop under
|
|
1174
|
+
// multi-session contention.
|
|
1168
1175
|
const entries = Array.isArray(payload.entries) ? payload.entries : [];
|
|
1169
1176
|
if (!entries.length) return { inserted: 0, sessionsSwept: 0 };
|
|
1170
1177
|
return db.flushSessionDiagnostics(entries);
|
|
@@ -1278,10 +1285,10 @@ async function _runOp(op, payload = {}, task = null) {
|
|
|
1278
1285
|
case 'persistModelSelections': {
|
|
1279
1286
|
// The batch body lives in the model-owner store (WP-0a corrective pass); its two helper
|
|
1280
1287
|
// modules are required here and injected, so the store never requires them itself.
|
|
1281
|
-
const { isGenericCodingSessionLabel
|
|
1288
|
+
const { isGenericCodingSessionLabel } = require('../lib/coding-agent-models');
|
|
1282
1289
|
const { applyProviderTitle, canWriteTier3Title } = require('../lib/session-title-mirror');
|
|
1283
1290
|
return persistModelSelectionBatch(db, payload, {
|
|
1284
|
-
isGenericCodingSessionLabel,
|
|
1291
|
+
isGenericCodingSessionLabel, applyProviderTitle, canWriteTier3Title,
|
|
1285
1292
|
});
|
|
1286
1293
|
}
|
|
1287
1294
|
case 'bindCodingSessionModelState':
|
|
@@ -1481,6 +1488,45 @@ async function _runOp(op, payload = {}, task = null) {
|
|
|
1481
1488
|
tabs,
|
|
1482
1489
|
});
|
|
1483
1490
|
}
|
|
1491
|
+
case 'linkDerivedClaudeTranscripts': {
|
|
1492
|
+
// WP-3 / D-5: bounded, idempotent. agent_sessions is CORE -> flip-aware core handle (see
|
|
1493
|
+
// the updateAgentSessionFileMetadata comment above). `jsonl_path = ''` is the selector, so a
|
|
1494
|
+
// row this op has already linked (or any other writer has) is never re-selected: the pass is
|
|
1495
|
+
// idempotent by construction, not by a marker. A row is linked only when the derived path
|
|
1496
|
+
// resolves to a plain local file whose first record names this very session
|
|
1497
|
+
// (lib/transcript-link.js), so a wrong prediction is counted, never written.
|
|
1498
|
+
const limit = Math.min(500, Math.max(1, Number(payload.limit) || 500));
|
|
1499
|
+
const homeDir = String(payload.homeDir || '');
|
|
1500
|
+
const claudeConfigDir = String(payload.claudeConfigDir || '');
|
|
1501
|
+
const startedAt = Date.now();
|
|
1502
|
+
const rows = db.getDomainDb('core').prepare(
|
|
1503
|
+
"SELECT agent_session_id, project_path FROM agent_sessions WHERE provider = 'claude' AND COALESCE(jsonl_path, '') = '' AND COALESCE(project_path, '') <> '' ORDER BY created_at DESC LIMIT ?",
|
|
1504
|
+
).all(limit);
|
|
1505
|
+
const out = { checked: rows.length, linked: 0, missing: 0, mismatched: 0, unreadable: 0, ms: 0 };
|
|
1506
|
+
for (const row of rows) {
|
|
1507
|
+
_assertTaskLive(task); // cooperative cancellation: never outlive the caller's deadline
|
|
1508
|
+
let derived;
|
|
1509
|
+
try {
|
|
1510
|
+
derived = deriveClaudeTranscriptPath({
|
|
1511
|
+
cwd: row.project_path,
|
|
1512
|
+
agentSessionId: row.agent_session_id,
|
|
1513
|
+
homeDir: homeDir || undefined,
|
|
1514
|
+
claudeConfigDir,
|
|
1515
|
+
});
|
|
1516
|
+
} catch {
|
|
1517
|
+
out.missing += 1;
|
|
1518
|
+
continue; // expected: an unusable project_path/session id counts as "no transcript there"
|
|
1519
|
+
}
|
|
1520
|
+
const verified = await verifyClaudeTranscriptAt(derived, row.agent_session_id);
|
|
1521
|
+
if (verified.ok) {
|
|
1522
|
+
out.linked += db.updateAgentSessionTranscriptLink(row.agent_session_id, derived).updated ? 1 : 0;
|
|
1523
|
+
} else if (verified.state === 'id-mismatch') out.mismatched += 1;
|
|
1524
|
+
else if (verified.state === 'unreadable' || verified.state === 'archived') out.unreadable += 1;
|
|
1525
|
+
else out.missing += 1;
|
|
1526
|
+
}
|
|
1527
|
+
out.ms = Date.now() - startedAt;
|
|
1528
|
+
return out;
|
|
1529
|
+
}
|
|
1484
1530
|
case 'recoverSessionIntegrity': {
|
|
1485
1531
|
// Apply ONLY the recovery WRITES for issues the off-worker (read-pool) detect already
|
|
1486
1532
|
// found, so the heavy full-corpus detection scan never runs on this single serial
|
|
@@ -21,6 +21,7 @@ require('../../shared/network/external-network-guard').armExternalNetworkGuardFr
|
|
|
21
21
|
const { parentPort, workerData } = require('node:worker_threads');
|
|
22
22
|
const fs = require('node:fs'), path = require('node:path');
|
|
23
23
|
const transcriptSource = require('../lib/transcript-source');
|
|
24
|
+
const { readAgentTitleBackfillPage } = require('../lib/agent-title-backfill-read');
|
|
24
25
|
const { serializeCleanupError } = require('../lib/worker-error-metadata');
|
|
25
26
|
const { createErrorSink } = require('../lib/error-sink');
|
|
26
27
|
const {
|
|
@@ -149,13 +150,13 @@ function _recycleReadonlyDbIfNeeded(now = Date.now()) {
|
|
|
149
150
|
const expired = !!_roDb
|
|
150
151
|
&& (now - _roDbOpenedAt > _roConnMaxAgeMs || _roDbOpsServed >= _roConnMaxOps);
|
|
151
152
|
if (!forced && !expired) return false;
|
|
152
|
-
|
|
153
|
-
|
|
153
|
+
// Forced or expired (expired implies an open handle): close and certify a reader gap (R3 D-1b).
|
|
154
|
+
_closeReadonlyDb();
|
|
154
155
|
_roRecycleRequested = false;
|
|
155
156
|
for (const requestId of _roRecycleRequestIds.splice(0)) {
|
|
156
|
-
try { parentPort?.postMessage({ type: 'recycle-conn-complete', requestId, recycled }); } catch {}
|
|
157
|
+
try { parentPort?.postMessage({ type: 'recycle-conn-complete', requestId, recycled: true }); } catch {}
|
|
157
158
|
}
|
|
158
|
-
return
|
|
159
|
+
return true;
|
|
159
160
|
}
|
|
160
161
|
|
|
161
162
|
function _requestReadonlyRecycle(requestId = 0) {
|
|
@@ -1751,7 +1752,7 @@ async function _runOp(op, payload = {}, task = null) {
|
|
|
1751
1752
|
const conn = _readonlyRoutedDb(payload.dbPath);
|
|
1752
1753
|
const rowsForCatalog = require('../lib/all-sessions-query').queryAllSessionsData(conn);
|
|
1753
1754
|
observeRecentCatalogBacking(rowsForCatalog, { sourceExists });
|
|
1754
|
-
input.sessions = require('../lib/recent-catalog-query').mapRecentSessionRows(rowsForCatalog, { hostname: payload.hostname, liveSessionIds: new Set(payload.liveSessionIds || []) });
|
|
1755
|
+
input.sessions = require('../lib/recent-catalog-query').mapRecentSessionRows(rowsForCatalog, { hostname: payload.hostname, liveSessionIds: new Set(payload.liveSessionIds || []), machineTags: payload.machineTags });
|
|
1755
1756
|
const rows = conn.prepare("SELECT key, value FROM settings WHERE key IN ('ui_pinned_sessions', 'last_active_project')").all();
|
|
1756
1757
|
for (const row of rows) {
|
|
1757
1758
|
let value = null;
|
|
@@ -2712,13 +2713,21 @@ async function _runOp(op, payload = {}, task = null) {
|
|
|
2712
2713
|
// The retired-store branch was already unreachable once agent_sessions existed. Keeping this
|
|
2713
2714
|
// query on current metadata tables also prevents an obsolete-schema error path.
|
|
2714
2715
|
const conn = _readonlyRoutedDb(payload.dbPath);
|
|
2716
|
+
// D-7 (WP-3): the tier-3 input filter classifies a candidate's first_message with
|
|
2717
|
+
// shared/conversation-provenance.js, which reads the row's provider. Project it, but only
|
|
2718
|
+
// when the schema carries it — same "include the column only when present" guard as
|
|
2719
|
+
// startupTasksScan below, so a minimal/legacy agent_sessions never throws "no such column".
|
|
2720
|
+
// ctm_sessions.provider mirrors the same value, so agent_sessions is the only probe needed.
|
|
2721
|
+
const agentCols = new Set(conn.prepare('PRAGMA table_info(agent_sessions)').all().map((c) => c.name));
|
|
2722
|
+
const providerExpr = agentCols.has('provider') ? "COALESCE(NULLIF(a.provider, ''), 'claude')" : "'claude'";
|
|
2715
2723
|
const rows = conn.prepare(`
|
|
2716
|
-
SELECT session_id, first_message, user_msg_count
|
|
2724
|
+
SELECT session_id, first_message, user_msg_count, provider
|
|
2717
2725
|
FROM (
|
|
2718
2726
|
SELECT
|
|
2719
2727
|
COALESCE(NULLIF(a.ctm_session_id, ''), a.agent_session_id) AS session_id,
|
|
2720
2728
|
a.first_message,
|
|
2721
2729
|
COALESCE(a.user_msg_count, 0) AS user_msg_count,
|
|
2730
|
+
${providerExpr} AS provider,
|
|
2722
2731
|
COALESCE(NULLIF(a.modified_at, ''), a.updated_at, a.created_at) AS sort_ts,
|
|
2723
2732
|
ROW_NUMBER() OVER (
|
|
2724
2733
|
PARTITION BY COALESCE(NULLIF(a.ctm_session_id, ''), a.agent_session_id)
|
|
@@ -2741,6 +2750,8 @@ async function _runOp(op, payload = {}, task = null) {
|
|
|
2741
2750
|
return _transferJson({ rows });
|
|
2742
2751
|
}
|
|
2743
2752
|
|
|
2753
|
+
case 'backfillAgentTitles': return _transferJson(readAgentTitleBackfillPage(_readonlyRoutedDb(payload.dbPath), payload)); // WP-6: <=64 KiB tail per row
|
|
2754
|
+
|
|
2744
2755
|
case 'sessionSearchStatus': {
|
|
2745
2756
|
const conn = _readonlyRoutedDb(payload.dbPath);
|
|
2746
2757
|
let runtimeAvailable = false;
|
|
@@ -207,10 +207,15 @@ function createSessionState(sessionId, o) {
|
|
|
207
207
|
};
|
|
208
208
|
state.mirrorFeed = createHostedMirrorFeedCoalescer({
|
|
209
209
|
cmd: () => state.cmd || '',
|
|
210
|
-
|
|
210
|
+
// WP-4 (clock-free-tests-followups-r4-2026-10-24.html §5 R-9, §6.5): same `receivedAt` ->
|
|
211
|
+
// `hostReceivedAt` relay as the dedicated host (workers/session-host-process.js) -- this op
|
|
212
|
+
// never leaves this process, so the stamp rides the 'typing-stage' message instead.
|
|
213
|
+
deliver: (data, meta) => {
|
|
211
214
|
if (!data) return;
|
|
212
215
|
if (process.env.CTM_DEBUG_MIRROR_FEED) console.error(`[mirror-feed-debug] deliver sid=${sessionId.slice(0, 8)} bytes=${data.length}`);
|
|
213
|
-
Promise.resolve(headless.handleMessage({
|
|
216
|
+
Promise.resolve(headless.handleMessage({
|
|
217
|
+
type: 'feed', sessionId, data, hostReceivedAt: meta && meta.receivedAt,
|
|
218
|
+
}))
|
|
214
219
|
.then(() => { if (process.env.CTM_DEBUG_MIRROR_FEED) console.error(`[mirror-feed-debug] fed-ok sid=${sessionId.slice(0, 8)} bytes=${data.length}`); })
|
|
215
220
|
.catch((err) => hostError(sessionId, err, { code: 'headless_feed_failed' }));
|
|
216
221
|
},
|
|
@@ -516,7 +521,7 @@ async function handleHello(msg, ctx) {
|
|
|
516
521
|
// WP-3: protocolVersion is echoed unconditionally -- the dialer (manager or
|
|
517
522
|
// probeHostAlive) is what decides whether it matches; this worker doesn't
|
|
518
523
|
// validate the hello's own protocolVersion.
|
|
519
|
-
ctx.reply({ type: 'state', recoveryShutdownVersion: 1, protocolVersion: PROTOCOL_VERSION, floorVersion: FLOOR_VERSION, closureHash: HOST_CLOSURE.closureHash, closureFiles: HOST_CLOSURE.closureFiles, sessions: buildSessionsState() });
|
|
524
|
+
ctx.reply({ type: 'state', recoveryShutdownVersion: 1, protocolVersion: PROTOCOL_VERSION, floorVersion: FLOOR_VERSION, closureHash: HOST_CLOSURE.closureHash, closureFiles: HOST_CLOSURE.closureFiles, sessions: buildSessionsState(), threadpool: _threadpoolSnapshotForState() });
|
|
520
525
|
if (role === CONTROL_CONNECTION_ROLE.CONTROLLER) probeHold.release(); // probe: held frames go out AFTER `state` (the dial ignores earlier frames)
|
|
521
526
|
if (role === CONTROL_CONNECTION_ROLE.PROBE) return;
|
|
522
527
|
for (const [sessionId, state] of Array.from(sessions)) {
|
|
@@ -675,12 +680,19 @@ function shutdownOnSignal() {
|
|
|
675
680
|
}
|
|
676
681
|
process.on('SIGTERM', shutdownOnSignal);
|
|
677
682
|
process.on('SIGHUP', shutdownOnSignal);
|
|
683
|
+
// D-6 (docs/nightly-followups-r3-pty-selector-flakes-2026-10-22.html §5): process.exit(1) in the
|
|
684
|
+
// same turn as a spawn closes the masters with node-pty's helpers still pre-exec, which parks them
|
|
685
|
+
// in XNU's carrier wait and strands them as ppid-1 orphans (census B, Table 2). SIGHUP every open
|
|
686
|
+
// PTY group synchronously first -- the exit code and the log line are unchanged, and for an
|
|
687
|
+
// already-exec'd child a SIGHUP before exit has the same effect as the kernel hang-up at exit (P-2).
|
|
678
688
|
process.on('uncaughtException', (err) => {
|
|
679
689
|
hostError('', err, { code: 'uncaught_exception' });
|
|
690
|
+
for (const state of sessions.values()) { if (!state.ptyClosed) signalPtyGroup(state, 'SIGHUP'); }
|
|
680
691
|
process.exit(1);
|
|
681
692
|
});
|
|
682
693
|
process.on('unhandledRejection', (err) => {
|
|
683
694
|
hostError('', err, { code: 'unhandled_rejection' });
|
|
695
|
+
for (const state of sessions.values()) { if (!state.ptyClosed) signalPtyGroup(state, 'SIGHUP'); }
|
|
684
696
|
process.exit(1);
|
|
685
697
|
});
|
|
686
698
|
|
|
@@ -735,10 +747,12 @@ if (!CONTROL_SOCKET_PATH) send({ type: 'ready', pid: process.pid, closureHash: H
|
|
|
735
747
|
// Host self-truth watchdog (D-4): a worker_thread reads a SharedArrayBuffer stamped before every headless-term op, so a wedged main
|
|
736
748
|
// thread stays observable (lib/host-self-truth-watchdog.js). Deferred to setImmediate so new Worker() cannot delay the socket chmod.
|
|
737
749
|
setImmediate(() => startHostSelfTruthWatchdog({ role: 'session-host', hostId: `pool-${process.pid}` }));
|
|
738
|
-
|
|
750
|
+
function _threadpoolSnapshotForState() { try { const s = _threadpoolMonitor.snapshot(); return s ? { state: s.state, oldestPendingMs: Number(s.oldestPendingMs) || 0 } : null; } catch { return null; } /* expected: a state reply must never fail on the probe (WP-3 D-4/S-9) */ }
|
|
739
751
|
// Dead libuv threadpool = a named, REPORT-ONLY fact within 10s (lib/host-threadpool-monitor.js).
|
|
740
752
|
const _threadpoolMonitor = createHostThreadpoolMonitor({
|
|
741
753
|
rootDir: getDataDir(),
|
|
754
|
+
// WP-0 (D-6): every frame names the sessions with an op in flight (5 oldest).
|
|
755
|
+
extraSnapshot: () => ({ sessionOps: headless.oldestInFlightOps(5) }),
|
|
742
756
|
onFrame: (frame) => send({ type: 'host-threadpool', pid: process.pid, ...frame }),
|
|
743
757
|
});
|
|
744
758
|
_threadpoolMonitor.start();
|
|
@@ -123,10 +123,15 @@ const headless = bindHeadlessTerminalService({
|
|
|
123
123
|
const mirrorFeed = createHostedMirrorFeedCoalescer({
|
|
124
124
|
cmd: () => sessionCmd,
|
|
125
125
|
protectIncompleteOnFlush: MIRROR_CONTROL_FLUSH_GUARD_ENABLED,
|
|
126
|
-
|
|
126
|
+
// WP-4 (clock-free-tests-followups-r4-2026-10-24.html §5 R-9, §6.5): carry the coalescer's own
|
|
127
|
+
// receipt time (first byte of a held batch, now() for the immediate path) on the op, so
|
|
128
|
+
// lib/headless-term-service.js can stamp 'host-pty-data' at it. An older caller that passes no
|
|
129
|
+
// meta simply yields `undefined`, and the service then stamps nothing.
|
|
130
|
+
deliver: (data, meta) => {
|
|
127
131
|
if (!data) return;
|
|
128
|
-
Promise.resolve(headless.handleMessage({
|
|
129
|
-
|
|
132
|
+
Promise.resolve(headless.handleMessage({
|
|
133
|
+
type: 'feed', sessionId, data, hostReceivedAt: meta && meta.receivedAt,
|
|
134
|
+
})).catch((err) => hostError(err, { code: 'headless_feed_failed' }));
|
|
130
135
|
},
|
|
131
136
|
});
|
|
132
137
|
|
|
@@ -566,12 +571,18 @@ function shutdownOnSignal() {
|
|
|
566
571
|
}
|
|
567
572
|
process.on('SIGTERM', shutdownOnSignal);
|
|
568
573
|
process.on('SIGHUP', shutdownOnSignal);
|
|
574
|
+
// D-6 (docs/nightly-followups-r3-pty-selector-flakes-2026-10-22.html §5): process.exit(1) in the
|
|
575
|
+
// same turn as a spawn closes the master with node-pty's helper still pre-exec, parking it in
|
|
576
|
+
// XNU's carrier wait as a ppid-1 orphan. SIGHUP the open PTY group synchronously first; the exit
|
|
577
|
+
// code and the log line are unchanged (for an exec'd child this matches the kernel hang-up at exit).
|
|
569
578
|
process.on('uncaughtException', (err) => {
|
|
570
579
|
hostError(err, { code: 'uncaught_exception' });
|
|
580
|
+
if (!ptyClosed) signalPtyGroup('SIGHUP');
|
|
571
581
|
process.exit(1);
|
|
572
582
|
});
|
|
573
583
|
process.on('unhandledRejection', (err) => {
|
|
574
584
|
hostError(err, { code: 'unhandled_rejection' });
|
|
585
|
+
if (!ptyClosed) signalPtyGroup('SIGHUP');
|
|
575
586
|
process.exit(1);
|
|
576
587
|
});
|
|
577
588
|
|
|
@@ -42,7 +42,7 @@ async function runOp(message) {
|
|
|
42
42
|
const input = message.input || {};
|
|
43
43
|
const opts = { ...input, store: createStore(message.requestId) };
|
|
44
44
|
switch (message.op) {
|
|
45
|
-
case 'archive': return archiver.runArchiveCycle(opts); // WP-9: archive,
|
|
45
|
+
case 'archive': return archiver.runArchiveCycle(opts); // WP-1/WP-9: archive, recover, scrub
|
|
46
46
|
case 'digest': return archiver.runDigestCycle(opts); // D-24: digest idle files whose size changed, no compression
|
|
47
47
|
case 'restore': return archiver.restoreUnit(input, opts); // D-20: archived / trashed members back as plain files
|
|
48
48
|
default:
|
|
@@ -10,6 +10,12 @@ const { createErrorSink } = require('../lib/error-sink');
|
|
|
10
10
|
const { scanReviewRoots } = require('../lib/review-root-scan');
|
|
11
11
|
const { lsTree } = require('../lib/review-tree-scan')(gitUtils.git);
|
|
12
12
|
const untrackedDiffer = require('../lib/review-untracked-diff').createReviewUntrackedDiff({ git: gitUtils.git, parseDiff: gitUtils.parseDiff });
|
|
13
|
+
// WP-2 (docs/remote-hub-followups-credential-projects-rows-idempotency-2026-10-23.html §6): the ONE
|
|
14
|
+
// lossless project-entry decoder (lib/decode-project-entry.js — backtracking existence search, then
|
|
15
|
+
// the transcript "cwd" fallback; memoized) and the gate-scratch predicate. Both are pure/DB-free,
|
|
16
|
+
// which is why this worker (never db.js) can load them.
|
|
17
|
+
const { decodeClaudeProjectEntry } = require('../lib/decode-project-entry');
|
|
18
|
+
const { isGateScratchPath } = require('../lib/review-repo-admission');
|
|
13
19
|
|
|
14
20
|
const errorSink = createErrorSink({ name: 'worker:worktree' });
|
|
15
21
|
let activeTask = null;
|
|
@@ -104,6 +110,34 @@ async function runOp(op, payload = {}, context = {}) {
|
|
|
104
110
|
return { observation: await observeWorktree(cwd, payload.integrationBaseRef) };
|
|
105
111
|
case 'listWorktrees':
|
|
106
112
|
return { worktrees: await gitUtils.listWorktrees(cwd) };
|
|
113
|
+
case 'gitRemoteKeys': {
|
|
114
|
+
// Remote machine hub WP-4 (§6.5): normalized origin key per /api/projects path ('' for a
|
|
115
|
+
// non-repo), so a hub can match the same repo across machines. Cached in git-utils.
|
|
116
|
+
const rows = (Array.isArray(payload.paths) ? payload.paths : []).map(p => ({ path: p }));
|
|
117
|
+
await gitUtils.attachGitRemoteKeys(rows);
|
|
118
|
+
return { keys: Object.fromEntries(rows.map(row => [row.path, row.gitRemoteKey || ''])) };
|
|
119
|
+
}
|
|
120
|
+
case 'projectRows': {
|
|
121
|
+
// Remote hub follow-ups WP-2 (D-5..D-8, §9 S-8/S-9): the /api/projects rows for
|
|
122
|
+
// `$HOME/.claude/projects`. Claude encodes EVERY non-alphanumeric character of a project's
|
|
123
|
+
// cwd as '-', so the old main-thread `entry.replace(/-/g,'/')` named a path that does not
|
|
124
|
+
// exist for 529 of the lead's 540 entries (214 ms cold for 540 entries — hence this op).
|
|
125
|
+
// Per entry, in input order: decode with the lossless decoder, keep the row only when the
|
|
126
|
+
// decoded path really is a directory and is not one of the gate's own scratch checkouts,
|
|
127
|
+
// then attach the same normalized origin key the gitRemoteKeys op uses. The entry (not the
|
|
128
|
+
// decoded path) stays the row id, so the client's project identity is unchanged.
|
|
129
|
+
const rows = [];
|
|
130
|
+
for (const entry of Array.isArray(payload.entries) ? payload.entries : []) {
|
|
131
|
+
const projectPath = decodeClaudeProjectEntry(entry);
|
|
132
|
+
let isDirectory = false;
|
|
133
|
+
try { isDirectory = fs.statSync(projectPath).isDirectory(); }
|
|
134
|
+
catch { /* expected: a decoded path that is gone (or that never existed) is simply not listed */ }
|
|
135
|
+
if (!isDirectory || isGateScratchPath(projectPath)) continue;
|
|
136
|
+
rows.push({ id: entry, path: projectPath, exists: true });
|
|
137
|
+
}
|
|
138
|
+
await gitUtils.attachGitRemoteKeys(rows);
|
|
139
|
+
return { rows: rows.map(row => ({ id: row.id, path: row.path, exists: true, gitRemoteKey: row.gitRemoteKey || '' })) };
|
|
140
|
+
}
|
|
107
141
|
case 'scanRoots':
|
|
108
142
|
// Review Hub root feed (WP-3, task-4-brief.md D-2b): fs-only depth-limited walk, no
|
|
109
143
|
// git at all — a candidate is any directory containing a `.git` entry (file or dir,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "walle",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "walle",
|
|
9
|
-
"version": "0.10.
|
|
9
|
+
"version": "0.10.2",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"pg": "^8.22.0"
|
package/template/package.json
CHANGED
|
@@ -25,6 +25,7 @@ const {
|
|
|
25
25
|
classifyRetainedConversationRow,
|
|
26
26
|
retainedHistorySqlPredicate: _retainedHistoryRowPredicate,
|
|
27
27
|
sanitizeInspectionViolations,
|
|
28
|
+
WALLE_BASELINE_EMPTY_COLUMNS,
|
|
28
29
|
} = require('../shared/conversation-storage-v2-contract');
|
|
29
30
|
const { classifyUserProvenance } = require('../shared/conversation-provenance');
|
|
30
31
|
const ctmStore = require('../coding-task-manager/lib/conversation-store-v2');
|
|
@@ -973,7 +974,11 @@ function _convertWalleConversationEventPayload(db) {
|
|
|
973
974
|
forked_from_turn_id=substr(json_extract(payload_json,'$.forked_from_turn_id'),1,240),
|
|
974
975
|
permanent=CAST(json_extract(payload_json,'$.permanent') AS INTEGER)
|
|
975
976
|
WHERE json_valid(payload_json)`);
|
|
976
|
-
|
|
977
|
+
// R-2 (clock-free r4 D-1): payload_json is one of the 8 allowed Wall-E baseline
|
|
978
|
+
// columns, so the typed-column conversion above is followed by an in-place
|
|
979
|
+
// sanitize instead of a DROP. The returned change count replaces the old
|
|
980
|
+
// _dropColumns result in the purge report.
|
|
981
|
+
return db.prepare("UPDATE conversation_events SET payload_json='{}' WHERE payload_json <> '{}'").run().changes;
|
|
977
982
|
}
|
|
978
983
|
|
|
979
984
|
function _retainSafeCtmHistoryRows(db) {
|
|
@@ -1091,24 +1096,24 @@ function purgeWalleLegacy(db) {
|
|
|
1091
1096
|
}
|
|
1092
1097
|
if (_tableExists(db, 'chat_messages')) {
|
|
1093
1098
|
report.chat_messages_deleted = db.prepare("DELETE FROM chat_messages WHERE role NOT IN ('user','assistant') OR length(trim(content))=0").run().changes;
|
|
1094
|
-
if (_columns(db, 'chat_messages').includes('attachments')) {
|
|
1095
|
-
report.chat_messages_sanitized = db.prepare('UPDATE chat_messages SET attachments=NULL WHERE attachments IS NOT NULL').run().changes;
|
|
1096
|
-
}
|
|
1097
1099
|
}
|
|
1098
1100
|
if (_tableExists(db, 'runtime_events')) {
|
|
1099
1101
|
report.runtime_events_deleted = _deleteAll(db, 'runtime_events');
|
|
1100
1102
|
}
|
|
1101
1103
|
try { db.exec('DROP INDEX IF EXISTS idx_chat_message_parts_type; DROP INDEX IF EXISTS idx_runtime_events_tool;'); } catch {}
|
|
1102
|
-
report.chat_message_columns = _dropColumns(db, 'chat_messages', ['attachments']);
|
|
1103
1104
|
report.chat_part_columns = _dropColumns(db, 'chat_message_parts', ['tool_name','status','title','summary','data_json','model_projection']);
|
|
1104
1105
|
report.runtime_event_columns = _dropColumns(db, 'runtime_events', ['message_id','tool_name','summary','payload_json']);
|
|
1105
|
-
report.skill_execution_columns = _dropColumns(db, 'skill_executions', ['tool_calls','tool_results','error'
|
|
1106
|
+
report.skill_execution_columns = _dropColumns(db, 'skill_executions', ['tool_calls','tool_results','error']);
|
|
1106
1107
|
report.coding_session_columns = _dropColumns(db, 'coding_agent_sessions', ['tool_calls','files_modified','git_diff']);
|
|
1107
|
-
report.conversation_turn_columns = _dropColumns(db, 'conversation_turns', ['attachments_json']);
|
|
1108
|
-
report.context_snapshot_columns = _dropColumns(db, 'conversation_context_snapshots', ['messages_json','provider_request_ref']);
|
|
1109
|
-
report.attempt_columns = _dropColumns(db, 'conversation_attempts', ['error']);
|
|
1110
|
-
report.context_generation_columns = _dropColumns(db, 'conversation_context_generations', ['messages_json']);
|
|
1111
1108
|
report.conversation_event_columns = _convertWalleConversationEventPayload(db);
|
|
1109
|
+
// R-2 (clock-free r4 D-1): the 8 Wall-E baseline columns are sanitized in place, never
|
|
1110
|
+
// dropped -- Wall-E still writes conversation_context_snapshots.messages_json, so a
|
|
1111
|
+
// DROP here breaks every later appendRunAttempt. The generic step replaces the former
|
|
1112
|
+
// inline `UPDATE chat_messages SET attachments=NULL` and the 8 _dropColumns entries;
|
|
1113
|
+
// the other prohibited columns keep their drops above. It runs AFTER
|
|
1114
|
+
// _convertWalleConversationEventPayload so conversation_events.payload_json is still
|
|
1115
|
+
// readable when the typed-column extraction reads it (that call owns emptying it).
|
|
1116
|
+
report.baseline_empty_sanitized = _sanitizeWalleBaselineEmptyColumns(db);
|
|
1112
1117
|
report.initiative_columns = _dropColumns(db, 'initiative_log', ['state_snapshot','reasoning','decision_data']);
|
|
1113
1118
|
report.session_columns = _dropColumns(db, 'sessions', ['compacted_messages','metadata']);
|
|
1114
1119
|
report.shadow_result_columns = _dropColumns(db, 'shadow_results', ['judge_reasoning','error']);
|
|
@@ -1175,6 +1180,49 @@ function _prohibitedColumns(kind) {
|
|
|
1175
1180
|
};
|
|
1176
1181
|
}
|
|
1177
1182
|
|
|
1183
|
+
// D-1 (clock-free r4): the conversation-storage v2 contract protects CONTENT, not
|
|
1184
|
+
// columns. These 8 columns are Wall-E's own baseline DDL (wall-e/brain/schema.js
|
|
1185
|
+
// createTables(), additive-only) and are legitimately present on every fresh brain.
|
|
1186
|
+
// Their mere presence is not a violation; a non-empty value is
|
|
1187
|
+
// (code 'prohibited_rows'). The empty set lives in the contract module so no
|
|
1188
|
+
// literal is duplicated here. `_quoteIdentifier` guards the identifier; the empty
|
|
1189
|
+
// value is a fixed contract constant, inlined as an SQL literal because
|
|
1190
|
+
// _countWhere/_existsWhere take no bind parameters.
|
|
1191
|
+
function _walleBaselineEmptyColumns() {
|
|
1192
|
+
return Object.entries(WALLE_BASELINE_EMPTY_COLUMNS)
|
|
1193
|
+
.map(([id, { empty }]) => {
|
|
1194
|
+
const separator = id.indexOf('.');
|
|
1195
|
+
return { id, table: id.slice(0, separator), column: id.slice(separator + 1), empty };
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
function _walleEmptySqlLiteral(empty) {
|
|
1200
|
+
return empty === null ? 'NULL' : `'${String(empty).replace(/'/g, "''")}'`;
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
function _walleBaselineEmptyPredicate(column, empty) {
|
|
1204
|
+
const col = _quoteIdentifier(column);
|
|
1205
|
+
// A NULL value is always "empty"; a NOT NULL column (three of the 8) still
|
|
1206
|
+
// takes its literal empty value, which is what the equality branch matches.
|
|
1207
|
+
if (empty === null) return `${col} IS NOT NULL`;
|
|
1208
|
+
return `NOT (${col} IS NULL OR ${col} = ${_walleEmptySqlLiteral(empty)})`;
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
// R-2 (clock-free r4): sanitize the 8 in place instead of dropping them, so a
|
|
1212
|
+
// Wall-E writer naming one of these columns (observed: conversation_context_snapshots.messages_json,
|
|
1213
|
+
// wall-e/brain/conversation.js:315-318) keeps working after the purge.
|
|
1214
|
+
function _sanitizeWalleBaselineEmptyColumns(db) {
|
|
1215
|
+
const report = {};
|
|
1216
|
+
for (const { id, table, column, empty } of _walleBaselineEmptyColumns()) {
|
|
1217
|
+
if (!_columns(db, table).includes(column)) continue;
|
|
1218
|
+
const where = _walleBaselineEmptyPredicate(column, empty);
|
|
1219
|
+
report[id] = db.prepare(
|
|
1220
|
+
`UPDATE ${_quoteIdentifier(table)} SET ${_quoteIdentifier(column)} = ${_walleEmptySqlLiteral(empty)} WHERE ${where}`,
|
|
1221
|
+
).run().changes;
|
|
1222
|
+
}
|
|
1223
|
+
return report;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1178
1226
|
function _countWhere(db, table, where = '1=1') {
|
|
1179
1227
|
if (!_tableExists(db, table)) return 0;
|
|
1180
1228
|
try { return Number(db.prepare(`SELECT COUNT(*) AS n FROM ${_quoteIdentifier(table)} WHERE ${where}`).get().n); }
|
|
@@ -1195,9 +1243,15 @@ function inspectDatabaseAbsence(db, {
|
|
|
1195
1243
|
allowRetainedCtmHistoryRows = false, countViolations = false,
|
|
1196
1244
|
} = {}) {
|
|
1197
1245
|
const prohibitedColumns = [];
|
|
1246
|
+
// D-1 (clock-free r4): the 8 Wall-E baseline columns are allowed to be present
|
|
1247
|
+
// while empty, so they are skipped here and content-checked below instead.
|
|
1248
|
+
const baselineEmptyIds = kind === 'walle' ? new Set(Object.keys(WALLE_BASELINE_EMPTY_COLUMNS)) : null;
|
|
1198
1249
|
for (const [table, names] of Object.entries(_prohibitedColumns(kind))) {
|
|
1199
1250
|
const present = new Set(_columns(db, table));
|
|
1200
|
-
for (const column of names)
|
|
1251
|
+
for (const column of names) {
|
|
1252
|
+
if (baselineEmptyIds?.has(`${table}.${column}`)) continue;
|
|
1253
|
+
if (present.has(column)) prohibitedColumns.push({ table, column });
|
|
1254
|
+
}
|
|
1201
1255
|
}
|
|
1202
1256
|
const existingLegacyTables = kind === 'ctm'
|
|
1203
1257
|
? CTM_LEGACY_CONVERSATION_TABLES.filter((table) => _tableExists(db, table))
|
|
@@ -1270,6 +1324,19 @@ function inspectDatabaseAbsence(db, {
|
|
|
1270
1324
|
addRows('chat_messages', "role NOT IN ('user','assistant') OR length(trim(content))=0");
|
|
1271
1325
|
if (_tableExists(db, 'memories')) addRows('memories',
|
|
1272
1326
|
"source IN ('claude-code-jsonl','codex-jsonl','gemini-jsonl','opencode-jsonl','walle-jsonl') OR memory_type LIKE 'coding_session_%'");
|
|
1327
|
+
// D-1 (clock-free r4): each allowed baseline column still fails closed on
|
|
1328
|
+
// CONTENT -- a row whose value is neither NULL nor the column's empty value
|
|
1329
|
+
// is a prohibited_rows violation keyed by `<table>.<column>`.
|
|
1330
|
+
for (const { id, table, column, empty } of _walleBaselineEmptyColumns()) {
|
|
1331
|
+
if (!_columns(db, table).includes(column)) continue;
|
|
1332
|
+
const where = _walleBaselineEmptyPredicate(column, empty);
|
|
1333
|
+
if (countViolations) {
|
|
1334
|
+
const count = _countWhere(db, table, where);
|
|
1335
|
+
if (count > 0) prohibitedRows.push({ table: id, count });
|
|
1336
|
+
} else if (_existsWhere(db, table, where)) {
|
|
1337
|
+
prohibitedRows.push({ table: id, count: 1 });
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1273
1340
|
}
|
|
1274
1341
|
const violations = sanitizeInspectionViolations([
|
|
1275
1342
|
...prohibitedColumns.map(({ table, column }) => ({
|
|
@@ -171,8 +171,19 @@ const INSPECTION_CODES = Object.freeze(new Set([
|
|
|
171
171
|
'prohibited_tables',
|
|
172
172
|
'retained_history_guard_missing',
|
|
173
173
|
'retained_history_dirty',
|
|
174
|
+
'inspection_failed',
|
|
174
175
|
]));
|
|
175
176
|
|
|
177
|
+
// REPORT (clock-free r6 OQ-5): an inspection that throws still plans a rerun, but the
|
|
178
|
+
// boot log names the error class -- the handful of SQLite driver codes and errno-style
|
|
179
|
+
// `E*` names -- instead of an empty violation list. Anything else is 'unknown_error'.
|
|
180
|
+
const INSPECTION_ERROR_CLASS_RE = /^(?:SQLITE_[A-Z_]{1,40}|E[A-Z]{2,20})$/;
|
|
181
|
+
|
|
182
|
+
function inspectionErrorClass(error) {
|
|
183
|
+
const code = error && typeof error === 'object' ? error.code : undefined;
|
|
184
|
+
return typeof code === 'string' && INSPECTION_ERROR_CLASS_RE.test(code) ? code : 'unknown_error';
|
|
185
|
+
}
|
|
186
|
+
|
|
176
187
|
// The walle prohibited-table and table.column ids below are copied verbatim from
|
|
177
188
|
// _prohibitedColumns('walle') in scripts/conversation-storage-v2-migration.js so that a
|
|
178
189
|
// walle inspection violation is nameable in the boot log instead of collapsing to
|
|
@@ -230,6 +241,21 @@ const WALLE_PROHIBITED_COLUMN_IDS = Object.freeze([
|
|
|
230
241
|
'eval_diagnostics.tool_sequence',
|
|
231
242
|
]);
|
|
232
243
|
|
|
244
|
+
// The 8 inherited Wall-E baseline columns (wall-e/brain/schema.js createTables(), additive-only
|
|
245
|
+
// ruling wall-e/brain/migrations.js:1741-1745). Allowed while every value is empty; any other
|
|
246
|
+
// value is a prohibited_rows violation (user ruling 2026-10-24, clock-free r4 D-1).
|
|
247
|
+
const WALLE_BASELINE_EMPTY_COLUMNS = Object.freeze({
|
|
248
|
+
'chat_messages.attachments': Object.freeze({ empty: null }),
|
|
249
|
+
'skill_executions.decision_reason': Object.freeze({ empty: null }),
|
|
250
|
+
'conversation_turns.attachments_json': Object.freeze({ empty: '[]' }),
|
|
251
|
+
'conversation_context_snapshots.messages_json': Object.freeze({ empty: '[]' }),
|
|
252
|
+
'conversation_context_snapshots.provider_request_ref': Object.freeze({ empty: null }),
|
|
253
|
+
'conversation_attempts.error': Object.freeze({ empty: null }),
|
|
254
|
+
'conversation_events.payload_json': Object.freeze({ empty: '{}' }),
|
|
255
|
+
'conversation_context_generations.messages_json': Object.freeze({ empty: '[]' }),
|
|
256
|
+
});
|
|
257
|
+
// exported next to WALLE_PROHIBITED_COLUMN_IDS; every key MUST also be in that list.
|
|
258
|
+
|
|
233
259
|
const FIXED_INSPECTION_OBJECT_IDS = Object.freeze(new Set([
|
|
234
260
|
...CTM_KNOWN_CONVERSATION_TABLES,
|
|
235
261
|
...CTM_RETAINED_HISTORY_TABLES,
|
|
@@ -346,12 +372,18 @@ function sanitizeInspectionViolations(violations) {
|
|
|
346
372
|
for (const violation of violations) {
|
|
347
373
|
if (!violation || typeof violation !== 'object' || Array.isArray(violation)) continue;
|
|
348
374
|
if (typeof violation.code !== 'string' || !INSPECTION_CODES.has(violation.code)) continue;
|
|
349
|
-
const objectId =
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
375
|
+
const objectId = violation.code === 'inspection_failed'
|
|
376
|
+
? (typeof violation.objectId === 'string'
|
|
377
|
+
&& (violation.objectId === 'unknown_error'
|
|
378
|
+
|| INSPECTION_ERROR_CLASS_RE.test(violation.objectId))
|
|
379
|
+
? violation.objectId
|
|
380
|
+
: 'unknown_error')
|
|
381
|
+
: (typeof violation.objectId === 'string'
|
|
382
|
+
&& (FIXED_INSPECTION_OBJECT_IDS.has(violation.objectId)
|
|
383
|
+
|| (violation.code === 'unknown_conversation_table_rows'
|
|
384
|
+
&& UNKNOWN_TABLE_OBJECT_ID_RE.test(violation.objectId)))
|
|
385
|
+
? violation.objectId
|
|
386
|
+
: 'unknown_schema_object');
|
|
355
387
|
const count = Number(violation.count);
|
|
356
388
|
if (!Number.isFinite(count) || count <= 0) continue;
|
|
357
389
|
const key = `${violation.code}\0${objectId}`;
|
|
@@ -380,7 +412,11 @@ module.exports = {
|
|
|
380
412
|
CTM_CONTENT_BEARING_TABLES,
|
|
381
413
|
CTM_KNOWN_CONVERSATION_TABLES,
|
|
382
414
|
CONVERSATION_TABLE_NAME_RE,
|
|
415
|
+
WALLE_PROHIBITED_TABLES,
|
|
416
|
+
WALLE_PROHIBITED_COLUMN_IDS,
|
|
417
|
+
WALLE_BASELINE_EMPTY_COLUMNS,
|
|
383
418
|
classifyRetainedConversationRow,
|
|
384
419
|
retainedHistorySqlPredicate,
|
|
385
420
|
sanitizeInspectionViolations,
|
|
421
|
+
inspectionErrorClass,
|
|
386
422
|
};
|