mirror of
https://github.com/NeuralNomadsAI/CodeNomad.git
synced 2026-11-01 03:20:37 +00:00
## Problem Missions on OpenCode Zen's free models (for example `opencode/deepseek-v4.1-flash-free`) fail at the coordinator's very first model request with **"Free usage limit reached. Connect a provider or subscribe to OpenCode Go…"**, while ordinary conversations on the same model and network keep working. ## Cause Missions created its coordinators, recurring passage coordinators and independent task roots with `ses_` + 26 hex characters of a SHA-256. OpenCode passes that ID to the provider as the session identity (`x-opencode-session-id`, `x-opencode-session`, `X-Session-Id`, `x-session-affinity`; `core/src/session/model-request.ts`), and native children send their **root's** ID as affinity (`core/src/session/affinity.ts`), so one such root blocks the whole mission family. Isolated probes against the real free tier (keyless OpenCode 2.1.4, OpenCode-generated control IDs accepted throughout) characterized two checks: | Check | Requirement | Otherwise | |---|---|---| | Shape | `ses_` + 12 lowercase hex + 14 alphanumerics (any case/charset for the 14) | 403 `FreeTierError` | | Time | the 12 hex decode, as OpenCode's descending identifier, to a date between ~86–90 days before and 24–30 h after the request | 429 `FreeUsageLimitError` | A hash prefix decodes to an arbitrary date over the ~795-day cycle, so most mission roots failed the time check. A real mission A/B (UI-created vs. the same mission attached to an OpenCode-created root) reproduced it: derived coordinator refused, native coordinator completed; a child with an ordinary ID under a hash-ID parent was refused too. ## Change - `missions/session-identity.ts`: mission roots take OpenCode's descending identifier for their **real creation time** followed by 14 hex characters derived from the mission or task identity. Ownership stays provable from the ID alone. - Creation: one-time coordinators (`control.ts`), independent task roots (`control.ts`) and recurring passage coordinators (`recurrence-store.ts`, passage `createdAt`). The time comes from the real clock (`options.now ?? Date.now()`), not the journal's monotonic timestamp, which may run ahead of it. - Ownership checks match the derived suffix and also accept the original 26-hex derivation held by existing journals: managed-root creation (`mission-root-creation.ts`, `ensureActorSession`), cleanup targets (`session-cleanup.ts`), recurring passage parsing/archive/current reads, and the creation readback (`mission-creation-pipeline.ts`, which no longer needs the exact coordinator ID in advance; the hold's `sessionID` is optional). - `dev-docs/MISSIONS.md` documents the identity rule. Task roots and recurring coordinators record their ID before creating the session, so retries still reuse the exact root. A one-time coordinator takes the clock at creation. ## Compatibility Existing missions keep their coordinator IDs (and remain refused on free models); new missions are accepted. Like any OpenCode session, a mission root older than about three months is refused by the free tier. No UI, API or journal schema change; no user-facing help change. ## Validation - `session-identity.test.ts`: time prefix against IDs OpenCode 2.1.4 generated at known milliseconds, descending order, suffix derivation, legacy acceptance, rejection of other missions/tasks/shapes. - Server typecheck; all Missions server tests (`src/missions`, mission routes, plugin, `src/opencode/missions`): 1140 pass, 1 pre-existing environment skip. - Native scripts against an isolated OpenCode 2.1.4: `test-missions-native`, `-trajectory`, `-family-control`, `-contract` pass. - Real free tier: a mission created through the real CodeNomad routes and plugin had its coordinator's first request accepted with the new identifier. The remaining real checks (native subagent child, independent task root, recurring coordinator) are pending: the probing exhausted the network's free allowance (an OpenCode-generated control is now refused too) and will be rerun after it resets. |
||
|---|---|---|
| .. | ||
| fixtures | ||
| missions-child-environment | ||
| recurring-simple-native | ||
| winget | ||
| benchmark-session-history.mjs | ||
| build-help.mjs | ||
| bump-version.js | ||
| compare-user-html-rendering.mjs | ||
| desktop-server-resources.cjs | ||
| desktop-server-resources.test.cjs | ||
| generate-icons.mjs | ||
| native-fixture-diagnostics.mjs | ||
| native-fixture-diagnostics.test.mjs | ||
| native-fixture-guards.mjs | ||
| native-fixture-guards.test.mjs | ||
| native-product-fixture.mjs | ||
| prepare-node-runtime.cjs | ||
| prepare-node-runtime.test.cjs | ||
| preview-git-history.mjs | ||
| profile-outline-projection.mjs | ||
| profile-outline-responsiveness.mts | ||
| profile-streaming-responsiveness.mjs | ||
| profile-ui-motion.mjs | ||
| run-session-pruning-native.mjs | ||
| smoke-packaged-resources.cjs | ||
| test-attachment-picker-desktop.mjs | ||
| test-automation-native.mjs | ||
| test-blank-session-cleanup-native.mjs | ||
| test-codemode-jobs-native.mjs | ||
| test-compaction-isolation-native.mjs | ||
| test-electron-owner-close.mjs | ||
| test-git-degraded-native.mjs | ||
| test-git-init-native.mjs | ||
| test-help-browser.mjs | ||
| test-help.mjs | ||
| test-missions-native-contract.mjs | ||
| test-missions-native-family-control.mjs | ||
| test-missions-native-trajectory.mjs | ||
| test-missions-native.mjs | ||
| test-native-event-relay.mjs | ||
| test-native-worktree-management.mjs | ||
| test-opencode-history-migration.mjs | ||
| test-opencode-install-native.mjs | ||
| test-opencode-legacy-replacement-native.mjs | ||
| test-opencode-location-native.mjs | ||
| test-opencode-proxy-native.mjs | ||
| test-opencode-setup-desktop.mjs | ||
| test-opencode-setup-wsl.mjs | ||
| test-opencode-upgrade-native.mjs | ||
| test-output-limit-native.mjs | ||
| test-panel-extension-native.mjs | ||
| test-pending-snapshot-native.mjs | ||
| test-permission-receipts-native.mjs | ||
| test-plugin-packages-native.mjs | ||
| test-plugin-runtime-native.mjs | ||
| test-promise-tool-failure-native.mjs | ||
| test-prompt-skills-native.mjs | ||
| test-provider-account-selection-native.mjs | ||
| test-provider-accounts-native.mjs | ||
| test-provider-usage-native.mjs | ||
| test-recurring-simple-native.mjs | ||
| test-release-workspace-version.mjs | ||
| test-render-cost-audit.mjs | ||
| test-service-usage-native.mjs | ||
| test-session-aside-native.mjs | ||
| test-session-environment-native.mjs | ||
| test-session-fork-native.mjs | ||
| test-session-history-native.mjs | ||
| test-session-interrupt-native.mjs | ||
| test-session-lifecycle-native.mjs | ||
| test-session-navigation-native.mjs | ||
| test-session-pruning-native.mjs | ||
| test-session-pruning-ui.mjs | ||
| test-subagent-depth-settings-native.mjs | ||
| test-tauri-f6.ps1 | ||
| test-tauri-input-deadlock.mjs | ||
| test-tauri-macos-window-result.test.mjs | ||
| test-tauri-macos-window.mjs | ||
| test-tauri-runner-refcount.mjs | ||
| test-tauri-view-menu.mjs | ||
| test-temporary-workspaces-native.mjs | ||
| test-websearch-settings-native.mjs | ||
| test-worktree-families-native.mjs | ||
| verify-bundled-node.cjs | ||