create-walle 0.10.2 → 0.10.3
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 +3 -1
- package/lib/release-schema.json +2 -2
- package/lib/runtime-closure-policy.json +8 -7
- package/package.json +1 -1
- package/template/coding-task-manager/api-prompts.js +45 -7
- package/template/coding-task-manager/bin/claude-hook.js +55 -1
- package/template/coding-task-manager/bin/ctm-relay-client.js +35 -12
- package/template/coding-task-manager/bin/land.js +2069 -0
- package/template/coding-task-manager/bin/memory-census.js +4 -2
- package/template/coding-task-manager/bin/memory-sync-verify.js +151 -0
- package/template/coding-task-manager/bin/probe-refusal-scope.js +530 -0
- package/template/coding-task-manager/db.js +156 -32
- package/template/coding-task-manager/lib/acp/acp-client.js +383 -0
- package/template/coding-task-manager/lib/acp/dsh-context-truth.js +176 -0
- package/template/coding-task-manager/lib/acp/dsh-launch-model.js +302 -0
- package/template/coding-task-manager/lib/acp/dsh-mcp-servers.js +194 -0
- package/template/coding-task-manager/lib/acp/dsh-prompt-lane.js +616 -0
- package/template/coding-task-manager/lib/acp/dsh-route-patch.js +308 -0
- package/template/coding-task-manager/lib/acp/dsh-session-runtime.js +522 -0
- package/template/coding-task-manager/lib/acp/dsh-transcript.js +395 -0
- package/template/coding-task-manager/lib/acp/dsh-usage-log.js +162 -0
- package/template/coding-task-manager/lib/acp/ndjson-stdio-transport.js +225 -0
- package/template/coding-task-manager/lib/adopted-host-redial.js +47 -11
- package/template/coding-task-manager/lib/adopted-launch-environment.js +123 -0
- package/template/coding-task-manager/lib/agent-auto-update-runtime.js +0 -3
- package/template/coding-task-manager/lib/agent-auto-update.js +26 -10
- package/template/coding-task-manager/lib/agent-bundle/build.js +657 -0
- package/template/coding-task-manager/lib/agent-bundle/codex-install.js +558 -0
- package/template/coding-task-manager/lib/agent-bundle/drift.js +120 -0
- package/template/coding-task-manager/lib/agent-bundle/gc.js +522 -0
- package/template/coding-task-manager/lib/agent-bundle/inventory.js +346 -0
- package/template/coding-task-manager/lib/agent-bundle/push.js +717 -0
- package/template/coding-task-manager/lib/agent-bundle/skill-transfer.js +724 -0
- package/template/coding-task-manager/lib/agent-bundle/spawn.js +119 -0
- package/template/coding-task-manager/lib/agent-bundle/store.js +568 -0
- package/template/coding-task-manager/lib/agent-capabilities.js +142 -12
- package/template/coding-task-manager/lib/agent-cli-cache.js +30 -5
- package/template/coding-task-manager/lib/agent-definitions.js +19 -0
- package/template/coding-task-manager/lib/agent-hooks-codex-toml.js +28 -16
- package/template/coding-task-manager/lib/agent-hooks-codex-workspace.js +9 -1
- package/template/coding-task-manager/lib/agent-hooks-installer.js +23 -8
- package/template/coding-task-manager/lib/agent-hooks-prune.js +37 -11
- package/template/coding-task-manager/lib/agent-hooks-shim.js +105 -0
- package/template/coding-task-manager/lib/agent-presets.js +84 -1
- package/template/coding-task-manager/lib/agent-upgrade-jobs.js +12 -1
- package/template/coding-task-manager/lib/agent-version-service.js +74 -11
- package/template/coding-task-manager/lib/all-sessions-query.js +6 -2
- package/template/coding-task-manager/lib/api/agent-bundles.js +436 -0
- package/template/coding-task-manager/lib/api/backup-retention.js +83 -0
- package/template/coding-task-manager/lib/api/conversation-sync-routes.js +124 -0
- package/template/coding-task-manager/lib/api/diagnostics.js +549 -69
- package/template/coding-task-manager/lib/api/fleet.js +118 -0
- package/template/coding-task-manager/lib/api/hub-bridge.js +243 -0
- package/template/coding-task-manager/lib/api/ingress.js +9 -1
- package/template/coding-task-manager/lib/api/landing.js +403 -0
- package/template/coding-task-manager/lib/api/machines.js +691 -2
- package/template/coding-task-manager/lib/api/memory-sync-routes.js +335 -0
- package/template/coding-task-manager/lib/api/misc-ops.js +8 -3
- package/template/coding-task-manager/lib/api/remote-sessions.js +1326 -0
- package/template/coding-task-manager/lib/api/session-attach.js +623 -0
- package/template/coding-task-manager/lib/api/session-messages.js +1384 -0
- package/template/coding-task-manager/lib/api/sessions.js +77 -51
- package/template/coding-task-manager/lib/api/setup-network.js +544 -16
- package/template/coding-task-manager/lib/api/setup-wizard-handlers.js +884 -0
- package/template/coding-task-manager/lib/api/setup.js +829 -10
- package/template/coding-task-manager/lib/api/walle-bridge.js +9 -1
- package/template/coding-task-manager/lib/attachment-reconciler-wiring.js +5 -2
- package/template/coding-task-manager/lib/auth-rate-limit.js +23 -0
- package/template/coding-task-manager/lib/auth-rules.js +292 -21
- package/template/coding-task-manager/lib/background-stop.js +369 -0
- package/template/coding-task-manager/lib/best-of-attempts.js +4 -1
- package/template/coding-task-manager/lib/best-of-launch-plan.js +52 -0
- package/template/coding-task-manager/lib/box-keep-awake.js +89 -0
- package/template/coding-task-manager/lib/broadcast-reason-stats.js +152 -0
- package/template/coding-task-manager/lib/broadcast-serialize.js +5 -0
- package/template/coding-task-manager/lib/build-info.js +4 -2
- package/template/coding-task-manager/lib/claude-model-truth.js +13 -2
- package/template/coding-task-manager/lib/claude-transcript-terminal-renderer.js +17 -13
- package/template/coding-task-manager/lib/client-diag-handler.js +64 -2
- package/template/coding-task-manager/lib/codex-app-server-client.js +14 -16
- package/template/coding-task-manager/lib/codex-configuration-history.js +55 -0
- package/template/coding-task-manager/lib/codex-harness-qualification.js +43 -20
- package/template/coding-task-manager/lib/codex-rollout-history.js +743 -0
- package/template/coding-task-manager/lib/coding-agent-models.js +27 -12
- package/template/coding-task-manager/lib/coding-cli-skill-installer.js +44 -14
- package/template/coding-task-manager/lib/coding-session-model-adapters.js +43 -2
- package/template/coding-task-manager/lib/coding-session-model-owner.js +1 -1
- package/template/coding-task-manager/lib/coding-session-model-public.js +7 -1
- package/template/coding-task-manager/lib/coding-session-model-runtime.js +23 -4
- package/template/coding-task-manager/lib/coding-session-model-scan.js +31 -0
- package/template/coding-task-manager/lib/coding-session-model-state.js +7 -0
- package/template/coding-task-manager/lib/conversation-freshness-diagnostics.js +280 -0
- package/template/coding-task-manager/lib/conversation-item-clock.js +261 -0
- package/template/coding-task-manager/lib/conversation-source-registry.js +5 -0
- package/template/coding-task-manager/lib/conversation-store-v2.js +44 -0
- package/template/coding-task-manager/lib/conversation-sync.js +355 -0
- package/template/coding-task-manager/lib/create/resolve-launch-params.js +96 -12
- package/template/coding-task-manager/lib/create/worker-role-profile.js +4 -4
- package/template/coding-task-manager/lib/create-intent-lease.js +51 -0
- package/template/coding-task-manager/lib/ctm-session-context-api.js +97 -6
- package/template/coding-task-manager/lib/db-domain-tables.js +1 -0
- package/template/coding-task-manager/lib/db-domains.js +1 -0
- package/template/coding-task-manager/lib/db-owner-dispatch-probe.js +32 -0
- package/template/coding-task-manager/lib/db-owner-request-counts.js +178 -0
- package/template/coding-task-manager/lib/db-owner-worker-client.js +68 -14
- package/template/coding-task-manager/lib/db-schema-source-files.js +5 -0
- package/template/coding-task-manager/lib/deferred-restore-attempt.js +6 -2
- package/template/coding-task-manager/lib/feature-manifest.js +4 -0
- package/template/coding-task-manager/lib/fleet-conversation-route.js +97 -0
- package/template/coding-task-manager/lib/fleet-fanout.js +78 -0
- package/template/coding-task-manager/lib/fleet-hub.js +762 -0
- package/template/coding-task-manager/lib/fleet-origin-follower.js +252 -0
- package/template/coding-task-manager/lib/fleet-resolver-effects.js +147 -0
- package/template/coding-task-manager/lib/fleet-resolver-tick.js +148 -0
- package/template/coding-task-manager/lib/fleet-resolver.js +454 -0
- package/template/coding-task-manager/lib/fleet-session-list-routes.js +114 -0
- package/template/coding-task-manager/lib/fleet-session-lists.js +672 -0
- package/template/coding-task-manager/lib/fleet-update.js +798 -0
- package/template/coding-task-manager/lib/fs-watcher-root-watch.js +141 -0
- package/template/coding-task-manager/lib/fs-watcher.js +58 -42
- package/template/coding-task-manager/lib/harness-history-transition.js +50 -9
- package/template/coding-task-manager/lib/headless-term-service.js +84 -8
- package/template/coding-task-manager/lib/hermetic-agent-launch-guard.js +10 -0
- package/template/coding-task-manager/lib/history-transition-read-op.js +175 -8
- package/template/coding-task-manager/lib/host-cpu-categories.js +310 -0
- package/template/coding-task-manager/lib/host-fseventsd-sampler.js +399 -0
- package/template/coding-task-manager/lib/host-handoff.js +16 -19
- package/template/coding-task-manager/lib/host-stats.js +150 -3
- package/template/coding-task-manager/lib/hosted-sync-worker.js +43 -320
- package/template/coding-task-manager/lib/hub-bridge-access.js +798 -0
- package/template/coding-task-manager/lib/hub-bridge-box.js +409 -0
- package/template/coding-task-manager/lib/hub-bridge-mcp.js +380 -0
- package/template/coding-task-manager/lib/hub-bridge-mesh.js +313 -0
- package/template/coding-task-manager/lib/hub-bridge-ops.js +721 -0
- package/template/coding-task-manager/lib/hub-bridge.js +398 -0
- package/template/coding-task-manager/lib/idle-notify.js +491 -0
- package/template/coding-task-manager/lib/instance-id-ownership-manifest.js +8 -0
- package/template/coding-task-manager/lib/instance-manifest.js +5 -1
- package/template/coding-task-manager/lib/instance-sync-status.js +18 -8
- package/template/coding-task-manager/lib/landing/agent-rule.txt +1 -0
- package/template/coding-task-manager/lib/landing/batch-runner.js +366 -0
- package/template/coding-task-manager/lib/landing/config.js +536 -0
- package/template/coding-task-manager/lib/landing/ctm-view.js +256 -0
- package/template/coding-task-manager/lib/landing/gate.js +360 -0
- package/template/coding-task-manager/lib/landing/git.js +344 -0
- package/template/coding-task-manager/lib/landing/lease.js +247 -0
- package/template/coding-task-manager/lib/landing/merge-delta.js +380 -0
- package/template/coding-task-manager/lib/landing/proof.js +223 -0
- package/template/coding-task-manager/lib/landing/queue.js +998 -0
- package/template/coding-task-manager/lib/landing/radar.js +489 -0
- package/template/coding-task-manager/lib/landing/resolve-cli.js +424 -0
- package/template/coding-task-manager/lib/landing/state.js +263 -0
- package/template/coding-task-manager/lib/landing/stop.js +49 -0
- package/template/coding-task-manager/lib/landing/sync-cli.js +475 -0
- package/template/coding-task-manager/lib/landing/sync.js +456 -0
- package/template/coding-task-manager/lib/landing/train.js +885 -0
- package/template/coding-task-manager/lib/landing/window.js +57 -0
- package/template/coding-task-manager/lib/launch-environment.js +121 -0
- package/template/coding-task-manager/lib/launch-model-override.js +36 -10
- package/template/coding-task-manager/lib/launch-plan-pool.js +2 -1
- package/template/coding-task-manager/lib/launch-plan-warm-cache.js +6 -0
- package/template/coding-task-manager/lib/lead-model-observer.js +57 -1
- package/template/coding-task-manager/lib/lead-model-options.js +160 -3
- package/template/coding-task-manager/lib/lead-model-restore-reconciliation.js +106 -24
- package/template/coding-task-manager/lib/lead-model-switch-runtime.js +352 -68
- package/template/coding-task-manager/lib/lead-model-switch.js +114 -10
- package/template/coding-task-manager/lib/lead-model-transition-runtime.js +14 -2
- package/template/coding-task-manager/lib/lead-model-transition-store.js +24 -6
- package/template/coding-task-manager/lib/lead-route-preflight.js +179 -0
- package/template/coding-task-manager/lib/lead-switch-history-mode.js +110 -0
- package/template/coding-task-manager/lib/lead-wire-agent.js +7 -0
- package/template/coding-task-manager/lib/lifecycle-wake-experiment.js +9 -2
- package/template/coding-task-manager/lib/live-defer-announce.js +45 -0
- package/template/coding-task-manager/lib/machine-registry.js +750 -5
- package/template/coding-task-manager/lib/macos-capabilities.js +32 -15
- package/template/coding-task-manager/lib/main-thread-lint-exemptions.json +433 -53
- package/template/coding-task-manager/lib/mainloop-observability.js +14 -9
- package/template/coding-task-manager/lib/media-draft-owner.js +16 -3
- package/template/coding-task-manager/lib/memory-join.js +337 -0
- package/template/coding-task-manager/lib/memory-sync-verify.js +393 -0
- package/template/coding-task-manager/lib/memory-sync.js +565 -0
- package/template/coding-task-manager/lib/migrations/v57-delegate-pref-mirror-opencode.js +68 -0
- package/template/coding-task-manager/lib/migrations/v58-subagent-launch-native-subagents.js +42 -0
- package/template/coding-task-manager/lib/migrations/v59-coding-session-model-state-dsh.js +73 -0
- package/template/coding-task-manager/lib/migrations/v60-delegate-pref-mirror-dsh.js +78 -0
- package/template/coding-task-manager/lib/migrations/v61-conversation-item-clock.js +71 -0
- package/template/coding-task-manager/lib/model-availability.js +727 -0
- package/template/coding-task-manager/lib/model-execution-recipe-metadata.js +4 -6
- package/template/coding-task-manager/lib/model-host-receipt.js +6 -3
- package/template/coding-task-manager/lib/model-id-rule.js +19 -0
- package/template/coding-task-manager/lib/model-proxy/anthropic-face.js +4 -0
- package/template/coding-task-manager/lib/model-proxy/auto-mode-review.js +110 -23
- package/template/coding-task-manager/lib/model-proxy/chat-response-translators.js +3 -0
- package/template/coding-task-manager/lib/model-proxy/generation-probe.js +60 -17
- package/template/coding-task-manager/lib/model-proxy/historical-tool-declarations.js +37 -0
- package/template/coding-task-manager/lib/model-proxy/lead-request-validation.js +1 -0
- package/template/coding-task-manager/lib/model-proxy/lead-token-admin.js +130 -0
- package/template/coding-task-manager/lib/model-proxy/refusal-scope.js +151 -0
- package/template/coding-task-manager/lib/model-proxy/request-budget-store.js +11 -2
- package/template/coding-task-manager/lib/model-proxy/tokens.js +69 -5
- package/template/coding-task-manager/lib/model-proxy/upstream-outcome.js +9 -0
- package/template/coding-task-manager/lib/native-agent-model-args.js +25 -22
- package/template/coding-task-manager/lib/native-history-control.js +6 -4
- package/template/coding-task-manager/lib/native-lead-settings-client.js +44 -4
- package/template/coding-task-manager/lib/oauth-proxy-supervisor.js +173 -36
- package/template/coding-task-manager/lib/online-backup-worker-client.js +2 -0
- package/template/coding-task-manager/lib/opencode-cli.js +480 -0
- package/template/coding-task-manager/lib/opencode-launch-model.js +471 -0
- package/template/coding-task-manager/lib/opencode-v1-plugin/model-carrier.mjs +35 -0
- package/template/coding-task-manager/lib/opencode-v2-plugin/server.js +118 -0
- package/template/coding-task-manager/lib/owner-action-manifest-data.json +1 -1
- package/template/coding-task-manager/lib/park-composer-draft.js +54 -0
- package/template/coding-task-manager/lib/park-fresh-relaunch.js +41 -10
- package/template/coding-task-manager/lib/perf-phase-trace.js +72 -0
- package/template/coding-task-manager/lib/perf-summary.js +7 -0
- package/template/coding-task-manager/lib/perf-tracker.js +63 -2
- package/template/coding-task-manager/lib/project-config.js +7 -0
- package/template/coding-task-manager/lib/prompt-purge-v2.js +52 -1
- package/template/coding-task-manager/lib/provider-login-broker.js +72 -15
- package/template/coding-task-manager/lib/provider-login-tab.js +10 -2
- package/template/coding-task-manager/lib/read-pool-client.js +89 -2
- package/template/coding-task-manager/lib/read-pool-worker-handle.js +29 -4
- package/template/coding-task-manager/lib/recent-catalog-query.js +15 -0
- package/template/coding-task-manager/lib/recent-session-catalog-response.js +67 -10
- package/template/coding-task-manager/lib/recovery-evidence.js +26 -11
- package/template/coding-task-manager/lib/relay-client.js +57 -3
- package/template/coding-task-manager/lib/relink-audit.js +34 -5
- package/template/coding-task-manager/lib/remote-machine-catalog.js +321 -26
- package/template/coding-task-manager/lib/remote-machine-create.js +576 -36
- package/template/coding-task-manager/lib/remote-machine-link.js +546 -59
- package/template/coding-task-manager/lib/remote-machine-proxy.js +143 -9
- package/template/coding-task-manager/lib/remote-session-forward.js +65 -7
- package/template/coding-task-manager/lib/remote-terminal-target.js +9 -2
- package/template/coding-task-manager/lib/restart-guard.js +18 -6
- package/template/coding-task-manager/lib/restore-seed-modes.js +87 -0
- package/template/coding-task-manager/lib/restored-scrollback-hydration-runtime.js +22 -2
- package/template/coding-task-manager/lib/resume-admission.js +17 -3
- package/template/coding-task-manager/lib/review-repo-registry.js +58 -19
- package/template/coding-task-manager/lib/root-delivery-runtime.js +2 -2
- package/template/coding-task-manager/lib/root-prompt-flow.js +1 -1
- package/template/coding-task-manager/lib/runtime-contract.js +3 -1
- package/template/coding-task-manager/lib/schema-indexes.js +1 -0
- package/template/coding-task-manager/lib/session-context-locator.js +742 -0
- package/template/coding-task-manager/lib/session-create/attachment.js +2 -2
- package/template/coding-task-manager/lib/session-create/create-phases.js +118 -0
- package/template/coding-task-manager/lib/session-create/delegate-worker.js +86 -16
- package/template/coding-task-manager/lib/session-create/dsh-session.js +930 -0
- package/template/coding-task-manager/lib/session-create/lead-route-launch.js +186 -13
- package/template/coding-task-manager/lib/session-create/native-lead-lifetime.js +55 -3
- package/template/coding-task-manager/lib/session-create/opencode-lead-provider.js +50 -0
- package/template/coding-task-manager/lib/session-create/prepared.js +162 -38
- package/template/coding-task-manager/lib/session-create/provider-process.js +160 -28
- package/template/coding-task-manager/lib/session-create/response.js +7 -7
- package/template/coding-task-manager/lib/session-create/structured-session.js +27 -0
- package/template/coding-task-manager/lib/session-create/subagent-pick-table.js +3 -1
- package/template/coding-task-manager/lib/session-create/subagent-pick.js +458 -9
- package/template/coding-task-manager/lib/session-create/transcript.js +1 -1
- package/template/coding-task-manager/lib/session-create/worker-budget-setup.js +21 -2
- package/template/coding-task-manager/lib/session-create/worker-continuation.js +7 -1
- package/template/coding-task-manager/lib/session-create/worker-launch-sandbox.js +39 -10
- package/template/coding-task-manager/lib/session-create/worker-observability.js +2 -2
- package/template/coding-task-manager/lib/session-empty.js +13 -10
- package/template/coding-task-manager/lib/session-host-manager.js +60 -0
- package/template/coding-task-manager/lib/session-jobs.js +3 -1
- package/template/coding-task-manager/lib/session-lifecycle.js +10 -4
- package/template/coding-task-manager/lib/session-model-action-preconditions.js +6 -2
- package/template/coding-task-manager/lib/session-model-intent-contract.js +11 -8
- package/template/coding-task-manager/lib/session-park.js +738 -0
- package/template/coding-task-manager/lib/session-path-grant.js +13 -4
- package/template/coding-task-manager/lib/session-status-ledger.js +106 -4
- package/template/coding-task-manager/lib/session-transport.js +17 -0
- package/template/coding-task-manager/lib/session-workspace-projection.js +54 -5
- package/template/coding-task-manager/lib/session-workspace-tracking-runtime.js +213 -1
- package/template/coding-task-manager/lib/skill-autocomplete-query.js +120 -3
- package/template/coding-task-manager/lib/skill-autocomplete.js +15 -1
- package/template/coding-task-manager/lib/sqlite-file-set.js +39 -0
- package/template/coding-task-manager/lib/standup-search-adapter.js +16 -2
- package/template/coding-task-manager/lib/state-sync/client-ledger.js +12 -0
- package/template/coding-task-manager/lib/state-sync/frame-emitter.js +319 -100
- package/template/coding-task-manager/lib/storage/coding-session-model-store.js +4 -1
- package/template/coding-task-manager/lib/storage/delegate-pref-mirror-store.js +32 -9
- package/template/coding-task-manager/lib/structured-session-boot-sweep.js +235 -0
- package/template/coding-task-manager/lib/submission-ack.js +90 -2
- package/template/coding-task-manager/lib/systemd-scope.js +115 -0
- package/template/coding-task-manager/lib/telemetry-receiver.js +39 -0
- package/template/coding-task-manager/lib/terminal-attach-geometry.js +985 -0
- package/template/coding-task-manager/lib/terminal-bootstrap.js +30 -0
- package/template/coding-task-manager/lib/terminal-draft-operation.js +357 -0
- package/template/coding-task-manager/lib/terminal-input-admission.js +17 -1
- package/template/coding-task-manager/lib/terminal-input-prepared.js +563 -0
- package/template/coding-task-manager/lib/transcript-cache-temps.js +171 -0
- package/template/coding-task-manager/lib/transcript-frame-cache.js +8 -3
- package/template/coding-task-manager/lib/transcript-source.js +36 -4
- package/template/coding-task-manager/lib/transcript-store.js +9 -0
- package/template/coding-task-manager/lib/typing-interaction-trace.js +106 -3
- package/template/coding-task-manager/lib/usage-ledger/backfill.js +40 -5
- package/template/coding-task-manager/lib/usage-ledger/client.js +4 -1
- package/template/coding-task-manager/lib/usage-ledger/dsh-parse.js +152 -0
- package/template/coding-task-manager/lib/usage-ledger/dsh-read.js +73 -0
- package/template/coding-task-manager/lib/usage-ledger/ingest.js +34 -6
- package/template/coding-task-manager/lib/usage-ledger/live.js +35 -8
- package/template/coding-task-manager/lib/usage-ledger/read.js +29 -20
- package/template/coding-task-manager/lib/usage-ledger/schema.js +61 -1
- package/template/coding-task-manager/lib/usage-ledger/task-coordinator.js +4 -2
- package/template/coding-task-manager/lib/wake-skip-reasons.js +1 -0
- package/template/coding-task-manager/lib/walle/turn.js +1 -1
- package/template/coding-task-manager/lib/walle-history-serve.js +838 -0
- package/template/coding-task-manager/lib/walle-kill-authority.js +2 -2
- package/template/coding-task-manager/lib/walle-log-rotation.js +164 -1
- package/template/coding-task-manager/lib/walle-mcp-auto-config.js +56 -2
- package/template/coding-task-manager/lib/walle-row-history.js +495 -0
- package/template/coding-task-manager/lib/walle-supervisor.js +33 -14
- package/template/coding-task-manager/lib/watch-worker-client.js +203 -0
- package/template/coding-task-manager/lib/worker-terminal-output.js +5 -2
- package/template/coding-task-manager/lib/ws/hub-bridge.js +35 -0
- package/template/coding-task-manager/lib/ws/lifecycle.js +6 -11
- package/template/coding-task-manager/lib/ws/misc.js +1 -1
- package/template/coding-task-manager/lib/ws/state-sync.js +106 -4
- package/template/coding-task-manager/lib/ws/terminal-attach.js +91 -0
- package/template/coding-task-manager/oauth-proxy.js +112 -115
- package/template/coding-task-manager/package-lock.json +10 -94
- package/template/coding-task-manager/package.json +4 -3
- package/template/coding-task-manager/protocol/message-table.json +10 -0
- package/template/coding-task-manager/protocol/messages.js +10 -0
- package/template/coding-task-manager/protocol/ws-schema.json +20 -0
- package/template/coding-task-manager/protocol/ws-schema.md +2 -0
- package/template/coding-task-manager/public/css/app.css +170 -0
- package/template/coding-task-manager/public/css/walle-session.css +4 -0
- package/template/coding-task-manager/public/index.html +473 -243
- package/template/coding-task-manager/public/js/agent-command.js +86 -0
- package/template/coding-task-manager/public/js/app/backups-panel.js +111 -5
- package/template/coding-task-manager/public/js/app/coding-agent-upgrade.js +103 -4
- package/template/coding-task-manager/public/js/app/machines-page.js +1328 -8
- package/template/coding-task-manager/public/js/app/models-tab.js +113 -38
- package/template/coding-task-manager/public/js/app/restart-banner.js +53 -0
- package/template/coding-task-manager/public/js/app/worktrees-panel.js +184 -2
- package/template/coding-task-manager/public/js/background-work.js +196 -27
- package/template/coding-task-manager/public/js/coding-session-model-presentation.js +138 -10
- package/template/coding-task-manager/public/js/core/active-session-groups.js +179 -0
- package/template/coding-task-manager/public/js/core/pending-create.js +238 -0
- package/template/coding-task-manager/public/js/core/recent-machine-source.js +228 -0
- package/template/coding-task-manager/public/js/core/session-commands.js +180 -14
- package/template/coding-task-manager/public/js/dashboard-client-function-order.json +8 -0
- package/template/coding-task-manager/public/js/document-review-links.js +9 -1
- package/template/coding-task-manager/public/js/file-resolution-client.js +52 -1
- package/template/coding-task-manager/public/js/history-app-seam.js +22 -2
- package/template/coding-task-manager/public/js/machine-pool-shared.js +558 -3
- package/template/coding-task-manager/public/js/message-renderer.js +4 -3
- package/template/coding-task-manager/public/js/model-picker.js +3 -1
- package/template/coding-task-manager/public/js/native-subagent-review.js +15 -2
- package/template/coding-task-manager/public/js/new-session-agent-grid.js +346 -0
- package/template/coding-task-manager/public/js/pasted-content.js +236 -0
- package/template/coding-task-manager/public/js/pe-private-content-lifetime.js +39 -7
- package/template/coding-task-manager/public/js/private-model-lifetime.js +6 -2
- package/template/coding-task-manager/public/js/prompts.js +11 -10
- package/template/coding-task-manager/public/js/protocol.js +10 -0
- package/template/coding-task-manager/public/js/restart-banner-policy.js +29 -1
- package/template/coding-task-manager/public/js/session-model-picker.js +447 -57
- package/template/coding-task-manager/public/js/session-search-utils.js +18 -2
- package/template/coding-task-manager/public/js/session-usage-view.js +2 -1
- package/template/coding-task-manager/public/js/session-workspace-tracking.js +51 -1
- package/template/coding-task-manager/public/js/state-sync-client.js +10 -1
- package/template/coding-task-manager/public/js/stream-view.js +6 -5
- package/template/coding-task-manager/public/js/terminal/conv-only-session.js +287 -0
- package/template/coding-task-manager/public/js/terminal/runtime-09.js +2 -0
- package/template/coding-task-manager/public/js/terminal/runtime-10.js +5 -5
- package/template/coding-task-manager/public/js/terminal/runtime-12.js +8 -1
- package/template/coding-task-manager/public/js/terminal/runtime-16.js +4 -0
- package/template/coding-task-manager/public/js/terminal/runtime-20.js +1 -1
- package/template/coding-task-manager/public/js/terminal-attachment-draft.js +67 -13
- package/template/coding-task-manager/public/js/terminal-image-orchestration.js +52 -6
- package/template/coding-task-manager/public/js/terminal-wheel.js +23 -3
- package/template/coding-task-manager/public/js/walle/chat-conversation.js +4 -4
- package/template/coding-task-manager/public/js/walle.js +6 -0
- package/template/coding-task-manager/public/js/ws/live-dispatch.js +10 -0
- package/template/coding-task-manager/public/m/app.css +140 -0
- package/template/coding-task-manager/public/m/app.js +507 -68
- package/template/coding-task-manager/public/m/index.html +17 -0
- package/template/coding-task-manager/public/m/machines.js +838 -4
- package/template/coding-task-manager/public/m/private-api.js +31 -1
- package/template/coding-task-manager/public/usage.html +1 -0
- package/template/coding-task-manager/scripts/dev-route-fixture/synthetic-route-upstream.js +104 -0
- package/template/coding-task-manager/scripts/dev-route-fixture.js +339 -0
- package/template/coding-task-manager/scripts/opencode-lead-route-probe.js +195 -0
- package/template/coding-task-manager/scripts/opencode-v2-contract-probe/fake-anthropic.js +168 -0
- package/template/coding-task-manager/scripts/opencode-v2-contract-probe/probe-plugin/server.js +95 -0
- package/template/coding-task-manager/scripts/opencode-v2-contract-probe.js +673 -0
- package/template/coding-task-manager/server.js +1950 -11679
- package/template/coding-task-manager/session-integrity.js +64 -4
- package/template/coding-task-manager/workers/db-owner-worker.js +19 -2
- package/template/coding-task-manager/workers/online-backup-worker.js +1 -0
- package/template/coding-task-manager/workers/read-pool-model-collector.js +51 -3
- package/template/coding-task-manager/workers/read-pool-worker.js +76 -6
- package/template/coding-task-manager/workers/session-host-pool-process.js +6 -6
- package/template/coding-task-manager/workers/session-host-process.js +5 -5
- package/template/coding-task-manager/workers/watch-worker.js +105 -0
- package/template/coding-task-manager/workers/worktree-worker.js +168 -33
- package/template/ctm-relay/lib/protocol.js +14 -1
- package/template/package-lock.json +2 -2
- package/template/package.json +1 -1
- package/template/shared/backup-retention.js +82 -0
- package/template/shared/conversation-admission.js +2 -0
- package/template/shared/conversation-provenance.js +3 -7
- package/template/shared/conversation-storage-v2-contract.js +5 -0
- package/template/shared/linked-worktree.js +51 -0
- package/template/shared/macos-fda-target.js +57 -0
- package/template/shared/orphan-parents.js +55 -0
- package/template/shared/release-schema.json +2 -2
- package/template/shared/storage/contract.js +3 -0
- package/template/wall-e/adapters/imessage.js +12 -0
- package/template/wall-e/agent.js +71 -4
- package/template/wall-e/api-walle.js +21 -1
- package/template/wall-e/bin/train-gemma-e4b-tooluse.js +2 -2
- package/template/wall-e/bin/walle-mcp-stdio.js +5 -5
- package/template/wall-e/brain/brain-join.js +859 -0
- package/template/wall-e/brain/brain-sync-membership.js +20 -0
- package/template/wall-e/brain/brain-sync-store.js +131 -77
- package/template/wall-e/brain/brain-sync-v2-schema.js +203 -0
- package/template/wall-e/brain/brain-sync-v2.js +578 -0
- package/template/wall-e/brain/delegate-model-prefs-store.js +13 -4
- package/template/wall-e/brain/deterministic-id.js +51 -0
- package/template/wall-e/brain/memories.js +2 -2
- package/template/wall-e/brain/migrations.js +40 -6
- package/template/wall-e/brain/model-identity-migration.js +1 -1
- package/template/wall-e/brain/owner-call-whitelist.js +23 -7
- package/template/wall-e/brain/schema.js +45 -85
- package/template/wall-e/brain.js +171 -35
- package/template/wall-e/chat.js +3 -3
- package/template/wall-e/coding/agent-shell-env.js +7 -2
- package/template/wall-e/coding/prompt-bundle.js +66 -21
- package/template/wall-e/config/main-loop-exemptions.json +2 -2
- package/template/wall-e/http/admin-api.js +37 -0
- package/template/wall-e/http/gws-api.js +4 -0
- package/template/wall-e/http/helper-rules-api.js +7 -1
- package/template/wall-e/http/model-admin.js +8 -1
- package/template/wall-e/http/model-delegate-pref-admin.js +3 -3
- package/template/wall-e/http/model-proxy-providers.js +174 -1
- package/template/wall-e/http/model-route-health.js +157 -0
- package/template/wall-e/http/sync-api.js +278 -464
- package/template/wall-e/jobs/job-runner.js +28 -1
- package/template/wall-e/lib/brain-owner-op-priority.js +9 -1
- package/template/wall-e/lib/ctm-data-dir.js +26 -0
- package/template/wall-e/lib/derivation-home.js +147 -0
- package/template/wall-e/lib/helper-rules/evaluate.js +50 -9
- package/template/wall-e/lib/helper-rules/grade.js +51 -8
- package/template/wall-e/lib/helper-rules/lead-call-hook.js +38 -5
- package/template/wall-e/lib/helper-rules/store.js +4 -2
- package/template/wall-e/lib/landing-mcp-tools.js +170 -0
- package/template/wall-e/lib/mcp-client-config.js +133 -14
- package/template/wall-e/lib/mcp-gateway-migrate.js +28 -64
- package/template/wall-e/lib/mcp-integration.js +58 -13
- package/template/wall-e/lib/parent-death.js +7 -1
- package/template/wall-e/lib/scheduler-worker-jobs.js +6 -4
- package/template/wall-e/llm/delegate-lead-prefs.js +16 -1
- package/template/wall-e/llm/delegate-vendor-default.js +12 -5
- package/template/wall-e/llm/model-roles.js +1 -1
- package/template/wall-e/llm/native-delegate-selection.js +56 -8
- package/template/wall-e/llm/worker-delegate-args.js +72 -7
- package/template/wall-e/llm/worker-mcp-routing.js +66 -17
- package/template/wall-e/loops/brain-custom-writes.js +19 -0
- package/template/wall-e/loops/ingest.js +17 -1
- package/template/wall-e/loops/think.js +19 -4
- package/template/wall-e/mcp-contract.js +222 -6
- package/template/wall-e/mcp-protocol-contract.js +40 -5
- package/template/wall-e/mcp-server.js +128 -29
- package/template/wall-e/mcp-worker-schemas.js +5 -5
- package/template/wall-e/memory/ctm-context-client.js +85 -0
- package/template/wall-e/memory/ctm-session-context.js +9 -3
- package/template/wall-e/memory/hub-bridge-client.js +388 -0
- package/template/wall-e/memory/replica-origin.js +56 -0
- package/template/wall-e/memory/session-pool.js +135 -0
- package/template/wall-e/runtime/live-capabilities.js +8 -3
- package/template/wall-e/server.js +4 -2
- package/template/wall-e/shared/release-schema.json +2 -2
- package/template/wall-e/shared/sqlite-file-set.js +39 -0
- package/template/wall-e/shared/storage/contract.js +3 -0
- package/template/wall-e/skills/_templates/delegate-worker/VERSION +1 -1
- package/template/wall-e/skills/_templates/delegate-worker/released-sha256.json +7 -1
- package/template/wall-e/skills/_templates/delegate-worker/templates/claude/SKILL.md +4 -4
- package/template/wall-e/skills/_templates/delegate-worker/templates/codex/SKILL.md +6 -6
- package/template/wall-e/skills/_templates/fleet-sync/VERSION +1 -0
- package/template/wall-e/skills/_templates/fleet-sync/released-sha256.json +16 -0
- package/template/wall-e/skills/_templates/fleet-sync/templates/claude/SKILL.md +64 -0
- package/template/wall-e/skills/_templates/fleet-sync/templates/codex/SKILL.md +64 -0
- package/template/wall-e/tools/chrome-automation.js +6 -0
- package/template/wall-e/training/setup-cuda-train-env.sh +2 -2
- package/template/wall-e/workers/brain-owner-worker.js +18 -4
- package/template/wall-e/workers/mcp-gateway-process.js +5 -5
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
// `../brain/job-store` here.
|
|
49
49
|
|
|
50
50
|
const { writeRunArtifact, pruneRunArtifacts, classifySkillError } = require('../lib/run-artifacts');
|
|
51
|
+
const { resolvePlacement } = require('../lib/derivation-home');
|
|
51
52
|
|
|
52
53
|
// The per-run execution budget constants and the prompt builder live in the
|
|
53
54
|
// require-free leaf `jobs/job-defaults.js` (moved there verbatim by fix round 2);
|
|
@@ -65,6 +66,13 @@ const {
|
|
|
65
66
|
// §4: default concurrency is 1 — run jobs one at a time per tick, no flag.
|
|
66
67
|
const DEFAULT_JOB_CONCURRENCY = 1;
|
|
67
68
|
|
|
69
|
+
// D-5/S-16 (shared-memory WP-2): job kinds whose INPUT is replicated brain rows, so the
|
|
70
|
+
// derived rows they mint (skill-executor's timestamped `source_id`, a prompt job's model
|
|
71
|
+
// output) would multiply across N replicas. Only the derivation home selects them;
|
|
72
|
+
// `builtin` jobs (e.g. `slack.inbound`) act on data this machine has and always run.
|
|
73
|
+
const DERIVED_JOB_ACTION_KINDS = new Set(['skill', 'prompt']);
|
|
74
|
+
const NOT_DERIVATION_HOME = 'not_derivation_home';
|
|
75
|
+
|
|
68
76
|
// §6.1 retention: keep the newest 200 runs per job.
|
|
69
77
|
const DEFAULT_RUN_KEEP = 200;
|
|
70
78
|
|
|
@@ -337,9 +345,13 @@ async function runJob(job, { trigger = 'schedule', now = Date.now, executors, ac
|
|
|
337
345
|
*
|
|
338
346
|
* @returns {Promise<{ran: number, skipped: number, considered: number, decisions: Array}>}
|
|
339
347
|
*/
|
|
340
|
-
async function runDueJobs({ now = Date.now, executors, brain, deps } = {}) {
|
|
348
|
+
async function runDueJobs({ now = Date.now, executors, brain, deps, placement } = {}) {
|
|
341
349
|
const io = resolveAccess(brain);
|
|
342
350
|
const at = typeof now === 'function' ? now() : now;
|
|
351
|
+
// D-5/S-16 (WP-2): the `jobs` table is host-local and stays untouched; the placement gate
|
|
352
|
+
// lives HERE, at the selection point, so a non-home node simply never selects a derived job.
|
|
353
|
+
// `placement` is the test seam; production resolves it from CTM (cached 60 s).
|
|
354
|
+
const resolvedPlacement = placement || await resolvePlacement();
|
|
343
355
|
|
|
344
356
|
const jobs = await io.read('listJobs', [{ includeDisabled: true }]);
|
|
345
357
|
const decisions = [];
|
|
@@ -350,6 +362,19 @@ async function runDueJobs({ now = Date.now, executors, brain, deps } = {}) {
|
|
|
350
362
|
for (const job of jobs || []) {
|
|
351
363
|
if (ran >= DEFAULT_JOB_CONCURRENCY) break;
|
|
352
364
|
considered += 1;
|
|
365
|
+
// WP-2: a derived job on a non-home node is skipped with its own reason, reported in the
|
|
366
|
+
// same `decisions` array every other skip uses (no row is disabled, no run is recorded).
|
|
367
|
+
if (!resolvedPlacement.home && DERIVED_JOB_ACTION_KINDS.has(job.action_kind)) {
|
|
368
|
+
skipped += 1;
|
|
369
|
+
decisions.push({
|
|
370
|
+
job_id: job.id,
|
|
371
|
+
name: job.name,
|
|
372
|
+
decision: 'skip',
|
|
373
|
+
reason: NOT_DERIVATION_HOME,
|
|
374
|
+
details: { action_kind: job.action_kind, placement: resolvedPlacement.reason },
|
|
375
|
+
});
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
353
378
|
// WP-5a (D-12): the connection record is the authority — a job that declares
|
|
354
379
|
// a requirement is judged by its kind's row, and a job that declares none is
|
|
355
380
|
// 'ok'. Only reconnect_required/disabled gate dispatch (§4/D-6).
|
|
@@ -527,4 +552,6 @@ module.exports = {
|
|
|
527
552
|
MIN_TASK_EXECUTION_TIMEOUT_MS,
|
|
528
553
|
DEFAULT_JOB_CONCURRENCY,
|
|
529
554
|
DEFAULT_RUN_KEEP,
|
|
555
|
+
DERIVED_JOB_ACTION_KINDS,
|
|
556
|
+
NOT_DERIVATION_HOME,
|
|
530
557
|
};
|
|
@@ -13,7 +13,15 @@ const OWNER_METHOD_PRIORITY = Object.freeze({
|
|
|
13
13
|
// background — scheduled, resumable
|
|
14
14
|
markTurnLedgerOutboxDelivered: 'background',
|
|
15
15
|
recordTurnLedgerOutboxFailure: 'background',
|
|
16
|
-
backfillEntityLinkBatch: 'background', backfillClassifyBatch: 'background',
|
|
16
|
+
backfillEntityLinkBatch: 'background', backfillClassifyBatch: 'background', brainSyncClockSeed: 'background',
|
|
17
|
+
// WP-1 §6.4: the v2 feed/apply pair and the hub bookkeeping — peer-driven, no user waits on
|
|
18
|
+
// them locally (the hub's own tick owns the latency budget), so they share the seed walk's
|
|
19
|
+
// class rather than competing with an interactive turn.
|
|
20
|
+
brainSyncV2Vector: 'background', brainSyncV2Changes: 'background', brainSyncV2Apply: 'background',
|
|
21
|
+
brainSyncV2MemberVector: 'background', brainSyncV2PruneTombstones: 'background', brainSyncV2Digest: 'background',
|
|
22
|
+
// WP-4 §6.7: the join trio + the import job's step — peer/job-driven, no local user waits on them.
|
|
23
|
+
brainSyncV2JoinSnapshot: 'background', brainSyncV2JoinImport: 'background',
|
|
24
|
+
brainSyncV2JoinStatus: 'background', brainSyncV2JoinStep: 'background',
|
|
17
25
|
backfillStripNoiseBatch: 'background', backfillInsertMemoryIndexBatch: 'background',
|
|
18
26
|
backfillMarkEmbedFailed: 'background', embeddingsUpsertBatch: 'background',
|
|
19
27
|
commitThinkExtraction: 'background', ingestInsertMemoryBatch: 'background',
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// R-6/R-7 (§5, D-4) — "CTM's data dir", computed the way CTM computes it for itself
|
|
4
|
+
// (coding-task-manager/lib/data-dir.js:17-21) but from a GIVEN env object.
|
|
5
|
+
//
|
|
6
|
+
// Call it in the Wall-E DAEMON (the process that serves POST /api/walle/sync/v2/join/import),
|
|
7
|
+
// NEVER in the brain-owner worker: the owner's env is a deliberate whitelist
|
|
8
|
+
// (lib/brain-owner-env.js) that sets WALL_E_DATA_DIR to the brain's own directory and drops
|
|
9
|
+
// CTM_DATA_DIR (I-5), so resolving the inbox root there names the wrong directory — which is
|
|
10
|
+
// exactly the Spark fault (every join import refused JOIN_PATH_INVALID while CTM wrote its
|
|
11
|
+
// snapshots to the CTM inbox). The daemon resolves the root and passes it down as `dataDir`
|
|
12
|
+
// (http/sync-api.js _handleV2JoinImport → brain/brain-join.js isInsideJoinInbox).
|
|
13
|
+
|
|
14
|
+
const os = require('node:os');
|
|
15
|
+
const path = require('node:path');
|
|
16
|
+
|
|
17
|
+
// CTM_DATA_DIR, then WALL_E_DATA_DIR (wall-e's own override, honoured by CTM's resolver too so a
|
|
18
|
+
// single value works for both processes), then <HOME>/.walle/data. An empty — or
|
|
19
|
+
// whitespace-only — value counts as unset, matching CTM's truthiness test on the raw value.
|
|
20
|
+
function resolveCtmDataDir(env = process.env) {
|
|
21
|
+
const override = String(env.CTM_DATA_DIR || env.WALL_E_DATA_DIR || '').trim();
|
|
22
|
+
if (override) return path.resolve(override);
|
|
23
|
+
return path.resolve(env.HOME || os.homedir(), '.walle', 'data');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
module.exports = { resolveCtmDataDir };
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// shared-memory WP-2 (design `wall-e/docs/shared-memory-every-machine-2026-10-31.html`
|
|
4
|
+
// §5 D-5, §9 S-16..S-21): WHERE derived work runs.
|
|
5
|
+
//
|
|
6
|
+
// After replication every machine holds the same brain rows. A producer whose INPUT is
|
|
7
|
+
// replicated rows would then run N times and mint N different rows (e.g.
|
|
8
|
+
// `skills/skill-executor.js` minting `skill-${skill.id}-${Date.now()}-${count}`), so D-5
|
|
9
|
+
// single-homes *derived* production on the "derivation home": the Wall-E whose CTM does
|
|
10
|
+
// not report `role:'box'`. Host-local ingest keeps running wherever the data lives; only
|
|
11
|
+
// the derived step is gated.
|
|
12
|
+
//
|
|
13
|
+
// The role fact comes from CTM (`memory/hub-bridge-client.js:fetchStatus` ->
|
|
14
|
+
// `GET /api/hub-bridge/status` -> `{ role, hubs, poolMembers }`), which answers null when
|
|
15
|
+
// CTM is unreachable. Three placements:
|
|
16
|
+
//
|
|
17
|
+
// role 'box' -> { home: false, reason: 'box' } (a box skips derived work)
|
|
18
|
+
// null / no string role -> { home: false, reason: 'role_unknown' } (D-5: skip, never guess)
|
|
19
|
+
// any other role -> { home: true, reason: 'not_box' } (hub, standalone installs)
|
|
20
|
+
//
|
|
21
|
+
// The answer is cached for CACHE_TTL_MS in BOTH directions: a probe per scheduler tick per
|
|
22
|
+
// producer would be a CTM round-trip storm, and a negative answer must not flap back to
|
|
23
|
+
// "home" mid-run. Tests never hit a real CTM — `resolvePlacement({ fetchStatus })` is the seam.
|
|
24
|
+
|
|
25
|
+
const hubBridgeClient = require('../memory/hub-bridge-client');
|
|
26
|
+
|
|
27
|
+
const CACHE_TTL_MS = 60 * 1000;
|
|
28
|
+
|
|
29
|
+
const REASON_NOT_BOX = 'not_box';
|
|
30
|
+
const REASON_BOX = 'box';
|
|
31
|
+
const REASON_ROLE_UNKNOWN = 'role_unknown';
|
|
32
|
+
const REASON_MEMBER = 'member';
|
|
33
|
+
|
|
34
|
+
// `{ at, value }` — one process-wide memo (positive AND negative), reset by
|
|
35
|
+
// `_resetPlacementCacheForTests()`.
|
|
36
|
+
let _cache = null;
|
|
37
|
+
|
|
38
|
+
function _classify(status) {
|
|
39
|
+
if (status == null || typeof status !== 'object') {
|
|
40
|
+
return { home: false, role: null, reason: REASON_ROLE_UNKNOWN };
|
|
41
|
+
}
|
|
42
|
+
const role = status.role;
|
|
43
|
+
// A missing key, an explicit null, and an empty string all mean "CTM did not tell us its
|
|
44
|
+
// role" — D-5 says skip derived work for that run rather than guess (fail closed).
|
|
45
|
+
if (typeof role !== 'string' || role === '') {
|
|
46
|
+
return { home: false, role: null, reason: REASON_ROLE_UNKNOWN };
|
|
47
|
+
}
|
|
48
|
+
if (role === 'box') return { home: false, role, reason: REASON_BOX };
|
|
49
|
+
return { home: true, role, reason: REASON_NOT_BOX };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Resolve where this Wall-E sits. Never throws: an unreachable CTM is the named
|
|
54
|
+
* `role_unknown`, not a crash.
|
|
55
|
+
*
|
|
56
|
+
* @param {Object} [opts]
|
|
57
|
+
* @param {Object} [opts.env=process.env] env handed to the CTM client
|
|
58
|
+
* @param {Function} [opts.fetchStatus] test seam (defaults to the hub-bridge client)
|
|
59
|
+
* @param {Function|number} [opts.now=Date.now] clock (injectable for the cache TTL)
|
|
60
|
+
* @returns {Promise<{home: boolean, role: string|null, reason: string}>}
|
|
61
|
+
*/
|
|
62
|
+
// The durable membership marker (brain/brain-sync-v2.js markMembership): a Wall-E a home has synced
|
|
63
|
+
// is a member. Read locally, before any network: CTM's role:'box' is only reported while a hub link is
|
|
64
|
+
// open (coding-task-manager/lib/hub-bridge-box.js:186), so it cannot be the only signal.
|
|
65
|
+
function _defaultReadMembership() {
|
|
66
|
+
try {
|
|
67
|
+
const brain = require('../brain');
|
|
68
|
+
const db = typeof brain.getDb === 'function' ? brain.getDb() : null;
|
|
69
|
+
if (!db) return null;
|
|
70
|
+
return require('../brain/brain-sync-membership').readMembership(db);
|
|
71
|
+
} catch {
|
|
72
|
+
return null; // HANDLE: no brain handle in this process yet — fall through to the CTM role
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function resolvePlacement({ env = process.env, fetchStatus, readMembership, now = Date.now } = {}) {
|
|
77
|
+
const clock = typeof now === 'function' ? now : () => now;
|
|
78
|
+
const at = clock();
|
|
79
|
+
if (_cache && (at - _cache.at) < CACHE_TTL_MS) return _cache.value;
|
|
80
|
+
const membership = (typeof readMembership === 'function' ? readMembership : _defaultReadMembership)();
|
|
81
|
+
if (membership && membership.role === 'member') {
|
|
82
|
+
const value = { home: false, role: 'member', reason: REASON_MEMBER };
|
|
83
|
+
_cache = { at, value };
|
|
84
|
+
return value;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const fetch = typeof fetchStatus === 'function' ? fetchStatus : hubBridgeClient.fetchStatus;
|
|
88
|
+
let status = null;
|
|
89
|
+
try {
|
|
90
|
+
status = await fetch({ env });
|
|
91
|
+
} catch {
|
|
92
|
+
// REPORT: a thrown probe is exactly the unreachable-CTM case the caller must treat as
|
|
93
|
+
// 'role_unknown' (hub-bridge-client.fetchStatus itself already answers null; this guards
|
|
94
|
+
// an injected seam that throws instead).
|
|
95
|
+
status = null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const value = _classify(status);
|
|
99
|
+
_cache = { at, value };
|
|
100
|
+
return value;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Convenience boolean: is this Wall-E the derivation home? */
|
|
104
|
+
async function isDerivationHome(opts) {
|
|
105
|
+
return (await resolvePlacement(opts)).home;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The skip record a gated producer returns instead of running. Same shape the loops already
|
|
110
|
+
* use for "did no work" (`{ skipped: true, reason, ... }`) so `onResult` needs no new branch.
|
|
111
|
+
*/
|
|
112
|
+
function placementSkip(name, placement) {
|
|
113
|
+
return {
|
|
114
|
+
skipped: true,
|
|
115
|
+
reason: (placement && placement.reason) || REASON_ROLE_UNKNOWN,
|
|
116
|
+
job: name,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Run `fn` only on the derivation home; otherwise answer the skip record. This is the wrapper
|
|
122
|
+
* agent.js puts around a `placement: 'home'` registration's `run`:
|
|
123
|
+
*
|
|
124
|
+
* run: () => runIfHome('reflect', () => reflect.runOnce())
|
|
125
|
+
*/
|
|
126
|
+
async function runIfHome(name, fn, opts = {}) {
|
|
127
|
+
const placement = await resolvePlacement(opts);
|
|
128
|
+
if (!placement.home) return placementSkip(name, placement);
|
|
129
|
+
return fn();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Test seam: clear the 60 s memo (both directions). */
|
|
133
|
+
function _resetPlacementCacheForTests() {
|
|
134
|
+
_cache = null;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
module.exports = {
|
|
138
|
+
resolvePlacement,
|
|
139
|
+
isDerivationHome,
|
|
140
|
+
placementSkip,
|
|
141
|
+
runIfHome,
|
|
142
|
+
_resetPlacementCacheForTests,
|
|
143
|
+
CACHE_TTL_MS,
|
|
144
|
+
REASON_NOT_BOX,
|
|
145
|
+
REASON_BOX,
|
|
146
|
+
REASON_ROLE_UNKNOWN,
|
|
147
|
+
};
|
|
@@ -124,6 +124,9 @@ function _watchMetrics(outcomes, watcherUsd) {
|
|
|
124
124
|
const silentUseful = outcomes.filter((row) => row.label === 'silent_useful').length;
|
|
125
125
|
const silentEmpty = outcomes.filter((row) => row.label === 'silent_empty').length;
|
|
126
126
|
const labelled = useful + empty;
|
|
127
|
+
// Legacy (WP-2): Wall-E no longer produces `silent_*` rows — nothing reads these fields any
|
|
128
|
+
// more — but events and rows written before the silent mode was retired still carry them, so
|
|
129
|
+
// the metrics shape stays for the panel.
|
|
127
130
|
const silentLabelled = silentUseful + silentEmpty;
|
|
128
131
|
const watcherUsdWindow = _watcherUsdWindow(watcherUsd);
|
|
129
132
|
return {
|
|
@@ -143,24 +146,62 @@ function _watchMetrics(outcomes, watcherUsd) {
|
|
|
143
146
|
};
|
|
144
147
|
}
|
|
145
148
|
|
|
146
|
-
|
|
147
|
-
|
|
149
|
+
/** A labelled row: a wake the lead answered in time (`useful`) or did not need (`empty`). */
|
|
150
|
+
function _isLabelledRow(row) {
|
|
151
|
+
return row.label === 'useful' || row.label === 'empty';
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* WP-2 (§6, lead ruling): the rows this cell's CURRENT regime produced — the ones at or after
|
|
156
|
+
* `state_changed_at`. A cell that just passed its probe still has up to PROBE_N pre-probe rows in
|
|
157
|
+
* the 20-row trailing window; measuring the whole window would read 7 probe-useful rows next to 9
|
|
158
|
+
* old empty ones as ~0.44 and turn the cell straight back off. resilience4j starts a fresh metrics
|
|
159
|
+
* window on every state transition for the same reason. Rows with no readable timestamp are kept
|
|
160
|
+
* (the same predicate `_evaluateExplore`'s probe filter uses).
|
|
161
|
+
*/
|
|
162
|
+
function _regimeRows(cell, outcomes) {
|
|
163
|
+
const changedAt = _toMs(cell.state_changed_at);
|
|
164
|
+
return outcomes.filter((row) => {
|
|
165
|
+
const createdMs = _toMs(row.created_at);
|
|
166
|
+
return changedAt == null || createdMs == null || createdMs >= changedAt;
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function _evaluateWatch(cell, outcomes, watcherUsd, now) {
|
|
171
|
+
const cellState = _stateOf(cell);
|
|
172
|
+
|
|
148
173
|
if (cellState === 'on') {
|
|
174
|
+
// Only the current regime is evidence: an on-cell demotes on its own rows, never on the
|
|
175
|
+
// pre-probe rows its last transition left in the window.
|
|
176
|
+
const metrics = _watchMetrics(_regimeRows(cell, outcomes), watcherUsd);
|
|
149
177
|
if (metrics.labelled >= MIN_LABELLED && metrics.precision < WATCH_OFF_BELOW) {
|
|
150
178
|
return _verdict('off', cellState, metrics, REASONS.WATCH_PRECISION_BELOW);
|
|
151
179
|
}
|
|
152
180
|
return _verdict(cellState, cellState, metrics, null);
|
|
153
181
|
}
|
|
182
|
+
|
|
154
183
|
if (cellState === 'off') {
|
|
155
|
-
//
|
|
156
|
-
//
|
|
157
|
-
metrics
|
|
158
|
-
|
|
159
|
-
|
|
184
|
+
// Rows never move an off cell — not the retired silent ticks, not any other label. Only
|
|
185
|
+
// elapsed time does, and only when the user has not vetoed the route.
|
|
186
|
+
const metrics = _watchMetrics(outcomes, watcherUsd);
|
|
187
|
+
const changedAt = _toMs(cell.state_changed_at);
|
|
188
|
+
const nowMs = _toMs(now) ?? Date.now();
|
|
189
|
+
const days = changedAt == null ? 0 : (nowMs - changedAt) / DAY_MS;
|
|
190
|
+
if (!_vetoOf(cell) && days >= EXPLORE_PROBE_AFTER_DAYS) {
|
|
191
|
+
return _verdict('probe', cellState, metrics, REASONS.EXPLORE_PROBE_AFTER);
|
|
160
192
|
}
|
|
161
193
|
return _verdict(cellState, cellState, metrics, null);
|
|
162
194
|
}
|
|
163
|
-
|
|
195
|
+
|
|
196
|
+
// probe: the next PROBE_N labelled rows that landed AFTER the probe started decide it.
|
|
197
|
+
const regime = _regimeRows(cell, outcomes);
|
|
198
|
+
const metrics = _watchMetrics(regime, watcherUsd);
|
|
199
|
+
const probeWindow = regime.filter(_isLabelledRow).slice(0, PROBE_N);
|
|
200
|
+
metrics.probed = probeWindow.length;
|
|
201
|
+
if (probeWindow.length < PROBE_N) return _verdict(cellState, cellState, metrics, null);
|
|
202
|
+
const precision = _ratio(probeWindow.filter((row) => row.label === 'useful').length, probeWindow.length);
|
|
203
|
+
if (precision >= WATCH_ON_ABOVE) return _verdict('on', cellState, metrics, REASONS.EXPLORE_PROBE_PASSED);
|
|
204
|
+
return _verdict('off', cellState, metrics, REASONS.EXPLORE_PROBE_FAILED);
|
|
164
205
|
}
|
|
165
206
|
|
|
166
207
|
// --- explore ----------------------------------------------------------------------
|
|
@@ -322,7 +363,7 @@ function evaluateCell(cell, trailingOutcomes, { now, leadBurstUsd, watcherUsd }
|
|
|
322
363
|
if (kind === 'explore' || String(cell?.cell_key || '').startsWith('explore|')) {
|
|
323
364
|
return _evaluateExplore(cell, outcomes, now, leadBurstUsd);
|
|
324
365
|
}
|
|
325
|
-
return _evaluateWatch(
|
|
366
|
+
return _evaluateWatch(cell, outcomes, watcherUsd, now);
|
|
326
367
|
}
|
|
327
368
|
|
|
328
369
|
/** The metrics a short-circuited (vetoed) cell reports — same shape as its kind's. */
|
|
@@ -25,13 +25,22 @@
|
|
|
25
25
|
// * an unparsed first reply earns ONE re-ask of the same pinned model with the parse error
|
|
26
26
|
// appended, and a second failure stores the raw reply so the failure is visible on the panel.
|
|
27
27
|
// A cheaper judge is still never substituted (D-19).
|
|
28
|
+
//
|
|
29
|
+
// Round 3 WP-1 (§4 D-1..D-5): the budget, and the truth of a cut-off reply.
|
|
30
|
+
// * the output ceiling is the role API's own MAX_COMPLETION_TOKENS, not a hand-picked number
|
|
31
|
+
// (D-1) and no thinking/effort knob is configured (D-2);
|
|
32
|
+
// * a `max_tokens` stop is `grade_truncated`: the text is cut off, so it is never parsed and
|
|
33
|
+
// never re-asked (D-3);
|
|
34
|
+
// * an empty reply is `grade_empty` and earns NO re-ask, so an empty assistant turn can never
|
|
35
|
+
// reach the provider guard (D-4);
|
|
36
|
+
// * every unavailable sample carries the stop reason, and the call carries the explore row's
|
|
37
|
+
// worker id as `sessionId` so grader spend joins the cell (D-5).
|
|
28
38
|
|
|
29
39
|
const fs = require('node:fs');
|
|
30
40
|
const path = require('node:path');
|
|
31
41
|
|
|
32
42
|
const EXPLORE_GRADE_EVERY = 5; // D-12: one in five completed hand-offs per cell
|
|
33
43
|
const GRADE_TASK = 'explore-handoff-grade';
|
|
34
|
-
const GRADE_MAX_TOKENS = 400;
|
|
35
44
|
const GRADE_TIMEOUT_MS = 120000;
|
|
36
45
|
const CARD_MAX_CHARS = 12000;
|
|
37
46
|
const BRIEF_MAX_CHARS = 4000; // the brief's share of the card; the report keeps the rest
|
|
@@ -138,6 +147,11 @@ function _replyText(reply) {
|
|
|
138
147
|
return _str(reply && reply.content);
|
|
139
148
|
}
|
|
140
149
|
|
|
150
|
+
/** D-3: `completeForRole` carries the provider's stop reason; a reply without one has none. */
|
|
151
|
+
function _stopReasonOf(reply) {
|
|
152
|
+
return _str(reply && reply.stopReason) || null;
|
|
153
|
+
}
|
|
154
|
+
|
|
141
155
|
/**
|
|
142
156
|
* D-8: a grader that wraps its JSON in one Markdown fence still yields its verdict. Only a fence
|
|
143
157
|
* the reply STARTS with is stripped, and only its matching close — prose around the block is left
|
|
@@ -170,12 +184,19 @@ function _parseReply(reply) {
|
|
|
170
184
|
|
|
171
185
|
/**
|
|
172
186
|
* Grade one exploration hand-off. Never throws; returns { ok:false, error } on any failure, and
|
|
173
|
-
* re-asks the same pinned model once when the first reply does not parse (D-8).
|
|
187
|
+
* re-asks the same pinned model once when the first reply does not parse (D-8). A truncated reply
|
|
188
|
+
* (round 3 D-3) is its own outcome and is never parsed or re-asked.
|
|
174
189
|
* @param {{ brief?:string, brief_path?:string, report?:string, report_path?:string, last_message_path?:string, toolLog:[{tool:string, path:string}] }} card clipped to CARD_MAX_CHARS (brief text, or read from brief_path; report text, or read from report_path/last_message_path)
|
|
175
|
-
* @param {{ completeForRole: Function, graderModel: string, brain?: object }} deps
|
|
176
|
-
* @returns {Promise<{ ok:true, sufficient:boolean, coverage:'all'|'most'|'little', inaccuracies:number, why:string } | { ok:false, error:string, raw?:string }>}
|
|
190
|
+
* @param {{ completeForRole: Function, graderModel: string, brain?: object, sessionId?: string|null }} deps
|
|
191
|
+
* @returns {Promise<{ ok:true, sufficient:boolean, coverage:'all'|'most'|'little', inaccuracies:number, why:string } | { ok:false, error:'grader_model_unset'|'grade_truncated'|'grade_empty'|'grade_unparsed'|string, stop_reason?:string|null, raw?:string }>}
|
|
177
192
|
*/
|
|
178
193
|
async function gradeHandoff(card, deps = {}) {
|
|
194
|
+
// Round 3 D-1: the grader's output budget IS the role API's ceiling. The pinned judge always
|
|
195
|
+
// thinks, and thinking counts inside max_tokens, so the old 400 was consumed before the verdict
|
|
196
|
+
// was written (14/19 live calls stopped on `max_tokens`). Billing is per token used, so the
|
|
197
|
+
// higher ceiling costs only what the judge actually thinks. Required here, not at module top:
|
|
198
|
+
// lib/ holds no load-time reference into llm/ (lead-call-hook.js's lazy-seam rule).
|
|
199
|
+
const { MAX_COMPLETION_TOKENS } = require('../../llm/model-roles');
|
|
179
200
|
const graderModel = _str(deps && deps.graderModel).trim();
|
|
180
201
|
// An unset pin is not a reason to grade with something else (D-0): the sample is unavailable.
|
|
181
202
|
if (!graderModel) return { ok: false, error: 'grader_model_unset' };
|
|
@@ -184,9 +205,12 @@ async function gradeHandoff(card, deps = {}) {
|
|
|
184
205
|
task: GRADE_TASK,
|
|
185
206
|
model: graderModel,
|
|
186
207
|
system: RUBRIC,
|
|
187
|
-
maxTokens:
|
|
208
|
+
maxTokens: MAX_COMPLETION_TOKENS,
|
|
188
209
|
timeoutMs: GRADE_TIMEOUT_MS,
|
|
189
210
|
temperature: 0,
|
|
211
|
+
// D-5: the explore row's worker id, so the grader's ledger row joins to the same cell the
|
|
212
|
+
// watcher spend is keyed by. A caller with no identity keeps today's NULL.
|
|
213
|
+
sessionId: deps.sessionId || null,
|
|
190
214
|
};
|
|
191
215
|
const userMessage = { role: 'user', content: _cardText(card) };
|
|
192
216
|
let reply;
|
|
@@ -197,10 +221,21 @@ async function gradeHandoff(card, deps = {}) {
|
|
|
197
221
|
// A call that never answered has no reply to re-ask about, so this is not retried.
|
|
198
222
|
return { ok: false, error: _errorCode(err) };
|
|
199
223
|
}
|
|
224
|
+
const firstStop = _stopReasonOf(reply);
|
|
225
|
+
// D-3: a `max_tokens` stop is a cut-off reply, not a verdict -- the text ends mid-object, so
|
|
226
|
+
// parsing it would fabricate a label and a re-ask at the same ceiling only truncates again.
|
|
227
|
+
if (firstStop === 'max_tokens') {
|
|
228
|
+
return { ok: false, error: 'grade_truncated', stop_reason: 'max_tokens', raw: _replyText(reply).slice(0, RAW_MAX_CHARS) };
|
|
229
|
+
}
|
|
200
230
|
const first = _parseReply(reply);
|
|
201
231
|
if (first.ok) return first;
|
|
202
232
|
const firstRaw = _replyText(reply);
|
|
233
|
+
// D-4: an empty first reply earns NO re-ask. The D-8 retry re-sends the raw reply as the
|
|
234
|
+
// assistant turn, and an empty one is rejected locally (WALLE_EMPTY_PROVIDER_MESSAGES) before
|
|
235
|
+
// any network call -- so the sample is stored as empty, with the stop reason that explains it.
|
|
236
|
+
if (!firstRaw.trim()) return { ok: false, error: 'grade_empty', stop_reason: firstStop };
|
|
203
237
|
let raw = firstRaw;
|
|
238
|
+
let stopReason = firstStop;
|
|
204
239
|
try {
|
|
205
240
|
// D-8: ONE bounded retry, the SAME pinned model and parameters, with the raw reply and the
|
|
206
241
|
// parse error on the wire (the MLflow "single retry with a tightened prompt" form).
|
|
@@ -212,15 +247,21 @@ async function gradeHandoff(card, deps = {}) {
|
|
|
212
247
|
{ role: 'user', content: `Reply with the JSON object only. Parse error: missing ${first.missing.join(', ')}` },
|
|
213
248
|
],
|
|
214
249
|
});
|
|
250
|
+
const retryStop = _stopReasonOf(retried);
|
|
251
|
+
if (retryStop === 'max_tokens') {
|
|
252
|
+
return { ok: false, error: 'grade_truncated', stop_reason: 'max_tokens', raw: _replyText(retried).slice(0, RAW_MAX_CHARS) };
|
|
253
|
+
}
|
|
215
254
|
const parsed = _parseReply(retried);
|
|
216
255
|
if (parsed.ok) return parsed;
|
|
217
256
|
raw = _replyText(retried);
|
|
257
|
+
stopReason = retryStop;
|
|
218
258
|
} catch {
|
|
219
259
|
// REPORT: the retry itself failed -- the sample is still stored as an unparsed grade, carrying
|
|
220
260
|
// the first raw reply, so the failure is visible rather than a silent hole in the rate.
|
|
221
261
|
raw = firstRaw;
|
|
262
|
+
stopReason = firstStop;
|
|
222
263
|
}
|
|
223
|
-
return { ok: false, error: 'grade_unparsed', raw: raw.slice(0, RAW_MAX_CHARS) };
|
|
264
|
+
return { ok: false, error: 'grade_unparsed', stop_reason: stopReason, raw: raw.slice(0, RAW_MAX_CHARS) };
|
|
224
265
|
}
|
|
225
266
|
|
|
226
267
|
/** D-12: every EXPLORE_GRADE_EVERY-th completed hand-off of a cell (its `helper_outcomes.seq`). */
|
|
@@ -231,11 +272,14 @@ function shouldGrade(seq) {
|
|
|
231
272
|
/**
|
|
232
273
|
* The persisted `helper_outcomes.grade_json` value: the four verdict fields, or `unavailable`.
|
|
233
274
|
* D-8: an unparsed sample keeps the raw reply (≤ RAW_MAX_CHARS) so the panel can show WHY it
|
|
234
|
-
* failed instead of an empty cell.
|
|
275
|
+
* failed instead of an empty cell. D-4: the stop reason is kept too (`max_tokens` reads as
|
|
276
|
+
* "budget", `end_turn` with no text as "the judge said nothing"), when the reply had one.
|
|
235
277
|
*/
|
|
236
278
|
function gradeToJson(result) {
|
|
237
279
|
if (!result || result.ok !== true) {
|
|
238
280
|
const json = { unavailable: true, error: _str(result && result.error) || 'grade_failed' };
|
|
281
|
+
const stopReason = _str(result && result.stop_reason);
|
|
282
|
+
if (stopReason) json.stop_reason = stopReason;
|
|
239
283
|
const raw = _str(result && result.raw);
|
|
240
284
|
if (raw) json.raw = raw.slice(0, RAW_MAX_CHARS);
|
|
241
285
|
return json;
|
|
@@ -265,7 +309,6 @@ module.exports = {
|
|
|
265
309
|
CARD_MAX_CHARS,
|
|
266
310
|
DEFAULT_GRADER_MODEL_KV,
|
|
267
311
|
EXPLORE_GRADE_EVERY,
|
|
268
|
-
GRADE_MAX_TOKENS,
|
|
269
312
|
GRADE_TASK,
|
|
270
313
|
GRADE_TIMEOUT_MS,
|
|
271
314
|
RAW_MAX_CHARS,
|
|
@@ -61,6 +61,13 @@ let openHandoffs = new Map(); // ctm_session_id -> { id, opened_at, brief_path }
|
|
|
61
61
|
// repeated terminal reads of one worker from re-sending the same close.
|
|
62
62
|
let closedWorkers = new Set();
|
|
63
63
|
let lastWarnAt = 0;
|
|
64
|
+
// D-8 (round 3): the three reasons watchModeFor (llm/worker-mcp-routing.js) returns null on. A null
|
|
65
|
+
// means CTM's default `on` -- a full-rate watcher -- so the reason a worker with an off cell still
|
|
66
|
+
// spent 40 watcher ticks has to be nameable, not inferred.
|
|
67
|
+
const WATCH_FALLBACK_REASONS = Object.freeze(['unknown_worker', 'no_lead_workers', 'hook_error']);
|
|
68
|
+
// Counters are per process since boot; `since` is the ISO time this module loaded (or last reset).
|
|
69
|
+
let watchFallbackTally = new Map(); // reason -> count
|
|
70
|
+
let watchFallbackSince = new Date().toISOString();
|
|
64
71
|
|
|
65
72
|
// --- small helpers -----------------------------------------------------------------
|
|
66
73
|
|
|
@@ -102,6 +109,22 @@ function _warn(message) {
|
|
|
102
109
|
console.warn(`[helper-rules] ${message}`);
|
|
103
110
|
}
|
|
104
111
|
|
|
112
|
+
// D-8: one fail-open fallback of the wait-watch decision, counted and named. A reason outside the
|
|
113
|
+
// list is not a fallback this module knows about, so it is ignored (never silently added as a key).
|
|
114
|
+
function noteWatchFallback(reason, workerId = null) {
|
|
115
|
+
if (!WATCH_FALLBACK_REASONS.includes(reason)) return;
|
|
116
|
+
watchFallbackTally.set(reason, (watchFallbackTally.get(reason) || 0) + 1);
|
|
117
|
+
_warn(`watch_mode_fallback reason=${reason} worker=${workerId || '-'}`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** D-8: a fresh copy of the per-reason fallback counts plus the window's start time. */
|
|
121
|
+
function watchFallbackCounts() {
|
|
122
|
+
const counts = {};
|
|
123
|
+
for (const reason of WATCH_FALLBACK_REASONS) counts[reason] = watchFallbackTally.get(reason) || 0;
|
|
124
|
+
counts.since = watchFallbackSince;
|
|
125
|
+
return counts;
|
|
126
|
+
}
|
|
127
|
+
|
|
105
128
|
function _write(method, ...args) {
|
|
106
129
|
const fail = (err) => _warn(`${method} failed: ${err && err.message ? err.message : err}`);
|
|
107
130
|
try {
|
|
@@ -153,6 +176,8 @@ function _resetForTests() {
|
|
|
153
176
|
openHandoffs = new Map();
|
|
154
177
|
closedWorkers = new Set();
|
|
155
178
|
lastWarnAt = 0;
|
|
179
|
+
watchFallbackTally = new Map();
|
|
180
|
+
watchFallbackSince = new Date().toISOString();
|
|
156
181
|
}
|
|
157
182
|
|
|
158
183
|
// --- the classification of one watcher decision --------------------------------------
|
|
@@ -354,7 +379,7 @@ function _toolLogOf(payload) {
|
|
|
354
379
|
return Object.entries(counts).map(([tool, count]) => ({ tool, path: String(count) }));
|
|
355
380
|
}
|
|
356
381
|
|
|
357
|
-
function _trackHandoff(call, res, clientInfo, nowMs) {
|
|
382
|
+
function _trackHandoff(call, res, clientInfo, nowMs, lead) {
|
|
358
383
|
if (!res) return;
|
|
359
384
|
if (call.tool === 'walle_delegate_implementation') {
|
|
360
385
|
const ctmSessionId = _string(res.ctm_session_id).trim();
|
|
@@ -378,6 +403,9 @@ function _trackHandoff(call, res, clientInfo, nowMs) {
|
|
|
378
403
|
opened_at: nowMs,
|
|
379
404
|
harness: res.harness == null ? null : res.harness,
|
|
380
405
|
brief_path: res.rendered_brief_path || null,
|
|
406
|
+
// D-5: the lead that owns this explore row, so a later lead-cost measurement can join the
|
|
407
|
+
// cell on it (helper_outcomes.lead_usd stays NULL).
|
|
408
|
+
lead_session_id: lead || null,
|
|
381
409
|
}),
|
|
382
410
|
label_version: LABEL_VERSION,
|
|
383
411
|
});
|
|
@@ -409,7 +437,7 @@ function _trackHandoff(call, res, clientInfo, nowMs) {
|
|
|
409
437
|
// The grade card is built HERE, while the terminal payload is in scope; the grade itself waits
|
|
410
438
|
// for the row's seq, which only the close write can return.
|
|
411
439
|
const toolLog = _toolLogOf(payload);
|
|
412
|
-
_writeThen('helperRulesCloseOutcomeByWorker', [workerId, { facts }], (result) => _gradeIfSampled(result, facts, toolLog));
|
|
440
|
+
_writeThen('helperRulesCloseOutcomeByWorker', [workerId, { facts }], (result) => _gradeIfSampled(result, facts, toolLog, workerId));
|
|
413
441
|
}
|
|
414
442
|
|
|
415
443
|
// --- the 1-in-5 spot check (WP-6, §6.5/D-19) -------------------------------------------
|
|
@@ -437,7 +465,7 @@ function _gradeDeps() {
|
|
|
437
465
|
// Fire-and-forget: the close already landed, so a grader outage costs a sample, never the write.
|
|
438
466
|
// S-3 (round 2): the store derives the label and returns it, so "was this a hand-off?" is read
|
|
439
467
|
// from `result.labelled`, and the card carries the report/log PATHS (grade.js reads them).
|
|
440
|
-
function _gradeIfSampled(result, facts, toolLog) {
|
|
468
|
+
function _gradeIfSampled(result, facts, toolLog, workerId) {
|
|
441
469
|
if (!result || result.closed !== true) return;
|
|
442
470
|
if (!result.labelled || result.labelled.decision !== 'handoff') return; // only an accepted hand-off
|
|
443
471
|
if (!shouldGrade(result.seq)) return; // D-12: every EXPLORE_GRADE_EVERY-th, in every cell state
|
|
@@ -459,7 +487,9 @@ function _gradeIfSampled(result, facts, toolLog) {
|
|
|
459
487
|
}
|
|
460
488
|
// REPORT: gradeHandoff turns a failed call into an unavailable sample, so the tail below only
|
|
461
489
|
// covers a throw from the write itself -- both are fire-and-forget by contract.
|
|
462
|
-
|
|
490
|
+
// D-5: the closing worker's id rides the grader call as `sessionId`, so the grader's ledger row
|
|
491
|
+
// joins the same cell the watcher spend is keyed by (round 2 WP-4a's convention).
|
|
492
|
+
gradeHandoff(card, { completeForRole: deps.completeForRole, graderModel: readGraderModel(deps.db), brain: deps.brain, sessionId: workerId })
|
|
463
493
|
.then((grade) => _write('helperRulesSetGrade', id, gradeToJson(grade)))
|
|
464
494
|
.catch((err) => _warn(`helperRulesSetGrade failed: ${err && err.message ? err.message : err}`));
|
|
465
495
|
}
|
|
@@ -482,7 +512,7 @@ function _record(options) {
|
|
|
482
512
|
_rememberDelegation(lead, call, res);
|
|
483
513
|
_openWatcherOutcomes(lead, call, res, nowMs);
|
|
484
514
|
_recordLateEnd(call, res, nowMs);
|
|
485
|
-
_trackHandoff(call, res, clientInfo, nowMs);
|
|
515
|
+
_trackHandoff(call, res, clientInfo, nowMs, lead);
|
|
486
516
|
|
|
487
517
|
const ring = callsByLead.get(lead) || [];
|
|
488
518
|
ring.push(call);
|
|
@@ -515,8 +545,11 @@ module.exports = {
|
|
|
515
545
|
TERMINAL_STATUSES,
|
|
516
546
|
WAIT_TOOLS,
|
|
517
547
|
WARN_THROTTLE_MS,
|
|
548
|
+
WATCH_FALLBACK_REASONS,
|
|
518
549
|
_resetForTests,
|
|
519
550
|
leadWorkersOf,
|
|
551
|
+
noteWatchFallback,
|
|
520
552
|
recordLeadToolCall,
|
|
553
|
+
watchFallbackCounts,
|
|
521
554
|
workerRouteOf,
|
|
522
555
|
};
|
|
@@ -625,14 +625,16 @@ function setCellState(d, cellKey, { state, user_veto, reason, evidence } = {}) {
|
|
|
625
625
|
* 1. `sweepAbandoned` — D-10's 4 h TTL, so a row no lead ever closed stops occupying the window;
|
|
626
626
|
* 2. `relabel` — D-5's recompute + D-6's one-time recovery (a no-op once the kv watermark is
|
|
627
627
|
* current, which is why it can ride the daily tick at all);
|
|
628
|
-
* 3. the evaluator over every explore
|
|
628
|
+
* 3. the evaluator over every explore and wait-watch cell — this is what advances `off → probe`
|
|
629
|
+
* for both kinds (WP-2: the wait-watch cell's probe timer needs the same daily clock the
|
|
630
|
+
* explore cell's already had).
|
|
629
631
|
* @returns {{cells: Array<{cell_key:string, state:string, changed:boolean}>, abandoned:number,
|
|
630
632
|
* relabelled:number}}
|
|
631
633
|
*/
|
|
632
634
|
function dailyTick(d) {
|
|
633
635
|
const abandoned = sweepAbandoned(d, {});
|
|
634
636
|
const relabelled = relabel(d, {});
|
|
635
|
-
const keys = d.prepare("SELECT cell_key FROM helper_rule_cells WHERE kind
|
|
637
|
+
const keys = d.prepare("SELECT cell_key FROM helper_rule_cells WHERE kind IN ('explore','wait-watch') OR cell_key LIKE 'explore|%' OR cell_key LIKE 'wait-watch|%'")
|
|
636
638
|
.all()
|
|
637
639
|
.map((row) => row.cell_key);
|
|
638
640
|
const run = d.transaction(() => keys.map((key) => evaluateAndApply(d, key)));
|