@intentic/sandbox-contract 1.344.0 → 1.346.0
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 +27 -9
- package/dist/contracts/accounts.contract.d.ts +24 -80
- package/dist/contracts/accounts.contract.d.ts.map +1 -1
- package/dist/contracts/agent.contract.d.ts +247 -8
- package/dist/contracts/agent.contract.d.ts.map +1 -1
- package/dist/contracts/agent.contract.js +13 -2
- package/dist/contracts/agent.contract.js.map +1 -1
- package/dist/contracts/agents.contract.d.ts +1570 -33
- package/dist/contracts/agents.contract.d.ts.map +1 -1
- package/dist/contracts/agents.contract.js +47 -4
- package/dist/contracts/agents.contract.js.map +1 -1
- package/dist/contracts/device.contract.d.ts +244 -1
- package/dist/contracts/device.contract.d.ts.map +1 -1
- package/dist/contracts/device.contract.js +5 -1
- package/dist/contracts/device.contract.js.map +1 -1
- package/dist/contracts/endpoints.contract.d.ts +2 -1
- package/dist/contracts/endpoints.contract.d.ts.map +1 -1
- package/dist/contracts/endpoints.contract.js +1 -0
- package/dist/contracts/endpoints.contract.js.map +1 -1
- package/dist/contracts/providers.contract.d.ts +0 -1
- package/dist/contracts/providers.contract.d.ts.map +1 -1
- package/dist/contracts/push.contract.d.ts +11 -0
- package/dist/contracts/push.contract.d.ts.map +1 -1
- package/dist/contracts/push.contract.js +10 -1
- package/dist/contracts/push.contract.js.map +1 -1
- package/dist/contracts/runner.contract.d.ts +149 -123
- package/dist/contracts/runner.contract.d.ts.map +1 -1
- package/dist/contracts/secrets.contract.d.ts +169 -0
- package/dist/contracts/secrets.contract.d.ts.map +1 -1
- package/dist/contracts/secrets.contract.js +35 -0
- package/dist/contracts/secrets.contract.js.map +1 -1
- package/dist/contracts/sessions.contract.d.ts +2 -0
- package/dist/contracts/sessions.contract.d.ts.map +1 -1
- package/dist/contracts/settings.contract.d.ts +37 -0
- package/dist/contracts/settings.contract.d.ts.map +1 -1
- package/dist/contracts/system.contract.d.ts +235 -31
- package/dist/contracts/system.contract.d.ts.map +1 -1
- package/dist/contracts/translator.contract.d.ts +24 -80
- package/dist/contracts/translator.contract.d.ts.map +1 -1
- package/dist/contracts/workspace.contract.d.ts +11 -0
- package/dist/contracts/workspace.contract.d.ts.map +1 -1
- package/dist/contracts/workspace.contract.js +11 -1
- package/dist/contracts/workspace.contract.js.map +1 -1
- package/dist/events/agent-events.d.ts +60 -0
- package/dist/events/agent-events.d.ts.map +1 -1
- package/dist/events/agent-events.js +44 -38
- package/dist/events/agent-events.js.map +1 -1
- package/dist/events/agent-transcript.d.ts +727 -0
- package/dist/events/agent-transcript.d.ts.map +1 -0
- package/dist/events/agent-transcript.js +34 -0
- package/dist/events/agent-transcript.js.map +1 -0
- package/dist/events/agent-words.d.ts +5 -0
- package/dist/events/agent-words.d.ts.map +1 -1
- package/dist/events/agent-words.js +9 -0
- package/dist/events/agent-words.js.map +1 -1
- package/dist/events/failure-rows.d.ts +14 -0
- package/dist/events/failure-rows.d.ts.map +1 -0
- package/dist/events/failure-rows.js +109 -0
- package/dist/events/failure-rows.js.map +1 -0
- package/dist/events/requests.d.ts +143 -0
- package/dist/events/requests.d.ts.map +1 -1
- package/dist/events/requests.js +35 -1
- package/dist/events/requests.js.map +1 -1
- package/dist/events/sandbox-notice.d.ts +23 -0
- package/dist/events/sandbox-notice.d.ts.map +1 -1
- package/dist/events/sandbox-notice.js +2 -0
- package/dist/events/sandbox-notice.js.map +1 -1
- package/dist/events/system-events.d.ts +156 -0
- package/dist/events/system-events.d.ts.map +1 -1
- package/dist/events/system-events.js +7 -1
- package/dist/events/system-events.js.map +1 -1
- package/dist/events/transcript.d.ts +20 -720
- package/dist/events/transcript.d.ts.map +1 -1
- package/dist/events/transcript.js +17 -19
- package/dist/events/transcript.js.map +1 -1
- package/dist/ids/conversation-ids.d.ts +2 -0
- package/dist/ids/conversation-ids.d.ts.map +1 -1
- package/dist/ids/conversation-ids.js +2 -0
- package/dist/ids/conversation-ids.js.map +1 -1
- package/dist/ids/row-ids.d.ts +3 -0
- package/dist/ids/row-ids.d.ts.map +1 -0
- package/dist/ids/row-ids.js +11 -0
- package/dist/ids/row-ids.js.map +1 -0
- package/dist/index.d.ts +2296 -199
- package/dist/index.d.ts.map +1 -1
- package/dist/models/agent-lanes.d.ts.map +1 -1
- package/dist/models/agent-lanes.js +6 -7
- package/dist/models/agent-lanes.js.map +1 -1
- package/dist/models/agent-standing.d.ts +6 -19
- package/dist/models/agent-standing.d.ts.map +1 -1
- package/dist/models/agent-standing.js +14 -38
- package/dist/models/agent-standing.js.map +1 -1
- package/dist/models/model-pins.d.ts +3 -0
- package/dist/models/model-pins.d.ts.map +1 -1
- package/dist/models/model-pins.js +2 -0
- package/dist/models/model-pins.js.map +1 -1
- package/dist/models/plan-pools.d.ts +26 -4
- package/dist/models/plan-pools.d.ts.map +1 -1
- package/dist/models/plan-pools.js +159 -40
- package/dist/models/plan-pools.js.map +1 -1
- package/dist/netd/generated/wire.d.ts +5 -0
- package/dist/netd/generated/wire.d.ts.map +1 -1
- package/dist/policy/command-classes.d.ts +1 -1
- package/dist/policy/command-classes.d.ts.map +1 -1
- package/dist/policy/command-classes.js +2 -2
- package/dist/policy/command-classes.js.map +1 -1
- package/dist/policy/keyring-origins.d.ts +27 -0
- package/dist/policy/keyring-origins.d.ts.map +1 -0
- package/dist/policy/keyring-origins.js +213 -0
- package/dist/policy/keyring-origins.js.map +1 -0
- package/dist/policy/keyring-seal.d.ts +9 -0
- package/dist/policy/keyring-seal.d.ts.map +1 -1
- package/dist/policy/keyring-seal.js +18 -6
- package/dist/policy/keyring-seal.js.map +1 -1
- package/dist/policy/safety-policy.d.ts +1 -1
- package/dist/policy/safety-policy.d.ts.map +1 -1
- package/dist/policy/safety-policy.js +1 -1
- package/dist/policy/safety-policy.js.map +1 -1
- package/dist/policy/turned-away.d.ts +1 -0
- package/dist/policy/turned-away.d.ts.map +1 -1
- package/dist/policy/turned-away.js +10 -0
- package/dist/policy/turned-away.js.map +1 -1
- package/dist/protocol/doors/host-protocol.d.ts +1 -0
- package/dist/protocol/doors/host-protocol.d.ts.map +1 -1
- package/dist/protocol/doors/host-protocol.js +1 -0
- package/dist/protocol/doors/host-protocol.js.map +1 -1
- package/dist/protocol/doors/runner-protocol.d.ts +1 -0
- package/dist/protocol/doors/runner-protocol.d.ts.map +1 -1
- package/dist/protocol/doors/runner-protocol.js +1 -0
- package/dist/protocol/doors/runner-protocol.js.map +1 -1
- package/dist/protocol/doors/webext-links.d.ts +1 -0
- package/dist/protocol/doors/webext-links.d.ts.map +1 -1
- package/dist/protocol/doors/webext-links.js +1 -0
- package/dist/protocol/doors/webext-links.js.map +1 -1
- package/dist/protocol/peer-dial.d.ts +2 -0
- package/dist/protocol/peer-dial.d.ts.map +1 -1
- package/dist/protocol/peer-dial.js +62 -29
- package/dist/protocol/peer-dial.js.map +1 -1
- package/dist/protocol/raw/raw-json-routes.d.ts +179 -1
- package/dist/protocol/raw/raw-json-routes.d.ts.map +1 -1
- package/dist/protocol/raw/raw-json-routes.js +5 -0
- package/dist/protocol/raw/raw-json-routes.js.map +1 -1
- package/dist/protocol/raw/raw-routes.d.ts +35 -0
- package/dist/protocol/raw/raw-routes.d.ts.map +1 -1
- package/dist/protocol/raw/raw-routes.js +9 -0
- package/dist/protocol/raw/raw-routes.js.map +1 -1
- package/dist/schemas/agent-next.d.ts +21 -0
- package/dist/schemas/agent-next.d.ts.map +1 -0
- package/dist/schemas/agent-next.js +21 -0
- package/dist/schemas/agent-next.js.map +1 -0
- package/dist/schemas/agent-place.d.ts +10 -0
- package/dist/schemas/agent-place.d.ts.map +1 -0
- package/dist/schemas/agent-place.js +15 -0
- package/dist/schemas/agent-place.js.map +1 -0
- package/dist/schemas/agent-search.d.ts +45 -0
- package/dist/schemas/agent-search.d.ts.map +1 -0
- package/dist/schemas/agent-search.js +28 -0
- package/dist/schemas/agent-search.js.map +1 -0
- package/dist/schemas/agent.d.ts +120 -78
- package/dist/schemas/agent.d.ts.map +1 -1
- package/dist/schemas/agent.js +40 -49
- package/dist/schemas/agent.js.map +1 -1
- package/dist/schemas/agents-list.d.ts +54 -0
- package/dist/schemas/agents-list.d.ts.map +1 -1
- package/dist/schemas/agents.d.ts +165 -59
- package/dist/schemas/agents.d.ts.map +1 -1
- package/dist/schemas/agents.js +25 -50
- package/dist/schemas/agents.js.map +1 -1
- package/dist/schemas/attach.d.ts +8 -0
- package/dist/schemas/attach.d.ts.map +1 -0
- package/dist/schemas/attach.js +14 -0
- package/dist/schemas/attach.js.map +1 -0
- package/dist/schemas/command-admission.d.ts +71 -0
- package/dist/schemas/command-admission.d.ts.map +1 -0
- package/dist/schemas/command-admission.js +27 -0
- package/dist/schemas/command-admission.js.map +1 -0
- package/dist/schemas/compose-overlay.d.ts +9 -0
- package/dist/schemas/compose-overlay.d.ts.map +1 -0
- package/dist/schemas/compose-overlay.js +11 -0
- package/dist/schemas/compose-overlay.js.map +1 -0
- package/dist/schemas/composer-drafts.d.ts +169 -0
- package/dist/schemas/composer-drafts.d.ts.map +1 -0
- package/dist/schemas/composer-drafts.js +60 -0
- package/dist/schemas/composer-drafts.js.map +1 -0
- package/dist/schemas/conversation-links.d.ts +44 -0
- package/dist/schemas/conversation-links.d.ts.map +1 -0
- package/dist/schemas/conversation-links.js +35 -0
- package/dist/schemas/conversation-links.js.map +1 -0
- package/dist/schemas/data-protection.d.ts +1 -1
- package/dist/schemas/data-protection.d.ts.map +1 -1
- package/dist/schemas/device-commands.d.ts +63 -0
- package/dist/schemas/device-commands.d.ts.map +1 -0
- package/dist/schemas/device-commands.js +42 -0
- package/dist/schemas/device-commands.js.map +1 -0
- package/dist/schemas/device-folder.d.ts +11 -0
- package/dist/schemas/device-folder.d.ts.map +1 -1
- package/dist/schemas/device-folder.js +1 -0
- package/dist/schemas/device-folder.js.map +1 -1
- package/dist/schemas/devices.d.ts +18 -68
- package/dist/schemas/devices.d.ts.map +1 -1
- package/dist/schemas/devices.js +8 -45
- package/dist/schemas/devices.js.map +1 -1
- package/dist/schemas/environment.d.ts.map +1 -1
- package/dist/schemas/environment.js.map +1 -1
- package/dist/schemas/hosts.d.ts +29 -0
- package/dist/schemas/hosts.d.ts.map +1 -1
- package/dist/schemas/hosts.js +23 -0
- package/dist/schemas/hosts.js.map +1 -1
- package/dist/schemas/keyring-native.d.ts +137 -0
- package/dist/schemas/keyring-native.d.ts.map +1 -0
- package/dist/schemas/keyring-native.js +69 -0
- package/dist/schemas/keyring-native.js.map +1 -0
- package/dist/schemas/keyring.d.ts +413 -0
- package/dist/schemas/keyring.d.ts.map +1 -1
- package/dist/schemas/keyring.js +139 -4
- package/dist/schemas/keyring.js.map +1 -1
- package/dist/schemas/phone-passwords.d.ts +186 -0
- package/dist/schemas/phone-passwords.d.ts.map +1 -0
- package/dist/schemas/phone-passwords.js +25 -0
- package/dist/schemas/phone-passwords.js.map +1 -0
- package/dist/schemas/privacy-egress.d.ts +41 -0
- package/dist/schemas/privacy-egress.d.ts.map +1 -0
- package/dist/schemas/privacy-egress.js +30 -0
- package/dist/schemas/privacy-egress.js.map +1 -0
- package/dist/schemas/privacy.d.ts +1 -0
- package/dist/schemas/privacy.d.ts.map +1 -1
- package/dist/schemas/privacy.js +1 -0
- package/dist/schemas/privacy.js.map +1 -1
- package/dist/schemas/providers/plan-limits.d.ts +76 -130
- package/dist/schemas/providers/plan-limits.d.ts.map +1 -1
- package/dist/schemas/providers/plan-limits.js +36 -23
- package/dist/schemas/providers/plan-limits.js.map +1 -1
- package/dist/schemas/providers/provider-oauth.d.ts +24 -82
- package/dist/schemas/providers/provider-oauth.d.ts.map +1 -1
- package/dist/schemas/providers/provider-oauth.js +1 -6
- package/dist/schemas/providers/provider-oauth.js.map +1 -1
- package/dist/schemas/providers/refusals.d.ts +64 -0
- package/dist/schemas/providers/refusals.d.ts.map +1 -0
- package/dist/schemas/providers/refusals.js +33 -0
- package/dist/schemas/providers/refusals.js.map +1 -0
- package/dist/schemas/providers/usage.d.ts +1 -0
- package/dist/schemas/providers/usage.d.ts.map +1 -1
- package/dist/schemas/providers/usage.js +1 -0
- package/dist/schemas/providers/usage.js.map +1 -1
- package/dist/schemas/push.d.ts +13 -0
- package/dist/schemas/push.d.ts.map +1 -1
- package/dist/schemas/push.js +11 -1
- package/dist/schemas/push.js.map +1 -1
- package/dist/schemas/sandbox-passwords.d.ts +288 -0
- package/dist/schemas/sandbox-passwords.d.ts.map +1 -0
- package/dist/schemas/sandbox-passwords.js +66 -0
- package/dist/schemas/sandbox-passwords.js.map +1 -0
- package/dist/schemas/secrets.d.ts +2 -0
- package/dist/schemas/secrets.d.ts.map +1 -1
- package/dist/schemas/secrets.js +4 -0
- package/dist/schemas/secrets.js.map +1 -1
- package/dist/schemas/sessions.js +1 -1
- package/dist/schemas/sessions.js.map +1 -1
- package/dist/schemas/settings-savings.d.ts +709 -0
- package/dist/schemas/settings-savings.d.ts.map +1 -0
- package/dist/schemas/settings-savings.js +53 -0
- package/dist/schemas/settings-savings.js.map +1 -0
- package/dist/schemas/settings.d.ts +7 -671
- package/dist/schemas/settings.d.ts.map +1 -1
- package/dist/schemas/settings.js +5 -50
- package/dist/schemas/settings.js.map +1 -1
- package/dist/schemas/system.d.ts +16 -0
- package/dist/schemas/system.d.ts.map +1 -1
- package/dist/schemas/system.js +11 -0
- package/dist/schemas/system.js.map +1 -1
- package/dist/schemas/terminal.d.ts +5 -0
- package/dist/schemas/terminal.d.ts.map +1 -1
- package/dist/schemas/terminal.js +4 -0
- package/dist/schemas/terminal.js.map +1 -1
- package/dist/schemas/work-assurance.d.ts +24 -0
- package/dist/schemas/work-assurance.d.ts.map +1 -0
- package/dist/schemas/work-assurance.js +23 -0
- package/dist/schemas/work-assurance.js.map +1 -0
- package/dist/schemas/workspace/workspace-tree.d.ts +23 -0
- package/dist/schemas/workspace/workspace-tree.d.ts.map +1 -1
- package/dist/schemas/workspace/workspace-tree.js +20 -0
- package/dist/schemas/workspace/workspace-tree.js.map +1 -1
- package/dist/state/auth-state.d.ts +4 -0
- package/dist/state/auth-state.d.ts.map +1 -0
- package/dist/state/auth-state.js +37 -0
- package/dist/state/auth-state.js.map +1 -0
- package/dist/state/definition.d.ts +12 -0
- package/dist/state/definition.d.ts.map +1 -1
- package/dist/state/runtime-state.d.ts +3 -0
- package/dist/state/runtime-state.d.ts.map +1 -1
- package/dist/state/runtime-state.js +1 -0
- package/dist/state/runtime-state.js.map +1 -1
- package/dist/state/sandbox-build.d.ts +20 -0
- package/dist/state/sandbox-build.d.ts.map +1 -0
- package/dist/state/sandbox-build.js +43 -0
- package/dist/state/sandbox-build.js.map +1 -0
- package/dist/state/ways-back.d.ts +4 -0
- package/dist/state/ways-back.d.ts.map +1 -0
- package/dist/state/ways-back.js +8 -0
- package/dist/state/ways-back.js.map +1 -0
- package/dist/text/land-rows.d.ts +14 -0
- package/dist/text/land-rows.d.ts.map +1 -0
- package/dist/text/land-rows.js +86 -0
- package/dist/text/land-rows.js.map +1 -0
- package/dist/text/transcript-fold.d.ts +4 -2
- package/dist/text/transcript-fold.d.ts.map +1 -1
- package/dist/text/transcript-fold.js +21 -187
- package/dist/text/transcript-fold.js.map +1 -1
- package/dist/webext/index.d.ts +1 -0
- package/dist/webext/index.d.ts.map +1 -1
- package/dist/webext/index.js +1 -0
- package/dist/webext/index.js.map +1 -1
- package/package.json +7 -6
- package/src/contracts/agent.contract.ts +13 -1
- package/src/contracts/agents.contract.ts +53 -28
- package/src/contracts/device.contract.ts +16 -0
- package/src/contracts/endpoints.contract.ts +3 -0
- package/src/contracts/push.contract.ts +23 -1
- package/src/contracts/secrets.contract.ts +39 -0
- package/src/contracts/workspace.contract.ts +16 -0
- package/src/events/agent-events.ts +99 -79
- package/src/events/agent-transcript.ts +48 -0
- package/src/events/agent-words.ts +13 -0
- package/src/events/failure-rows.ts +148 -0
- package/src/events/requests.ts +41 -3
- package/src/events/sandbox-notice.ts +14 -2
- package/src/events/system-events.ts +14 -4
- package/src/events/transcript.ts +30 -28
- package/src/ids/conversation-ids.ts +7 -0
- package/src/ids/project-dir.test.ts +2 -2
- package/src/ids/project-dir.ts +4 -4
- package/src/ids/row-ids.ts +20 -0
- package/src/models/agent-lanes.ts +16 -24
- package/src/models/agent-runtimes.ts +2 -2
- package/src/models/agent-standing.ts +38 -95
- package/src/models/model-pins.test.ts +31 -1
- package/src/models/model-pins.ts +17 -0
- package/src/models/plan-pools.test.ts +274 -31
- package/src/models/plan-pools.ts +294 -79
- package/src/netd/generated/netd-wire.json +25 -0
- package/src/netd/generated/wire.ts +1 -1
- package/src/policy/command-classes.ts +2 -2
- package/src/policy/keyring-origins.test.ts +132 -0
- package/src/policy/keyring-origins.ts +287 -0
- package/src/policy/keyring-seal.test.ts +37 -2
- package/src/policy/keyring-seal.ts +33 -7
- package/src/policy/safety-policy.ts +1 -1
- package/src/policy/tests/safety-policy.test.ts +1 -1
- package/src/policy/turned-away.ts +15 -0
- package/src/protocol/doors/host-protocol.ts +3 -0
- package/src/protocol/doors/runner-protocol.ts +4 -1
- package/src/protocol/doors/webext-links.ts +3 -0
- package/src/protocol/peer-dial.test.ts +90 -4
- package/src/protocol/peer-dial.ts +83 -39
- package/src/protocol/raw/raw-json-routes.ts +13 -0
- package/src/protocol/raw/raw-routes.ts +13 -1
- package/src/schemas/agent-next.ts +34 -0
- package/src/schemas/agent-place.ts +22 -0
- package/src/schemas/agent-search.ts +51 -0
- package/src/schemas/agent.ts +63 -90
- package/src/schemas/agents.ts +55 -99
- package/src/schemas/attach.ts +23 -0
- package/src/schemas/command-admission.ts +57 -0
- package/src/schemas/compose-overlay.test.ts +35 -0
- package/src/schemas/compose-overlay.ts +19 -0
- package/src/schemas/composer-drafts.ts +86 -0
- package/src/schemas/conversation-links.ts +62 -0
- package/src/schemas/data-protection.ts +1 -1
- package/src/schemas/device-commands.ts +89 -0
- package/src/schemas/device-folder.ts +9 -0
- package/src/schemas/devices.ts +28 -110
- package/src/schemas/environment.ts +8 -9
- package/src/schemas/hosts.ts +60 -0
- package/src/schemas/keyring-native.test.ts +13 -0
- package/src/schemas/keyring-native.ts +101 -0
- package/src/schemas/keyring.ts +202 -4
- package/src/schemas/machine-presence.test.ts +33 -0
- package/src/schemas/phone-passwords.ts +51 -0
- package/src/schemas/privacy-egress.test.ts +83 -0
- package/src/schemas/privacy-egress.ts +86 -0
- package/src/schemas/privacy.ts +4 -0
- package/src/schemas/project-delivery.ts +1 -1
- package/src/schemas/providers/plan-limits.test.ts +16 -0
- package/src/schemas/providers/plan-limits.ts +55 -49
- package/src/schemas/providers/provider-oauth.ts +1 -13
- package/src/schemas/providers/refusals.ts +62 -0
- package/src/schemas/providers/usage.ts +2 -0
- package/src/schemas/push.ts +19 -3
- package/src/schemas/sandbox-passwords.ts +88 -0
- package/src/schemas/secrets.ts +4 -0
- package/src/schemas/sessions.ts +1 -1
- package/src/schemas/settings-savings.ts +125 -0
- package/src/schemas/settings.ts +10 -116
- package/src/schemas/system.ts +15 -0
- package/src/schemas/terminal.ts +8 -0
- package/src/schemas/work-assurance.ts +36 -0
- package/src/schemas/workspace/workspace-tree.ts +32 -0
- package/src/state/auth-state.ts +89 -0
- package/src/state/runtime-state.ts +10 -4
- package/src/state/sandbox-build.test.ts +95 -0
- package/src/state/sandbox-build.ts +96 -0
- package/src/state/ways-back.test.ts +36 -0
- package/src/state/ways-back.ts +19 -0
- package/src/state/workspace-state.ts +1 -1
- package/src/text/land-rows.ts +111 -0
- package/src/text/transcript-fold.test.ts +105 -9
- package/src/text/transcript-fold.ts +30 -232
- package/src/webext/index.ts +2 -0
- package/dist/events/undelivered.d.ts +0 -6
- package/dist/events/undelivered.d.ts.map +0 -1
- package/dist/events/undelivered.js +0 -9
- package/dist/events/undelivered.js.map +0 -1
- package/dist/state/history-state.d.ts +0 -3
- package/dist/state/history-state.d.ts.map +0 -1
- package/dist/state/history-state.js +0 -137
- package/dist/state/history-state.js.map +0 -1
- package/src/events/undelivered.ts +0 -15
- package/src/state/history-state.ts +0 -270
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
|
+
answerCovers,
|
|
2
3
|
bindingWindow,
|
|
3
4
|
currentWindows,
|
|
4
5
|
gatesModel,
|
|
5
6
|
gatingWindows,
|
|
6
|
-
|
|
7
|
+
judgedReading,
|
|
8
|
+
fleetCapacity,
|
|
9
|
+
readingHeadroom,
|
|
7
10
|
preferredAccount,
|
|
8
11
|
refusalVerdict,
|
|
12
|
+
refusedPoolReset,
|
|
9
13
|
roomiestAccount,
|
|
10
14
|
scopedWindow,
|
|
15
|
+
uncoveredModels,
|
|
11
16
|
serviceState,
|
|
12
17
|
serviceStates,
|
|
13
18
|
windowLive,
|
|
@@ -155,14 +160,14 @@ const at = (measuredAt: number, ...windows: UsageWindow[]): AccountUsage => ({ w
|
|
|
155
160
|
const refusal = (over: Partial<ProviderRefusal> & Pick<ProviderRefusal, "kind">): ProviderRefusal => ({ at: 1_000, message: "no.", ...over });
|
|
156
161
|
|
|
157
162
|
test("spent is the contract's one line: 99.5% still has room, 100% is spent until its last full pool reopens", () => {
|
|
158
|
-
expect(
|
|
163
|
+
expect(readingHeadroom(usage(window({ kind: "five_hour", utilization: 99.5 })))).toEqual({ kind: "ready", room: 0.5 });
|
|
159
164
|
expect(
|
|
160
|
-
|
|
165
|
+
readingHeadroom(usage(window({ kind: "five_hour", utilization: 100, resetsAt: 50 }), window({ kind: "seven_day", utilization: 100, resetsAt: 900 }))),
|
|
161
166
|
).toEqual({ kind: "spent", reopensAt: 900 });
|
|
162
|
-
expect(
|
|
163
|
-
expect(
|
|
164
|
-
expect(
|
|
165
|
-
expect(
|
|
167
|
+
expect(readingHeadroom(usage(window({ kind: "five_hour", utilization: 100 })))).toEqual({ kind: "spent" });
|
|
168
|
+
expect(readingHeadroom(undefined)).toEqual({ kind: "unknown" });
|
|
169
|
+
expect(readingHeadroom(CLAUDE, { id: "claude-haiku-4-5" })).toEqual({ kind: "ready", room: 70 });
|
|
170
|
+
expect(readingHeadroom(CLAUDE, { id: "claude-opus-4-6" })).toEqual({ kind: "spent", pool: "Opus" });
|
|
166
171
|
});
|
|
167
172
|
|
|
168
173
|
// Anthropic reports whole percents: an account read at 100 kept serving turns for hours, so that reading is the line,
|
|
@@ -170,29 +175,29 @@ test("spent is the contract's one line: 99.5% still has room, 100% is spent unti
|
|
|
170
175
|
test("a pool read at 100 in whole percents is at the line with no room, until a refusal proves it empty", () => {
|
|
171
176
|
const week = window({ kind: "seven_day", utilization: 100, resetsAt: 900, rounded: true });
|
|
172
177
|
const atLine = usage(window({ kind: "five_hour", utilization: 75, rounded: true }), week);
|
|
173
|
-
expect(
|
|
174
|
-
expect(
|
|
178
|
+
expect(readingHeadroom(atLine)).toEqual({ kind: "ready", room: 0 });
|
|
179
|
+
expect(readingHeadroom(atLine, { id: "claude-opus-5-5" })).toEqual({ kind: "ready", room: 0 });
|
|
175
180
|
// A precise 100 is still spent.
|
|
176
|
-
expect(
|
|
181
|
+
expect(readingHeadroom(usage(window({ kind: "seven_day", utilization: 100, resetsAt: 900 })))).toEqual({ kind: "spent", reopensAt: 900 });
|
|
177
182
|
// The provider refused it: spent until the pool reopens, and a reading still at the line does not answer that.
|
|
178
183
|
const facts = { account: "a", usage: { ...atLine, measuredAt: 2_000 } };
|
|
179
184
|
const refused = refusal({ kind: "limit", account: "a" });
|
|
180
185
|
expect(refusalVerdict(refused, [facts])).toBe("standing");
|
|
181
|
-
expect(serviceStates([facts], refused).get("a")).toEqual({ kind: "spent", reopensAt: 900 });
|
|
186
|
+
expect(serviceStates([facts], [refused]).get("a")).toEqual({ kind: "spent", reopensAt: 900 });
|
|
182
187
|
});
|
|
183
188
|
|
|
184
189
|
test("with no model named, an account is spent only when no model can run on it", () => {
|
|
185
190
|
// A full Opus slice leaves every other model the room of the fullest pool still open.
|
|
186
|
-
expect(
|
|
187
|
-
expect(
|
|
191
|
+
expect(readingHeadroom(CLAUDE)).toEqual({ kind: "ready", room: 70 });
|
|
192
|
+
expect(readingHeadroom(GOOGLE)).toEqual({ kind: "ready", room: 73 });
|
|
188
193
|
// A pool gating every model, full: nothing runs, and it reopens with that pool.
|
|
189
|
-
expect(
|
|
194
|
+
expect(readingHeadroom(usage(window({ kind: "seven_day", utilization: 100, resetsAt: 900 }), window({ kind: "model:Opus", utilization: 10, gates: { models: ["Opus"] } })))).toEqual({
|
|
190
195
|
kind: "spent",
|
|
191
196
|
reopensAt: 900,
|
|
192
197
|
});
|
|
193
198
|
// Every slice full: the first to reopen lets some model run again.
|
|
194
199
|
expect(
|
|
195
|
-
|
|
200
|
+
readingHeadroom(
|
|
196
201
|
usage(
|
|
197
202
|
window({ kind: "g", utilization: 100, resetsAt: 500, gates: { models: ["gemini"] } }),
|
|
198
203
|
window({ kind: "c", utilization: 100, resetsAt: 800, gates: { models: ["claude"] } }),
|
|
@@ -229,15 +234,15 @@ test("a revoked sign-in outranks a lost seat, which outranks a bench, whatever t
|
|
|
229
234
|
|
|
230
235
|
test("a standing refusal blocks by its kind, and a limit refusal pins only the pool its model spends", () => {
|
|
231
236
|
const facts = { account: "a", usage: CLAUDE };
|
|
232
|
-
expect(serviceState(facts, refusal({ kind: "auth" }))).toEqual({ kind: "blocked", fix: "reconnect", reason: "no." });
|
|
233
|
-
expect(serviceState(facts, refusal({ kind: "entitlement" }))).toEqual({ kind: "blocked", fix: "admin", reason: "no." });
|
|
237
|
+
expect(serviceState(facts, [refusal({ kind: "auth" })])).toEqual({ kind: "blocked", fix: "reconnect", reason: "no." });
|
|
238
|
+
expect(serviceState(facts, [refusal({ kind: "entitlement" })])).toEqual({ kind: "blocked", fix: "admin", reason: "no." });
|
|
234
239
|
// Refused on Haiku: the 5-hour/weekly binding pool (seven_day, 30%) reads full, so Haiku is spent too.
|
|
235
|
-
expect(serviceState(facts, refusal({ kind: "limit", model: "claude-haiku-4-5" }), { id: "claude-haiku-4-5" })).toEqual({ kind: "spent" });
|
|
240
|
+
expect(serviceState(facts, [refusal({ kind: "limit", model: "claude-haiku-4-5" })], { id: "claude-haiku-4-5" })).toEqual({ kind: "spent" });
|
|
236
241
|
// Refused on Opus: its own slice was already full; Haiku keeps the room its pools show.
|
|
237
|
-
expect(serviceState(facts, refusal({ kind: "limit", model: "claude-opus-4-6" }), { id: "claude-haiku-4-5" })).toEqual({ kind: "ready", room: 70 });
|
|
242
|
+
expect(serviceState(facts, [refusal({ kind: "limit", model: "claude-opus-4-6" })], { id: "claude-haiku-4-5" })).toEqual({ kind: "ready", room: 70 });
|
|
238
243
|
// No reading at all: the refusal is the evidence, unless it was about another model.
|
|
239
|
-
expect(serviceState({ account: "a" }, refusal({ kind: "limit" }))).toEqual({ kind: "spent" });
|
|
240
|
-
expect(serviceState({ account: "a" }, refusal({ kind: "limit", model: "opus" }), { id: "haiku" })).toEqual({ kind: "unknown" });
|
|
244
|
+
expect(serviceState({ account: "a" }, [refusal({ kind: "limit" })])).toEqual({ kind: "spent" });
|
|
245
|
+
expect(serviceState({ account: "a" }, [refusal({ kind: "limit", model: "opus" })], { id: "haiku" })).toEqual({ kind: "unknown" });
|
|
241
246
|
});
|
|
242
247
|
|
|
243
248
|
test("a refusal stands until a later reading contradicts it, and never past its account's disconnection", () => {
|
|
@@ -258,17 +263,42 @@ test("a refusal stands until a later reading contradicts it, and never past its
|
|
|
258
263
|
expect(refusalVerdict(refusal({ kind: "limit", account: "a" }), [])).toBe("standing");
|
|
259
264
|
});
|
|
260
265
|
|
|
261
|
-
//
|
|
262
|
-
test("an allowance no reading measures stands against
|
|
266
|
+
// An admin's allowance (Cursor's team spend limit) is one the refused account's own reading does not measure.
|
|
267
|
+
test("an allowance no reading measures stands against its own account's reading, until the provider's own reset", () => {
|
|
263
268
|
const room = at(Date.now() + 60_000, window({ kind: "seven_day", utilization: 43 }));
|
|
264
269
|
const credit = refusal({ kind: "limit", unmetered: true, at: Date.now(), resetsAt: Math.floor(Date.now() / 1000) + 3_600 });
|
|
265
|
-
expect(refusalVerdict(credit, [{ account: "a", usage: room }, { account: "b", usage: room }])).toBe("standing");
|
|
266
|
-
expect(refusalVerdict(
|
|
267
|
-
|
|
268
|
-
);
|
|
270
|
+
expect(refusalVerdict({ ...credit, account: "a" }, [{ account: "a", usage: room }, { account: "b", usage: room }])).toBe("standing");
|
|
271
|
+
expect(refusalVerdict(credit, [{ account: "a", usage: room }])).toBe("standing");
|
|
272
|
+
expect(refusalVerdict({ ...credit, account: "a", resetsAt: Math.floor(Date.now() / 1000) - 1 }, [{ account: "a", usage: room }])).toBe("answered");
|
|
269
273
|
expect(refusalVerdict({ ...credit, resetsAt: undefined }, [{ account: "a", usage: room }])).toBe("standing");
|
|
270
274
|
});
|
|
271
275
|
|
|
276
|
+
// 2026-10-19: one routed refusal ("try again at 1:53 PM", filed a day out, as an admin's credit) named no account and
|
|
277
|
+
// held all three Codex accounts spent for that day, two free ones reading 0% of their month used among them.
|
|
278
|
+
test("a nameless refusal over several accounts is answered by any of them reading room since, whatever it named", () => {
|
|
279
|
+
const filed = Date.parse("2026-10-19T13:53:35Z");
|
|
280
|
+
const now = Date.parse("2026-10-20T09:22:10Z");
|
|
281
|
+
const monthly = at(Date.parse("2026-10-20T09:22:03Z"), window({ kind: "monthly", label: "Monthly · all models", utilization: 0 }));
|
|
282
|
+
const fiveHour = at(Date.parse("2026-10-20T09:22:03Z"), window({ kind: "five_hour", utilization: 0 }), window({ kind: "seven_day", utilization: 0 }));
|
|
283
|
+
const accounts = [
|
|
284
|
+
{ account: "free-1", usage: monthly },
|
|
285
|
+
{ account: "free-2", usage: monthly },
|
|
286
|
+
{ account: "team", usage: fiveHour },
|
|
287
|
+
];
|
|
288
|
+
const codex = refusal({ kind: "limit", at: filed, model: "gpt-6.1-sol", resetsAt: Date.parse("2026-10-20T13:53:00Z") / 1000, unmetered: true });
|
|
289
|
+
expect(refusalVerdict(codex, accounts, now)).toBe("answered");
|
|
290
|
+
expect(Object.fromEntries(serviceStates(accounts, [codex], undefined, now))).toEqual({
|
|
291
|
+
"free-1": { kind: "ready", room: 100 },
|
|
292
|
+
"free-2": { kind: "ready", room: 100 },
|
|
293
|
+
team: { kind: "ready", room: 100 },
|
|
294
|
+
});
|
|
295
|
+
// Until one of them is read with room after it, it stands over all of them.
|
|
296
|
+
const before = accounts.map((entry) => ({ ...entry, usage: { ...entry.usage, measuredAt: filed - 1 } }));
|
|
297
|
+
expect(refusalVerdict(codex, before, now)).toBe("standing");
|
|
298
|
+
// And never past the instant the provider named.
|
|
299
|
+
expect(refusalVerdict(codex, before, Date.parse("2026-10-20T13:53:00Z"))).toBe("answered");
|
|
300
|
+
});
|
|
301
|
+
|
|
272
302
|
|
|
273
303
|
// Codex's usage endpoint kept reading room while every turn was refused "try again at 3:38 PM": the provider's own
|
|
274
304
|
// instant is what ends the refusal, where it is known which account it refused.
|
|
@@ -282,14 +312,92 @@ test("a spent allowance with the provider's own reset stands until that instant,
|
|
|
282
312
|
// Over several, the translator benches the one it refused and routes on, so another's room still answers it.
|
|
283
313
|
expect(refusalVerdict(refusal(until), [{ account: "a", usage: room }, { account: "b", usage: room }], 9_999)).toBe("answered");
|
|
284
314
|
// Spent until the instant the provider named, not the pool's own reset.
|
|
285
|
-
expect(serviceStates([{ account: "a", usage: room }], refusal({ ...until, account: "a" }), undefined, 9_999).get("a")).toEqual({ kind: "spent", reopensAt: 10 });
|
|
315
|
+
expect(serviceStates([{ account: "a", usage: room }], [refusal({ ...until, account: "a" })], undefined, 9_999).get("a")).toEqual({ kind: "spent", reopensAt: 10 });
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
// 2026-10-20: a spent allowance the provider gave no instant for stood past the reset of the pool it was refused in, the
|
|
319
|
+
// "back at" every surface showed, until the next reading landed (up to the daemon's 15-minute idle sweep).
|
|
320
|
+
test("a spent allowance with no instant named is stamped with its pool's reset, and ends there everywhere at once", () => {
|
|
321
|
+
const reset = 10;
|
|
322
|
+
const filling = at(500, window({ kind: "five_hour", utilization: 96, resetsAt: reset }), window({ kind: "seven_day", utilization: 40, resetsAt: 900 }));
|
|
323
|
+
const accounts = [{ account: "a", usage: filling }];
|
|
324
|
+
const spent = refusal({ kind: "limit", account: "a", model: "gpt-6.1-sol" });
|
|
325
|
+
expect(refusedPoolReset(spent, accounts)).toBe(reset);
|
|
326
|
+
const filed = { ...spent, poolResetsAt: reset };
|
|
327
|
+
expect(refusalVerdict(filed, accounts, reset * 1000 - 1)).toBe("standing");
|
|
328
|
+
expect(serviceStates(accounts, [filed], undefined, reset * 1000 - 1).get("a")).toEqual({ kind: "spent", reopensAt: reset });
|
|
329
|
+
expect(refusalVerdict(filed, accounts, reset * 1000)).toBe("answered");
|
|
330
|
+
// Even once the reading has lapsed that pool, so the weekly one binds: the stamp, not the reading, says when.
|
|
331
|
+
const lapsed = at(500, window({ kind: "five_hour", utilization: 0, lapsedAt: reset }), window({ kind: "seven_day", utilization: 40, resetsAt: 900 }));
|
|
332
|
+
expect(refusedPoolReset(spent, [{ account: "a", usage: lapsed }])).toBe(900);
|
|
333
|
+
expect(refusalVerdict(filed, [{ account: "a", usage: lapsed }], reset * 1000)).toBe("answered");
|
|
334
|
+
expect(serviceStates([{ account: "a", usage: lapsed }], [filed], undefined, reset * 1000).get("a")).toEqual({ kind: "ready", room: 60 });
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
// 2026-10-21: Claude refused at 5h 98% and weekly 97% (rounded) with no time named, so the refusal was stamped with the
|
|
338
|
+
// five-hour reset, the fullest pool then. Once that window reopened the weekly pool read 100, and the passed stamp ended
|
|
339
|
+
// the refusal anyway: a rounded 100 is no proof of empty, so the account read ready with no room and every turn let
|
|
340
|
+
// through was refused again. A stamp ends the refusal where nothing read since says otherwise, never over a reading.
|
|
341
|
+
test("a stamped reset ends a refusal only where no reading since it says the pool is still at the line", () => {
|
|
342
|
+
const fiveHourReset = 1_800_000_000;
|
|
343
|
+
const weeklyReset = 1_800_259_200;
|
|
344
|
+
const refusedIn = at(
|
|
345
|
+
1_799_989_000_000,
|
|
346
|
+
window({ kind: "five_hour", utilization: 98, rounded: true, resetsAt: fiveHourReset }),
|
|
347
|
+
window({ kind: "seven_day", utilization: 97, rounded: true, resetsAt: weeklyReset }),
|
|
348
|
+
);
|
|
349
|
+
const spent = refusal({ kind: "limit", account: "a", at: 1_799_990_000_000 });
|
|
350
|
+
expect(refusedPoolReset(spent, [{ account: "a", usage: refusedIn }])).toBe(fiveHourReset);
|
|
351
|
+
const stamped = { ...spent, poolResetsAt: fiveHourReset };
|
|
352
|
+
const now = (fiveHourReset + 700) * 1000;
|
|
353
|
+
const weeklyFull = at(
|
|
354
|
+
(fiveHourReset + 600) * 1000,
|
|
355
|
+
window({ kind: "five_hour", utilization: 4, rounded: true, resetsAt: fiveHourReset + 18_000 }),
|
|
356
|
+
window({ kind: "seven_day", utilization: 100, rounded: true, resetsAt: weeklyReset }),
|
|
357
|
+
);
|
|
358
|
+
const unstampedVerdict = serviceStates([{ account: "a", usage: weeklyFull }], [spent], undefined, now).get("a");
|
|
359
|
+
expect(unstampedVerdict).toEqual({ kind: "spent", reopensAt: weeklyReset });
|
|
360
|
+
expect(serviceStates([{ account: "a", usage: weeklyFull }], [stamped], undefined, now).get("a")).toEqual(unstampedVerdict);
|
|
361
|
+
expect(fleetCapacity([{ account: "a", usage: weeklyFull }], [stamped], undefined, now)).toMatchObject({ kind: "spent", reopensAt: weeklyReset });
|
|
362
|
+
// Nothing read since the stamp: it ends there. Read with room since: over.
|
|
363
|
+
expect(serviceStates([{ account: "a", usage: refusedIn }], [stamped], undefined, now).get("a")).toEqual({ kind: "ready", room: 2 });
|
|
364
|
+
const roomSince = at((fiveHourReset + 600) * 1000, window({ kind: "five_hour", utilization: 4, resetsAt: fiveHourReset + 18_000 }), window({ kind: "seven_day", utilization: 60, resetsAt: weeklyReset }));
|
|
365
|
+
expect(refusalVerdict(stamped, [{ account: "a", usage: roomSince }], now)).toBe("answered");
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
test("the stamp is the refused account's pool, or the soonest of any where the refusal named none", () => {
|
|
369
|
+
const soon = at(500, window({ kind: "five_hour", utilization: 96, resetsAt: 10 }));
|
|
370
|
+
const later = at(500, window({ kind: "five_hour", utilization: 96, resetsAt: 50 }));
|
|
371
|
+
const accounts = [{ account: "b", usage: later }, { account: "a", usage: soon }];
|
|
372
|
+
expect(refusedPoolReset(refusal({ kind: "limit" }), accounts)).toBe(10);
|
|
373
|
+
expect(refusedPoolReset(refusal({ kind: "limit", account: "b" }), accounts)).toBe(50);
|
|
374
|
+
// The pool the model spends, not the account's fullest.
|
|
375
|
+
const opus = at(500, window({ kind: "five_hour", utilization: 20, resetsAt: 10 }), window({ kind: "model:Opus", label: "Opus", utilization: 99, resetsAt: 70, gates: { models: ["Opus"] } }));
|
|
376
|
+
expect(refusedPoolReset(refusal({ kind: "limit", model: "claude-opus-4-6" }), [{ account: "a", usage: opus }])).toBe(70);
|
|
377
|
+
expect(refusedPoolReset(refusal({ kind: "limit", model: "claude-haiku-4-5" }), [{ account: "a", usage: opus }])).toBe(10);
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
test("nothing is stamped where a pool's reset cannot speak for the refusal", () => {
|
|
381
|
+
const reopening = at(500, window({ kind: "five_hour", utilization: 96, resetsAt: 10 }));
|
|
382
|
+
// A reading older than the window it was refused in: that reset was over before the refusal came.
|
|
383
|
+
expect(refusedPoolReset(refusal({ kind: "limit", at: 20_000 }), [{ account: "a", usage: reopening }])).toBeUndefined();
|
|
384
|
+
expect(refusedPoolReset(refusal({ kind: "limit" }), [{ account: "a", usage: at(500, window({ kind: "monthly", utilization: 96 })) }])).toBeUndefined();
|
|
385
|
+
expect(refusedPoolReset(refusal({ kind: "limit" }), [{ account: "a" }])).toBeUndefined();
|
|
386
|
+
expect(refusedPoolReset(refusal({ kind: "limit", account: "gone" }), [{ account: "a", usage: reopening }])).toBeUndefined();
|
|
387
|
+
// The provider's own instant, an allowance no reading measures, a person's mark, and any refusal but a spent allowance.
|
|
388
|
+
expect(refusedPoolReset(refusal({ kind: "limit", resetsAt: 5 }), [{ account: "a", usage: reopening }])).toBeUndefined();
|
|
389
|
+
expect(refusedPoolReset(refusal({ kind: "limit", unmetered: true }), [{ account: "a", usage: reopening }])).toBeUndefined();
|
|
390
|
+
expect(refusedPoolReset(refusal({ kind: "limit", byHand: true }), [{ account: "a", usage: reopening }])).toBeUndefined();
|
|
391
|
+
expect(refusedPoolReset(refusal({ kind: "entitlement" }), [{ account: "a", usage: reopening }])).toBeUndefined();
|
|
392
|
+
// And a refusal filed unstamped keeps standing until a reading answers it, as before.
|
|
393
|
+
expect(refusalVerdict(refusal({ kind: "limit", account: "a" }), [{ account: "a", usage: reopening }], 9e12)).toBe("standing");
|
|
286
394
|
});
|
|
287
395
|
|
|
288
396
|
test("a provider's accounts are judged together: a standing refusal lands only on the account it names", () => {
|
|
289
397
|
const room = at(500, window({ kind: "five_hour", utilization: 40 }));
|
|
290
|
-
const states = serviceStates([{ account: "a", usage: room }, { account: "b", usage: room }], refusal({ kind: "entitlement", account: "a" }));
|
|
398
|
+
const states = serviceStates([{ account: "a", usage: room }, { account: "b", usage: room }], [refusal({ kind: "entitlement", account: "a" })]);
|
|
291
399
|
expect(Object.fromEntries(states)).toEqual({ a: { kind: "blocked", fix: "admin", reason: "no." }, b: { kind: "ready", room: 60 } });
|
|
292
|
-
const answered = serviceStates([{ account: "a", usage: at(2_000, window({ kind: "five_hour", utilization: 40 })) }], refusal({ kind: "limit", account: "a" }));
|
|
400
|
+
const answered = serviceStates([{ account: "a", usage: at(2_000, window({ kind: "five_hour", utilization: 40 })) }], [refusal({ kind: "limit", account: "a" })]);
|
|
293
401
|
expect(answered.get("a")).toEqual({ kind: "ready", room: 60 });
|
|
294
402
|
});
|
|
295
403
|
|
|
@@ -310,7 +418,7 @@ test("each account answers to the newest refusal on file that still stands over
|
|
|
310
418
|
b: { kind: "blocked", fix: "reconnect", reason: "no." },
|
|
311
419
|
});
|
|
312
420
|
// Only the provider's last one: the first account is back at the line, no room but not proven spent.
|
|
313
|
-
expect(serviceStates(accounts, elsewhere, undefined, 9_999).get("a")).toEqual({ kind: "ready", room: 0 });
|
|
421
|
+
expect(serviceStates(accounts, [elsewhere], undefined, 9_999).get("a")).toEqual({ kind: "ready", room: 0 });
|
|
314
422
|
// Past the instant the provider named, its refusal is over and the reading speaks alone.
|
|
315
423
|
expect(serviceStates(accounts, [elsewhere, own], undefined, 20_000).get("a")).toEqual({ kind: "ready", room: 0 });
|
|
316
424
|
// A newer refusal on the same account outranks the older one.
|
|
@@ -340,3 +448,138 @@ test("an account at the line is tried after an unmeasured one and before a spent
|
|
|
340
448
|
expect(roomiestAccount([entry("line", atLine), entry("spent", { kind: "spent" })])).toBeUndefined();
|
|
341
449
|
expect(roomiestAccount([entry("line", atLine), entry("low", { kind: "ready", room: 2 })])?.id).toBe("low");
|
|
342
450
|
});
|
|
451
|
+
|
|
452
|
+
// A reading covers what its pools gate, and nothing more: a model no pool names is unknown, never covered by the rest.
|
|
453
|
+
test("names the served models no pool covers, and none when a pool gates every model", () => {
|
|
454
|
+
const sliced = usage(window({ kind: "google:3p-weekly", utilization: 100, gates: { models: ["claude", "gpt"] } }));
|
|
455
|
+
expect(uncoveredModels(sliced.windows, [{ id: "claude-opus-4-6-thinking" }, { id: "gemini-3.8-flash-high" }, { id: "gpt-oss-120b-medium" }])).toEqual([
|
|
456
|
+
"gemini-3.8-flash-high",
|
|
457
|
+
]);
|
|
458
|
+
expect(uncoveredModels([window({ kind: "five_hour" })], [{ id: "opus" }, { id: "sonnet" }])).toEqual([]);
|
|
459
|
+
// A pool gated `none` is shown, never a cover.
|
|
460
|
+
expect(uncoveredModels([window({ kind: "surface:web", gates: "none" })], [{ id: "opus" }])).toEqual(["opus"]);
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
// 2026-10-19: Google's summary stopped naming the Gemini pool, and every account read spent off its full Claude pool
|
|
464
|
+
// while its Gemini models served.
|
|
465
|
+
test("an account whose only named pools are full, with models no pool covers, is unknown rather than spent", () => {
|
|
466
|
+
const thirdPartySpent = window({ kind: "google:3p-weekly", utilization: 100, resetsAt: 9_000, gates: { models: ["claude", "gpt"] } });
|
|
467
|
+
expect(readingHeadroom({ ...usage(thirdPartySpent), uncovered: ["gemini-3.8-flash-high"] })).toEqual({ kind: "unknown" });
|
|
468
|
+
// Without the gap it is the spent account it always was, and a model the full pool gates is spent either way.
|
|
469
|
+
expect(readingHeadroom(usage(thirdPartySpent))).toEqual({ kind: "spent", reopensAt: 9_000 });
|
|
470
|
+
expect(readingHeadroom({ ...usage(thirdPartySpent), uncovered: ["gemini-3.8-flash-high"] }, { id: "claude-opus-4-6-thinking" })).toEqual({
|
|
471
|
+
kind: "spent",
|
|
472
|
+
reopensAt: 9_000,
|
|
473
|
+
});
|
|
474
|
+
// A full pool gating every model still holds every model, covered or not.
|
|
475
|
+
expect(readingHeadroom({ ...usage(window({ kind: "seven_day", utilization: 100, resetsAt: 7_000 })), uncovered: ["x"] })).toEqual({
|
|
476
|
+
kind: "spent",
|
|
477
|
+
reopensAt: 7_000,
|
|
478
|
+
});
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
test("a reading contradicted by an answered turn holds that model's full pools at the line, not spent", () => {
|
|
482
|
+
const full = usage(window({ kind: "google:gemini-weekly", utilization: 100, resetsAt: 9_000, gates: { models: ["gemini"] } }));
|
|
483
|
+
const contradicted: AccountUsage = { ...full, contradicted: { at: 1, model: "gemini-3.8-flash-high" } };
|
|
484
|
+
expect(readingHeadroom(contradicted, { id: "gemini-3.8-flash-high" })).toEqual({ kind: "ready", room: 0 });
|
|
485
|
+
expect(readingHeadroom(contradicted)).toEqual({ kind: "ready", room: 0 });
|
|
486
|
+
// Another family's pool is not what the turn proved anything about.
|
|
487
|
+
const other: AccountUsage = { ...full, contradicted: { at: 1, model: "claude-opus-4-6-thinking" } };
|
|
488
|
+
expect(readingHeadroom(other, { id: "gemini-3.8-flash-high" })).toEqual({ kind: "spent", reopensAt: 9_000 });
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
test("a pool the provider stopped reporting is dropped once its window closes, not kept at a floor", () => {
|
|
492
|
+
const missing = window({ kind: "google:gemini-weekly", utilization: 60, resetsAt: 1_000, missingSince: 500 });
|
|
493
|
+
const live = window({ kind: "google:3p-weekly", utilization: 20, resetsAt: 9_000 });
|
|
494
|
+
expect(currentWindows(usage(missing, live), 2_000_000)).toEqual([live]);
|
|
495
|
+
expect(currentWindows(usage(missing, live), 900_000)).toEqual([missing, live]);
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
// The one rule the daemon's verdict and the editor's live re-reading both judge a standing refusal by (2026-10-20: the
|
|
499
|
+
// editor drew "spent until 19:55", the pinned pool's own reset, over a daemon verdict of 15:53).
|
|
500
|
+
test("a standing refusal pins the pool its model spends, reopening when the provider said, for every surface alike", () => {
|
|
501
|
+
const reading = at(2_000, window({ kind: "five_hour", utilization: 0, resetsAt: 20_000 }), window({ kind: "seven_day", utilization: 0, resetsAt: 600_000 }));
|
|
502
|
+
const said = refusal({ kind: "limit", model: "gpt-6.1-sol", resetsAt: 9_000 });
|
|
503
|
+
expect(judgedReading(reading, [said])?.windows.map((entry) => [entry.kind, entry.utilization, entry.resetsAt])).toEqual([
|
|
504
|
+
["five_hour", 100, 9_000],
|
|
505
|
+
["seven_day", 0, 600_000],
|
|
506
|
+
]);
|
|
507
|
+
expect(serviceState({ account: "a", usage: reading }, [said], undefined, 0)).toEqual({ kind: "spent", reopensAt: 9_000 });
|
|
508
|
+
// Where it named no instant, the pinned pool keeps its own reset, and that is when it reopens.
|
|
509
|
+
expect(serviceState({ account: "a", usage: reading }, [{ ...said, resetsAt: undefined }], undefined, 0)).toEqual({ kind: "spent", reopensAt: 20_000 });
|
|
510
|
+
// No reading at all (a plan that publishes none): the refusal is a pool of its own, for its own model and no other's.
|
|
511
|
+
expect(judgedReading(undefined, [said])?.windows).toEqual([
|
|
512
|
+
{ kind: "refused:gpt-6.1-sol", label: "GPT 6.1 Sol", utilization: 100, gates: { models: ["gpt-6.1-sol"] }, resetsAt: 9_000 },
|
|
513
|
+
]);
|
|
514
|
+
expect(serviceState({ account: "a" }, [said], undefined, 0)).toEqual({ kind: "spent", reopensAt: 9_000, pool: "GPT 6.1 Sol" });
|
|
515
|
+
expect(serviceState({ account: "a" }, [said], { id: "gpt-6-luna" }, 0)).toEqual({ kind: "unknown" });
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
// 2026-10-09/10-20: a routed model's bench (model-cooldowns.json) and the provider's last refusal were two copies of one
|
|
519
|
+
// refusal, and the picker greyed by one while the rail judged by the other. One ledger: every refusal standing over an
|
|
520
|
+
// account is laid on its reading, so two models refused on two pools both read spent.
|
|
521
|
+
test("every refusal standing over an account is laid on it, not only the provider's last", () => {
|
|
522
|
+
const reading = at(
|
|
523
|
+
500,
|
|
524
|
+
window({ kind: "five_hour", utilization: 10, resetsAt: 7_000 }),
|
|
525
|
+
window({ kind: "model:Opus", label: "Opus", utilization: 40, resetsAt: 8_000, gates: { models: ["opus"] } }),
|
|
526
|
+
);
|
|
527
|
+
const opus = refusal({ kind: "limit", account: "a", model: "claude-opus-5-5", at: 1_000 });
|
|
528
|
+
const sonnet = refusal({ kind: "limit", account: "a", model: "claude-sonnet-5", at: 2_000, resetsAt: 7_000 });
|
|
529
|
+
const states = (model: string) => serviceStates([{ account: "a", usage: reading }], [opus, sonnet], { id: model }, 5_000).get("a");
|
|
530
|
+
expect(states("claude-opus-5-5")).toEqual({ kind: "spent", reopensAt: 8_000, pool: "Opus" });
|
|
531
|
+
expect(states("claude-sonnet-5")).toEqual({ kind: "spent", reopensAt: 7_000 });
|
|
532
|
+
// A spent allowance refused after a refused sign-in says the sign-in worked: the newest word on the account decides.
|
|
533
|
+
const revoked = refusal({ kind: "auth", account: "a", at: 1_500 });
|
|
534
|
+
expect(serviceStates([{ account: "a", usage: reading }], [revoked, sonnet], { id: "claude-sonnet-5" }, 5_000).get("a")).toEqual({ kind: "spent", reopensAt: 7_000 });
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
// 2026-10-17: a Kimi credential benched for thirty minutes, its five-hour window two hours from reopening, was re-run at
|
|
538
|
+
// thirty minutes and refused again. A bench is a floor under the account's reopening, never the reopening itself.
|
|
539
|
+
test("a translator bench lifts only once the pools it holds have reopened too", () => {
|
|
540
|
+
const full = at(500, window({ kind: "five_hour", utilization: 100, resetsAt: 9_000 }));
|
|
541
|
+
expect(serviceState({ account: "a", usage: full, cooling: { until: 2_000, reason: "429" } }, [], undefined, 1_000_000)).toEqual({
|
|
542
|
+
kind: "blocked",
|
|
543
|
+
fix: "wait",
|
|
544
|
+
reason: "429",
|
|
545
|
+
until: 9_000,
|
|
546
|
+
});
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
// The answer every gate, listing and picker reads (2026-10-13: Sol subagents spawned onto a Codex whose every account
|
|
550
|
+
// was refused, while the picker greyed the row; 2026-10-19: Auto read the readings alone).
|
|
551
|
+
test("a provider's capacity for a model is spent only when no account can serve it, and says when one is back", () => {
|
|
552
|
+
const room = at(5_000, window({ kind: "five_hour", utilization: 30, resetsAt: 9_000 }));
|
|
553
|
+
const accounts = [
|
|
554
|
+
{ account: "a", usage: room },
|
|
555
|
+
{ account: "b", usage: room },
|
|
556
|
+
];
|
|
557
|
+
const a = refusal({ kind: "limit", account: "a", model: "sol", resetsAt: 8_000, at: 4_000 });
|
|
558
|
+
const b = refusal({ kind: "limit", account: "b", model: "sol", resetsAt: 7_000, at: 4_000 });
|
|
559
|
+
expect(fleetCapacity(accounts, [a, b], { id: "sol" }, 6_000_000)).toEqual({ kind: "spent", accounts: 2, reopensAt: 7_000, pool: undefined });
|
|
560
|
+
expect(fleetCapacity(accounts, [a], { id: "sol" }, 6_000_000)).toEqual({ kind: "serving", serving: 1, accounts: 2, roomMeasuredAt: 5_000 });
|
|
561
|
+
// An account nothing has measured may still answer: it keeps the model servable.
|
|
562
|
+
expect(fleetCapacity([...accounts, { account: "c" }], [a, b], { id: "sol" }, 6_000_000)).toEqual({ kind: "serving", serving: 1, accounts: 3, roomMeasuredAt: undefined });
|
|
563
|
+
// No account at all says nothing either way.
|
|
564
|
+
expect(fleetCapacity([], [a], { id: "sol" })).toEqual({ kind: "unknown" });
|
|
565
|
+
// A plan that publishes no reading (Cursor's) is spent for a model every account refused, and only that model.
|
|
566
|
+
const cursor = [{ account: "x" }, { account: "y" }];
|
|
567
|
+
const refused = [refusal({ kind: "limit", account: "x", model: "composer-2.5" }), refusal({ kind: "limit", account: "y", model: "composer-2.5" })];
|
|
568
|
+
expect(fleetCapacity(cursor, refused, { id: "composer-2.5" }, 2_000).kind).toBe("spent");
|
|
569
|
+
expect(fleetCapacity(cursor, refused, { id: "gpt-6" }, 2_000).kind).toBe("serving");
|
|
570
|
+
// An account refused outright is blocked for every model.
|
|
571
|
+
expect(fleetCapacity([{ account: "x" }], [refusal({ kind: "entitlement", account: "x" })], { id: "gpt-6" }, 2_000).kind).toBe("spent");
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
test("an answer on one model covers another only where every pool the other spends gates it too", () => {
|
|
575
|
+
const codex = usage(window({ kind: "five_hour", utilization: 0 }), window({ kind: "seven_day", utilization: 0 }));
|
|
576
|
+
expect(answerCovers(codex, { id: "gpt-6-luna" }, { id: "gpt-6.1-sol" })).toBe(true);
|
|
577
|
+
// A plan with no entitlement to a model meters it by a pool of its own.
|
|
578
|
+
const free = usage(window({ kind: "monthly", utilization: 0 }), window({ kind: "entitlement:gpt-6.1-sol", utilization: 100, gates: { models: ["gpt-6.1-sol"] } }));
|
|
579
|
+
expect(answerCovers(free, { id: "gpt-6-luna" }, { id: "gpt-6.1-sol" })).toBe(false);
|
|
580
|
+
// Haiku's answer says nothing of Opus's own slice, and Opus's says everything of Haiku's pools.
|
|
581
|
+
expect(answerCovers(CLAUDE, { id: "claude-haiku-4-5" }, { id: "claude-opus-4-6" })).toBe(false);
|
|
582
|
+
expect(answerCovers(CLAUDE, { id: "claude-opus-4-6" }, { id: "claude-haiku-4-5" })).toBe(true);
|
|
583
|
+
// Nothing read proves nothing.
|
|
584
|
+
expect(answerCovers(undefined, { id: "gpt-6-luna" }, { id: "gpt-6.1-sol" })).toBe(false);
|
|
585
|
+
});
|