create-walle 0.10.1 → 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 +4 -0
- 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 +6 -4
- package/package.json +1 -1
- 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/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/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 +5 -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-launch-health.js +29 -2
- package/template/coding-task-manager/lib/codex-link-preparation.js +9 -8
- package/template/coding-task-manager/lib/codex-paths.js +2 -1
- 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-schema-source-files.js +1 -0
- package/template/coding-task-manager/lib/feature-manifest.js +1 -1
- package/template/coding-task-manager/lib/fs-watcher.js +3 -2
- package/template/coding-task-manager/lib/harness-history-transition.js +3 -3
- 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 +55 -17
- 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/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-switch-runtime.js +57 -4
- package/template/coding-task-manager/lib/lead-model-switch.js +3 -2
- 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 +1 -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 +52 -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-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/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/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 +2 -2
- 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-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/read-pool-client.js +5 -2
- package/template/coding-task-manager/lib/read-pool-op-registry.js +10 -1
- 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 +13 -1
- 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 +33 -2
- package/template/coding-task-manager/lib/root-prompt-flow.js +167 -33
- package/template/coding-task-manager/lib/scrollback-archive-store.js +7 -4
- 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 +34 -37
- 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 +18 -0
- package/template/coding-task-manager/lib/session-model-action-preconditions.js +9 -0
- package/template/coding-task-manager/lib/session-resource-sampler.js +19 -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-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 +92 -0
- package/template/coding-task-manager/lib/typing-worker-stages.js +60 -0
- 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/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/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 -1
- package/template/coding-task-manager/public/css/reviews.css +4 -0
- package/template/coding-task-manager/public/index.html +294 -223
- 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/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 -8
- package/template/coding-task-manager/public/js/prompt-submission-tray.js +281 -0
- 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 +4 -2
- 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/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 -1
- 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 +902 -239
- 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/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/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 +6 -4
- 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
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Lead-cost routing WP-5b (design §6.7, contract §2/S-11..S-18): the ONE place a lead's
|
|
4
|
+
// Wall-E tool call is remembered, and the only writer of wait-watch / explore outcomes
|
|
5
|
+
// outside WP-5a's store.
|
|
6
|
+
//
|
|
7
|
+
// The MCP dispatch (mcp-server.js) calls recordLeadToolCall(...) once per lead-tool call --
|
|
8
|
+
// one line per site, because that file is at its frozen size ceiling. Everything the rules
|
|
9
|
+
// need is derived here:
|
|
10
|
+
//
|
|
11
|
+
// 1. a ring buffer of the lead's last CALL_RING calls, so "what did the lead do next?"
|
|
12
|
+
// is answerable without ever reading the lead's transcript (the hook has no fs import);
|
|
13
|
+
// 2. a bounded map of the workers the lead launched (ctm_session_id → route/agent/
|
|
14
|
+
// invocation/profile), which is what turns a worker id into the wait-watch cell key;
|
|
15
|
+
// 3. the outcome rows themselves: a watcher wake or silent tick is opened as a PENDING wait
|
|
16
|
+
// outcome by the WAIT call that produced it and labelled by the lead's NEXT call
|
|
17
|
+
// (label.js's pure functions); an exploration hand-off is opened by the delegate call and
|
|
18
|
+
// closed by the status/wait call that reports it terminal.
|
|
19
|
+
//
|
|
20
|
+
// Every write goes through loops/brain-write (the owner-routing seam): the loop process holds
|
|
21
|
+
// a read-write brain, the scheduler/MCP worker routes the same call to the brain owner. It is
|
|
22
|
+
// required lazily, per write, for two reasons: lib/ must not hold a module-top reference into
|
|
23
|
+
// loops/ (the shared-walle dependency ladder), and a test can then substitute its own writer
|
|
24
|
+
// by seeding require.cache for loops/brain-write.
|
|
25
|
+
//
|
|
26
|
+
// Nothing here is allowed to fail a lead's tool call: every write is fire-and-forget with a
|
|
27
|
+
// reporter that warns at most once a minute, and the recordLeadToolCall body is guarded.
|
|
28
|
+
|
|
29
|
+
const {
|
|
30
|
+
LABEL_VERSION,
|
|
31
|
+
factsFromPayload,
|
|
32
|
+
labelFromFacts,
|
|
33
|
+
labelLateEnd,
|
|
34
|
+
workerPayloadOf,
|
|
35
|
+
} = require('./label');
|
|
36
|
+
const { leadAgentFromClientInfo } = require('./cell-state');
|
|
37
|
+
const { gradeHandoff, gradeToJson, readGraderModel, shouldGrade } = require('./grade');
|
|
38
|
+
|
|
39
|
+
const ANONYMOUS_LEAD = 'anonymous';
|
|
40
|
+
const CALL_RING = 8;
|
|
41
|
+
const MAP_MAX = 256;
|
|
42
|
+
const WARN_THROTTLE_MS = 60000;
|
|
43
|
+
// §6.7: a pending outcome whose lead never called back is not evidence -- 10 minutes is the
|
|
44
|
+
// point where "the wake bought nothing" is the honest reading (the wait it belongs to has
|
|
45
|
+
// long since returned).
|
|
46
|
+
const PENDING_TTL_MS = 10 * 60 * 1000;
|
|
47
|
+
|
|
48
|
+
// The two tools that park on a worker. Their results carry watcher_decisions / woke_on.
|
|
49
|
+
const WAIT_TOOLS = new Set(['walle_worker_wait', 'walle_worker_status']);
|
|
50
|
+
// A worker status that means the hand-off is over (report_ready is CTM's terminal-with-report).
|
|
51
|
+
const TERMINAL_STATUSES = new Set(['report_ready', 'failed', 'exited']);
|
|
52
|
+
|
|
53
|
+
let callsByLead = new Map(); // lead key -> [ { tool, at, args } ] (last CALL_RING)
|
|
54
|
+
let workerRoutes = new Map(); // ctm_session_id -> { route, agent, invocation_id, profile }
|
|
55
|
+
let workerLeads = new Map(); // ctm_session_id -> lead key (owner of the delegation)
|
|
56
|
+
let pending = []; // wait-watch outcomes waiting for the lead's next call
|
|
57
|
+
let lastDecisionByWorker = new Map(); // worker_id -> the last decision the watcher recorded
|
|
58
|
+
let openHandoffs = new Map(); // ctm_session_id -> { id, opened_at, brief_path } (best-effort cache; D-5)
|
|
59
|
+
// D-5/S-5: every worker id this process already sent a close for. A close is keyed on the row's
|
|
60
|
+
// worker_id (the store resolves it), so a restart cannot orphan it -- this set is only what keeps
|
|
61
|
+
// repeated terminal reads of one worker from re-sending the same close.
|
|
62
|
+
let closedWorkers = new Set();
|
|
63
|
+
let lastWarnAt = 0;
|
|
64
|
+
|
|
65
|
+
// --- small helpers -----------------------------------------------------------------
|
|
66
|
+
|
|
67
|
+
function _leadKey(agentSessionId) {
|
|
68
|
+
const value = typeof agentSessionId === 'string' ? agentSessionId.trim() : '';
|
|
69
|
+
return value || ANONYMOUS_LEAD;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function _atMs(at) {
|
|
73
|
+
const value = at == null ? Date.now() : at;
|
|
74
|
+
if (value instanceof Date) return Number.isFinite(value.getTime()) ? value.getTime() : Date.now();
|
|
75
|
+
if (typeof value === 'number') return Number.isFinite(value) ? value : Date.now();
|
|
76
|
+
const parsed = Date.parse(String(value));
|
|
77
|
+
return Number.isFinite(parsed) ? parsed : Date.now();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function _stamp(ms) {
|
|
81
|
+
return new Date(ms).toISOString();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function _string(value) {
|
|
85
|
+
return typeof value === 'string' ? value : '';
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function _evict(map, extraMap) {
|
|
89
|
+
while (map.size > MAP_MAX) {
|
|
90
|
+
const oldest = map.keys().next().value;
|
|
91
|
+
map.delete(oldest);
|
|
92
|
+
if (extraMap) extraMap.delete(oldest);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// The owner-routing write seam (see the header). Never throws: a missing/unreachable brain is
|
|
97
|
+
// a warning, not a failed tool call.
|
|
98
|
+
function _warn(message) {
|
|
99
|
+
const now = Date.now();
|
|
100
|
+
if (now - lastWarnAt < WARN_THROTTLE_MS) return;
|
|
101
|
+
lastWarnAt = now;
|
|
102
|
+
console.warn(`[helper-rules] ${message}`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function _write(method, ...args) {
|
|
106
|
+
const fail = (err) => _warn(`${method} failed: ${err && err.message ? err.message : err}`);
|
|
107
|
+
try {
|
|
108
|
+
Promise.resolve(require('../../loops/brain-write').brainWrite(method, ...args)).catch(fail);
|
|
109
|
+
} catch (err) {
|
|
110
|
+
fail(err); // REPORT: the write seam itself is unavailable -- the tool call still succeeds
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Same seam and the same never-throw contract as _write, but the resolved result is handed to
|
|
115
|
+
// `onResult` (WP-6: the close write is what returns the row's `seq`, the grader's sampling
|
|
116
|
+
// counter). A throw from `onResult` is reported like any other failure -- never propagated.
|
|
117
|
+
function _writeThen(method, args, onResult) {
|
|
118
|
+
const fail = (err) => _warn(`${method} failed: ${err && err.message ? err.message : err}`);
|
|
119
|
+
try {
|
|
120
|
+
Promise.resolve(require('../../loops/brain-write').brainWrite(method, ...args))
|
|
121
|
+
.then((result) => onResult(result))
|
|
122
|
+
.catch(fail);
|
|
123
|
+
} catch (err) {
|
|
124
|
+
fail(err); // REPORT: the write seam itself is unavailable -- the tool call still succeeds
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// --- reads the wait path and the panel use ------------------------------------------
|
|
129
|
+
|
|
130
|
+
/** The delegation record of one worker, or null. Never throws. */
|
|
131
|
+
function workerRouteOf(ctmSessionId) {
|
|
132
|
+
const entry = workerRoutes.get(_string(ctmSessionId));
|
|
133
|
+
return entry ? { ...entry } : null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Every worker this lead launched, oldest first (the whole-set wait's mode is over these). */
|
|
137
|
+
function leadWorkersOf(agentSessionId) {
|
|
138
|
+
const lead = _leadKey(agentSessionId);
|
|
139
|
+
const out = [];
|
|
140
|
+
for (const [ctmSessionId, entry] of workerRoutes) {
|
|
141
|
+
if (workerLeads.get(ctmSessionId) === lead) out.push({ ctm_session_id: ctmSessionId, ...entry });
|
|
142
|
+
}
|
|
143
|
+
return out;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Test seam: empties every buffer this module keeps (no clock, no db, no other side effect). */
|
|
147
|
+
function _resetForTests() {
|
|
148
|
+
callsByLead = new Map();
|
|
149
|
+
workerRoutes = new Map();
|
|
150
|
+
workerLeads = new Map();
|
|
151
|
+
pending = [];
|
|
152
|
+
lastDecisionByWorker = new Map();
|
|
153
|
+
openHandoffs = new Map();
|
|
154
|
+
closedWorkers = new Set();
|
|
155
|
+
lastWarnAt = 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// --- the classification of one watcher decision --------------------------------------
|
|
159
|
+
|
|
160
|
+
// 'wake' = a non-silent WAKE_LEAD the wait result reports as the reason it returned;
|
|
161
|
+
// 'silent' = a silent WAKE_LEAD (mode 'silent' keeps collecting, D-16); null = nothing to
|
|
162
|
+
// store. A KEEP_WAITING tick, silent or not, is never an outcome row: precision (and silent
|
|
163
|
+
// precision) is the share of WAKES the lead's next call confirmed, and the missed wakes are
|
|
164
|
+
// caught by the late-end positive control below -- lead review, WP-5b.
|
|
165
|
+
function _pendingClass(decision, wokeOn) {
|
|
166
|
+
if (decision.decision !== 'WAKE_LEAD') return null;
|
|
167
|
+
if (decision.silent === true) return 'silent';
|
|
168
|
+
return wokeOn === 'watcher' ? 'wake' : null;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function _argsOf(call) {
|
|
172
|
+
return call && call.args && typeof call.args === 'object' ? call.args : {};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** §6.4: the wait-watch facts of one outcome row (labelFromFacts('wait-watch', …) reads these). */
|
|
176
|
+
function _waitWatchFacts(item, nextCall) {
|
|
177
|
+
const namesWorker = Boolean(item.workerId) && _argsOf(nextCall).ctm_session_id === item.workerId;
|
|
178
|
+
return {
|
|
179
|
+
decision: item.decision,
|
|
180
|
+
silent: item.silent === true,
|
|
181
|
+
woke_on: item.wokeOn == null ? null : item.wokeOn,
|
|
182
|
+
worker_id: item.workerId,
|
|
183
|
+
next_call: nextCall ? { tool: typeof nextCall.tool === 'string' ? nextCall.tool : '', names_worker: namesWorker } : null,
|
|
184
|
+
terminal_status: item.terminalStatus == null ? null : item.terminalStatus,
|
|
185
|
+
dropped: item.dropped === true,
|
|
186
|
+
late: item.late === true,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// §6.4: every wait-watch row stores its facts and its label_version; the label is derived here
|
|
191
|
+
// by the one pure rule, never passed in by a caller.
|
|
192
|
+
function _reportOutcome(item, nextCall) {
|
|
193
|
+
const facts = _waitWatchFacts(item, nextCall);
|
|
194
|
+
_write('helperRulesRecordOutcome', {
|
|
195
|
+
id: item.id,
|
|
196
|
+
cell_key: item.cellKey,
|
|
197
|
+
kind: 'wait-watch',
|
|
198
|
+
label: labelFromFacts('wait-watch', facts).label,
|
|
199
|
+
decision: item.decision,
|
|
200
|
+
worker_id: item.workerId,
|
|
201
|
+
facts_json: JSON.stringify(facts),
|
|
202
|
+
label_version: LABEL_VERSION,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// S-4 (round 2): both reads go through the one payload accessor; a `worker`-nested result is the
|
|
207
|
+
// no-id wait's shape, and an id-less wait still falls back to the call's own args.
|
|
208
|
+
function _workerIdOf(call, res) {
|
|
209
|
+
const payload = workerPayloadOf(res);
|
|
210
|
+
const direct = payload ? _string(payload.ctm_session_id) : '';
|
|
211
|
+
if (direct) return direct;
|
|
212
|
+
return _string(call.args.ctm_session_id);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function _statusOf(res) {
|
|
216
|
+
const payload = workerPayloadOf(res);
|
|
217
|
+
return payload ? _string(payload.status) : '';
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// session-stops-followups-2026-10-24.html D-3: a `report_ready` whose report_provisional is true
|
|
221
|
+
// is a live worker's interim report, not its final one -- it must not close or grade the hand-off.
|
|
222
|
+
function _provisionalOf(res) {
|
|
223
|
+
const payload = workerPayloadOf(res);
|
|
224
|
+
return !!(payload && payload.report_provisional === true);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// --- the three pending/labelling steps ------------------------------------------------
|
|
228
|
+
|
|
229
|
+
// §6.7: a pending outcome with no next call is labelled empty / silent_empty by the NEXT hook
|
|
230
|
+
// invocation, whatever lead it belongs to.
|
|
231
|
+
function _expirePending(nowMs) {
|
|
232
|
+
if (!pending.length) return;
|
|
233
|
+
const open = [];
|
|
234
|
+
for (const item of pending) {
|
|
235
|
+
if (nowMs - item.at >= PENDING_TTL_MS) _reportOutcome(item, null);
|
|
236
|
+
else open.push(item);
|
|
237
|
+
}
|
|
238
|
+
pending = open;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// The lead's next call IS the label for every wake it was left holding: a silent wake is
|
|
242
|
+
// judged by the same rule with the silent prefix (would the lead have wanted it?).
|
|
243
|
+
function _labelPendingForLead(lead, nextCall) {
|
|
244
|
+
if (!pending.length) return;
|
|
245
|
+
const open = [];
|
|
246
|
+
for (const item of pending) {
|
|
247
|
+
if (item.lead !== lead) {
|
|
248
|
+
open.push(item);
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
_reportOutcome(item, nextCall);
|
|
252
|
+
}
|
|
253
|
+
pending = open;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function _openWatcherOutcomes(lead, call, res, nowMs) {
|
|
257
|
+
if (!WAIT_TOOLS.has(call.tool) || !res || !Array.isArray(res.watcher_decisions)) return;
|
|
258
|
+
const wokeOn = _string(res.woke_on);
|
|
259
|
+
const stamp = _stamp(nowMs);
|
|
260
|
+
res.watcher_decisions.forEach((decision, index) => {
|
|
261
|
+
if (!decision || typeof decision !== 'object') return;
|
|
262
|
+
const workerId = _string(decision.worker_id);
|
|
263
|
+
if (workerId) {
|
|
264
|
+
lastDecisionByWorker.set(workerId, _string(decision.decision));
|
|
265
|
+
_evict(lastDecisionByWorker, null);
|
|
266
|
+
}
|
|
267
|
+
const kind = _pendingClass(decision, wokeOn);
|
|
268
|
+
if (!kind) return;
|
|
269
|
+
const entry = workerRoutes.get(workerId);
|
|
270
|
+
if (!workerId || !entry || !entry.route) return; // unknown route -> no cell to write
|
|
271
|
+
// S-7 (round 2): a wake the bounded buffer pushes out is still recorded -- as a dropped
|
|
272
|
+
// (empty) row -- instead of vanishing silently.
|
|
273
|
+
if (pending.length >= MAP_MAX) {
|
|
274
|
+
const dropped = pending.shift();
|
|
275
|
+
_reportOutcome({ ...dropped, dropped: true }, null);
|
|
276
|
+
}
|
|
277
|
+
pending.push({
|
|
278
|
+
id: `${stamp}:${workerId}:${index}`,
|
|
279
|
+
lead,
|
|
280
|
+
cellKey: `wait-watch|default|${entry.route}`,
|
|
281
|
+
workerId,
|
|
282
|
+
decision: _string(decision.decision),
|
|
283
|
+
silent: kind === 'silent',
|
|
284
|
+
wokeOn: wokeOn || null,
|
|
285
|
+
at: nowMs,
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// The positive control (§6.7): a worker that only ended failed after the watcher last chose to
|
|
291
|
+
// keep waiting was a wake the watcher missed.
|
|
292
|
+
function _recordLateEnd(call, res, nowMs) {
|
|
293
|
+
if (!WAIT_TOOLS.has(call.tool) || !res || _string(res.woke_on) !== 'terminal') return;
|
|
294
|
+
// D-2: an error body is not evidence -- no late row, no close, nothing written for it.
|
|
295
|
+
const payload = workerPayloadOf(res);
|
|
296
|
+
if (!payload || payload.error) return;
|
|
297
|
+
const workerId = _workerIdOf(call, res);
|
|
298
|
+
if (!workerId) return;
|
|
299
|
+
const entry = workerRoutes.get(workerId);
|
|
300
|
+
if (!entry || !entry.route) return;
|
|
301
|
+
const terminalStatus = _statusOf(res);
|
|
302
|
+
const label = labelLateEnd({
|
|
303
|
+
lastDecision: lastDecisionByWorker.get(workerId),
|
|
304
|
+
terminalStatus,
|
|
305
|
+
});
|
|
306
|
+
if (!label) return;
|
|
307
|
+
_reportOutcome({
|
|
308
|
+
id: `${_stamp(nowMs)}:${workerId}:late`,
|
|
309
|
+
cellKey: `wait-watch|default|${entry.route}`,
|
|
310
|
+
workerId,
|
|
311
|
+
decision: 'KEEP_WAITING',
|
|
312
|
+
silent: false,
|
|
313
|
+
wokeOn: _string(res.woke_on) || null,
|
|
314
|
+
terminalStatus,
|
|
315
|
+
late: true,
|
|
316
|
+
}, null);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// --- the delegation record and the exploration hand-off --------------------------------
|
|
320
|
+
|
|
321
|
+
function _rememberDelegation(lead, call, res) {
|
|
322
|
+
if (call.tool !== 'walle_delegate_implementation' || !res) return;
|
|
323
|
+
const ctmSessionId = _string(res.ctm_session_id).trim();
|
|
324
|
+
if (!ctmSessionId) return;
|
|
325
|
+
workerRoutes.set(ctmSessionId, {
|
|
326
|
+
route: _string(res.route),
|
|
327
|
+
agent: _string(res.agent),
|
|
328
|
+
invocation_id: _string(res.delegation_invocation_id),
|
|
329
|
+
profile: _string(res.worker_profile),
|
|
330
|
+
});
|
|
331
|
+
workerLeads.set(ctmSessionId, lead);
|
|
332
|
+
_evict(workerRoutes, workerLeads);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// The lead's own agent (the cell is `explore|default|<lead provider>`). Client info is only
|
|
336
|
+
// available to a caller that has it (the initialize path); the delegate's own `agent` is the
|
|
337
|
+
// documented fallback.
|
|
338
|
+
function _leadAgent(args, clientInfo) {
|
|
339
|
+
if (clientInfo && typeof clientInfo === 'object') return leadAgentFromClientInfo(clientInfo);
|
|
340
|
+
const agent = _string(args.agent);
|
|
341
|
+
return agent === 'codex' || agent === 'claude' ? agent : 'claude';
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/** The wait/status variant, for the row's facts (§6.4): the recommended no-id wait has no id. */
|
|
345
|
+
function _waitVariant(call) {
|
|
346
|
+
if (call.tool === 'walle_worker_status') return 'status_by_id';
|
|
347
|
+
return _string(call.args.ctm_session_id) ? 'wait_by_id' : 'wait_no_id';
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// "The paths a tool touched are not in the status payload, so the per-tool count is the honest
|
|
351
|
+
// stand-in for the log -- the card says how much of each tool the worker used, not where."
|
|
352
|
+
function _toolLogOf(payload) {
|
|
353
|
+
const counts = payload && payload.tool_counts && typeof payload.tool_counts === 'object' ? payload.tool_counts : {};
|
|
354
|
+
return Object.entries(counts).map(([tool, count]) => ({ tool, path: String(count) }));
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function _trackHandoff(call, res, clientInfo, nowMs) {
|
|
358
|
+
if (!res) return;
|
|
359
|
+
if (call.tool === 'walle_delegate_implementation') {
|
|
360
|
+
const ctmSessionId = _string(res.ctm_session_id).trim();
|
|
361
|
+
const id = _string(res.delegation_invocation_id);
|
|
362
|
+
if (!ctmSessionId || res.worker_profile !== 'review' || !id || openHandoffs.has(ctmSessionId)) return;
|
|
363
|
+
// WP-6 grades the card from the brief the helper was given. This module has no fs access (see
|
|
364
|
+
// AC-5e's source check), so it parks the delegation's `rendered_brief_path`; grade.js reads the
|
|
365
|
+
// text, bounded, when the sample is drawn. The report and the tool log arrive with the
|
|
366
|
+
// terminal read.
|
|
367
|
+
openHandoffs.set(ctmSessionId, { id, opened_at: nowMs, brief_path: _string(res.rendered_brief_path) });
|
|
368
|
+
_evict(openHandoffs, null);
|
|
369
|
+
// S-6 (round 2): the open row is addressable by worker_id and carries its facts + version, so
|
|
370
|
+
// the close path can resolve it after a restart (D-5).
|
|
371
|
+
_write('helperRulesRecordOutcome', {
|
|
372
|
+
id,
|
|
373
|
+
cell_key: `explore|default|${_leadAgent(call.args, clientInfo)}`,
|
|
374
|
+
kind: 'explore',
|
|
375
|
+
decision: 'open',
|
|
376
|
+
worker_id: ctmSessionId,
|
|
377
|
+
facts_json: JSON.stringify({
|
|
378
|
+
opened_at: nowMs,
|
|
379
|
+
harness: res.harness == null ? null : res.harness,
|
|
380
|
+
brief_path: res.rendered_brief_path || null,
|
|
381
|
+
}),
|
|
382
|
+
label_version: LABEL_VERSION,
|
|
383
|
+
});
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
if (!WAIT_TOOLS.has(call.tool)) return;
|
|
387
|
+
// D-2: a payload with an `error` key is not terminal evidence -- it closes nothing. The route
|
|
388
|
+
// wait (no worker payload at all) has no status, so it falls through here too.
|
|
389
|
+
const payload = workerPayloadOf(res);
|
|
390
|
+
if (!payload || payload.error) return;
|
|
391
|
+
const status = _string(payload.status);
|
|
392
|
+
// D-3 (session-stops-followups-2026-10-24.html): a provisional report_ready is a live worker's
|
|
393
|
+
// interim report, not its final one -- it closes and grades nothing.
|
|
394
|
+
if (!TERMINAL_STATUSES.has(status) || _provisionalOf(res)) return;
|
|
395
|
+
const workerId = _string(payload.ctm_session_id) || _string(call.args.ctm_session_id);
|
|
396
|
+
if (!workerId || closedWorkers.has(workerId)) return;
|
|
397
|
+
// D-5: the cache is a best-effort source of opened_at/brief_path; the close itself is keyed on
|
|
398
|
+
// worker_id, so a cache miss (a restart, or eviction) still closes the row.
|
|
399
|
+
const handoff = openHandoffs.get(workerId) || null;
|
|
400
|
+
if (handoff) openHandoffs.delete(workerId);
|
|
401
|
+
closedWorkers.add(workerId);
|
|
402
|
+
_evict(closedWorkers, null);
|
|
403
|
+
const facts = factsFromPayload(payload, {
|
|
404
|
+
opened_at: handoff ? handoff.opened_at : null,
|
|
405
|
+
terminal_at: nowMs,
|
|
406
|
+
wait_variant: _waitVariant(call),
|
|
407
|
+
woke_on: _string(res.woke_on) || null,
|
|
408
|
+
});
|
|
409
|
+
// The grade card is built HERE, while the terminal payload is in scope; the grade itself waits
|
|
410
|
+
// for the row's seq, which only the close write can return.
|
|
411
|
+
const toolLog = _toolLogOf(payload);
|
|
412
|
+
_writeThen('helperRulesCloseOutcomeByWorker', [workerId, { facts }], (result) => _gradeIfSampled(result, facts, toolLog));
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// --- the 1-in-5 spot check (WP-6, §6.5/D-19) -------------------------------------------
|
|
416
|
+
|
|
417
|
+
// llm/ and brain.js are reached lazily and only from here, for the same reason the write seam
|
|
418
|
+
// is: lib/ must not hold a module-top reference into llm/ or brain.js, and a test substitutes
|
|
419
|
+
// them by seeding require.cache. No brain (a bare call) reads as "no pin", never as "grade
|
|
420
|
+
// with whatever is cheap" (D-0).
|
|
421
|
+
function _gradeDeps() {
|
|
422
|
+
const { completeForRole } = require('../../llm/model-roles');
|
|
423
|
+
let db = null;
|
|
424
|
+
let brain = null;
|
|
425
|
+
try {
|
|
426
|
+
const events = require('../brain-events');
|
|
427
|
+
db = events.getDb();
|
|
428
|
+
brain = events.getBrainCapabilities();
|
|
429
|
+
} catch {
|
|
430
|
+
// expected: no brain in this process -- readGraderModel(null) is '' -> the sample is unavailable
|
|
431
|
+
db = null;
|
|
432
|
+
brain = null;
|
|
433
|
+
}
|
|
434
|
+
return { completeForRole, db, brain };
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// Fire-and-forget: the close already landed, so a grader outage costs a sample, never the write.
|
|
438
|
+
// S-3 (round 2): the store derives the label and returns it, so "was this a hand-off?" is read
|
|
439
|
+
// from `result.labelled`, and the card carries the report/log PATHS (grade.js reads them).
|
|
440
|
+
function _gradeIfSampled(result, facts, toolLog) {
|
|
441
|
+
if (!result || result.closed !== true) return;
|
|
442
|
+
if (!result.labelled || result.labelled.decision !== 'handoff') return; // only an accepted hand-off
|
|
443
|
+
if (!shouldGrade(result.seq)) return; // D-12: every EXPLORE_GRADE_EVERY-th, in every cell state
|
|
444
|
+
const merged = result.facts && typeof result.facts === 'object' ? result.facts : (facts || {});
|
|
445
|
+
const card = {
|
|
446
|
+
brief_path: merged.brief_path || '',
|
|
447
|
+
report_path: merged.report_path == null ? null : merged.report_path,
|
|
448
|
+
last_message_path: merged.last_message_path == null ? null : merged.last_message_path,
|
|
449
|
+
toolLog,
|
|
450
|
+
};
|
|
451
|
+
const id = result.id;
|
|
452
|
+
let deps;
|
|
453
|
+
try {
|
|
454
|
+
deps = _gradeDeps();
|
|
455
|
+
} catch (err) {
|
|
456
|
+
// REPORT: the grade is advisory -- a missing dependency costs a sample, never the tool call.
|
|
457
|
+
_warn(`grade deps failed: ${err && err.message ? err.message : err}`);
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
// REPORT: gradeHandoff turns a failed call into an unavailable sample, so the tail below only
|
|
461
|
+
// covers a throw from the write itself -- both are fire-and-forget by contract.
|
|
462
|
+
gradeHandoff(card, { completeForRole: deps.completeForRole, graderModel: readGraderModel(deps.db), brain: deps.brain })
|
|
463
|
+
.then((grade) => _write('helperRulesSetGrade', id, gradeToJson(grade)))
|
|
464
|
+
.catch((err) => _warn(`helperRulesSetGrade failed: ${err && err.message ? err.message : err}`));
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// --- the entry point ------------------------------------------------------------------
|
|
468
|
+
|
|
469
|
+
function _record(options) {
|
|
470
|
+
const { agentSessionId, tool, args, result, at, clientInfo } = options;
|
|
471
|
+
const lead = _leadKey(agentSessionId);
|
|
472
|
+
const nowMs = _atMs(at);
|
|
473
|
+
const call = {
|
|
474
|
+
tool: _string(tool),
|
|
475
|
+
args: args && typeof args === 'object' ? args : {},
|
|
476
|
+
at: nowMs,
|
|
477
|
+
};
|
|
478
|
+
const res = result && typeof result === 'object' ? result : null;
|
|
479
|
+
|
|
480
|
+
_expirePending(nowMs);
|
|
481
|
+
_labelPendingForLead(lead, call);
|
|
482
|
+
_rememberDelegation(lead, call, res);
|
|
483
|
+
_openWatcherOutcomes(lead, call, res, nowMs);
|
|
484
|
+
_recordLateEnd(call, res, nowMs);
|
|
485
|
+
_trackHandoff(call, res, clientInfo, nowMs);
|
|
486
|
+
|
|
487
|
+
const ring = callsByLead.get(lead) || [];
|
|
488
|
+
ring.push(call);
|
|
489
|
+
while (ring.length > CALL_RING) ring.shift();
|
|
490
|
+
callsByLead.set(lead, ring);
|
|
491
|
+
_evict(callsByLead, null);
|
|
492
|
+
return call;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Remember one lead tool call and label whatever the previous one left pending.
|
|
497
|
+
* @param {{agentSessionId?:string, tool:string, args?:object, result?:object, at?:number|string|Date,
|
|
498
|
+
* clientInfo?:object}} options agentSessionId is the injected parent_agent_session_id;
|
|
499
|
+
* clientInfo is optional (the initialize path) and only decides the explore cell's agent.
|
|
500
|
+
* @returns {void} never throws -- a labelling side path may not fail the lead's tool call.
|
|
501
|
+
*/
|
|
502
|
+
function recordLeadToolCall(options = {}) {
|
|
503
|
+
try {
|
|
504
|
+
_record(options);
|
|
505
|
+
} catch (err) {
|
|
506
|
+
// REPORT: see above -- the call itself already succeeded by the time this runs.
|
|
507
|
+
_warn(`recordLeadToolCall failed: ${err && err.message ? err.message : err}`);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
module.exports = {
|
|
512
|
+
ANONYMOUS_LEAD,
|
|
513
|
+
CALL_RING,
|
|
514
|
+
PENDING_TTL_MS,
|
|
515
|
+
TERMINAL_STATUSES,
|
|
516
|
+
WAIT_TOOLS,
|
|
517
|
+
WARN_THROTTLE_MS,
|
|
518
|
+
_resetForTests,
|
|
519
|
+
leadWorkersOf,
|
|
520
|
+
recordLeadToolCall,
|
|
521
|
+
workerRouteOf,
|
|
522
|
+
};
|