Files
dsh/upstream/container/platform/test/updater.test.mjs
T

1889 lines
78 KiB
JavaScript

import assert from 'node:assert/strict'
import { createHash } from 'node:crypto'
import { spawnSync } from 'node:child_process'
import { mkdir, mkdtemp, readFile, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import test from 'node:test'
import { canonicalJson } from '../lib/canonical-json.mjs'
import { VerifiedObjectStore } from '../stage0/lib/artifacts.mjs'
import { TrustLedger } from '../stage0/lib/ledger.mjs'
import { UpdateConflictError, UpdateCoordinator } from '../../control-plane/modules/updater/lib/coordinator.mjs'
import { MetadataClient, MetadataUnavailableError, NpmRegistryClient } from '../../control-plane/modules/updater/lib/metadata.mjs'
import { TargetPreparer } from '../../control-plane/modules/updater/lib/preparer.mjs'
import { OfficialDshDownloader } from '../../control-plane/modules/updater/lib/official-dsh-download.mjs'
import { UpdateStateStore } from '../../control-plane/modules/updater/lib/state.mjs'
import { UpdateJournal } from '../../control-plane/modules/updater/lib/journal.mjs'
import {
reconcileRecoveredState,
recoverInterruptedUpdate,
resumeInterruptedReconcile,
} from '../../control-plane/modules/updater/lib/recovery.mjs'
import { PlatformActivator } from '../../control-plane/modules/updater/lib/activator.mjs'
import { ChannelStateStore } from '../../control-plane/modules/updater/lib/channel-state.mjs'
import { keyPair, keyring, officialDshPolicy, registryCandidate, registryKeyPair, signature } from './helpers.mjs'
function descriptor(id, bytes, mediaType = 'application/octet-stream') {
return {
id,
mediaType,
sha256: createHash('sha256').update(bytes).digest('hex'),
size: bytes.byteLength,
url: `https://release.example/${id}`,
}
}
function response(bytes, status = 200) {
return new Response(bytes, { status })
}
async function releaseFixture() {
const recovery = keyPair()
const current = keyPair()
const next = keyPair()
const registry = registryKeyPair()
const component = Buffer.from('component')
const bootstrapPackage = Buffer.from('bootstrap')
const environmentManifest = canonicalJson({
schema: 1,
manifestType: 'environment',
version: '1.0.0',
keyringGeneration: 1,
targetSequence: 1,
issuedAt: '2026-08-19T00:00:00.000Z',
artifacts: [descriptor('environment-component', component)],
bootstrapApi: 1,
components: [],
patches: [],
systemPlugins: [],
})
const bootstrapManifest = canonicalJson({
schema: 1,
manifestType: 'bootstrap',
version: '1.0.0',
keyringGeneration: 1,
targetSequence: 1,
issuedAt: '2026-08-19T00:00:00.000Z',
artifacts: [descriptor('bootstrap-package', bootstrapPackage)],
bootstrapApi: 1,
entrypoint: '/opt/bootstrap/index.mjs',
})
const environmentSignature = canonicalJson(signature(environmentManifest, current))
const bootstrapSignature = canonicalJson(signature(bootstrapManifest, current))
const dsh = Buffer.from('dsh tarball')
const dshCandidate = registryCandidate(registry, '0.1.0-rc.7', dsh)
const artifacts = [
descriptor('environment-manifest', environmentManifest, 'application/vnd.dsh-platform.manifest.v1+json'),
descriptor('environment-signature', environmentSignature, 'application/vnd.dsh-platform.signature.v1+json'),
descriptor('bootstrap-manifest', bootstrapManifest, 'application/vnd.dsh-platform.manifest.v1+json'),
descriptor('bootstrap-signature', bootstrapSignature, 'application/vnd.dsh-platform.signature.v1+json'),
]
const stable = canonicalJson({
schema: 1,
updateApi: 1,
keyringGeneration: 1,
targetSequence: 1,
issuedAt: '2026-08-19T00:00:00.000Z',
artifacts,
desired: {
bootstrap: { version: '1.0.0', manifestArtifactId: 'bootstrap-manifest', signatureArtifactId: 'bootstrap-signature' },
environment: { version: '1.0.0', manifestArtifactId: 'environment-manifest', signatureArtifactId: 'environment-signature' },
dsh: {
version: '0.1.0-rc.7',
integrity: `sha512-${createHash('sha512').update(dsh).digest('base64')}`,
},
},
officialDshPolicy: officialDshPolicy(registry),
})
const ring = canonicalJson(keyring(1, current, next))
const files = new Map([
['https://metadata.example/keyring.json', ring],
['https://metadata.example/keyring.sig.json', canonicalJson(signature(ring, recovery))],
['https://metadata.example/stable.json', stable],
['https://metadata.example/stable.sig.json', canonicalJson(signature(stable, current))],
...artifacts.map(artifact => [artifact.url, {
'environment-manifest': environmentManifest,
'environment-signature': environmentSignature,
'bootstrap-manifest': bootstrapManifest,
'bootstrap-signature': bootstrapSignature,
}[artifact.id]]),
['https://release.example/environment-component', component],
['https://release.example/bootstrap-package', bootstrapPackage],
['https://registry.npmjs.org/%40deepseek-ai%2Fdsh', Buffer.from(JSON.stringify({
versions: { [dshCandidate.version]: dshCandidate },
}))],
[dshCandidate.dist.tarball, dsh],
])
return { recovery, current, next, files, stable }
}
async function system() {
const fixture = await releaseFixture()
const root = await mkdtemp(join(tmpdir(), 'dsh-updater-'))
const untrustedRoot = join(root, 'downloads', 'untrusted')
await mkdir(untrustedRoot, { recursive: true })
const ledger = new TrustLedger(join(root, 'trust'), fixture.recovery.publicKey)
const fetchImpl = async (url, options = {}) => {
const bytes = fixture.files.get(String(url))
if (bytes === undefined) return response('missing', 404)
if (String(url).startsWith('https://release.example/')) {
const headers = new Headers(options.headers)
if (headers.get('accept-encoding') !== 'identity') {
return new Response(bytes, { headers: { 'content-encoding': 'gzip', 'content-length': '1' } })
}
}
return response(bytes)
}
const objects = new VerifiedObjectStore({ root: join(root, 'trust'), untrustedRoot, ledger })
const trust = {
acceptKeyring: (bytes, value) => ledger.acceptKeyring(bytes, value),
acceptTarget: (bytes, value) => ledger.acceptTarget(bytes, value),
importArtifact: (id, path, parent) => parent === null
? objects.importFromTarget(id, path)
: objects.importFromManifest(parent, id, path),
acceptManifest: (token, signatureToken) => objects.acceptManifest(token, signatureToken),
ensureOfficialDsh: (version, metadataPath, tarballPath) => (
objects.ensureOfficialDsh(version, metadataPath, tarballPath)
),
activate: tokens => objects.activate(tokens),
}
const metadata = new MetadataClient({ baseUrl: 'https://metadata.example/', trust, fetchImpl, retryMs: 1 })
const preparer = new TargetPreparer({ untrustedRoot, trust, fetchImpl })
return { fixture, root, ledger, objects, trust, metadata, preparer }
}
test('checks Recovery keyring before stable and prepares the complete signed Artifact graph', async () => {
const { metadata, preparer, ledger, objects } = await system()
const checked = await metadata.check()
assert.equal(checked.value.targetSequence, 1)
let requestedVersion
const ensureOfficialDsh = preparer.trust.ensureOfficialDsh
preparer.trust.ensureOfficialDsh = (version, metadataPath, tarballPath) => {
requestedVersion = version
return ensureOfficialDsh(version, metadataPath, tarballPath)
}
const progress = []
const prepared = await preparer.prepare(checked.value, { onProgress: value => { progress.push(value) } })
assert.equal(prepared.receipts.size, 6)
assert.equal(prepared.dsh.receipt.authorityType, 'official-dsh')
assert.equal(prepared.receiptTokens.length, 7)
assert.equal(requestedVersion, checked.value.desired.dsh.version)
assert.equal([...prepared.paths.values()].every(path => path.includes('/trust/objects/')), true)
assert.equal((await ledger.currentKeyring()).value.generation, 1)
assert.equal((await objects.readReceipt(prepared.environment.manifestReceipt.token)).authoritySignature.keyId.length, 64)
assert.ok(progress.at(-1).processedBytes > 0)
assert.equal(progress.at(-1).totalBytes, null)
assert.equal(progress.at(-1).processedItems, progress.at(-1).totalItems)
for (let index = 1; index < progress.length; index += 1) {
assert.ok(progress[index].processedBytes >= progress[index - 1].processedBytes)
}
})
test('rejects encoded signed Artifact responses without retrying transformed bytes', async t => {
for (const encoding of ['identity', 'gzip', 'br', 'deflate']) {
await t.test(encoding, async () => {
const { fixture, metadata, preparer } = await system()
const checked = await metadata.check()
let requests = 0
let imports = 0
preparer.trust.importArtifact = async () => { imports += 1 }
preparer.fetchImpl = async url => {
requests += 1
return new Response(fixture.files.get(String(url)), {
headers: { 'content-encoding': encoding, 'content-length': '1' },
})
}
await assert.rejects(preparer.prepare(checked.value), /must not use content encoding/)
assert.equal(requests, 1)
assert.equal(imports, 0)
})
}
})
test('downloads official DSH metadata and tarball with bounded retry and measurable progress', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-official-downloader-'))
const registry = registryKeyPair()
const content = Buffer.alloc(2 * 1024 * 1024, 0x61)
const candidate = registryCandidate(registry, '0.1.0-rc.8', content)
const metadata = JSON.stringify({ versions: { [candidate.version]: candidate } })
let request = 0
const progress = []
const downloader = new OfficialDshDownloader({
attempts: 3,
retryMs: 1,
fetchImpl: async () => {
request += 1
if (request === 1 || request === 3) throw new TypeError('temporary connection failure')
return request === 2
? new Response(metadata, { headers: { 'content-length': String(Buffer.byteLength(metadata)) } })
: new Response(content, { headers: { 'content-length': String(content.byteLength) } })
},
})
const downloaded = await downloader.download(candidate.version, root, {
onProgress: value => { progress.push(value) },
})
assert.equal(request, 4)
assert.deepEqual(await readFile(downloaded.metadataPath), Buffer.from(metadata))
assert.deepEqual(await readFile(downloaded.tarballPath), content)
assert.equal(progress.at(-1).processedBytes, progress.at(-1).totalBytes)
assert.equal(progress.at(-1).processedItems, 2)
assert.equal(progress.at(-1).totalItems, 2)
for (let index = 1; index < progress.length; index += 1) {
assert.ok(progress[index].processedBytes >= progress[index - 1].processedBytes)
}
})
test('rejects an encoded official DSH tarball without retrying transformed bytes', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-official-encoding-'))
const registry = registryKeyPair()
const content = Buffer.from('official-dsh')
const candidate = registryCandidate(registry, '0.1.0-rc.8', content)
const metadata = JSON.stringify({ versions: { [candidate.version]: candidate } })
let requests = 0
const downloader = new OfficialDshDownloader({
attempts: 3,
retryMs: 1,
fetchImpl: async () => {
requests += 1
return requests === 1
? new Response(metadata)
: new Response(content, { headers: { 'content-encoding': 'br' } })
},
})
await assert.rejects(downloader.download(candidate.version, root), /must not use content encoding/)
assert.equal(requests, 2)
})
test('does not follow an untrusted official DSH metadata redirect', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-official-redirect-'))
const downloader = new OfficialDshDownloader({
attempts: 1,
fetchImpl: async () => ({
ok: true,
redirected: true,
url: 'https://mirror.example/packument',
headers: new Headers(),
arrayBuffer: async () => new ArrayBuffer(0),
}),
})
await assert.rejects(downloader.download('0.1.0-rc.8', root), /changed origin or redirected/)
})
test('constructs Pristine DSH only from a receipt-backed archive', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-trusted-pristine-'))
const source = join(root, 'source', 'package')
await mkdir(source, { recursive: true })
await writeFile(join(source, 'package.json'), JSON.stringify({ name: '@deepseek-ai/dsh', version: '0.1.0-rc.8' }))
const trusted = join(root, 'trust', 'objects', 'trusted-object')
await mkdir(join(root, 'trust', 'objects'), { recursive: true })
const archived = spawnSync('tar', ['-czf', trusted, '-C', join(root, 'source'), 'package'], { encoding: 'utf8' })
assert.equal(archived.status, 0, archived.stderr)
const activator = new PlatformActivator({ dataRoot: join(root, 'data'), bootstrap: {}, stage0: {} })
const pristine = await activator.pristine('0.1.0-rc.8', { path: trusted })
assert.equal(JSON.parse(await readFile(join(pristine, 'package.json'), 'utf8')).version, '0.1.0-rc.8')
})
test('reports Stable switching only after the Managed Deployment is prepared', async () => {
const calls = []
const record = { id: 'managed-record' }
const receipt = { token: 'bootstrap-receipt' }
const activator = new PlatformActivator({
dataRoot: '/unused',
builder: { buildStable: async (prepared, { onProgress }) => {
calls.push('build')
await onProgress(87)
return { record }
} },
bootstrap: {
request: async (method, path, body) => {
calls.push('activate')
assert.equal(method, 'POST')
assert.equal(path, '/v1/deployments/activate')
assert.equal(body.record, record)
},
},
stage0: {
stageBootstrap: async (token, version) => {
calls.push('stage-bootstrap')
assert.equal(token, receipt.token)
assert.equal(version, '1.0.0')
return { status: 'staged', restartRequired: false }
},
},
})
await activator.activate({
stable: { desired: { bootstrap: { version: '1.0.0' } } },
bootstrap: { manifest: { artifacts: [{ id: 'bootstrap-package' }] } },
receipts: new Map([['bootstrap-package', receipt]]),
}, {
onProgress: async progress => { calls.push(`progress:${progress}`) },
onSwitching: async () => { calls.push('switching') },
})
assert.deepEqual(calls, ['stage-bootstrap', 'build', 'progress:87', 'switching', 'activate'])
})
test('hands Stable activation to Stage-0 when same-version Bootstrap content changes', async () => {
const receipt = { token: 'bootstrap-receipt' }
let built = false
const activator = new PlatformActivator({
dataRoot: '/unused',
builder: { buildStable: async () => { built = true; return { record: { id: 'unexpected' } } } },
bootstrap: {},
stage0: {
stageBootstrap: async () => ({ status: 'switching', restartRequired: true }),
},
})
const activation = activator.activate({
stable: { desired: { bootstrap: { version: '1.0.0' } } },
bootstrap: { manifest: { artifacts: [{ id: 'bootstrap-package' }] } },
receipts: new Map([['bootstrap-package', receipt]]),
})
const outcome = await Promise.race([
activation.then(() => 'completed'),
new Promise(resolve => setTimeout(() => resolve('handoff'), 25)),
])
assert.equal(outcome, 'handoff')
assert.equal(built, false)
})
test('resumes Stable activation after Stage-0 switches to a newer Bootstrap', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-bootstrap-update-handoff-'))
const state = new UpdateStateStore(join(root, 'state', 'update.json'))
const target = {
targetSequence: 2,
desired: {
bootstrap: { version: '2.0.0' },
environment: { version: 'env-2' },
dsh: { version: '0.1.0-rc.8' },
},
}
const prepared = {
stable: target,
bootstrap: { manifest: { artifacts: [{ id: 'bootstrap-package' }] } },
receipts: new Map([['bootstrap-package', { token: 'bootstrap-receipt' }]]),
}
const metadata = { check: async () => ({ value: target }) }
const preparer = { prepare: async () => prepared }
const staged = Promise.withResolvers()
let oldBootstrapBuilt = false
const oldCoordinator = new UpdateCoordinator({
metadata,
preparer,
activator: new PlatformActivator({
dataRoot: root,
builder: { buildStable: async () => { oldBootstrapBuilt = true } },
bootstrap: {},
stage0: {
stageBootstrap: async (_token, version) => {
assert.equal(version, '2.0.0')
staged.resolve()
return { status: 'switching', restartRequired: true }
},
},
}),
state,
})
oldCoordinator.start()
await staged.promise
assert.equal((await state.read()).status, 'building-candidate')
assert.equal(oldBootstrapBuilt, false)
let current = {
id: 'deployment-old', authority: 'stable', targetSequence: 1,
dshVersion: '0.1.0-rc.7', environmentVersion: 'env-1', snapshotId: null,
receiptTokens: ['old-receipt'],
}
const desired = {
id: 'deployment-new', authority: 'stable', targetSequence: 2,
dshVersion: '0.1.0-rc.8', environmentVersion: 'env-2', snapshotId: null,
receiptTokens: ['new-receipt'],
}
let newBootstrapBuilt = false
let restaged = 0
const bootstrap = {
request: async (method, path, body) => {
if (method === 'GET' && path === '/v1/deployments/current') return { record: current }
if (method === 'GET' && path === '/v1/health') return { healthy: true, components: [] }
if (method === 'POST' && path === '/v1/deployments/activate') {
assert.deepEqual(body.record, desired)
current = desired
return { record: current }
}
throw new Error(`Unexpected Bootstrap request: ${method} ${path}`)
},
}
const newCoordinator = new UpdateCoordinator({
metadata,
preparer,
activator: new PlatformActivator({
dataRoot: root,
builder: {
buildStable: async () => {
newBootstrapBuilt = true
return { record: desired }
},
},
bootstrap,
stage0: {
stageBootstrap: async (_token, version) => {
assert.equal(version, '2.0.0')
restaged += 1
return { status: 'staged', restartRequired: false }
},
},
}),
state,
channelState: { read: async () => ({ updateChannel: 'stable', holds: [], experimentalBlocked: null }) },
})
const recovered = await reconcileRecoveredState({
journal: new UpdateJournal(join(root, 'state', 'transaction.json')),
state,
})
assert.equal(recovered.persisted.status, 'building-candidate')
const resumed = resumeInterruptedReconcile({
coordinator: newCoordinator,
persisted: recovered.persisted,
report: async () => {},
audit: async () => {},
})
await resumed.completion
assert.equal(newBootstrapBuilt, true)
assert.equal(restaged, 1)
assert.equal(current.id, desired.id)
assert.equal((await state.read()).status, 'success')
})
test('waits for the initial Deployment while Bootstrap startup is incomplete', async () => {
const calls = []
let currentRequests = 0
const activator = new PlatformActivator({
dataRoot: '/unused',
sleep: async milliseconds => { calls.push(`sleep:${milliseconds}`) },
bootstrap: { request: async (method, path) => {
calls.push(`${method} ${path}`)
if (path === '/v1/deployments/current') {
currentRequests += 1
return currentRequests === 1
? { record: null }
: { record: {
authority: 'stable', targetSequence: 1, dshVersion: '0.1.1-rc.2',
id: 'deployment-record-current', environmentVersion: '1.0.5',
snapshotId: null, receiptTokens: [],
} }
}
if (path === '/v1/status') return { startupComplete: false }
throw new Error(`unexpected request: ${method} ${path}`)
} },
stage0: {},
})
assert.deepEqual(await activator.currentDeployment(), {
authority: 'stable', targetSequence: 1, dsh: '0.1.1-rc.2',
runtime: 'deployment-record-current', environment: '1.0.5',
dataSnapshot: null, receiptTokens: [],
})
assert.deepEqual(calls, [
'GET /v1/deployments/current',
'GET /v1/status',
'sleep:100',
'GET /v1/deployments/current',
])
})
test('does not hide a missing Deployment after Bootstrap startup completes', async () => {
const activator = new PlatformActivator({
dataRoot: '/unused',
bootstrap: { request: async (method, path) => {
if (path === '/v1/deployments/current') return { record: null }
if (path === '/v1/status') return { startupComplete: true }
throw new Error(`unexpected request: ${method} ${path}`)
} },
stage0: {},
})
await assert.rejects(activator.currentDeployment(), /current Deployment is required/)
})
test('bounds the initial Deployment startup wait', async () => {
let currentRequests = 0
let statusRequests = 0
const activator = new PlatformActivator({
dataRoot: '/unused',
sleep: async () => {},
bootstrap: { request: async (method, path) => {
if (path === '/v1/deployments/current') {
currentRequests += 1
return { record: null }
}
if (path === '/v1/status') {
statusRequests += 1
return { startupComplete: false }
}
throw new Error(`unexpected request: ${method} ${path}`)
} },
stage0: {},
})
await assert.rejects(activator.currentDeployment(), /current Deployment is required/)
assert.equal(currentRequests, 100)
assert.equal(statusRequests, 100)
})
test('coalesces overlapping metadata checks into one request', async () => {
let checks = 0
let complete
const state = {
value: { status: 'idle', progress: 0 },
async read() { return this.value },
async write(status, fields) { this.value = { ...this.value, ...fields, status }; return this.value },
}
const coordinator = new UpdateCoordinator({
metadata: {
check: () => {
checks += 1
return new Promise(resolve => { complete = resolve })
},
},
state,
preparer: {},
activator: {},
})
const first = coordinator.check()
const second = coordinator.check()
assert.equal(first, second)
await new Promise(resolve => setImmediate(resolve))
assert.equal(checks, 1)
complete({ value: { targetSequence: 1, desired: {
bootstrap: { version: '1.0.0' }, environment: { version: 'env-1' }, dsh: { version: 'rc.1' },
} } })
await first
assert.equal(state.value.status, 'idle')
})
test('keeps telemetry within a phase and clears it at operation and phase boundaries', async () => {
const state = {
value: { status: 'idle', phase: null, operation: null, progress: 0 },
async read() { return this.value },
async write(status, fields) { this.value = { ...this.value, ...fields, status }; return this.value },
}
const coordinator = new UpdateCoordinator({ metadata: {}, preparer: {}, activator: {}, state })
await coordinator.transition('downloading', {
operation: 'update', processedBytes: 20, totalBytes: 100,
processedItems: 1, totalItems: 4, detail: 'downloading',
})
await coordinator.transition('downloading', { progress: 20, processedBytes: 40 })
assert.equal(state.value.totalBytes, 100)
assert.equal(state.value.processedItems, 1)
assert.equal(state.value.detail, 'downloading')
await coordinator.transition('building-candidate', { progress: 75 })
assert.equal(state.value.processedBytes, null)
assert.equal(state.value.totalBytes, null)
assert.equal(state.value.processedItems, null)
assert.equal(state.value.totalItems, null)
assert.equal(state.value.detail, null)
await coordinator.transition('building-candidate', {
processedBytes: 75, totalBytes: 100, processedItems: 3, totalItems: 4,
})
await coordinator.transition('failed', { error: 'build failed' })
assert.equal(state.value.processedBytes, 75)
assert.equal(state.value.processedItems, 3)
await coordinator.transition('checking', { operation: 'check', taskId: null, progress: 0 })
assert.equal(state.value.processedBytes, null)
assert.equal(state.value.totalBytes, null)
assert.equal(state.value.processedItems, null)
assert.equal(state.value.totalItems, null)
})
test('starts an update only after an in-flight metadata check has settled', async () => {
let finishCheck
const events = []
const state = {
value: { status: 'idle', progress: 0 },
async read() { return this.value },
async write(status, fields) { this.value = { ...this.value, ...fields, status }; return this.value },
}
const coordinator = new UpdateCoordinator({
metadata: {
check: () => new Promise(resolve => { finishCheck = resolve }),
},
state,
preparer: {},
activator: {},
})
const checking = coordinator.check('page-open')
await new Promise(resolve => setImmediate(resolve))
coordinator.run = async taskId => {
events.push(['update', taskId, state.value.status])
return coordinator.transition('success', { taskId, operation: 'update', progress: 100 })
}
const update = coordinator.start()
assert.equal(coordinator.hasActiveTask(), true)
assert.throws(() => coordinator.start(), UpdateConflictError)
await new Promise(resolve => setImmediate(resolve))
assert.deepEqual(events, [])
finishCheck({ value: { targetSequence: 1, desired: {
bootstrap: { version: '1.0.0' }, environment: { version: 'env-1' }, dsh: { version: 'rc.1' },
} } })
await checking
await update.completion
assert.deepEqual(events, [['update', update.taskId, 'idle']])
assert.equal(state.value.status, 'success')
assert.equal(state.value.taskId, update.taskId)
})
test('only an automatic check records update notification candidates', async () => {
const recorded = []
const state = {
value: { status: 'idle' },
async read() { return this.value },
async write(status, fields) { this.value = { ...this.value, ...fields, status }; return this.value },
}
const plan = {
action: 'experimental', updateChannel: 'experimental', aheadOfStable: false, experimentalBlocked: null, holds: [],
current: { targetSequence: 1, dsh: '0.1.0-rc.7', environment: 'env-1', runtime: 'runtime-a' },
supported: { dsh: '0.1.0-rc.8', environment: 'env-1' }, upstream: { version: '0.1.0-rc.10' },
target: { targetSequence: 2, desired: {
bootstrap: { version: '1.0.0' }, environment: { version: 'env-1' }, dsh: { version: '0.1.0-rc.8' },
} },
}
const coordinator = new UpdateCoordinator({
metadata: {}, preparer: {}, activator: {}, state, channelState: {},
automaticChecks: { record: async value => recorded.push(value), read: async () => ({ automaticCheck: {}, latestAutomatic: {} }) },
})
coordinator.desiredState = async () => plan
coordinator.rollbackPlan = async () => null
await coordinator.check('page-open')
assert.equal(recorded.length, 0)
await coordinator.check('automatic')
assert.equal(recorded.length, 1)
assert.equal(recorded[0].upstream.version, '0.1.0-rc.10')
})
test('keeps the last verified target when a later remote check fails', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-check-last-verified-'))
const state = new UpdateStateStore(join(root, 'state', 'update.json'))
const plan = {
action: 'experimental', updateChannel: 'experimental', aheadOfStable: false, experimentalBlocked: null, holds: [],
current: { targetSequence: 1, dsh: '0.1.0-rc.7', environment: 'env-1', runtime: 'runtime-a' },
supported: { dsh: '0.1.0-rc.8', environment: 'env-1' }, upstream: { version: '0.1.0-rc.10' },
target: { targetSequence: 2, desired: {
bootstrap: { version: '1.0.0' }, environment: { version: 'env-1' }, dsh: { version: '0.1.0-rc.8' },
} },
}
const coordinator = new UpdateCoordinator({
metadata: {}, preparer: {}, activator: {}, state, channelState: {},
now: () => new Date('2026-08-25T00:00:00.000Z'),
})
coordinator.rollbackPlan = async () => null
coordinator.desiredState = async () => plan
await coordinator.check()
const verified = await state.read()
coordinator.desiredState = async () => { throw new Error('keyring.json timed out after 2 attempts') }
await assert.rejects(coordinator.check(), /timed out/)
const failed = await state.read()
assert.equal(failed.status, 'idle')
assert.deepEqual(failed.supported, verified.supported)
assert.deepEqual(failed.upstream, verified.upstream)
assert.deepEqual(failed.available, verified.available)
assert.equal(failed.updateAvailable, verified.updateAvailable)
assert.equal(failed.checkedAt, verified.checkedAt)
assert.equal(failed.remoteCheckError, 'keyring.json timed out after 2 attempts')
assert.equal(failed.remoteCheckFailedAt, '2026-08-25T00:00:00.000Z')
assert.equal(failed.remoteCheckSource, 'stable')
assert.equal(failed.error, null)
})
test('identifies an official DSH discovery failure independently from Stable metadata', async () => {
const state = {
value: { status: 'idle' },
async read() { return this.value },
async write(status, fields) { this.value = { ...this.value, ...fields, status }; return this.value },
}
const coordinator = new UpdateCoordinator({
metadata: { check: async () => ({ value: {
targetSequence: 2,
officialDshPolicy: {},
desired: { bootstrap: { version: '1.0.0' }, environment: { version: 'env-1' }, dsh: { version: '0.1.0-rc.8' } },
} }) },
npm: { discover: async () => { throw new Error('npm registry timed out') } },
preparer: {},
activator: { currentDeployment: async () => ({ targetSequence: 1, dsh: '0.1.0-rc.7', environment: 'env-1', runtime: 'runtime-a' }) },
state,
channelState: { read: async () => ({ updateChannel: 'experimental', holds: [], experimentalBlocked: null }) },
})
coordinator.rollbackPlan = async () => null
await assert.rejects(coordinator.check(), /npm registry timed out/)
assert.equal(state.value.status, 'idle')
assert.equal(state.value.remoteCheckError, 'npm registry timed out')
assert.equal(state.value.remoteCheckSource, 'upstream')
assert.equal(state.value.checkedAt, undefined)
assert.equal(state.value.upstream, undefined)
})
test('reports unpublished metadata only for development images', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-development-metadata-'))
const state = new UpdateStateStore(join(root, 'state', 'update.json'))
const channelState = new ChannelStateStore(join(root, 'state', 'channel.json'))
await channelState.setChannel('experimental')
let metadataChecks = 0
const coordinator = new UpdateCoordinator({
metadata: { check: async () => { metadataChecks += 1; throw new MetadataUnavailableError() } },
npm: { discover: async () => ({ version: '0.1.0-rc.10' }) },
preparer: {}, activator: {}, state, channelState,
allowUnavailableMetadata: true,
})
assert.deepEqual(await coordinator.check(), {
unavailable: true,
upstream: { version: '0.1.0-rc.10' },
})
assert.equal(metadataChecks, 0)
const persisted = await state.read()
assert.equal(persisted.status, 'idle')
assert.equal(persisted.error, null)
assert.equal(persisted.metadataUnavailable, true)
assert.deepEqual(persisted.upstream, { version: '0.1.0-rc.10' })
})
test('development images skip foreign Recovery roots while formal images reject them', async () => {
const mismatch = Object.assign(new Error('keyring signature key is not trusted'), {
code: 'TRUST_UNKNOWN_KEY',
localApiPath: '/v1/keyring',
})
const developmentRoot = await mkdtemp(join(tmpdir(), 'dsh-development-root-mismatch-'))
let developmentMetadataChecks = 0
const development = new UpdateCoordinator({
metadata: { check: async () => { developmentMetadataChecks += 1; throw mismatch } },
preparer: {}, activator: {}, state: new UpdateStateStore(join(developmentRoot, 'state', 'update.json')),
allowUnavailableMetadata: true,
})
assert.deepEqual(await development.check(), { unavailable: true, upstream: null })
assert.equal(developmentMetadataChecks, 0)
assert.equal((await development.state.read()).metadataUnavailable, true)
const targetError = Object.assign(new Error('target signature key is not trusted'), {
code: 'TRUST_UNKNOWN_KEY',
localApiPath: '/v1/target',
})
const targetRoot = await mkdtemp(join(tmpdir(), 'dsh-development-target-mismatch-'))
const invalidTarget = new UpdateCoordinator({
metadata: { check: async () => { throw targetError } },
preparer: {}, activator: {}, state: new UpdateStateStore(join(targetRoot, 'state', 'update.json')),
})
await assert.rejects(invalidTarget.check(), /target signature key is not trusted/)
const formalRoot = await mkdtemp(join(tmpdir(), 'dsh-formal-root-mismatch-'))
const formal = new UpdateCoordinator({
metadata: { check: async () => { throw mismatch } },
preparer: {}, activator: {}, state: new UpdateStateStore(join(formalRoot, 'state', 'update.json')),
})
await assert.rejects(formal.check(), /keyring signature key is not trusted/)
})
test('records unpublished formal metadata as a remote check failure', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-formal-metadata-'))
const state = new UpdateStateStore(join(root, 'state', 'update.json'))
const coordinator = new UpdateCoordinator({
metadata: { check: async () => { throw new MetadataUnavailableError() } },
preparer: {}, activator: {}, state,
})
await assert.rejects(coordinator.check(), MetadataUnavailableError)
const failed = await state.read()
assert.equal(failed.status, 'idle')
assert.equal(failed.remoteCheckError, 'signed update metadata has not been published')
})
test('does not retry missing signed metadata files', async () => {
let requests = 0
const client = new MetadataClient({
baseUrl: 'https://metadata.example/',
trust: {},
attempts: 3,
retryMs: 1,
fetchImpl: async () => { requests += 1; return response('missing', 404) },
})
await assert.rejects(client.check(), MetadataUnavailableError)
assert.equal(requests, 2)
})
test('bounds stalled signed metadata and npm Registry requests', async () => {
const stalledFetch = async (_url, options) => new Promise((resolve, reject) => {
if (options.signal.aborted) {
reject(options.signal.reason)
return
}
options.signal.addEventListener('abort', () => reject(options.signal.reason), { once: true })
})
const metadata = new MetadataClient({
baseUrl: 'https://metadata.example/',
trust: {},
fetchImpl: stalledFetch,
attempts: 1,
requestTimeoutMs: 10,
})
const npm = new NpmRegistryClient({ fetchImpl: stalledFetch, requestTimeoutMs: 10 })
await assert.rejects(metadata.check(), error => error?.name === 'TimeoutError')
await assert.rejects(npm.discover(), error => error?.name === 'TimeoutError')
})
test('retries only a slow metadata file with the extended retry budget', async () => {
const fixture = await releaseFixture()
const requests = new Map()
const fetchImpl = async (url, options) => {
const key = String(url)
requests.set(key, (requests.get(key) ?? 0) + 1)
if (key.endsWith('/keyring.json')) {
await new Promise((resolve, reject) => {
const timer = setTimeout(resolve, 20)
options.signal.addEventListener('abort', () => {
clearTimeout(timer)
reject(options.signal.reason)
}, { once: true })
})
}
return response(fixture.files.get(key) ?? 'missing', fixture.files.has(key) ? 200 : 404)
}
const ledger = new TrustLedger(await mkdtemp(join(tmpdir(), 'dsh-metadata-retry-')), fixture.recovery.publicKey)
const metadata = new MetadataClient({
baseUrl: 'https://metadata.example/',
trust: {
acceptKeyring: (bytes, value) => ledger.acceptKeyring(bytes, value),
acceptTarget: (bytes, value) => ledger.acceptTarget(bytes, value),
},
fetchImpl,
retryMs: 1,
requestTimeoutMs: 10,
retryRequestTimeoutMs: 40,
})
assert.equal((await metadata.check()).value.targetSequence, 1)
assert.equal(requests.get('https://metadata.example/keyring.json'), 2)
assert.equal(requests.get('https://metadata.example/keyring.sig.json'), 1)
assert.equal(requests.get('https://metadata.example/stable.json'), 1)
assert.equal(requests.get('https://metadata.example/stable.sig.json'), 1)
})
test('refetches only the metadata pair whose signature is briefly inconsistent', async () => {
const fixture = await releaseFixture()
const requests = new Map()
const fetchImpl = async url => {
const key = String(url)
requests.set(key, (requests.get(key) ?? 0) + 1)
if (key.endsWith('/stable.sig.json') && requests.get(key) === 1) return response('{}')
return response(fixture.files.get(key) ?? 'missing', fixture.files.has(key) ? 200 : 404)
}
const ledger = new TrustLedger(await mkdtemp(join(tmpdir(), 'dsh-metadata-pair-retry-')), fixture.recovery.publicKey)
const metadata = new MetadataClient({
baseUrl: 'https://metadata.example/',
trust: {
acceptKeyring: (bytes, value) => ledger.acceptKeyring(bytes, value),
acceptTarget: (bytes, value) => ledger.acceptTarget(bytes, value),
},
fetchImpl,
retryMs: 1,
})
assert.equal((await metadata.check()).value.targetSequence, 1)
assert.equal(requests.get('https://metadata.example/keyring.json'), 1)
assert.equal(requests.get('https://metadata.example/keyring.sig.json'), 1)
assert.equal(requests.get('https://metadata.example/stable.json'), 2)
assert.equal(requests.get('https://metadata.example/stable.sig.json'), 2)
})
test('uses the extended retry budget for a slow npm Registry response', async () => {
let requests = 0
const npm = new NpmRegistryClient({
requestTimeoutMs: 10,
retryRequestTimeoutMs: 40,
retryMs: 1,
fetchImpl: async (_url, options) => {
requests += 1
await new Promise((resolve, reject) => {
const timer = setTimeout(resolve, 20)
options.signal.addEventListener('abort', () => {
clearTimeout(timer)
reject(options.signal.reason)
}, { once: true })
})
return response(JSON.stringify({
'dist-tags': { latest: '0.1.1-rc.1' },
versions: { '0.1.1-rc.1': { version: '0.1.1-rc.1' } },
}))
},
})
assert.deepEqual(await npm.discover(), { version: '0.1.1-rc.1' })
assert.equal(requests, 2)
})
test('serializes one update task and persists success progress', async () => {
const { root, metadata, preparer } = await system()
let activated
const activationStates = []
const state = new UpdateStateStore(join(root, 'state', 'update.json'))
const coordinator = new UpdateCoordinator({
metadata,
preparer,
activator: {
activate: async (prepared, { onSwitching }) => {
activationStates.push((await state.read()).status)
await onSwitching()
activationStates.push((await state.read()).status)
activated = prepared.stable.targetSequence
},
health: async () => ({ healthy: true, components: [
{ id: 'gateway', healthy: true }, { id: 'dsh-runtime', healthy: true },
] }),
currentDeployment: async () => ({
dsh: '0.1.0-rc.7', environment: '1.0.0', runtime: 'runtime-current',
}),
},
state,
})
const task = coordinator.start()
assert.throws(() => coordinator.start(), UpdateConflictError)
assert.deepEqual(await coordinator.check('page-open'), { busy: true })
await assert.rejects(coordinator.check(), UpdateConflictError)
const result = await task.completion
assert.equal(result.status, 'success')
assert.equal(activated, 1)
assert.deepEqual(activationStates, ['building-candidate', 'switching'])
assert.equal((await state.read()).progress, 100)
assert.equal((await state.read()).readyServices, 2)
assert.equal((await state.read()).totalServices, 2)
assert.deepEqual((await state.read()).current, {
dsh: '0.1.0-rc.7', environment: '1.0.0', runtime: 'runtime-current',
})
assert.equal((await state.read()).updateAvailable, false)
})
test('samples high-frequency Runtime copy metrics without losing final totals', async () => {
const { root, metadata, preparer } = await system()
const reports = []
const coordinator = new UpdateCoordinator({
metadata,
preparer,
activator: {
activate: async (_prepared, { onProgress, onSwitching }) => {
await onProgress(82)
await onProgress(80)
for (let item = 1; item <= 1_000; item += 1) {
await onProgress({
processedBytes: item,
totalBytes: 1_000,
processedItems: item,
totalItems: 1_000,
})
}
await onSwitching()
},
health: async () => ({ healthy: true, components: [] }),
},
state: new UpdateStateStore(join(root, 'state', 'update.json')),
report: (message, fields) => { reports.push({ message, fields }) },
})
await coordinator.start().completion
const buildReports = reports.filter(entry => entry.message === 'update.phase.changed'
&& entry.fields.status === 'building-candidate')
assert.ok(buildReports.length <= 18)
assert.deepEqual(
buildReports.map(entry => entry.fields.progress),
buildReports.map(entry => entry.fields.progress).toSorted((left, right) => left - right),
)
assert.equal(buildReports.at(-1).fields.processedBytes, 1_000)
assert.equal(buildReports.at(-1).fields.processedItems, 1_000)
})
test('keeps overall download progress monotonic when later manifests expand totals', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-updater-progress-'))
const reports = []
const target = {
targetSequence: 2,
artifacts: [],
desired: {
bootstrap: { version: '1.0.0' },
environment: { version: '1.0.0' },
dsh: { version: '0.1.0-rc.7' },
},
}
const coordinator = new UpdateCoordinator({
metadata: { check: async () => ({ value: target }) },
preparer: {
prepare: async (_target, { onProgress }) => {
await onProgress({ processedBytes: 90, totalBytes: 100, processedItems: 1, totalItems: 1 })
await onProgress({ processedBytes: 90, totalBytes: 1_000, processedItems: 1, totalItems: 2 })
await onProgress({ processedBytes: 1_000, totalBytes: 1_000, processedItems: 2, totalItems: 2 })
return { stable: target }
},
},
activator: {
activate: async (_prepared, { onSwitching }) => onSwitching(),
health: async () => ({ healthy: true, components: [] }),
currentDeployment: async () => ({
dsh: '0.1.0-rc.7', environment: '1.0.0', runtime: 'runtime-current',
}),
},
state: new UpdateStateStore(join(root, 'state', 'update.json')),
report: (message, fields) => { reports.push({ message, fields }) },
})
await coordinator.start().completion
const downloads = reports.filter(entry => entry.message === 'update.phase.changed'
&& entry.fields.status === 'downloading')
assert.deepEqual(
downloads.map(entry => entry.fields.progress),
downloads.map(entry => entry.fields.progress).toSorted((left, right) => left - right),
)
assert.equal(downloads.some(entry => entry.fields.totalBytes === 1_000), true)
assert.equal(downloads.some(entry => entry.fields.totalItems === 2), true)
})
test('persists a failed update without activating receipts and permits a later retry', async () => {
const { root, metadata, objects, preparer } = await system()
let fail = true
const reports = []
const state = new UpdateStateStore(join(root, 'state', 'update.json'))
const coordinator = new UpdateCoordinator({
metadata,
preparer,
activator: { activate: async () => { if (fail) throw new Error('activation failed') } },
state,
report: (message, fields) => { reports.push({ message, fields }) },
})
await assert.rejects(coordinator.start().completion, /activation failed/)
assert.equal((await state.read()).status, 'failed')
assert.equal((await state.read()).phase, 'building-candidate')
assert.equal((await objects.allReceipts()).every(receipt => receipt.status === 'staged'), true)
assert.equal(reports.some(entry => entry.message === 'update.stable.failed'
&& entry.fields.error instanceof Error
&& entry.fields.taskId !== undefined), true)
assert.equal(reports.some(entry => entry.message === 'update.phase.changed'
&& entry.fields.status === 'failed'
&& entry.fields.phase === 'building-candidate'
&& entry.fields.level === 'error'), true)
fail = false
await coordinator.start().completion
assert.equal((await state.read()).status, 'success')
})
test('reports secondary cleanup failures without failing a successful update', async () => {
const { root, metadata, preparer } = await system()
const reports = []
const coordinator = new UpdateCoordinator({
metadata,
preparer,
activator: {
activate: async () => {},
currentDeployment: async () => ({ runtime: 'runtime-a' }),
},
state: new UpdateStateStore(join(root, 'state', 'update.json')),
automaticChecks: { clearSatisfied: async () => { throw new Error('notification state is read-only') } },
report: (message, fields) => { reports.push({ message, fields }) },
})
assert.equal((await coordinator.start().completion).status, 'success')
const warning = reports.find(entry => entry.message === 'update.notifications.cleanup.failed')
assert.equal(warning.fields.level, 'warning')
assert.match(warning.fields.error.message, /read-only/)
})
test('treats Bootstrap-owned receipt activation failure as one failed switch', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-updater-rollback-'))
const prepared = { receiptTokens: ['receipt'] }
const coordinator = new UpdateCoordinator({
metadata: { check: async () => ({ value: { targetSequence: 1 } }) },
preparer: {
prepare: async () => prepared,
trust: { activate: async () => { throw new Error('Updater must not activate receipts directly') } },
},
activator: {
activate: async value => {
assert.equal(value, prepared)
throw new Error('receipt activation failed inside Bootstrap transaction')
},
},
state: new UpdateStateStore(join(root, 'state', 'update.json')),
})
await assert.rejects(coordinator.start().completion, /receipt activation failed/)
})
function experimentalSystem(root, overrides = {}) {
const calls = []
const stable = {
targetSequence: 11,
desired: {
bootstrap: { version: '1.0.0' },
environment: { version: 'env-1' },
dsh: { version: '0.1.0-rc.7' },
},
}
const prepared = { receiptTokens: ['experimental-receipt'] }
const activator = {
bootstrap: { status: async () => ({ bootstrapVersion: '1.0.0' }) },
currentDeployment: async () => ({
authority: 'stable', targetSequence: 11,
dsh: '0.1.0-rc.7', environment: 'env-1', runtime: 'runtime-a', dataSnapshot: null, receiptTokens: ['stable-receipt'],
}),
prepareExperimental: async (_prepared, options) => {
assert.deepEqual(options, { targetSequence: 11 })
return { runtimeId: 'runtime-b', environmentVersion: 'env-1', dshVersion: '0.1.0-rc.8' }
},
suspendDsh: async () => { calls.push('suspend') },
resumeDsh: async () => { calls.push('resume') },
switchExperimental: async id => { calls.push(`switch:${id}`) },
commitExperimental: async id => { calls.push(`commit:${id}`) },
health: async () => ({ healthy: true, components: [
{ id: 'gateway', healthy: true }, { id: 'dsh-runtime', healthy: true },
] }),
experimentalActivationTokens: async tokens => ['stable-receipt', ...tokens],
restoreDeployment: async (from, options) => { calls.push(`restore-runtime:${from.runtime}:${String(options?.resume)}`) },
...overrides.activator,
}
const snapshots = {
create: async value => { calls.push(`snapshot:${value.id}`); return { id: value.id } },
restore: async id => { calls.push(`restore-data:${id}`) },
...overrides.snapshots,
}
const trust = {
activate: async tokens => { calls.push(`activate:${tokens.join(',')}`) },
...overrides.trust,
}
const coordinator = new UpdateCoordinator({
metadata: { check: async () => ({ value: stable }) },
npm: { latest: async () => ({ version: '0.1.0-rc.8' }) },
preparer: { prepareExperimental: async () => prepared, trust },
activator,
snapshots,
journal: new UpdateJournal(join(root, 'state', 'transaction.json')),
state: new UpdateStateStore(join(root, 'state', 'update.json')),
probationSeconds: 0,
channelState: overrides.channelState,
})
return { calls, coordinator }
}
test('runs a user-started Experimental candidate through snapshot and probation', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-experimental-success-'))
const { calls, coordinator } = experimentalSystem(root)
const result = await coordinator.startExperimental().completion
assert.equal(result.readyServices, 2)
assert.equal(result.totalServices, 2)
assert.equal((await coordinator.journal.read()).phase, 'committed')
assert.deepEqual(calls.map(value => value.replace(/[0-9a-f-]{36}/, 'task')), [
'suspend', 'snapshot:task', 'switch:runtime-b', 'commit:runtime-b',
])
const state = await coordinator.state.read()
assert.deepEqual(state.current, { dsh: '0.1.0-rc.8', environment: 'env-1', runtime: 'runtime-b' })
assert.equal(state.aheadOfStable, true)
assert.equal(state.updateAvailable, false)
assert.equal(state.outcome, 'frozen')
assert.equal(state.probationUntil, null)
})
test('does not switch when the mandatory snapshot fails', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-experimental-snapshot-fail-'))
const { calls, coordinator } = experimentalSystem(root, {
snapshots: { create: async () => { throw new Error('snapshot failed') } },
})
await assert.rejects(coordinator.startExperimental().completion, /snapshot failed/)
assert.equal((await coordinator.journal.read()).phase, 'failed')
assert.deepEqual(calls, ['suspend', 'resume'])
})
test('restores exact Runtime and data when Experimental probation fails', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-experimental-health-fail-'))
let healthChecks = 0
const { calls, coordinator } = experimentalSystem(root, {
activator: {
health: async () => {
healthChecks += 1
return healthChecks === 1
? { healthy: false, components: [{ id: 'dsh-runtime', healthy: false }] }
: { healthy: true, components: [{ id: 'dsh-runtime', healthy: true }] }
},
},
snapshots: {
restore: async (id, { onProgress } = {}) => {
calls.push(`restore-data:${id}`)
await onProgress?.({ processedItems: 0, totalItems: 4 })
await onProgress?.({ processedItems: 4, totalItems: 4 })
},
},
})
const states = []
coordinator.on('state', value => { states.push(value) })
await assert.rejects(coordinator.startExperimental().completion, /probation/)
assert.equal((await coordinator.journal.read()).phase, 'rolled-back')
assert.deepEqual(calls.map(value => value.replace(/[0-9a-f-]{36}/, 'task')), [
'suspend', 'snapshot:task', 'switch:runtime-b', 'suspend',
'restore-runtime:runtime-a:false', 'restore-data:task', 'resume',
])
assert.deepEqual(
[...new Set(states.filter(value => value.phase === 'restoring-data').map(value => value.detail))],
['recovery:suspend', 'recovery:deployment', 'recovery:snapshot', 'recovery:runtime', 'recovery:health'],
)
assert.ok(states.some(value => (
value.phase === 'restoring-data'
&& value.detail === 'recovery:snapshot'
&& value.processedItems === 4
&& value.totalItems === 4
)))
const failed = await coordinator.state.read()
assert.equal(failed.status, 'failed')
assert.equal(failed.phase, 'probation')
assert.equal(failed.readyServices, 0)
assert.equal(failed.totalServices, 1)
})
test('keeps restoration resumable when rollback itself is interrupted', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-experimental-rollback-interrupted-'))
const { coordinator } = experimentalSystem(root, {
activator: { health: async () => ({ healthy: false }) },
snapshots: { restore: async () => { throw new Error('restore interrupted') } },
})
await assert.rejects(coordinator.startExperimental().completion, /probation/)
assert.equal((await coordinator.journal.read()).phase, 'restoring-data')
assert.match((await coordinator.state.read()).error, /rollback failed: restore interrupted/)
})
test('restores an interrupted Experimental transaction before DSH starts', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-experimental-boot-recovery-'))
const journal = new UpdateJournal(join(root, 'state', 'transaction.json'))
const from = {
dsh: '0.1.0-rc.7', environment: 'env-1', runtime: 'runtime-a',
dataSnapshot: null, receiptTokens: ['stable-receipt'],
}
await journal.begin({
transactionId: 'interrupted', mode: 'experimental', from,
to: { dsh: '0.1.0-rc.8', environment: 'env-1', runtime: 'runtime-b' },
})
await journal.transition('candidate-ready', { receiptTokens: ['experimental-receipt'] })
await journal.transition('suspended')
await journal.transition('snapshot-created', { snapshotId: 'snapshot-a' })
await journal.transition('switched')
await journal.transition('probation', { probationUntil: '2026-08-19T00:02:00.000Z' })
const calls = []
await recoverInterruptedUpdate({
journal,
snapshots: { restore: async id => calls.push(`restore-data:${id}`) },
activator: {
restoreDeployment: async (deployment, options) => calls.push(`restore-runtime:${deployment.runtime}:${String(options.resume)}`),
suspendDsh: async () => calls.push('suspend'),
resumeDsh: async () => calls.push('resume'),
},
resume: false,
})
assert.deepEqual(calls, ['restore-runtime:runtime-a:false', 'restore-data:snapshot-a'])
assert.equal((await journal.read()).phase, 'rolled-back')
})
test('marks a pre-switch interruption failed without touching DSH during boot', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-experimental-early-recovery-'))
const journal = new UpdateJournal(join(root, 'state', 'transaction.json'))
await journal.begin({
transactionId: 'interrupted', mode: 'experimental',
from: {
dsh: '0.1.0-rc.7', environment: 'env-1', runtime: 'runtime-a',
dataSnapshot: null, receiptTokens: ['stable-receipt'],
},
to: { dsh: '0.1.0-rc.8', environment: 'env-1', runtime: 'runtime-b' },
})
const calls = []
await recoverInterruptedUpdate({
journal,
snapshots: { restore: async () => calls.push('restore-data') },
activator: {
restoreDeployment: async () => calls.push('restore-runtime'),
suspendDsh: async () => calls.push('suspend'),
resumeDsh: async () => calls.push('resume'),
},
resume: false,
})
assert.deepEqual(calls, [])
assert.equal((await journal.read()).phase, 'failed')
})
test('reconciles a committed journal with a state write interrupted after activation', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-experimental-state-recovery-'))
const journal = new UpdateJournal(join(root, 'state', 'transaction.json'))
const state = new UpdateStateStore(join(root, 'state', 'update.json'))
await journal.begin({
transactionId: 'task-a', mode: 'experimental',
from: {
dsh: '0.1.0-rc.7', environment: 'env-1', runtime: 'runtime-a',
dataSnapshot: null, receiptTokens: ['stable-receipt'],
},
to: { dsh: '0.1.0-rc.8', environment: 'env-1', runtime: 'runtime-b' },
})
await journal.transition('candidate-ready', { receiptTokens: ['experimental-receipt'] })
await journal.transition('suspended')
await journal.transition('snapshot-created', { snapshotId: 'snapshot-a' })
await journal.transition('switched')
await journal.transition('probation', { probationUntil: '2026-08-19T00:02:00.000Z' })
await journal.transition('committed')
await state.write('probation', { taskId: 'task-a', progress: 85 })
const recovered = await reconcileRecoveredState({ journal, state })
assert.equal(recovered.persisted.status, 'success')
assert.equal(recovered.persisted.progress, 100)
await state.write('downloading', { taskId: 'stable-task', progress: 10 })
const unrelated = await reconcileRecoveredState({ journal, state })
assert.equal(unrelated.persisted.status, 'downloading')
})
test('clears a metadata check interrupted by Management restart', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-check-state-recovery-'))
const journal = new UpdateJournal(join(root, 'state', 'transaction.json'))
const state = new UpdateStateStore(join(root, 'state', 'update.json'))
await state.write('checking', {
taskId: null,
checkSource: 'page-open',
progress: 0,
available: { dsh: '0.1.1-rc.1' },
})
const recovered = await reconcileRecoveredState({ journal, state })
assert.equal(recovered.persisted.status, 'idle')
assert.equal(recovered.persisted.taskId, null)
assert.equal(recovered.persisted.checkSource, null)
assert.deepEqual(recovered.persisted.available, { dsh: '0.1.1-rc.1' })
})
test('resumes interrupted updates through channel-aware reconcile and closes audit logs', async () => {
const completion = Promise.withResolvers()
const reports = []
const audits = []
let stableStarts = 0
let reconcileStarts = 0
const task = resumeInterruptedReconcile({
coordinator: {
start: () => { stableStarts += 1 },
startReconcile: () => {
reconcileStarts += 1
return { taskId: 'resumed-task', completion: completion.promise }
},
},
persisted: { taskId: 'interrupted-task' },
report: async (message, fields) => { reports.push({ message, fields }) },
audit: async (message, fields) => { audits.push({ message, fields }) },
})
assert.equal(task.taskId, 'resumed-task')
assert.equal(stableStarts, 0)
assert.equal(reconcileStarts, 1)
completion.resolve()
await completion.promise
await new Promise(resolve => setImmediate(resolve))
assert.deepEqual(audits, [{
message: 'update.failed',
fields: {
taskId: 'interrupted-task', outcome: 'interrupted',
resumedByTaskId: 'resumed-task', level: 'warning',
},
}])
assert.deepEqual(reports.map(value => value.message), [
'update.resume.started',
'update.resume.completed',
])
assert.equal(reports.every(value => value.fields.taskId === 'resumed-task'), true)
assert.equal(reports.every(value => value.fields.interruptedTaskId === 'interrupted-task'), true)
})
test('records a terminal failure when an interrupted reconcile cannot resume', async () => {
const completion = Promise.withResolvers()
const reports = []
resumeInterruptedReconcile({
coordinator: {
startReconcile: () => ({ taskId: 'resumed-task', completion: completion.promise }),
},
persisted: { taskId: 'interrupted-task' },
report: async (message, fields) => { reports.push({ message, fields }) },
audit: async () => {},
})
completion.reject(new Error('resume failed'))
await completion.promise.catch(() => {})
await new Promise(resolve => setImmediate(resolve))
assert.deepEqual(reports.map(value => value.message), [
'update.resume.started',
'update.resume.failed',
])
assert.equal(reports[1].fields.error.message, 'resume failed')
})
test('replaces the prior official DSH authority while retaining Stable deployment receipts', async () => {
const activator = new PlatformActivator({
dataRoot: '/unused',
bootstrap: {},
stage0: {
activeReceipts: async () => ({ receipts: [
{ token: 'stable-a', authorityType: 'stable' },
{ token: 'official-old', authorityType: 'official-dsh' },
{ token: 'stable-b', authorityType: 'stable' },
] }),
},
})
assert.deepEqual(
await activator.experimentalActivationTokens(['experimental-new']),
['stable-a', 'stable-b', 'experimental-new'],
)
})
test('treats an uninitialized Deployment as an empty public status without hiding read failures', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-uninitialized-status-'))
const reports = []
let fail = false
const activator = new PlatformActivator({
dataRoot: '/unused',
bootstrap: { request: async (method, path) => {
if (path === '/v1/deployments/current') {
if (fail) throw new Error('Bootstrap socket is unavailable')
return { record: null }
}
if (path === '/v1/deployments/rollback-plan') return { plan: null }
throw new Error(`unexpected request: ${method} ${path}`)
} },
stage0: {},
})
const coordinator = new UpdateCoordinator({
activator,
state: new UpdateStateStore(join(root, 'state', 'update.json')),
report: (message, fields) => { reports.push({ message, fields }) },
})
assert.equal((await coordinator.publicStatus()).current, null)
assert.equal(reports.some(entry => entry.message === 'update.status.current.failed'), false)
fail = true
assert.equal((await coordinator.publicStatus()).current, null)
assert.equal(reports.some(entry => (
entry.message === 'update.status.current.failed'
&& entry.fields.level === 'warning'
&& entry.fields.error.message === 'Bootstrap socket is unavailable'
)), true)
})
test('restores a staged complete Deployment through Bootstrap candidate cancellation', async () => {
const calls = []
const activator = new PlatformActivator({
dataRoot: '/unused',
bootstrap: { request: async (method, path) => {
calls.push(`${method}:${path}`)
if (path.endsWith('/cancel')) return { cancelled: true }
if (path.endsWith('/current')) return { record: { id: 'runtime-a' } }
return {}
} },
stage0: {},
})
await activator.restoreDeployment({
runtime: 'runtime-a', environment: 'env-1', receiptTokens: ['stable-a'],
}, { resume: false })
assert.deepEqual(calls, [
'POST:/v1/deployments/candidate/cancel',
'GET:/v1/deployments/current',
])
})
test('restores the materialized previous Deployment recorded by Bootstrap slots', async () => {
const calls = []
const previous = {
id: 'runtime-a-materialized', dshVersion: '0.1.0-rc.7', environmentVersion: 'env-1',
receiptTokens: ['stable-a'],
}
const activator = new PlatformActivator({
dataRoot: '/unused',
bootstrap: { request: async (method, path, body) => {
calls.push({ method, path, body })
if (path.endsWith('/cancel')) return { cancelled: true }
if (path.endsWith('/current')) return { record: { id: 'runtime-b' } }
if (path.endsWith('/rollback-plan')) return { current: { id: 'runtime-b' }, previous }
if (path.endsWith('/rollback')) return { slots: {} }
throw new Error(`unexpected request: ${method} ${path}`)
} },
stage0: {},
})
await activator.restoreDeployment({
runtime: 'runtime-a-image', dsh: '0.1.0-rc.7', environment: 'env-1', receiptTokens: ['stable-a'],
}, { resume: false })
assert.deepEqual(calls.at(-1), {
method: 'POST', path: '/v1/deployments/rollback', body: { recordId: 'runtime-a-materialized' },
})
})
test('restores an equivalent materialized current Deployment without a previous slot', async () => {
const calls = []
const current = {
id: 'runtime-a-materialized', dshVersion: '0.1.0-rc.7', environmentVersion: 'env-1',
receiptTokens: ['stable-a'], snapshotId: null,
}
const activator = new PlatformActivator({
dataRoot: '/unused',
bootstrap: { request: async (method, path) => {
calls.push(`${method}:${path}`)
if (path.endsWith('/cancel')) return { cancelled: false }
if (path.endsWith('/current')) return { record: current }
throw new Error(`unexpected request: ${method} ${path}`)
} },
stage0: {},
})
await activator.restoreDeployment({
runtime: 'runtime-a-image', dsh: '0.1.0-rc.7', environment: 'env-1',
receiptTokens: ['stable-a'], dataSnapshot: null,
}, { resume: false })
assert.deepEqual(calls, [
'POST:/v1/deployments/candidate/cancel',
'GET:/v1/deployments/current',
])
})
test('rejects a materialized previous Deployment that differs from the recovery journal', async () => {
const activator = new PlatformActivator({
dataRoot: '/unused',
bootstrap: { request: async (method, path) => {
if (path.endsWith('/cancel')) return { cancelled: true }
if (path.endsWith('/current')) return { record: { id: 'runtime-b' } }
if (path.endsWith('/rollback-plan')) return {
current: { id: 'runtime-b' },
previous: {
id: 'runtime-a-materialized', dshVersion: '0.1.0-rc.9', environmentVersion: 'env-1',
receiptTokens: ['stable-a'],
},
}
throw new Error(`unexpected request: ${method} ${path}`)
} },
stage0: {},
})
await assert.rejects(activator.restoreDeployment({
runtime: 'runtime-a-image', dsh: '0.1.0-rc.7', environment: 'env-1', receiptTokens: ['stable-a'],
}, { resume: false }), /differs from the recovery journal/)
})
test('removes the superseded snapshot only after the next Experimental commit', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-experimental-retention-'))
const { coordinator } = experimentalSystem(root)
const removed = []
coordinator.snapshots.remove = async id => removed.push(id)
await coordinator.startExperimental().completion
assert.deepEqual(removed, [])
coordinator.activator.currentDeployment = async () => ({
dsh: '0.1.0-rc.7', environment: 'env-1', runtime: 'runtime-b', dataSnapshot: null, receiptTokens: ['stable-receipt'],
})
await coordinator.startExperimental().completion
assert.equal(removed.length, 1)
})
test('treats removal of an already absent superseded snapshot as complete', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-experimental-absent-snapshot-'))
const { coordinator } = experimentalSystem(root)
await coordinator.startExperimental().completion
coordinator.activator.currentDeployment = async () => ({
dsh: '0.1.0-rc.7', environment: 'env-1', runtime: 'runtime-b', dataSnapshot: null, receiptTokens: ['stable-receipt'],
})
coordinator.snapshots.remove = async () => false
await coordinator.startExperimental().completion
assert.equal((await coordinator.state.read()).status, 'success')
})
test('reads npm latest from the official packument without trusting it locally', async () => {
const candidate = {
name: '@deepseek-ai/dsh', version: '0.1.0-rc.8',
dist: { integrity: `sha512-${Buffer.alloc(64).toString('base64')}`, tarball: 'https://registry.npmjs.org/@deepseek-ai/dsh/-/dsh-0.1.0-rc.8.tgz', signatures: [{ keyid: 'key', sig: 'signature' }] },
}
const client = new NpmRegistryClient({ fetchImpl: async () => response(JSON.stringify({
'dist-tags': { latest: candidate.version }, versions: { [candidate.version]: candidate },
})) })
assert.deepEqual(await client.discover(), { version: candidate.version })
const found = await client.latest({
desired: { dsh: { version: '0.1.0-rc.7' } },
officialDshPolicy: { registry: 'https://registry.npmjs.org/', packageName: '@deepseek-ai/dsh' },
})
assert.deepEqual(found, { version: candidate.version })
})
test('keeps the official npm version visible when it is not newer', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-upstream-display-'))
const channelState = new ChannelStateStore(join(root, 'state', 'channel.json'))
await channelState.setChannel('experimental')
const coordinator = new UpdateCoordinator({
metadata: { check: async () => ({ value: {
desired: { bootstrap: { version: '1.0.0' }, environment: { version: 'env-1' }, dsh: { version: '0.1.0-rc.7' } },
officialDshPolicy: { registry: 'https://registry.npmjs.org/', packageName: '@deepseek-ai/dsh' },
targetSequence: 1,
} }) },
npm: { discover: async () => ({ version: '0.1.0-rc.7' }) },
activator: { currentDeployment: async () => ({
authority: 'stable', targetSequence: 1, dsh: '0.1.0-rc.7', environment: 'env-1', runtime: 'runtime-a',
}) },
state: new UpdateStateStore(join(root, 'state', 'update.json')),
channelState,
})
const plan = await coordinator.desiredState()
assert.equal(plan.action, 'none')
assert.deepEqual(plan.upstream, { version: '0.1.0-rc.7' })
await coordinator.check()
const status = await coordinator.publicStatus()
assert.deepEqual(status.upstream, { version: '0.1.0-rc.7' })
assert.equal(status.update.updateAvailable, false)
await channelState.setChannel('stable')
await coordinator.check()
const stableStatus = await coordinator.publicStatus()
assert.deepEqual(stableStatus.supported, { dsh: '0.1.0-rc.7', environment: 'env-1' })
assert.deepEqual(stableStatus.upstream, { version: '0.1.0-rc.7' })
assert.equal(stableStatus.update.updateAvailable, false)
})
test('does not misclassify a missing npm package as unpublished signed metadata', async () => {
const client = new NpmRegistryClient({ fetchImpl: async () => response('missing', 404) })
await assert.rejects(client.discover(), error => (
!(error instanceof MetadataUnavailableError)
&& error.message === 'npm packument returned HTTP 404'
))
})
test('records candidate and combination Holds without holding snapshot failures', async () => {
const candidateRoot = await mkdtemp(join(tmpdir(), 'dsh-experimental-candidate-hold-'))
const candidateState = new ChannelStateStore(join(candidateRoot, 'state', 'channel.json'))
const candidate = experimentalSystem(candidateRoot, {
channelState: candidateState,
})
const npmFailure = [
'npm warn ERESOLVE overriding peer dependency',
'x'.repeat(600),
'npm error notarget No matching version found for @deepseek-ai/dsh-acp-app@^0.1.5-rc.1.',
].join('\n')
candidate.coordinator.preparer.prepareExperimental = async () => { throw new Error(npmFailure) }
await assert.rejects(candidate.coordinator.startExperimental().completion, /ERESOLVE/)
const candidateHold = (await candidateState.read()).holds[0]
assert.equal(candidateHold.type, 'version')
assert.equal(candidateHold.reason, 'No matching version found for @deepseek-ai/dsh-acp-app@^0.1.5-rc.1.')
const combinationRoot = await mkdtemp(join(tmpdir(), 'dsh-experimental-combination-hold-'))
const combinationState = new ChannelStateStore(join(combinationRoot, 'state', 'channel.json'))
const combination = experimentalSystem(combinationRoot, {
channelState: combinationState,
activator: { health: async () => ({ healthy: false }) },
})
await assert.rejects(combination.coordinator.startExperimental().completion, /probation/)
assert.equal((await combinationState.read()).holds[0].type, 'combination')
const snapshotRoot = await mkdtemp(join(tmpdir(), 'dsh-experimental-no-snapshot-hold-'))
const snapshotState = new ChannelStateStore(join(snapshotRoot, 'state', 'channel.json'))
const snapshot = experimentalSystem(snapshotRoot, {
channelState: snapshotState,
snapshots: { create: async () => { throw new Error('disk full') } },
})
await assert.rejects(snapshot.coordinator.startExperimental().completion, /disk full/)
assert.equal((await snapshotState.read()).holds.length, 0)
})
test('blocks a failed Experimental combination after converging a newer Stable Environment', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-experimental-environment-block-'))
const channelState = new ChannelStateStore(join(root, 'state', 'channel.json'))
const system = experimentalSystem(root, {
channelState,
activator: { health: async () => ({ healthy: false }) },
})
await assert.rejects(
system.coordinator.runExperimental('task-a', { blockCombination: true }),
/probation/,
)
const local = await channelState.read()
assert.equal(local.holds.length, 0)
assert.equal(local.experimentalBlocked.type, 'combination')
assert.equal(local.experimentalBlocked.dshVersion, '0.1.0-rc.8')
assert.equal(local.experimentalBlocked.environmentVersion, 'env-1')
})
test('allows Stable return only to a recovery point no newer than signed Stable', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-return-stable-'))
let restored = false
const phases = []
const previous = { dsh: '0.1.0-rc.8', environment: 'env-1', runtime: 'runtime-a' }
const recovery = {
plan: async () => ({ planId: 'plan-a', previous }),
restore: async (_planId, options) => {
restored = true
await options.onProgress('switching', 35)
await options.onProgress('verifying', 90)
return { status: 'rolled-back' }
},
}
const coordinator = new UpdateCoordinator({
metadata: { check: async () => ({ value: { desired: { dsh: { version: '0.1.0-rc.7' } } } }) },
preparer: {}, activator: { currentDeployment: async () => previous }, completeRecovery: recovery,
state: new UpdateStateStore(join(root, 'state', 'update.json')),
})
coordinator.on('state', value => {
if (value.operation === 'return-stable' && value.status === 'restoring-data') phases.push([value.rollbackPhase, value.progress])
})
await assert.rejects(coordinator.startCompleteRollback('plan-a', {
requireConfirmation: true, confirmDataLoss: true,
}).completion, /no verified/)
assert.equal(restored, false)
coordinator.metadata.check = async () => ({ value: { desired: {
dsh: { version: '0.1.0-rc.8' }, environment: { version: 'env-1' },
} } })
phases.length = 0
await coordinator.startCompleteRollback('plan-a', { requireConfirmation: true, confirmDataLoss: true }).completion
assert.equal(restored, true)
assert.deepEqual(phases, [['preparing', 5], ['switching', 35], ['verifying', 90]])
assert.equal((await coordinator.state.read()).operation, 'return-stable')
})
test('refreshes current and availability state after a complete rollback', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-rollback-state-'))
const state = new UpdateStateStore(join(root, 'state', 'update.json'))
await state.write('success', {
available: { targetSequence: 11, dsh: '0.1.1-rc.1', environment: 'env-1' },
supported: { dsh: '0.1.1-rc.1', environment: 'env-1' },
upstream: { version: '0.1.1-rc.2' },
current: { dsh: '0.1.1-rc.2', environment: 'env-1', runtime: 'runtime-experimental' },
aheadOfStable: true,
updateAvailable: false,
})
const channelState = new ChannelStateStore(join(root, 'state', 'channel.json'))
await channelState.setChannel('experimental')
const previous = {
authority: 'stable', targetSequence: 11,
dsh: '0.1.1-rc.1', environment: 'env-1', runtime: 'runtime-stable',
}
const recovery = {
plan: async () => ({ planId: 'plan-a', previous, snapshot: { id: 'snapshot-a' } }),
restore: async () => ({ status: 'rolled-back' }),
}
const coordinator = new UpdateCoordinator({
metadata: {}, preparer: {}, state, channelState, completeRecovery: recovery,
activator: { currentDeployment: async () => previous },
})
await coordinator.startCompleteRollback('plan-a').completion
const update = await state.read()
assert.deepEqual(update.current, {
dsh: '0.1.1-rc.1', environment: 'env-1', runtime: 'runtime-stable',
})
assert.equal(update.aheadOfStable, false)
assert.equal(update.updateAvailable, true)
assert.equal(update.outcome, null)
})
test('persists a planner failure started through the selected channel', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-reconcile-planning-failure-'))
const state = new UpdateStateStore(join(root, 'state', 'update.json'))
const coordinator = new UpdateCoordinator({
metadata: { check: async () => { throw new Error('metadata unavailable') } },
preparer: {}, activator: {}, state,
channelState: { read: async () => ({ updateChannel: 'experimental', holds: [], experimentalBlocked: null }) },
})
await assert.rejects(coordinator.startReconcile().completion, /metadata unavailable/)
assert.equal((await state.read()).status, 'failed')
assert.match((await state.read()).error, /metadata unavailable/)
})
test('continues from Stable convergence into Experimental activation in one task', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-reconcile-stable-then-experimental-'))
const coordinator = new UpdateCoordinator({
metadata: {}, preparer: {}, activator: {},
state: new UpdateStateStore(join(root, 'state', 'update.json')),
})
const actions = []
let planned = false
coordinator.desiredState = async () => {
if (!planned) {
planned = true
return {
action: 'stable',
current: { authority: 'experimental', environment: 'env-old' },
supported: { environment: 'env-new' },
}
}
return { action: 'experimental' }
}
coordinator.run = async (taskId, options) => { actions.push(['stable', taskId, options]) }
coordinator.runExperimental = async (taskId, options) => { actions.push(['experimental', taskId, options]) }
await coordinator.runReconcile('task-a')
assert.deepEqual(actions, [
['stable', 'task-a', { complete: false }],
['experimental', 'task-a', { blockCombination: true }],
])
})
test('keeps ordinary Stable-to-Experimental reconciliation retryable', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-reconcile-ordinary-experimental-'))
const coordinator = new UpdateCoordinator({
metadata: {}, preparer: {}, activator: {},
state: new UpdateStateStore(join(root, 'state', 'update.json')),
})
let planned = false
let options
coordinator.desiredState = async () => {
if (!planned) {
planned = true
return {
action: 'stable',
current: { authority: 'stable', environment: 'env-old' },
supported: { environment: 'env-new' },
}
}
return { action: 'experimental' }
}
coordinator.run = async () => {}
coordinator.runExperimental = async (_taskId, value) => { options = value }
await coordinator.runReconcile('task-a')
assert.deepEqual(options, { blockCombination: false })
})
test('refreshes current and availability after Stable reconciliation', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-reconcile-stable-current-'))
const state = new UpdateStateStore(join(root, 'state', 'update.json'))
const coordinator = new UpdateCoordinator({
metadata: {}, preparer: {}, activator: {}, state,
})
let planned = false
coordinator.desiredState = async () => {
if (!planned) {
planned = true
return {
action: 'stable',
current: { authority: 'stable', dsh: 'old', environment: 'env-old', runtime: 'runtime-old' },
supported: { environment: 'env-new' },
}
}
return {
action: 'none',
current: { authority: 'stable', dsh: 'new', environment: 'env-new', runtime: 'runtime-new' },
aheadOfStable: false,
experimentalBlocked: null,
holds: [],
}
}
coordinator.run = async () => {}
await coordinator.runReconcile('task-a')
const update = await state.read()
assert.deepEqual(update.current, { dsh: 'new', environment: 'env-new', runtime: 'runtime-new' })
assert.equal(update.updateAvailable, false)
assert.equal(update.outcome, 'none')
})