mirror of
https://github.com/stablyai/orca.git
synced 2026-10-03 08:02:12 +00:00
Lands daemon-protocol-facts.mjs from the Windows update diagnostic branch with a stricter parser, and adds check-daemon-protocol-crossing.mjs (rule R1): the working tree must attach the newest release tag's daemon. Rollback crossing is reported only. Runs in the cross-version-wire job, which already has full tags; tag selection moves to config/scripts/stable-release-tags.mjs so both use one rule. Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
91 lines
3.2 KiB
JavaScript
91 lines
3.2 KiB
JavaScript
import { readFileSync } from 'node:fs'
|
|
import { join, resolve } from 'node:path'
|
|
import { describe, expect, it } from 'vitest'
|
|
import {
|
|
DAEMON_PROTOCOL_SOURCE_PATH,
|
|
canAttach,
|
|
crossingRequirements,
|
|
parseDaemonProtocolFacts
|
|
} from './daemon-protocol-facts.mjs'
|
|
|
|
const projectDir = resolve(import.meta.dirname, '../..')
|
|
|
|
function source(current, previous) {
|
|
return [
|
|
`export const PROTOCOL_VERSION = ${current}`,
|
|
'export const OTHER_DAEMON_PROTOCOL_VERSION = 5',
|
|
`export const PREVIOUS_DAEMON_PROTOCOL_VERSIONS = [${previous}] as const`
|
|
].join('\n')
|
|
}
|
|
|
|
const facts = (protocolVersion, previousProtocolVersions) => ({
|
|
protocolVersion,
|
|
previousProtocolVersions
|
|
})
|
|
|
|
describe('parseDaemonProtocolFacts', () => {
|
|
it('reads the working tree declarations and keeps the append-only range', () => {
|
|
const parsed = parseDaemonProtocolFacts(
|
|
readFileSync(join(projectDir, DAEMON_PROTOCOL_SOURCE_PATH), 'utf8')
|
|
)
|
|
expect(parsed.protocolVersion).toBeGreaterThan(1)
|
|
expect(parsed.previousProtocolVersions).toEqual(
|
|
Array.from({ length: parsed.protocolVersion - 1 }, (_, index) => index + 1)
|
|
)
|
|
})
|
|
|
|
it('parses multi-line lists and type annotations', () => {
|
|
const text = [
|
|
'// PROTOCOL_VERSION = 99 in a comment is ignored',
|
|
'export const PROTOCOL_VERSION: number = 4',
|
|
'export const PREVIOUS_DAEMON_PROTOCOL_VERSIONS: readonly number[] = [',
|
|
' 1, 2,',
|
|
' 3,',
|
|
']'
|
|
].join('\n')
|
|
expect(parseDaemonProtocolFacts(text)).toEqual(facts(4, [1, 2, 3]))
|
|
})
|
|
|
|
it.each([
|
|
['a missing PROTOCOL_VERSION', 'export const PREVIOUS_DAEMON_PROTOCOL_VERSIONS = [1]'],
|
|
['a missing previous list', 'export const PROTOCOL_VERSION = 2'],
|
|
['a non-literal PROTOCOL_VERSION', source('NEXT_VERSION', '1')],
|
|
['a spread in the previous list', source(3, '...LEGACY, 2')],
|
|
['a comment in the previous list', source(3, '1, // legacy\n 2')],
|
|
['an empty previous list past v1', source(3, '')],
|
|
['a previous version at or above current', source(3, '1, 2, 3')],
|
|
['a duplicate declaration', `${source(3, '1, 2')}\nexport const PROTOCOL_VERSION = 4`],
|
|
[
|
|
'a list moved behind a constant',
|
|
'export const PROTOCOL_VERSION = 3\nexport const PREVIOUS_DAEMON_PROTOCOL_VERSIONS = LEGACY'
|
|
]
|
|
])('fails loudly on %s', (_name, text) => {
|
|
expect(() => parseDaemonProtocolFacts(text, 'fixture.ts')).toThrow(/fixture\.ts/)
|
|
})
|
|
})
|
|
|
|
describe('protocol crossing', () => {
|
|
const release = facts(37, [36, 35])
|
|
|
|
it('lets a same-version or listing candidate adopt the release daemon', () => {
|
|
expect(canAttach(facts(37, [36, 35]), release)).toBe(true)
|
|
expect(canAttach(facts(38, [37, 36, 35]), release)).toBe(true)
|
|
})
|
|
|
|
it('rejects a candidate that dropped the release version', () => {
|
|
expect(canAttach(facts(38, [36, 35]), release)).toBe(false)
|
|
})
|
|
|
|
it('cannot roll back past a protocol bump', () => {
|
|
expect(canAttach(release, facts(38, [37, 36, 35]))).toBe(false)
|
|
expect(canAttach(release, facts(36, [35]))).toBe(true)
|
|
})
|
|
|
|
it('describes the requirements in both directions', () => {
|
|
expect(crossingRequirements(release)).toMatchObject({
|
|
upgrade: 'candidate speaks 37 or lists 37 as previous',
|
|
rollback: expect.stringContaining('35..37')
|
|
})
|
|
})
|
|
})
|