@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
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// settings-savings: what each token-reduction mechanism saved and how the turn-level ones are measured, as the
|
|
2
|
+
// settings routes report them. Re-exported by settings.ts, whose routes carry them.
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
// What each token-reduction mechanism actually saved. Input-side: both sides of the comparison come off the same
|
|
6
|
+
// command (raw in, emitted out), so the counterfactual is observed, not estimated — exact, per command.
|
|
7
|
+
|
|
8
|
+
// Sequential attribution (sums exactly to raw − emitted, drawable as a stacked bar); not what disabling this stage
|
|
9
|
+
// would save, since downstream would eat some of the same lines. Negative for `footer`, which adds cost back.
|
|
10
|
+
export const SavingsStageSchema = z.object({ id: z.string(), commands: z.number(), savedTokens: z.number() });
|
|
11
|
+
// Aggregated from historyRoot/logs/filter-stats.jsonl (one row per Bash command). Windowed on the ledger's own UTC-day
|
|
12
|
+
// calendar, so the reader's date range and these figures agree.
|
|
13
|
+
export const InputSavingsSchema = z.object({
|
|
14
|
+
// Epoch ms of the ledger's last command, so the card can show its age rather than implying freshness.
|
|
15
|
+
updatedAt: z.number().optional(),
|
|
16
|
+
commands: z.number(),
|
|
17
|
+
rawTokens: z.number(),
|
|
18
|
+
emittedTokens: z.number(),
|
|
19
|
+
savedPct: z.number(),
|
|
20
|
+
// Per-stage attribution, biggest first.
|
|
21
|
+
perCleaner: z.array(SavingsStageSchema),
|
|
22
|
+
// The measured control (raw vs. cleaned); the only real whole-pipeline counterfactual, not an estimate.
|
|
23
|
+
holdout: z.object({ cleaned: z.number(), heldOut: z.number(), measuredSavedPct: z.number().optional() }),
|
|
24
|
+
// Grouped by command text: worth a handler is judged by total tokens across runs, not one outlier's size.
|
|
25
|
+
gaps: z.array(z.object({ command: z.string(), commands: z.number(), tokens: z.number() })),
|
|
26
|
+
});
|
|
27
|
+
export type InputSavings = z.infer<typeof InputSavingsSchema>;
|
|
28
|
+
// One arm of a turn-level experiment; mean is per turn, since the two arms never hold the same count.
|
|
29
|
+
// `mean` is over samples capped at both arms' pooled 95th percentile, so one runaway conversation cannot carry an arm.
|
|
30
|
+
// For a yes/no reading (`openedWithListing`) it is the share of yeses, 0 to 1, and uncapped.
|
|
31
|
+
export const SavingsArmSchema = z.object({ turns: z.number(), mean: z.number() });
|
|
32
|
+
// One metric's reading of a turn-level experiment (the two arms, plus the arithmetic over them). `metric` says what
|
|
33
|
+
// `mean`/`deltaPct` count:
|
|
34
|
+
// searchCalls: searches a turn ran (the search teaching).
|
|
35
|
+
// openingSearches: same, narrowed to before the turn first touched a file.
|
|
36
|
+
// openedWithListing: whether a turn listed directories to orient itself, as a share of turns (the project map).
|
|
37
|
+
// callsBeforeTarget: how far a turn walked before touching a file it went on to edit.
|
|
38
|
+
// failedCalls: tool calls that ended in error (the field notes, whose largest section is a failure taxonomy).
|
|
39
|
+
// openingPrompt: tokens a turn's first request sent (cache reads plus cache writes), which is what every later call of
|
|
40
|
+
// the turn reads again (tool search, which moves the tool schemas out of it).
|
|
41
|
+
// openingWrite: tokens a follow-up turn's first request wrote to the cache instead of reading them (the stable prompt).
|
|
42
|
+
// Every reading is the main agent's own: a subagent's calls are counted toward the turn and read for nothing.
|
|
43
|
+
// Never cost: each mechanism moves one small part of a turn's work, inside the noise of the rest. The prompt's size is
|
|
44
|
+
// the exception that proves it: it is the part every call pays again, so it is read directly rather than through cost.
|
|
45
|
+
export const TurnMetricReadingSchema = z.object({
|
|
46
|
+
metric: z.enum(["searchCalls", "openingSearches", "openedWithListing", "callsBeforeTarget", "failedCalls", "openingPrompt", "openingWrite"]),
|
|
47
|
+
on: SavingsArmSchema,
|
|
48
|
+
off: SavingsArmSchema,
|
|
49
|
+
// Additional control turns to reach a fixed target resolution, not today's delta (which inherits noise and always
|
|
50
|
+
// promises "next week"). Absent means nothing to wait for: under `minTurns`, already published, or already resolved
|
|
51
|
+
// enough.
|
|
52
|
+
controlTurnsNeeded: z.number().optional(),
|
|
53
|
+
// ± percentage points at 95% (Welch); present once both arms clear `minTurns`, even when `deltaPct` is withheld —
|
|
54
|
+
// "smaller than ±35 points" is still a useful, true answer.
|
|
55
|
+
marginPct: z.number().optional(),
|
|
56
|
+
// Present only once the margin excludes zero — clearing `minTurns` alone isn't enough, or a wide, unresolved swing
|
|
57
|
+
// reads as a real number.
|
|
58
|
+
// deltaPct: change in the metric's mean per turn; negative is a saving.
|
|
59
|
+
// saved: what that delta was worth over the turns that ran with it, in the metric's own unit.
|
|
60
|
+
deltaPct: z.number().optional(),
|
|
61
|
+
saved: z.number().optional(),
|
|
62
|
+
});
|
|
63
|
+
export type TurnMetricReading = z.infer<typeof TurnMetricReadingSchema>;
|
|
64
|
+
// One coin flip, several readings: `metrics` is a list since splitting readings into separate entries would duplicate
|
|
65
|
+
// the arm assignment. Screens read `metrics[0]` as the headline, the rest as supporting lines.
|
|
66
|
+
export const TurnExperimentSchema = z.object({
|
|
67
|
+
// A head and a tail, not a plain array, so "always a headline" is a type fact, not a check every screen repeats.
|
|
68
|
+
// `.nonempty()` doesn't do this in zod 4 (a runtime check, still typed as a plain array).
|
|
69
|
+
metrics: z.tuple([TurnMetricReadingSchema], TurnMetricReadingSchema),
|
|
70
|
+
// Carried on the wire so "measuring…" reflects the daemon's real threshold, not a guess; shared across every
|
|
71
|
+
// reading, since they're the same turns.
|
|
72
|
+
minTurns: z.number(),
|
|
73
|
+
// Turn mechanisms randomize by turn; session-loaded teaching randomizes whole conversations; a once-sent treatment
|
|
74
|
+
// (the map) samples one turn per conversation, not an average, or its effect divides by the conversation's length.
|
|
75
|
+
sampleUnit: z.enum(["turns", "conversations", "opening turns"]).optional(),
|
|
76
|
+
// Content-addressed treatment version; the reader filters to the latest so two instruction revisions don't blur
|
|
77
|
+
// into one experiment.
|
|
78
|
+
cohort: z.string().optional(),
|
|
79
|
+
// The latest earlier cohort that reached an answer, with only its answered readings (a margin, with or without a
|
|
80
|
+
// delta), so restarting a comparison does not wipe a finding off the screen while the new one is early. `from` and
|
|
81
|
+
// `to` are its first and last measured turn inside the window read, epoch ms. Absent when no earlier one answered.
|
|
82
|
+
previous: z
|
|
83
|
+
.object({ from: z.number(), to: z.number(), cohort: z.string().optional(), metrics: z.array(TurnMetricReadingSchema) })
|
|
84
|
+
.optional(),
|
|
85
|
+
// Whether the treatment was taken up at all, which no reading above can tell: the share, 0 to 1, of each group's
|
|
86
|
+
// searches that ran iq, pooled over the turns of this cohort that recorded it. `turns` is the treated group's count;
|
|
87
|
+
// absent until it reaches `minTurns`. The search teaching only.
|
|
88
|
+
uptake: z.object({ on: z.number(), off: z.number(), turns: z.number() }).optional(),
|
|
89
|
+
});
|
|
90
|
+
export type TurnExperiment = z.infer<typeof TurnExperimentSchema>;
|
|
91
|
+
// What the settings row can say about the brief without opening it: whether there is one, how much of it this budget
|
|
92
|
+
// reaches, and whether anything is scheduled to rewrite it. Read off the file and the automation store, never stored.
|
|
93
|
+
export const FieldNotesStatusSchema = z.object({
|
|
94
|
+
// False means the automation has never run (or was never set up) — the ordinary state before the first month.
|
|
95
|
+
present: z.boolean(),
|
|
96
|
+
// Epoch ms the file was last written. Absent when there is no file.
|
|
97
|
+
writtenAt: z.number().optional(),
|
|
98
|
+
// How many ranked sections the current budget reaches, out of how many the file holds. The pair is the point: "5"
|
|
99
|
+
// alone cannot tell a generous budget from a short file.
|
|
100
|
+
ranksSent: z.number().optional(),
|
|
101
|
+
ranksTotal: z.number().optional(),
|
|
102
|
+
// What the brief costs the prompt, in characters, at the current budget.
|
|
103
|
+
chars: z.number().optional(),
|
|
104
|
+
// The monthly rewrite: absent until the owner creates it from the offered template, since an automation names the
|
|
105
|
+
// models it spends and nothing chooses those for them.
|
|
106
|
+
automation: z.enum(["missing", "enabled", "disabled"]),
|
|
107
|
+
// When it next runs, epoch ms; absent when there is nothing scheduled.
|
|
108
|
+
nextRunAt: z.number().optional(),
|
|
109
|
+
// Said out loud rather than shown as "no file": a brief that exists and cannot be read is a broken automation.
|
|
110
|
+
unreadable: z.string().optional(),
|
|
111
|
+
// Blocks of the file its priority table does not rank, so no limit ever sends them. Absent when there are none.
|
|
112
|
+
unlisted: z.array(z.string()).optional(),
|
|
113
|
+
});
|
|
114
|
+
export type FieldNotesStatus = z.infer<typeof FieldNotesStatusSchema>;
|
|
115
|
+
export const SavingsReportSchema = z.object({
|
|
116
|
+
input: InputSavingsSchema,
|
|
117
|
+
search: TurnExperimentSchema.optional(),
|
|
118
|
+
// Same absence rule as `search`: not measured, never zero.
|
|
119
|
+
map: TurnExperimentSchema.optional(),
|
|
120
|
+
notes: TurnExperimentSchema.optional(),
|
|
121
|
+
toolSearch: TurnExperimentSchema.optional(),
|
|
122
|
+
stablePrompt: TurnExperimentSchema.optional(),
|
|
123
|
+
coldTrim: TurnExperimentSchema.optional(),
|
|
124
|
+
});
|
|
125
|
+
export type SavingsReport = z.infer<typeof SavingsReportSchema>;
|
package/src/schemas/settings.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { claudeExperimentSettings, iqSearchSettings } from "./settings-experimen
|
|
|
6
6
|
import { CommandJudgeModeSchema, ProjectInstallModeSchema } from "../policy/safety-policy.js";
|
|
7
7
|
import { ModelRoleSchema } from "../models/model-roles.js";
|
|
8
8
|
import { MODEL_SETUP_ID, ModelSetupSchema } from "../models/model-setups.js";
|
|
9
|
-
import { AdmissionPolicySchema, AdmissionRuleSchema } from "./
|
|
9
|
+
import { AdmissionPolicySchema, AdmissionRuleSchema } from "./command-admission.js";
|
|
10
10
|
import { KeepWarmSettingsSchema } from "./keep-warm.js";
|
|
11
11
|
import { LimitHandoffSchema } from "./providers/handoff.js";
|
|
12
12
|
import { SessionsPlacementSchema } from "./offload.js";
|
|
@@ -597,6 +597,13 @@ export const SandboxSettingsSchema = z.object({
|
|
|
597
597
|
.max(10)
|
|
598
598
|
.default(3)
|
|
599
599
|
.describe("How many levels deep the delegation may go, since a subagent can start subagents of its own."),
|
|
600
|
+
// How far off a reset a spawned child's spent turn is booked to re-run by itself (classify-failure.ts); one with fallbacks
|
|
601
|
+
// keeps 90 minutes. 2026-10-18: was a fixed 90 minutes, which ended every child behind a five-hour window.
|
|
602
|
+
childRerunHorizonHours: z.number().int().min(0).max(24).default(6).describe(
|
|
603
|
+
"How long a subagent refused for a spent allowance waits for the provider's reset before it goes again by itself. Past it, or at 0, it stops and its parent hears where else the work can go. One spawned with fallbacks waits at most 90 minutes and then moves to them.",
|
|
604
|
+
),
|
|
605
|
+
subagentBudget: z.boolean().default(true).describe("Start a subagent only where an account's allowance can carry it through its windows, on the account left with the most room after it. The rest wait as pending and start by themselves as running ones end or a window reopens. Off, every subagent starts at once, wherever the most room reads now."),
|
|
606
|
+
subagentReservePercent: z.number().int().min(0).max(50).default(10).describe("How much of each allowance window, in points of 100, subagents leave for your own conversations: a fan-out is planned against what is left past it."),
|
|
600
607
|
// Width again, for a team-chat automation rather than a turn: each thread a message lands in is a conversation of
|
|
601
608
|
// its own, and threads of one automation are worked on side by side up to this many (automations/scheduler.ts in
|
|
602
609
|
// the daemon); one more waits, told it is queued, until a slot frees. Read per fire, so a change holds from the next
|
|
@@ -668,121 +675,8 @@ export type TimezoneState = z.infer<typeof TimezoneStateSchema>;
|
|
|
668
675
|
// from, so a fork from an older build reads as a snapshot.
|
|
669
676
|
export const BuiltinPromptTextSchema = z.object({ text: z.string(), version: z.string() });
|
|
670
677
|
export type BuiltinPromptText = z.infer<typeof BuiltinPromptTextSchema>;
|
|
671
|
-
// What each token-reduction mechanism
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
// Sequential attribution (sums exactly to raw − emitted, drawable as a stacked bar); not what disabling this stage
|
|
675
|
-
// would save, since downstream would eat some of the same lines. Negative for `footer`, which adds cost back.
|
|
676
|
-
export const SavingsStageSchema = z.object({ id: z.string(), commands: z.number(), savedTokens: z.number() });
|
|
677
|
-
// Aggregated from historyRoot/logs/filter-stats.jsonl (one row per Bash command). Windowed on the ledger's own UTC-day
|
|
678
|
-
// calendar, so the reader's date range and these figures agree.
|
|
679
|
-
export const InputSavingsSchema = z.object({
|
|
680
|
-
// Epoch ms of the ledger's last command, so the card can show its age rather than implying freshness.
|
|
681
|
-
updatedAt: z.number().optional(),
|
|
682
|
-
commands: z.number(),
|
|
683
|
-
rawTokens: z.number(),
|
|
684
|
-
emittedTokens: z.number(),
|
|
685
|
-
savedPct: z.number(),
|
|
686
|
-
// Per-stage attribution, biggest first.
|
|
687
|
-
perCleaner: z.array(SavingsStageSchema),
|
|
688
|
-
// The measured control (raw vs. cleaned); the only real whole-pipeline counterfactual, not an estimate.
|
|
689
|
-
holdout: z.object({ cleaned: z.number(), heldOut: z.number(), measuredSavedPct: z.number().optional() }),
|
|
690
|
-
// Grouped by command text: worth a handler is judged by total tokens across runs, not one outlier's size.
|
|
691
|
-
gaps: z.array(z.object({ command: z.string(), commands: z.number(), tokens: z.number() })),
|
|
692
|
-
});
|
|
693
|
-
export type InputSavings = z.infer<typeof InputSavingsSchema>;
|
|
694
|
-
// One arm of a turn-level experiment; mean is per turn, since the two arms never hold the same count.
|
|
695
|
-
// `mean` is over samples capped at both arms' pooled 95th percentile, so one runaway conversation cannot carry an arm.
|
|
696
|
-
// For a yes/no reading (`openedWithListing`) it is the share of yeses, 0 to 1, and uncapped.
|
|
697
|
-
export const SavingsArmSchema = z.object({ turns: z.number(), mean: z.number() });
|
|
698
|
-
// One metric's reading of a turn-level experiment (the two arms, plus the arithmetic over them). `metric` says what
|
|
699
|
-
// `mean`/`deltaPct` count:
|
|
700
|
-
// searchCalls: searches a turn ran (the search teaching).
|
|
701
|
-
// openingSearches: same, narrowed to before the turn first touched a file.
|
|
702
|
-
// openedWithListing: whether a turn listed directories to orient itself, as a share of turns (the project map).
|
|
703
|
-
// callsBeforeTarget: how far a turn walked before touching a file it went on to edit.
|
|
704
|
-
// failedCalls: tool calls that ended in error (the field notes, whose largest section is a failure taxonomy).
|
|
705
|
-
// openingPrompt: tokens a turn's first request sent (cache reads plus cache writes), which is what every later call of
|
|
706
|
-
// the turn reads again (tool search, which moves the tool schemas out of it).
|
|
707
|
-
// openingWrite: tokens a follow-up turn's first request wrote to the cache instead of reading them (the stable prompt).
|
|
708
|
-
// Every reading is the main agent's own: a subagent's calls are counted toward the turn and read for nothing.
|
|
709
|
-
// Never cost: each mechanism moves one small part of a turn's work, inside the noise of the rest. The prompt's size is
|
|
710
|
-
// the exception that proves it: it is the part every call pays again, so it is read directly rather than through cost.
|
|
711
|
-
export const TurnMetricReadingSchema = z.object({
|
|
712
|
-
metric: z.enum(["searchCalls", "openingSearches", "openedWithListing", "callsBeforeTarget", "failedCalls", "openingPrompt", "openingWrite"]),
|
|
713
|
-
on: SavingsArmSchema,
|
|
714
|
-
off: SavingsArmSchema,
|
|
715
|
-
// Additional control turns to reach a fixed target resolution, not today's delta (which inherits noise and always
|
|
716
|
-
// promises "next week"). Absent means nothing to wait for: under `minTurns`, already published, or already resolved
|
|
717
|
-
// enough.
|
|
718
|
-
controlTurnsNeeded: z.number().optional(),
|
|
719
|
-
// ± percentage points at 95% (Welch); present once both arms clear `minTurns`, even when `deltaPct` is withheld —
|
|
720
|
-
// "smaller than ±35 points" is still a useful, true answer.
|
|
721
|
-
marginPct: z.number().optional(),
|
|
722
|
-
// Present only once the margin excludes zero — clearing `minTurns` alone isn't enough, or a wide, unresolved swing
|
|
723
|
-
// reads as a real number.
|
|
724
|
-
// deltaPct: change in the metric's mean per turn; negative is a saving.
|
|
725
|
-
// saved: what that delta was worth over the turns that ran with it, in the metric's own unit.
|
|
726
|
-
deltaPct: z.number().optional(),
|
|
727
|
-
saved: z.number().optional(),
|
|
728
|
-
});
|
|
729
|
-
export type TurnMetricReading = z.infer<typeof TurnMetricReadingSchema>;
|
|
730
|
-
// One coin flip, several readings: `metrics` is a list since splitting readings into separate entries would duplicate
|
|
731
|
-
// the arm assignment. Screens read `metrics[0]` as the headline, the rest as supporting lines.
|
|
732
|
-
export const TurnExperimentSchema = z.object({
|
|
733
|
-
// A head and a tail, not a plain array, so "always a headline" is a type fact, not a check every screen repeats.
|
|
734
|
-
// `.nonempty()` doesn't do this in zod 4 (a runtime check, still typed as a plain array).
|
|
735
|
-
metrics: z.tuple([TurnMetricReadingSchema], TurnMetricReadingSchema),
|
|
736
|
-
// Carried on the wire so "measuring…" reflects the daemon's real threshold, not a guess; shared across every
|
|
737
|
-
// reading, since they're the same turns.
|
|
738
|
-
minTurns: z.number(),
|
|
739
|
-
// Turn mechanisms randomize by turn; session-loaded teaching randomizes whole conversations; a once-sent treatment
|
|
740
|
-
// (the map) samples one turn per conversation, not an average, or its effect divides by the conversation's length.
|
|
741
|
-
sampleUnit: z.enum(["turns", "conversations", "opening turns"]).optional(),
|
|
742
|
-
// Content-addressed treatment version; the reader filters to the latest so two instruction revisions don't blur
|
|
743
|
-
// into one experiment.
|
|
744
|
-
cohort: z.string().optional(),
|
|
745
|
-
// The latest earlier cohort that reached an answer, with only its answered readings (a margin, with or without a
|
|
746
|
-
// delta), so restarting a comparison does not wipe a finding off the screen while the new one is early. `from` and
|
|
747
|
-
// `to` are its first and last measured turn inside the window read, epoch ms. Absent when no earlier one answered.
|
|
748
|
-
previous: z
|
|
749
|
-
.object({ from: z.number(), to: z.number(), cohort: z.string().optional(), metrics: z.array(TurnMetricReadingSchema) })
|
|
750
|
-
.optional(),
|
|
751
|
-
});
|
|
752
|
-
export type TurnExperiment = z.infer<typeof TurnExperimentSchema>;
|
|
753
|
-
// What the settings row can say about the brief without opening it: whether there is one, how much of it this budget
|
|
754
|
-
// reaches, and whether anything is scheduled to rewrite it. Read off the file and the automation store, never stored.
|
|
755
|
-
export const FieldNotesStatusSchema = z.object({
|
|
756
|
-
// False means the automation has never run (or was never set up) — the ordinary state before the first month.
|
|
757
|
-
present: z.boolean(),
|
|
758
|
-
// Epoch ms the file was last written. Absent when there is no file.
|
|
759
|
-
writtenAt: z.number().optional(),
|
|
760
|
-
// How many ranked sections the current budget reaches, out of how many the file holds. The pair is the point: "5"
|
|
761
|
-
// alone cannot tell a generous budget from a short file.
|
|
762
|
-
ranksSent: z.number().optional(),
|
|
763
|
-
ranksTotal: z.number().optional(),
|
|
764
|
-
// What the brief costs the prompt, in characters, at the current budget.
|
|
765
|
-
chars: z.number().optional(),
|
|
766
|
-
// The monthly rewrite: absent until the owner creates it from the offered template, since an automation names the
|
|
767
|
-
// models it spends and nothing chooses those for them.
|
|
768
|
-
automation: z.enum(["missing", "enabled", "disabled"]),
|
|
769
|
-
// When it next runs, epoch ms; absent when there is nothing scheduled.
|
|
770
|
-
nextRunAt: z.number().optional(),
|
|
771
|
-
// Said out loud rather than shown as "no file": a brief that exists and cannot be read is a broken automation.
|
|
772
|
-
unreadable: z.string().optional(),
|
|
773
|
-
});
|
|
774
|
-
export type FieldNotesStatus = z.infer<typeof FieldNotesStatusSchema>;
|
|
775
|
-
export const SavingsReportSchema = z.object({
|
|
776
|
-
input: InputSavingsSchema,
|
|
777
|
-
search: TurnExperimentSchema.optional(),
|
|
778
|
-
// Same absence rule as `search`: not measured, never zero.
|
|
779
|
-
map: TurnExperimentSchema.optional(),
|
|
780
|
-
notes: TurnExperimentSchema.optional(),
|
|
781
|
-
toolSearch: TurnExperimentSchema.optional(),
|
|
782
|
-
stablePrompt: TurnExperimentSchema.optional(),
|
|
783
|
-
coldTrim: TurnExperimentSchema.optional(),
|
|
784
|
-
});
|
|
785
|
-
export type SavingsReport = z.infer<typeof SavingsReportSchema>;
|
|
678
|
+
// What each token-reduction mechanism saved, and the comparisons that measure the turn-level ones, in a file of their own.
|
|
679
|
+
export * from "./settings-savings.js";
|
|
786
680
|
|
|
787
681
|
// ---- what a REPOSITORY declares for itself, at `<repo>/.intentic/checks.json` ----
|
|
788
682
|
// Here rather than in a file of its own because the line between these shapes and the settings above is authority, not
|
package/src/schemas/system.ts
CHANGED
|
@@ -61,6 +61,17 @@ export const PreparingUpdateSchema = z.object({
|
|
|
61
61
|
percent: z.number().min(0).max(100).optional().describe("How far through the download it is, from 0 to 100. Absent for a step with no measure of its own."),
|
|
62
62
|
});
|
|
63
63
|
export type PreparingUpdate = z.infer<typeof PreparingUpdateSchema>;
|
|
64
|
+
// What answers (state/sandbox-build.ts RunningSandbox): the build this container runs and when its daemon started.
|
|
65
|
+
export const RunningSandboxSchema = z.object({
|
|
66
|
+
build: z
|
|
67
|
+
.object({
|
|
68
|
+
base: z.string().describe("The base image as the machine that runs it named it; empty when it said nothing."),
|
|
69
|
+
baseDigest: z.string().optional().describe("That base's registry digest, when the machine read one."),
|
|
70
|
+
overlay: z.string().optional().describe("The hash of the environment recipe built on the base. Absent on a stock image."),
|
|
71
|
+
})
|
|
72
|
+
.describe("Which build this container is: its base image and the environment built on it."),
|
|
73
|
+
bootedAt: z.number().describe("When the daemon answering started, in milliseconds. A container swapped in is a new boot."),
|
|
74
|
+
});
|
|
64
75
|
export const InfoSchema = z.object({
|
|
65
76
|
name: z.string().optional().describe("What this sandbox is called."),
|
|
66
77
|
image: z.string().optional().describe("The image it is running."),
|
|
@@ -129,6 +140,10 @@ export const InfoSchema = z.object({
|
|
|
129
140
|
autoUpdate: AutoUpdateSchema.optional().describe(
|
|
130
141
|
"Whether and when this sandbox takes a downloaded update by itself, and what it is waiting on. Absent where it cannot: a hosted sandbox, one built from a checkout, or one older than automatic updates.",
|
|
131
142
|
),
|
|
143
|
+
// What answers now, for a page telling a swap it pressed from one still running; absent from a daemon older than it.
|
|
144
|
+
running: RunningSandboxSchema.optional().describe(
|
|
145
|
+
"Which build answers and when its daemon started, so a page that asked for a rebuild, an update or a rollback can tell when the new container is the one answering. Absent from a sandbox older than this field.",
|
|
146
|
+
),
|
|
132
147
|
});
|
|
133
148
|
export type Info = z.infer<typeof InfoSchema>;
|
|
134
149
|
// What the daemon could not read in its own `.intentic/` state files, and in the files on its volume that
|
package/src/schemas/terminal.ts
CHANGED
|
@@ -219,6 +219,14 @@ export const SubagentVerificationSchema = z.object({
|
|
|
219
219
|
),
|
|
220
220
|
});
|
|
221
221
|
export type SubagentVerification = z.infer<typeof SubagentVerificationSchema>;
|
|
222
|
+
// Where the Claude runtime keeps an in-process subagent's own record: beside the session it ran in, under the runtime's
|
|
223
|
+
// own id for it. The daemon pairs the two while the subagent runs and writes them onto its delegation's card, so the
|
|
224
|
+
// subagent's whole run reads back from that record after a restart, when nothing in memory still knows where it is.
|
|
225
|
+
export const SubagentSdkRecordSchema = z.object({
|
|
226
|
+
sessionId: z.string().describe("The provider session the subagent ran in."),
|
|
227
|
+
agentId: z.string().describe("The runtime's own id for the subagent, which names its record beside that session."),
|
|
228
|
+
});
|
|
229
|
+
export type SubagentSdkRecord = z.infer<typeof SubagentSdkRecordSchema>;
|
|
222
230
|
export const SubagentSessionSchema = z.object({
|
|
223
231
|
id: z
|
|
224
232
|
.string()
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
// WHAT HAS LOOKED AT A CONVERSATION'S WORK, as its card says it: what its last turn checked of its own work, and the
|
|
4
|
+
// latest code review it reported. Both written by a turn's settle from what the turn did, never asked of the model.
|
|
5
|
+
// Re-exported by agents.ts, whose summary carries them.
|
|
6
|
+
|
|
7
|
+
// What the last turn showed of its own work, read off its tool calls and never asked of the model: the record a card
|
|
8
|
+
// badges instead of sending the turn back to prove anything. CI checks what the owner pushes (schemas/ci.ts).
|
|
9
|
+
export const TurnProofSchema = z.object({
|
|
10
|
+
at: z.number().describe("When the turn that left this ended, in milliseconds."),
|
|
11
|
+
verification: z
|
|
12
|
+
.enum(["verified", "unproven", "failing", "no-code"])
|
|
13
|
+
.describe(
|
|
14
|
+
"Verified: a check it ran passed after its last edit to code. Failing: the last one it ran failed. Unproven: it changed code and ran nothing that checked it. No-code: it changed nothing a check could speak to.",
|
|
15
|
+
),
|
|
16
|
+
check: z.string().optional().describe("The command that spoke, when one did, so a targeted test is never read as the whole suite."),
|
|
17
|
+
unviewed: z
|
|
18
|
+
.number()
|
|
19
|
+
.optional()
|
|
20
|
+
.describe("How many rendered files it changed (pages, components, styles) without looking at the result afterwards. Absent when none."),
|
|
21
|
+
});
|
|
22
|
+
export type TurnProof = z.infer<typeof TurnProofSchema>;
|
|
23
|
+
// The latest code review a conversation reported (events/review.ts), counted rather than carried: the findings stay in
|
|
24
|
+
// its chat, where the card that sends them to be fixed draws them. Kept until a later review replaces it, since a turn
|
|
25
|
+
// that reviews nothing has not undone the one before.
|
|
26
|
+
export const ReviewTallySchema = z.object({
|
|
27
|
+
at: z.number().describe("When the turn that reported it ended, in milliseconds."),
|
|
28
|
+
source: z.enum(["claude", "codex"]).describe("Which harness's reviewer reported it."),
|
|
29
|
+
findings: z.number().int().nonnegative().describe("How many findings it reported."),
|
|
30
|
+
open: z
|
|
31
|
+
.number()
|
|
32
|
+
.int()
|
|
33
|
+
.nonnegative()
|
|
34
|
+
.describe("How many of those no re-report has marked fixed or set aside yet. Equal to `findings` until the review is reported again with its fixes applied."),
|
|
35
|
+
});
|
|
36
|
+
export type ReviewTally = z.infer<typeof ReviewTallySchema>;
|
|
@@ -143,6 +143,38 @@ export const WorkspaceMediaTicketSchema = z.object({
|
|
|
143
143
|
ticket: z.string().describe("Hand this to the streaming route in the query string. It buys exactly the one file it was minted for."),
|
|
144
144
|
expiresAt: z.number().describe("When it stops working, in milliseconds, so a player can tell a dead ticket from a dead file."),
|
|
145
145
|
});
|
|
146
|
+
// The long edges a picture is re-encoded at for drawing (GET /workspace/thumb's `size=e<edge>`), smallest first. A reader
|
|
147
|
+
// asks for the smallest one at least as long as the box the picture fills on its screen, device pixels counted, the
|
|
148
|
+
// way a browser picks from a srcset. Steps of about one and a half, so a pick is never much larger than it needs, and
|
|
149
|
+
// few enough that the pictures of a folder seen at several sizes share their renditions.
|
|
150
|
+
export const PICTURE_EDGES = [384, 512, 768, 1024, 1536, 2048] as const;
|
|
151
|
+
export type PictureEdge = (typeof PICTURE_EDGES)[number];
|
|
152
|
+
|
|
153
|
+
// The box each picture or video is drawn in, asked of a folder's worth at once: a gallery lays its rows out from every
|
|
154
|
+
// picture's shape before any of them has loaded, so a row never reflows under the reader as its pictures arrive.
|
|
155
|
+
export const WORKSPACE_DIMENSIONS_MAX = 500;
|
|
156
|
+
export const WorkspaceDimensionsQuerySchema = WorkspaceScopeSchema.extend({
|
|
157
|
+
paths: z
|
|
158
|
+
.array(z.string().min(1))
|
|
159
|
+
.min(1)
|
|
160
|
+
.max(WORKSPACE_DIMENSIONS_MAX)
|
|
161
|
+
.describe("The pictures and videos to measure, as workspace paths. Anything else, or anything unreadable, is left out of the answer."),
|
|
162
|
+
});
|
|
163
|
+
export const WorkspaceDimensionSchema = z.object({
|
|
164
|
+
path: z.string().describe("The path as it was asked for."),
|
|
165
|
+
width: z.number().describe("Width in pixels, as the picture is shown: a phone photo's or a phone video's rotation is already applied."),
|
|
166
|
+
height: z.number().describe("Height in pixels, as the picture is shown."),
|
|
167
|
+
duration: z.number().optional().describe("A video's running time in seconds, where its container says."),
|
|
168
|
+
});
|
|
169
|
+
export type WorkspaceDimension = z.infer<typeof WorkspaceDimensionSchema>;
|
|
170
|
+
export const WorkspaceDimensionsSchema = z.object({
|
|
171
|
+
items: z
|
|
172
|
+
.array(WorkspaceDimensionSchema)
|
|
173
|
+
.describe(
|
|
174
|
+
"One entry per path that could be measured. A path missing here is not a picture this could read, which is an answer, not an error.",
|
|
175
|
+
),
|
|
176
|
+
});
|
|
177
|
+
export type WorkspaceDimensions = z.infer<typeof WorkspaceDimensionsSchema>;
|
|
146
178
|
// Credential for GET /workspace/download, which the browser navigates to so its own download manager streams the archive
|
|
147
179
|
// to disk. The ticket carries the whole selection, resolved when minted, so however many entries it names the URL stays
|
|
148
180
|
// short.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { STATE_DIR } from "@intentic/constants";
|
|
2
|
+
import type { StateFile } from "./state-portability.js";
|
|
3
|
+
import type { WorkspaceStatePath } from "./workspace-state.js";
|
|
4
|
+
|
|
5
|
+
// The auth root holds AI-provider logins, the sandbox's secret vaults and the trust files a turn must not edit (mode
|
|
6
|
+
// 0600, off the file routes, tree walk and search index). It lives at `.intentic/secrets/auth/` unless AGENT_AUTH_DIR
|
|
7
|
+
// moved it, and the workspace table names it once, as a `secret` directory. This table classifies what is inside, so
|
|
8
|
+
// an export does not carry this sandbox's own keys and pairings with the credentials, and does not drop the owner's
|
|
9
|
+
// restrictions with them either. auth-state-coverage.test.ts in the daemon keeps it complete.
|
|
10
|
+
//
|
|
11
|
+
// The default for a path no entry claims is `secret`, the class of the directory itself: a provider home (`claude/`,
|
|
12
|
+
// `codex/`, `cliproxy/`, `opencode/`…) is a login, and a new provider lands secret by construction.
|
|
13
|
+
//
|
|
14
|
+
// The classes follow the history table's precedent. A restriction the owner set is `carry`: a secret that travels must
|
|
15
|
+
// not arrive ungated. A yes the owner gave (a grant, a release, a widened rule) is `identity`, like the hook and extension
|
|
16
|
+
// approvals there: a trust decision the target's owner makes again.
|
|
17
|
+
|
|
18
|
+
// Where the auth root sits inside the workspace when AGENT_AUTH_DIR does not move it; a declared workspace path.
|
|
19
|
+
export const AUTH_ROOT_IN_WORKSPACE = `${STATE_DIR}/secrets/auth/` as const satisfies WorkspaceStatePath;
|
|
20
|
+
|
|
21
|
+
// Auth-root-relative paths, forward-slash, matched by prefix; a directory keeps its trailing slash.
|
|
22
|
+
export const AUTH_STATE_FILES: readonly StateFile[] = [
|
|
23
|
+
/* ---- the owner's restrictions: no credential in them, and loosened if left behind ---- */
|
|
24
|
+
|
|
25
|
+
// Which credentials need a named person's click (secrets/credential-gates.ts).
|
|
26
|
+
{ path: "credential-gates.json", portability: "carry" },
|
|
27
|
+
// Where each secret may be sent (secrets/guards/host-guards.ts).
|
|
28
|
+
{ path: "secret-hosts.json", portability: "carry" },
|
|
29
|
+
// The privacy shield's policy: whether it masks, what it looks for, which providers it trusts.
|
|
30
|
+
{ path: "privacy-shield.json", portability: "carry" },
|
|
31
|
+
// The execution boundary agents run in (workload/domain/agent-domain-policy.ts).
|
|
32
|
+
{ path: "agent-domain.json", portability: "carry" },
|
|
33
|
+
|
|
34
|
+
/* ---- credentials and what holds their values ---- */
|
|
35
|
+
|
|
36
|
+
{ path: "sandbox-secrets.json", portability: "secret" },
|
|
37
|
+
{ path: "capability-secrets.json", portability: "secret" },
|
|
38
|
+
{ path: "extension-secrets.json", portability: "secret" },
|
|
39
|
+
// The personal data the shield masked, by token, and the pictures it painted over.
|
|
40
|
+
{ path: "privacy-vault.json", portability: "secret" },
|
|
41
|
+
{ path: "privacy-images/", portability: "secret" },
|
|
42
|
+
{ path: "ssh-keys/", portability: "secret" },
|
|
43
|
+
// An update's pre-images of the files above; a vault's copy is a vault.
|
|
44
|
+
{ path: "converting/", portability: "secret" },
|
|
45
|
+
|
|
46
|
+
/* ---- yeses the owner gave here: decided again on the target ---- */
|
|
47
|
+
|
|
48
|
+
// Sandbox-wide permissions ("Always: <line>") and each conversation's own (personas/owner-grants.ts,
|
|
49
|
+
// conversation-grants.ts); a conversation's card simply asks again, so only the sandbox-wide ones carry a note.
|
|
50
|
+
{ path: "owner-grants.json", portability: "identity", note: "Give sandbox-wide permissions again from the Access tab." },
|
|
51
|
+
{ path: "conversation-grants.json", portability: "identity" },
|
|
52
|
+
// An approver's release of a gated credential for one conversation.
|
|
53
|
+
{ path: "credential-releases.json", portability: "identity" },
|
|
54
|
+
// Programs a secret may be typed into unasked; unset, every typing asks.
|
|
55
|
+
{ path: "secret-programs.json", portability: "identity", note: "Allow programs to receive secrets again from Secrets." },
|
|
56
|
+
// Per-card credential rules and raw delivery, the owner's widening of a connector's own rules.
|
|
57
|
+
{ path: "credential-policy.json", portability: "identity", note: "Set a connection's credential rules and delivery again from Capabilities." },
|
|
58
|
+
|
|
59
|
+
/* ---- this sandbox's own keys, and what it is paired with ---- */
|
|
60
|
+
|
|
61
|
+
// The keyring keypair the owner's computers pinned their shares to; only the public halves ever leave.
|
|
62
|
+
{ path: "keyring-keys.json", portability: "identity", note: "Passwords shared from your computers are shared again with the new sandbox." },
|
|
63
|
+
// What each connected computer's keyring said, the entries copied to this sandbox's key, deliveries waiting for a
|
|
64
|
+
// computer, and the needs raised to them.
|
|
65
|
+
{ path: "keyring-devices.json", portability: "identity" },
|
|
66
|
+
{ path: "keyring-copies.json", portability: "identity" },
|
|
67
|
+
{ path: "keyring-sync-mailbox.json", portability: "identity" },
|
|
68
|
+
{ path: "keyring-needs.json", portability: "identity" },
|
|
69
|
+
// The credential broker's signing key and the privacy gateway's token key, each minted on first use.
|
|
70
|
+
{ path: "broker-session.key", portability: "identity" },
|
|
71
|
+
{ path: "privacy-gateway.key", portability: "identity" },
|
|
72
|
+
// The organisation policy the platform hands this sandbox; the target's platform hands its own.
|
|
73
|
+
{ path: "org-policy.json", portability: "identity" },
|
|
74
|
+
|
|
75
|
+
/* ---- regenerated by the target ---- */
|
|
76
|
+
|
|
77
|
+
// Seat refusals the provider answered, and the model catalogs fetched for each runtime.
|
|
78
|
+
{ path: "claude/seats.json", portability: "derived" },
|
|
79
|
+
{ path: "claude/models.json", portability: "derived" },
|
|
80
|
+
{ path: "cursor/models.json", portability: "derived" },
|
|
81
|
+
{ path: "devin/models.json", portability: "derived" },
|
|
82
|
+
{ path: "gemini/models.json", portability: "derived" },
|
|
83
|
+
// Each custom endpoint's last discovered model list, fetched again from the endpoint.
|
|
84
|
+
{ path: "endpoints/", portability: "derived" },
|
|
85
|
+
// Values a computer released for one use each, for masking only; never outlive the process handed them.
|
|
86
|
+
{ path: "keyring-released.json", portability: "derived" },
|
|
87
|
+
// The shell script and socket OpenCode runs commands through, written at boot.
|
|
88
|
+
{ path: "opencode-shell/", portability: "derived" },
|
|
89
|
+
];
|
|
@@ -53,10 +53,11 @@ const RUNTIME_DOMAINS = [
|
|
|
53
53
|
// Commit subject drafted after landing; arrives too late for the turn-end refresh, needs its own push.
|
|
54
54
|
{ domain: "landings", invalidates: [["git", "changes"]] },
|
|
55
55
|
|
|
56
|
-
// A pipeline run
|
|
57
|
-
// poll is the freshness floor, not the answer: somebody watching a run
|
|
58
|
-
// Runs only: the frame doesn't name which run moved, and re-reading every open
|
|
59
|
-
// vendor call per row.
|
|
56
|
+
// A pipeline run or one of its jobs moved: every webhook delivery, in flight or ended (2026-10-20), or the REST poll
|
|
57
|
+
// for a repo with no hook. The board's own poll is the freshness floor, not the answer: somebody watching a run
|
|
58
|
+
// must not wait out a poll interval. Runs only: the frame doesn't name which run moved, and re-reading every open
|
|
59
|
+
// row's job graph would cost a vendor call per row. An open in-flight row re-reads its own graph when the board's
|
|
60
|
+
// runs land (useRunJobs.ts); the daemon's CI-shaped watches recheck on it too (watchers.ts).
|
|
60
61
|
{ domain: "ci", invalidates: [["ci-runs"]] },
|
|
61
62
|
|
|
62
63
|
// An engine install starting or ending, whoever started it; the card's only feed, since a read costs registry calls.
|
|
@@ -72,6 +73,11 @@ const RUNTIME_DOMAINS = [
|
|
|
72
73
|
// A standing yes written or taken back outside a need's answer: a permission card's pass, a release, a purge. They
|
|
73
74
|
// live under the auth root, which no file push watches, and the Allowed list must move with the card that wrote one.
|
|
74
75
|
{ domain: "grants", invalidates: [["grants"]] },
|
|
76
|
+
|
|
77
|
+
// Somebody's composer draft was written, cleared or sent. The frame names no conversation and carries no words, since
|
|
78
|
+
// every member hears it: each window reads back its own caller's drafts (agents.drafts). The key is the editor's draft
|
|
79
|
+
// store's, which reads them back itself rather than through a cached query (models/conversations/drafts/).
|
|
80
|
+
{ domain: "drafts", invalidates: [["drafts"]] },
|
|
75
81
|
] as const satisfies readonly RuntimeDomainBinding[];
|
|
76
82
|
|
|
77
83
|
export const RUNTIME_DOMAIN_BINDINGS: readonly RuntimeDomainBinding[] = RUNTIME_DOMAINS;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { DEV_SANDBOX_IMAGE } from "../policy/overlay-lint.js";
|
|
2
|
+
import { buildParity, builtFromCheckout, rebuildPending, type RunningSandbox, type SandboxBuild, sameBuild, swapVerdict } from "./sandbox-build.js";
|
|
3
|
+
|
|
4
|
+
// Every "which build" question is one of these, asked of two SandboxBuild records; a surface that compares fields of its
|
|
5
|
+
// own choosing is how "pending rebuild" outlived a rebuild and a runner read outdated for good (2026-10).
|
|
6
|
+
|
|
7
|
+
const stable = "ghcr.io/intentic/sandbox:stable";
|
|
8
|
+
const digest = (byte: string): string => `sha256:${byte.repeat(64)}`;
|
|
9
|
+
|
|
10
|
+
test("a rebuild is pending exactly when the overlay wanted is not the one running", () => {
|
|
11
|
+
expect(rebuildPending("h1", "h1")).toBe(false);
|
|
12
|
+
expect(rebuildPending("h2", "h1")).toBe(true);
|
|
13
|
+
// A stock container wanting an overlay waits for it; one wanting none waits for nothing, whatever it runs.
|
|
14
|
+
expect(rebuildPending("h1", undefined)).toBe(true);
|
|
15
|
+
expect(rebuildPending(undefined, undefined)).toBe(false);
|
|
16
|
+
expect(rebuildPending(undefined, "h1")).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test("a runner on the parent's base and overlay is current, and either moving is outdated", () => {
|
|
20
|
+
const parent: SandboxBuild = { base: stable, overlay: "abc123" };
|
|
21
|
+
expect(buildParity(parent, { ...parent })).toBe("current");
|
|
22
|
+
expect(buildParity(parent, { ...parent, overlay: "def456" })).toBe("outdated");
|
|
23
|
+
expect(buildParity(parent, { ...parent, base: "ghcr.io/intentic/sandbox:2.2.0" })).toBe("outdated");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test("an overlay on one side only is a difference; neither side having one is not", () => {
|
|
27
|
+
expect(buildParity({ base: stable }, { base: stable })).toBe("current");
|
|
28
|
+
expect(buildParity({ base: stable, overlay: "abc" }, { base: stable })).toBe("outdated");
|
|
29
|
+
expect(buildParity({ base: stable }, { base: stable, overlay: "abc" })).toBe("outdated");
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// One tag is one name for whatever the registry held when each machine pulled it; the digest is the build.
|
|
33
|
+
test("the base is compared by digest when both sides read one, and by its reference otherwise", () => {
|
|
34
|
+
expect(buildParity({ base: stable, baseDigest: digest("a") }, { base: stable, baseDigest: digest("b") })).toBe("outdated");
|
|
35
|
+
expect(buildParity({ base: stable, baseDigest: digest("a") }, { base: "ghcr.io/intentic/sandbox:beta", baseDigest: digest("a") })).toBe("current");
|
|
36
|
+
expect(buildParity({ base: stable, baseDigest: digest("a") }, { base: stable })).toBe("current");
|
|
37
|
+
expect(buildParity({ base: stable, baseDigest: digest("a") }, { base: "ghcr.io/intentic/sandbox:beta" })).toBe("outdated");
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Each machine's `intentic-sandbox:dev` is whatever its checkout held, so the name agreeing proves nothing, and an update
|
|
41
|
+
// cannot bring it level: `ic` refuses to move a checkout build onto the published image (recreate.rs).
|
|
42
|
+
test("nothing to compare, or a build from a checkout on either side, reads as unknown rather than as a warning", () => {
|
|
43
|
+
const parent: SandboxBuild = { base: stable, overlay: "abc" };
|
|
44
|
+
expect(buildParity(parent, undefined)).toBe("unknown");
|
|
45
|
+
expect(buildParity(parent, { base: "" })).toBe("unknown");
|
|
46
|
+
expect(buildParity({ base: "" }, parent)).toBe("unknown");
|
|
47
|
+
expect(buildParity({ base: DEV_SANDBOX_IMAGE, overlay: "abc" }, { base: DEV_SANDBOX_IMAGE, overlay: "abc" })).toBe("unknown");
|
|
48
|
+
expect(buildParity(parent, { base: DEV_SANDBOX_IMAGE, overlay: "abc" })).toBe("unknown");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// A rollback pin is a local tag too, and a rolled-back sandbox rejoins its channel by updating, not by a checkout.
|
|
52
|
+
test("only the dogfood base is a build from a checkout", () => {
|
|
53
|
+
expect(builtFromCheckout({ base: DEV_SANDBOX_IMAGE })).toBe(true);
|
|
54
|
+
expect(builtFromCheckout({ base: stable })).toBe(false);
|
|
55
|
+
expect(builtFromCheckout({ base: "intentic-sandbox-rollback-demo:f6e917ce9b90" })).toBe(false);
|
|
56
|
+
expect(builtFromCheckout({ base: "" })).toBe(false);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// A swap is told landed by what answers, never by the version: a checkout build is 0.0.0 before and after, and an update
|
|
60
|
+
// of one followed by "the version moved" waited out its deadline and said the sandbox never came back (2026-10).
|
|
61
|
+
const running = (build: SandboxBuild, bootedAt: number): RunningSandbox => ({ build, bootedAt });
|
|
62
|
+
|
|
63
|
+
test("two builds are the same only when something can tell, and differ the moment the overlay or digest does", () => {
|
|
64
|
+
expect(sameBuild({ base: stable, baseDigest: digest("a") }, { base: stable, baseDigest: digest("a") })).toBe(true);
|
|
65
|
+
expect(sameBuild({ base: stable, baseDigest: digest("a") }, { base: stable, baseDigest: digest("b") })).toBe(false);
|
|
66
|
+
expect(sameBuild({ base: stable, overlay: "h1" }, { base: stable, overlay: "h2" })).toBe(false);
|
|
67
|
+
expect(sameBuild({ base: stable }, { base: "ghcr.io/intentic/sandbox:beta" })).toBe(false);
|
|
68
|
+
expect(sameBuild({ base: stable }, { base: stable })).toBeUndefined();
|
|
69
|
+
expect(sameBuild({ base: DEV_SANDBOX_IMAGE }, { base: DEV_SANDBOX_IMAGE })).toBeUndefined();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test("an update of a checkout build lands on the new boot, though every version reads 0.0.0", () => {
|
|
73
|
+
const from = running({ base: DEV_SANDBOX_IMAGE }, 1000);
|
|
74
|
+
expect(swapVerdict({ from }, from)).toBe("waiting");
|
|
75
|
+
expect(swapVerdict({ from }, running({ base: DEV_SANDBOX_IMAGE }, 2000))).toBe("landed");
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("an update of a release lands when the digest moves, and a new boot on the old digest came back unmoved", () => {
|
|
79
|
+
const from = running({ base: stable, baseDigest: digest("a") }, 1000);
|
|
80
|
+
expect(swapVerdict({ from }, running({ base: stable, baseDigest: digest("b") }, 2000))).toBe("landed");
|
|
81
|
+
expect(swapVerdict({ from }, running({ base: stable, baseDigest: digest("a") }, 2000))).toBe("unmoved");
|
|
82
|
+
expect(swapVerdict({ from }, from)).toBe("waiting");
|
|
83
|
+
// A rollback names another tag: moved, digest or not.
|
|
84
|
+
expect(swapVerdict({ from: running({ base: stable }, 1000) }, running({ base: "ghcr.io/intentic/sandbox:0.9.0" }, 1000))).toBe("landed");
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("a rebuild lands on its overlay, and a new boot on any other overlay came back without it", () => {
|
|
88
|
+
const from = running({ base: stable, overlay: "old" }, 1000);
|
|
89
|
+
expect(swapVerdict({ from, overlay: "new" }, running({ base: stable, overlay: "new" }, 2000))).toBe("landed");
|
|
90
|
+
expect(swapVerdict({ from, overlay: "new" }, running({ base: stable, overlay: "old" }, 2000))).toBe("unmoved");
|
|
91
|
+
expect(swapVerdict({ from, overlay: "new" }, from)).toBe("waiting");
|
|
92
|
+
// Pressed with nothing read: only the overlay can say.
|
|
93
|
+
expect(swapVerdict({ from: undefined, overlay: "new" }, running({ base: stable, overlay: "new" }, 2000))).toBe("landed");
|
|
94
|
+
expect(swapVerdict({ from: undefined }, running({ base: stable }, 2000))).toBe("waiting");
|
|
95
|
+
});
|