fix(invariants): assert runtime relationships, not API shapes

This commit is contained in:
Tianyi Cui
2026-07-20 19:34:19 +08:00
parent 1254c07025
commit 1145ee5fc3
124 changed files with 2923 additions and 2334 deletions

View File

@@ -1,34 +1,24 @@
/** Package-owned runtime contracts for @deepseek-ai/dsh-acp-snapshot. @module @deepseek-ai/dsh-acp-snapshot/invariant */
/**
* Package-owned invariant companion for `@deepseek-ai/dsh-acp-snapshot`.
* @module @deepseek-ai/dsh-acp-snapshot/invariant
*/
/* jscpd:ignore-start */
import type { Context } from 'cordis'
import { assertInvariant, type InvariantInstaller } from '@deepseek-ai/dsh-invariants'
import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
const PACKAGE_NAME = '@deepseek-ai/dsh-acp-snapshot'
/** Cordis companion plugin name. */
export const name = 'acp-snapshot-invariant'
/** Services required before the companion can register. */
/** Service required before the companion can reserve package ownership. */
export const inject = ['invariants']
/** Assert stable JSON-RPC correlation and volatile-value tokenization. */
const install: InvariantInstaller = async (_ctx, fail) => {
const { normalizeStdout } = await import('./normalize.ts')
const sessionId = '12345678-1234-1234-1234-123456789abc'
const volatile = { sessionIds: [sessionId], cwd: '/tmp/dsh-acp-invariant' }
const raw = [
JSON.stringify({ jsonrpc: '2.0', id: 'request-7', result: { cwd: volatile.cwd } }),
JSON.stringify({ jsonrpc: '2.0', id: 'request-7', result: { sessionId } }),
].join('\n')
const normalized = normalizeStdout(raw, volatile)
assertInvariant(fail,
normalized.includes('"id":1')
&& normalized.includes('"cwd":"{{cwd}}"')
&& normalized.includes('"sessionId":"{{sessionId}}"'),
'ACP normalization must preserve RPC correlation while tokenizing cwd and session ids')
assertInvariant(fail, normalizeStdout(normalized, volatile) === normalized,
'ACP stdout normalization must be idempotent')
}
/**
* No runtime invariant: this test-support package owns no production event stream or mutable data;
* consuming test suites exercise its behavior.
*/
const install: InvariantInstaller = () => {}
/**
* Register this package's invariant companion.

View File

@@ -1,25 +1,24 @@
/** Package-owned runtime contracts for @deepseek-ai/dsh-agent-loop-testkit. @module @deepseek-ai/dsh-agent-loop-testkit/invariant */
/**
* Package-owned invariant companion for `@deepseek-ai/dsh-agent-loop-testkit`.
* @module @deepseek-ai/dsh-agent-loop-testkit/invariant
*/
/* jscpd:ignore-start */
import type { Context } from 'cordis'
import { assertInvariant, type InvariantInstaller } from '@deepseek-ai/dsh-invariants'
import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
const PACKAGE_NAME = '@deepseek-ai/dsh-agent-loop-testkit'
/** Cordis companion plugin name. */
export const name = 'agent-loop-testkit-invariant'
/** Services required before the companion can register. */
/** Service required before the companion can reserve package ownership. */
export const inject = ['invariants']
/** Assert the awaitable helper shape and optional-options call boundary. */
const install: InvariantInstaller = async (_ctx, fail) => {
const { mountAgentLoopTestDependencies } = await import('./index.ts')
assertInvariant(fail,
mountAgentLoopTestDependencies.constructor.name === 'AsyncFunction',
'the prerequisite mount helper must remain awaitable so tests cannot race service activation')
assertInvariant(fail, mountAgentLoopTestDependencies.length === 1,
'the prerequisite mount helper must keep its options argument optional')
}
/**
* No runtime invariant: this test-support package owns no production event stream or mutable data;
* consuming test suites exercise its behavior.
*/
const install: InvariantInstaller = () => {}
/**
* Register this package's invariant companion.

View File

@@ -12,38 +12,37 @@ interface Config {
}
```
Defaults are `enabled: true`, `package_allowlist: []`, and `package_blocklist: []`. A package is selected only when the service is enabled, the empty allowlist or at least one allowlist pattern matches its full npm name, and no blocklist pattern matches. Blocklist matches therefore override allowlist matches.
Defaults are `enabled: true`, `package_allowlist: []`, and `package_blocklist: []`. A package is selected only when the service is enabled, the allowlist is empty or at least one allowlist pattern matches its full npm name, and no blocklist pattern matches. Blocklist matches therefore override allowlist matches.
Each entry is a case-sensitive JavaScript regular-expression source compiled with `new RegExp(pattern)`. Matching is unanchored unless the source supplies `^` and `$`; `/pattern/flags` syntax is not parsed. Blank, whitespace-padded, invalid, or duplicate entries within one list fail service startup. A valid pattern may match no currently loaded package so later loading and HMR remain deterministic.
`ctx.invariants.register(packageName, installer)` reserves one active registration for the full npm package name, including when filters keep its installer inactive, and returns its disposer. An enabled contribution runs in a dedicated child Cordis fiber. The installer can declare its required service surface through `installer.inject` and receives `fail(message)`, which throws an `InvariantError` bound to the registering package. Synchronous or asynchronous installer completion is joined before registration succeeds; failure disposes the child and releases ownership atomically.
The service owns every registration fiber, while the returned disposer also belongs to the companion fiber. Unloading either side removes the listeners and reservation completely. A companion can therefore reload and register the same package name without retaining trace state or duplicate listeners; packages that need an existing baseline rebuild it during installation.
The service owns every registration fiber, while the returned disposer also belongs to the companion fiber. Unloading either side removes listeners, trace state, and the reservation. A companion can therefore reload and register the same package name without retaining its previous state. Session-backed companions rebuild their baseline from durable events; live-only companions observe operations that begin after reload.
`InvariantError` extends `Error`, carries stable `code: 'INVARIANT'`, and exposes the owning `packageName` without adding a product-package dependency to the service.
`InvariantError` extends `Error`, carries stable `code: 'INVARIANT'`, and exposes the owning `packageName` without adding a product dependency to the service.
## Package companions
Every companion installs at least one executable, package-specific contract and reports failure through its bound reporter. There is no generated or ownership-only baseline. `pnpm run verify-package-invariants` rejects generated markers, empty installers, installers that ignore the reporter, duplicate name-based plugin observers, incorrect registration names, and incomplete export, publication, dependency, TypeScript-reference, or bundle wiring.
Publication and registration are exhaustive; runtime assertions are deliberately not synthetic. A companion installs a check only when its package owns an observable event relationship or relevant mutable-data relationship. Confirming a required method, plugin name, injection, effect, or fixed pure-function result is a type, load, or unit-test concern rather than a runtime invariant.
Packages select the narrowest runtime form that protects their public contract:
When no plausible runtime relationship exists, the companion uses an empty installer with a package-specific leading `No runtime invariant:` comment explaining why. This is common for pure utilities, thin implementations whose behavior is already observed through their seam, composition-only packages, binaries, persistence adapters whose contracts require crash/round-trip tests, and test-support packages. The explanation must be revisited when the owner gains mutable state or an event protocol.
| Package shape | Companion check |
The current executable companions protect these relationships:
| Companion | Checks |
|---|---|
| Cordis plugin | `observePluginInvariant` validates the plugin's own declared name, required injections, owned effect group, provided services, and optional package-specific relation for existing, late, and HMR-activated fibers. |
| Cordis service seam | `observeServiceInvariant` plus `serviceShapeViolation` validates current and future structural implementations, including conforming third-party backends and test doubles. |
| Pure library, bin, or support package | `assertInvariant` checks stable protocol algebra, parser mapping, path/timeout/retention rules, normalization, or entrypoint shape during child startup. |
| `dsh-session`, `dsh-agent`, `dsh-scope`, `dsh-agent-loop` | Session enclosure and call/result trace, agent-status transitions, scoped subjects, and model-request reconstruction. |
| `dsh-llm`, `dsh-tools`, `dsh-system-prompt` | Stream grammar, tool-pipeline stages and frozen results, and authoritative prompt-assembly data. |
| `dsh-compact`, `dsh-hook-protocol`, `dsh-bash` | Durable compaction and hook pairing, compaction metadata, and sandbox-mode vocabulary. |
| `dsh-fs`, `dsh-subagent`, `dsh-workflow` | Filesystem event identity, provider/child pairing, and workflow/agent lifecycle identity. |
| `dsh-permission`, `dsh-user-approval` | Active-preset references and approval asked/decided audit pairing. |
| `dsh-tasks`, `dsh-tool-todo` | Task snapshot lifecycle/ownership fields and durable whole-list todo structure. |
| `dsh-time-context` | Durable clock readings agree with their turn, step, elapsed baseline, and event timestamp. |
Four companions additionally install stateful event and request checks:
The root entrypoint of each owner remains independent of diagnostics. Loading the service alone installs no product checks, and loading a companion without the service waits on its declared `invariants` injection.
| Companion | Registration | Checks |
|---|---|---|
| `@deepseek-ai/dsh-session/invariant` | `@deepseek-ai/dsh-session` | sequence, turn/step enclosure, and same-step tool call/result trace |
| `@deepseek-ai/dsh-agent/invariant` | `@deepseek-ai/dsh-agent` | agent-status transitions |
| `@deepseek-ai/dsh-scope/invariant` | `@deepseek-ai/dsh-scope` | scoped-event carrier presence and subject consistency |
| `@deepseek-ai/dsh-agent-loop/invariant` | `@deepseek-ai/dsh-agent-loop` | loop-built model-request reconstruction from the session log |
The root entrypoint of each owner remains independent of diagnostics. Loading the service alone installs no checks; loading a companion without the service remains pending on its declared `invariants` dependency. Name-based plugin observers match only a fiber's own declared runtime name, not anonymous child fibers that inherit a parent display name. They avoid importing the product entrypoint before it is loaded; pure-library checks likewise defer owner imports into the installer child so Vitest mocks and deployment loaders establish their module boundary first.
`pnpm run verify-package-invariants` discovers all workspace packages. It rejects generated markers, unexplained empty installers, non-empty installers that omit or ignore the reporter, incorrect registration names, and incomplete export, publication, dependency, TypeScript-reference, or bundle wiring. This source rule is a minimum ownership check; focused tests prove each executable companion's semantics.
## Composition
@@ -62,11 +61,13 @@ ctx.plugin(InvariantService, {
ctx.plugin(SessionInvariant)
```
The standard agent spine mounts the service and the four stateful companions. Custom compositions explicitly add the companions for the packages whose contracts they want checked and may disable or filter them without changing package entrypoints. Plugin and service helpers multiplex package contracts through indexed lifecycle listeners shared by the Cordis root, while contribution disposal removes only that owner's contract. Vitest gives every ordinary root an explicitly enabled service and mounts the current test package's companion; one exhaustive topology test mounts all companions once, and focused invariant-service tests construct their own topology to exercise filtering and lifecycle behavior.
The standard agent spine mounts the service and its four core stateful companions. Custom compositions explicitly add companions for other loaded packages whose contracts they want checked; filters can disable or select registrations without changing package entrypoints.
Every ordinary Vitest topology mounts an explicitly enabled service and the current test package's companion. Focused suites cover valid and invalid observations for executable companions, while one exhaustive topology mounts all companions to prove registration and disposal wiring.
## Model Experience
None, as the service and companions observe runtime events and requests but never alter prompts, messages, schemas, streams, or tool results.
None. The service and companions observe runtime events, mutable snapshots, and requests but never alter prompts, messages, schemas, streams, or tool results.
#### KV Cache effect
@@ -74,7 +75,6 @@ None; invariant checks do not assemble or send provider requests.
## Known Limitations and Deferred Work
- A name-based plugin observer assumes Cordis plugin names are unique within one root; a package can provide the exact callback when importing it does not preload an unrelated runtime.
- Pure-library contracts are sampled when their companion child activates rather than observed continuously; mutable package behavior belongs on an event, service, or plugin-fiber observer.
- Request reconstruction covers frozen loop-built requests with a live session id; direct one-shot calls remain outside that companion's marker contract.
- Request reconstruction covers frozen loop-built requests with a live session id; direct one-shot LLM calls remain outside that marker contract.
- Live-only lifecycle companions cannot reconstruct operations that began before their own reload. Standard and test compositions mount them before the corresponding operations begin.
- Regular-expression filters are fixed for the service lifetime; changing them requires ordinary Cordis plugin reload.

View File

@@ -6,8 +6,8 @@
* @module @deepseek-ai/dsh-invariants
*/
import { Context, FiberState, Service } from 'cordis'
import type { Fiber, Inject, Plugin } from 'cordis'
import { Context, Service } from 'cordis'
import type { Inject } from 'cordis'
import z from 'schemastery'
import type Schema from 'schemastery'
@@ -41,300 +41,6 @@ export interface InvariantInstaller {
readonly inject?: Inject
}
/** Runtime facts one package expects from its Cordis plugin fiber. */
export interface PluginInvariantContract {
/** Exact plugin value when checking it does not preload an unrelated runtime; otherwise matching uses `name`. */
readonly plugin?: Plugin
/** Exact Cordis display name for the plugin fiber. */
readonly name: string
/** Required service injections that must be present when the fiber activates. */
readonly inject?: readonly string[]
/** Required owned effect labels; an inner array means at least one alternative must exist. */
readonly effects?: readonly (string | readonly string[])[]
/** Services the active fiber must provide. */
readonly services?: readonly string[]
/** Optional package-owned validation after the structural checks pass. */
readonly validate?: (fiber: Fiber, effectLabels: ReadonlySet<string>) => string | undefined
}
/** Collect all live effect labels below a plugin fiber. */
function collectEffectLabels(fiber: Fiber): ReadonlySet<string> {
const labels = new Set<string>()
const visit = (effects: ReturnType<Fiber['getEffects']>): void => {
for (const effect of effects) {
labels.add(effect.label)
visit(effect.children)
}
}
visit(fiber.getEffects())
return labels
}
/** One package check routed by a root-shared plugin lifecycle dispatcher. */
interface PluginObservation {
readonly callback: globalThis.Function | undefined
readonly contract: PluginInvariantContract
readonly fail: InvariantFailure
}
/** Indexed plugin checks and the two lifecycle listeners shared by one root. */
interface PluginObservationHub {
readonly byCallback: Map<globalThis.Function, Set<PluginObservation>>
readonly byName: Map<string, Set<PluginObservation>>
}
const pluginObservationHubs = new WeakMap<Context, PluginObservationHub>()
/** Check one already-matched active plugin fiber. */
function inspectPluginObservation(observation: PluginObservation, fiber: Fiber): void {
if (fiber.state !== FiberState.ACTIVE || fiber.uid === null) return
const { callback, contract, fail } = observation
if (callback !== undefined && fiber.name !== contract.name) {
fail(`active plugin name must be ${JSON.stringify(contract.name)}, got ${JSON.stringify(fiber.name)}`)
}
const injections = new Set(Object.keys(fiber.inject))
for (const service of contract.inject ?? []) {
if (!injections.has(service)) fail(`active plugin must inject ${JSON.stringify(service)}`)
}
const effectLabels = collectEffectLabels(fiber)
for (const requirement of contract.effects ?? []) {
const alternatives = typeof requirement === 'string' ? [requirement] : requirement
if (!alternatives.some(label => effectLabels.has(label))) {
fail(`active plugin must own effect ${alternatives.map(label => JSON.stringify(label)).join(' or ')}`)
}
}
for (const service of contract.services ?? []) {
const provided = Reflect.ownKeys(fiber.ctx.reflect.store).some((key) => {
const implementation = fiber.ctx.reflect.store[key as symbol]
return implementation?.fiber === fiber && implementation.name === service
})
if (!provided) fail(`active plugin must provide service ${JSON.stringify(service)}`)
}
const message = contract.validate?.(fiber, effectLabels)
if (message !== undefined) fail(message)
}
/** Route one lifecycle notification only to checks that can match its runtime. */
function inspectObservedPlugin(hub: PluginObservationHub, fiber: Fiber): void {
const callback = fiber.runtime?.callback
if (callback !== undefined) {
for (const observation of hub.byCallback.get(callback) ?? []) {
inspectPluginObservation(observation, fiber)
}
}
const runtimeName = fiber.runtime?.name
if (runtimeName !== undefined) {
for (const observation of hub.byName.get(runtimeName) ?? []) {
inspectPluginObservation(observation, fiber)
}
}
}
/** Return the root's shared plugin dispatcher, creating its two listeners once. */
function pluginObservationHub(ctx: Context): PluginObservationHub {
const root = ctx.root
const existing = pluginObservationHubs.get(root)
if (existing !== undefined) return existing
const hub: PluginObservationHub = {
byCallback: new Map(),
byName: new Map(),
}
pluginObservationHubs.set(root, hub)
root.on('internal/plugin', (fiber) => { inspectObservedPlugin(hub, fiber) }, { global: true })
root.on('internal/status', (fiber) => { inspectObservedPlugin(hub, fiber) }, { global: true })
return hub
}
/** Add one plugin observation to a typed exact-key index. */
function addIndexedPluginObservation<Key>(
index: Map<Key, Set<PluginObservation>>,
key: Key,
observation: PluginObservation,
): () => void {
const observations = index.get(key) ?? new Set<PluginObservation>()
index.set(key, observations)
observations.add(observation)
return () => {
observations.delete(observation)
if (observations.size === 0) index.delete(key)
}
}
/** Add one observation to its exact callback or runtime-name index. */
function addPluginObservation(hub: PluginObservationHub, observation: PluginObservation): () => void {
if (observation.callback === undefined) {
return addIndexedPluginObservation(hub.byName, observation.contract.name, observation)
}
return addIndexedPluginObservation(hub.byCallback, observation.callback, observation)
}
/**
* Observe one package plugin and fail whenever an active fiber violates its
* declared name, dependency, effect, service, or package-specific contract.
* Existing fibers are checked immediately; later starts and HMR activations
* are checked through two indexed lifecycle listeners shared by the root.
* @param ctx - invariant child context that owns the observers.
* @param fail - reporter bound to the package that owns the plugin.
* @param contract - expected runtime facts for the package plugin.
* @returns nothing after lifecycle observers are installed.
*/
export function observePluginInvariant(
ctx: Context,
fail: InvariantFailure,
contract: PluginInvariantContract,
): void {
const callback = contract.plugin === undefined ? undefined : ctx.registry.resolve(contract.plugin)
if (contract.plugin !== undefined && callback === undefined) {
fail('invariant contract does not identify a Cordis plugin')
}
const observation: PluginObservation = { callback, contract, fail }
if (contract.plugin === undefined) {
for (const runtime of ctx.registry.values()) {
if (runtime.name !== contract.name) continue
for (const fiber of runtime.fibers) inspectPluginObservation(observation, fiber)
}
} else {
for (const fiber of ctx.registry.get(contract.plugin)?.fibers ?? []) {
inspectPluginObservation(observation, fiber)
}
}
const hub = pluginObservationHub(ctx)
ctx.effect(
() => addPluginObservation(hub, observation),
`invariants.observePlugin(${JSON.stringify(contract.name)})`,
)
}
/** One structural check routed by a root-shared service lifecycle dispatcher. */
interface ServiceObservation {
readonly fail: InvariantFailure
readonly validate: (value: unknown) => string | undefined
}
/** Service checks and the single service listener shared by one root. */
interface ServiceObservationHub {
readonly byName: Map<string, Set<ServiceObservation>>
}
const serviceObservationHubs = new WeakMap<Context, ServiceObservationHub>()
/** Check one present service implementation. */
function inspectServiceObservation(observation: ServiceObservation, value: unknown): void {
if (value === undefined) return
const message = observation.validate(value)
if (message !== undefined) observation.fail(message)
}
/** Return the root's shared service dispatcher, creating its listener once. */
function serviceObservationHub(ctx: Context): ServiceObservationHub {
const root = ctx.root
const existing = serviceObservationHubs.get(root)
if (existing !== undefined) return existing
const hub: ServiceObservationHub = { byName: new Map() }
serviceObservationHubs.set(root, hub)
root.on('internal/service', (name, value: unknown) => {
for (const observation of hub.byName.get(name) ?? []) {
inspectServiceObservation(observation, value)
}
}, { global: true })
return hub
}
/** Add one service observation to its exact service-name index. */
function addServiceObservation(
hub: ServiceObservationHub,
serviceName: string,
observation: ServiceObservation,
): () => void {
const observations = hub.byName.get(serviceName) ?? new Set<ServiceObservation>()
hub.byName.set(serviceName, observations)
observations.add(observation)
return () => {
observations.delete(observation)
if (observations.size === 0) hub.byName.delete(serviceName)
}
}
/**
* Validate every current and future implementation bound to one Cordis
* service through the root's indexed shared service listener.
* @param ctx - invariant child context that owns the service observer.
* @param fail - reporter bound to the package that owns the service seam.
* @param serviceName - Cordis service name to observe.
* @param validate - returns the violated contract, or `undefined` for a valid implementation.
* @returns nothing after the current binding is checked and the observer is installed.
*/
export function observeServiceInvariant(
ctx: Context,
fail: InvariantFailure,
serviceName: string,
validate: (value: unknown) => string | undefined,
): void {
const observation: ServiceObservation = { fail, validate }
const current: unknown = ctx.get(serviceName)
inspectServiceObservation(observation, current)
const hub = serviceObservationHub(ctx)
ctx.effect(
() => addServiceObservation(hub, serviceName, observation),
`invariants.observeService(${JSON.stringify(serviceName)})`,
)
}
/** Structural runtime surface required from a Cordis service implementation. */
export interface ServiceShapeInvariant {
/** Members that must be callable. */
readonly methods: readonly string[]
/** Members that must be non-empty strings. */
readonly stringProperties?: readonly string[]
}
/**
* Describe the first missing member in a structural service implementation.
* This deliberately accepts test doubles and third-party implementations that
* satisfy the seam without inheriting the first-party abstract service class.
* @param value - candidate service implementation.
* @param shape - callable and string members owned by the service package.
* @returns the violated shape, or `undefined` when the candidate conforms.
*/
export function serviceShapeViolation(
value: unknown,
shape: ServiceShapeInvariant,
): string | undefined {
if ((typeof value !== 'object' && typeof value !== 'function') || value === null) {
return 'service implementation must be an object'
}
const record = value as Record<string, unknown>
for (const method of shape.methods) {
if (typeof record[method] !== 'function') return `service implementation must expose method ${JSON.stringify(method)}`
}
for (const property of shape.stringProperties ?? []) {
if (typeof record[property] !== 'string' || record[property].length === 0) {
return `service implementation must expose non-empty string ${JSON.stringify(property)}`
}
}
return undefined
}
/**
* Report a failed package-owned synchronous invariant.
* @param fail - reporter bound to the package that owns the assertion.
* @param condition - condition that must hold.
* @param message - violated contract when `condition` is false.
* @returns nothing when the condition holds.
*/
export function assertInvariant(
fail: InvariantFailure,
condition: unknown,
message: string,
): void {
if (!condition) fail(message)
}
/** Internal effect shape used to join child startup before a companion loads. */
interface PendingInvariantRegistration extends PromiseLike<() => void> {
(): void | Promise<void>

View File

@@ -1,28 +1,24 @@
/** Package-owned runtime contract checks for `@deepseek-ai/dsh-invariants`. @module @deepseek-ai/dsh-invariants/invariant */
/**
* Package-owned invariant companion for `@deepseek-ai/dsh-invariants`.
* @module @deepseek-ai/dsh-invariants/invariant
*/
/* jscpd:ignore-start */
import type { Context } from 'cordis'
import InvariantService, { observePluginInvariant, type InvariantInstaller } from './index.ts'
import type { InvariantInstaller } from './index.ts'
const PACKAGE_NAME = '@deepseek-ai/dsh-invariants'
/** Cordis companion plugin name. */
export const name = 'invariants-invariant'
/** Services required before the companion can register. */
/** Service required before the companion can reserve package ownership. */
export const inject = ['invariants']
/** Install checks for this package's active plugin fibers. */
const install: InvariantInstaller = (ctx, fail) => {
observePluginInvariant(ctx, fail, {
plugin: InvariantService,
name: 'InvariantService',
effects: [
'ctx.provide("invariants")',
],
services: [
'invariants',
],
})
}
/**
* No runtime invariant: registration ownership and child lifecycle are the service's mutation
* boundary itself; observing them from the same registry would only duplicate its implementation.
*/
const install: InvariantInstaller = () => {}
/**
* Register this package's invariant companion.
@@ -31,3 +27,4 @@ const install: InvariantInstaller = (ctx, fail) => {
*/
export const apply = (ctx: Context): Promise<() => void> =>
Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install))
/* jscpd:ignore-end */

View File

@@ -2,19 +2,12 @@ import { describe, expect, it, vi } from 'vitest'
import { Context, Service } from 'cordis'
import InvariantService, {
InvariantError,
assertInvariant,
observePluginInvariant,
observeServiceInvariant,
serviceShapeViolation,
type Config,
type InvariantInstaller,
type PluginInvariantContract,
} from '@deepseek-ai/dsh-invariants'
declare module 'cordis' {
interface Context {
invariantProbe: InvariantProbeService
watchedInvariantProbe: WatchedInvariantProbeService
}
interface Events {
@@ -28,12 +21,6 @@ class InvariantProbeService extends Service {
}
}
class WatchedInvariantProbeService extends Service {
constructor(ctx: Context) {
super(ctx, 'watchedInvariantProbe')
}
}
interface RuntimeRegistration extends PromiseLike<() => void> {
(): void | Promise<void>
}
@@ -299,277 +286,3 @@ describe('InvariantService lifecycle', () => {
expect(() => service.register('@deepseek-ai/dsh-session', () => {})).toThrow(/inactive/i)
})
})
describe('package-owned invariant helpers', () => {
interface InvariantDisposer {
(): void | Promise<void>
}
async function registerInstaller(
ctx: Context,
packageName: string,
installer: InvariantInstaller,
): Promise<InvariantDisposer> {
const registration = runtimeRegistration(ctx.invariants.register(packageName, installer))
const dispose = await Promise.resolve(registration)
return dispose
}
function effectPlugin(options: {
name?: string
inject?: string[]
effect?: string
service?: string
} = {}) {
return {
name: options.name ?? 'effect-probe',
inject: options.inject ?? [],
apply(ctx: Context) {
if (options.service !== undefined) ctx.provide(options.service, {})
if (options.effect !== undefined) {
ctx.effect(() => {
ctx.effect(() => () => {}, `${options.effect}.child`)
return () => {}
}, options.effect)
}
},
}
}
async function expectPluginViolation(
contract: PluginInvariantContract,
plugin: ReturnType<typeof effectPlugin>,
message: RegExp,
): Promise<void> {
const { ctx } = await setup()
await registerInstaller(ctx, `@deepseek-ai/${contract.name}`, (child, fail) => {
observePluginInvariant(child, fail, contract)
})
await expect(Promise.resolve(ctx.plugin(plugin))).rejects.toThrow(message)
}
it('checks existing and later plugin fibers, including nested effects and alternatives', async () => {
const { ctx } = await setup()
await ctx.plugin(InvariantProbeService)
const plugin = effectPlugin({
inject: ['invariantProbe'],
effect: 'probe.effect',
service: 'pluginProbe',
})
await ctx.plugin(plugin)
const validated = vi.fn(() => undefined)
await registerInstaller(ctx, '@deepseek-ai/dsh-existing-probe', (child, fail) => {
observePluginInvariant(child, fail, {
plugin,
name: 'effect-probe',
inject: ['invariantProbe'],
effects: [['missing.effect', 'probe.effect.child']],
services: ['pluginProbe'],
validate: validated,
})
})
expect(validated).toHaveBeenCalledOnce()
const later = effectPlugin({ name: 'later-probe', effect: 'later.effect' })
await registerInstaller(ctx, '@deepseek-ai/dsh-later-probe', (child, fail) => {
observePluginInvariant(child, fail, {
plugin: later,
name: 'later-probe',
effects: ['later.effect'],
})
})
await ctx.plugin(later)
})
it('matches package plugins by Cordis name without importing their callback', async () => {
const { ctx } = await setup()
const plugin = {
name: 'name-only-probe',
apply(pluginCtx: Context) {
pluginCtx.effect(() => () => {}, 'name-only.effect')
pluginCtx.inject([], () => {})
},
}
await registerInstaller(ctx, '@deepseek-ai/dsh-name-only-probe', (child, fail) => {
observePluginInvariant(child, fail, {
name: 'name-only-probe',
effects: ['name-only.effect'],
})
})
await ctx.plugin(plugin)
})
it('multiplexes same-runtime plugin checks through one root listener pair and disposes each owner', async () => {
const { ctx } = await setup()
const firstValidation = vi.fn(() => undefined)
const secondValidation = vi.fn(() => undefined)
const first = await registerInstaller(ctx, '@deepseek-ai/dsh-shared-plugin-first', (child, fail) => {
observePluginInvariant(child, fail, { name: 'shared-plugin-probe', validate: firstValidation })
})
const second = await registerInstaller(ctx, '@deepseek-ai/dsh-shared-plugin-second', (child, fail) => {
observePluginInvariant(child, fail, { name: 'shared-plugin-probe', validate: secondValidation })
})
const rootEffectLabels = ctx.fiber.getEffects().map(effect => effect.label)
expect(rootEffectLabels.filter(label => label === 'ctx.on("internal/plugin")')).toHaveLength(1)
expect(rootEffectLabels.filter(label => label === 'ctx.on("internal/status")')).toHaveLength(1)
const plugin = effectPlugin({ name: 'shared-plugin-probe' })
const firstFiber = await ctx.plugin(plugin)
expect(firstValidation).toHaveBeenCalledOnce()
expect(secondValidation).toHaveBeenCalledOnce()
await first()
await firstFiber.dispose()
const secondFiber = await ctx.plugin(plugin)
expect(firstValidation).toHaveBeenCalledOnce()
expect(secondValidation).toHaveBeenCalledTimes(2)
await second()
await secondFiber.dispose()
await ctx.plugin(plugin)
expect(firstValidation).toHaveBeenCalledOnce()
expect(secondValidation).toHaveBeenCalledTimes(2)
})
it('rejects a contract that does not identify a plugin', async () => {
const { ctx } = await setup()
const registration = runtimeRegistration(ctx.invariants.register('@deepseek-ai/dsh-invalid-plugin', (child, fail) => {
observePluginInvariant(child, fail, {
plugin: {} as never,
name: 'invalid-plugin',
})
}))
await expect(Promise.resolve(registration)).rejects.toThrow(/does not identify a Cordis plugin/)
})
it('rejects wrong plugin names, missing injections, effects, services, and custom checks', async () => {
const wrongName = effectPlugin({ name: 'actual-name', effect: 'probe.effect' })
await expectPluginViolation({
plugin: wrongName,
name: 'expected-name',
}, wrongName, /plugin name must be "expected-name"/)
const missingInjection = effectPlugin({ effect: 'probe.effect' })
await expectPluginViolation({
plugin: missingInjection,
name: 'effect-probe',
inject: ['missingService'],
}, missingInjection, /must inject "missingService"/)
const missingEffect = effectPlugin()
await expectPluginViolation({
plugin: missingEffect,
name: 'effect-probe',
effects: [['first.effect', 'second.effect']],
}, missingEffect, /must own effect "first.effect" or "second.effect"/)
const missingService = effectPlugin({ effect: 'probe.effect' })
await expectPluginViolation({
plugin: missingService,
name: 'effect-probe',
services: ['missingService'],
}, missingService, /must provide service "missingService"/)
const invalidCustom = effectPlugin({ effect: 'probe.effect' })
await expectPluginViolation({
plugin: invalidCustom,
name: 'effect-probe',
validate: () => 'custom plugin contract failed',
}, invalidCustom, /custom plugin contract failed/)
})
it('checks existing and future service implementations while ignoring unrelated changes', async () => {
const existing = await setup()
await existing.ctx.plugin(WatchedInvariantProbeService)
await registerInstaller(existing.ctx, '@deepseek-ai/dsh-existing-service', (child, fail) => {
observeServiceInvariant(child, fail, 'watchedInvariantProbe', value => (
value instanceof WatchedInvariantProbeService ? undefined : 'wrong watched service'
))
})
const future = await setup()
await registerInstaller(future.ctx, '@deepseek-ai/dsh-future-service', (child, fail) => {
observeServiceInvariant(child, fail, 'watchedInvariantProbe', value => (
value instanceof WatchedInvariantProbeService ? undefined : 'wrong watched service'
))
})
await future.ctx.plugin(InvariantProbeService)
await future.ctx.plugin(WatchedInvariantProbeService)
const invalid = await setup()
await registerInstaller(invalid.ctx, '@deepseek-ai/dsh-invalid-service', (child, fail) => {
observeServiceInvariant(child, fail, 'watchedInvariantProbe', () => 'wrong watched service')
})
await expect(Promise.resolve(invalid.ctx.plugin(WatchedInvariantProbeService)))
.rejects.toThrow(/wrong watched service/)
})
it('multiplexes same-name service checks through one root listener and disposes each owner', async () => {
const { ctx } = await setup()
const firstValidation = vi.fn(() => undefined)
const secondValidation = vi.fn(() => undefined)
const first = await registerInstaller(ctx, '@deepseek-ai/dsh-shared-service-first', (child, fail) => {
observeServiceInvariant(child, fail, 'watchedInvariantProbe', firstValidation)
})
const second = await registerInstaller(ctx, '@deepseek-ai/dsh-shared-service-second', (child, fail) => {
observeServiceInvariant(child, fail, 'watchedInvariantProbe', secondValidation)
})
const rootEffectLabels = ctx.fiber.getEffects().map(effect => effect.label)
expect(rootEffectLabels.filter(label => label === 'ctx.on("internal/service")')).toHaveLength(1)
const firstFiber = await ctx.plugin(WatchedInvariantProbeService)
expect(firstValidation).toHaveBeenCalledOnce()
expect(secondValidation).toHaveBeenCalledOnce()
await first()
const firstCallsAfterDisposal = firstValidation.mock.calls.length
const secondCallsBeforeRemount = secondValidation.mock.calls.length
await firstFiber.dispose()
const secondFiber = await ctx.plugin(WatchedInvariantProbeService)
expect(firstValidation).toHaveBeenCalledTimes(firstCallsAfterDisposal)
expect(secondValidation.mock.calls.length).toBeGreaterThan(secondCallsBeforeRemount)
await second()
const firstCallsAfterBothDisposals = firstValidation.mock.calls.length
const secondCallsAfterBothDisposals = secondValidation.mock.calls.length
await secondFiber.dispose()
await ctx.plugin(WatchedInvariantProbeService)
expect(firstValidation).toHaveBeenCalledTimes(firstCallsAfterBothDisposals)
expect(secondValidation).toHaveBeenCalledTimes(secondCallsAfterBothDisposals)
})
it('reports synchronous package assertions through the bound failure reporter', async () => {
const { ctx } = await setup()
const valid = await registerInstaller(ctx, '@deepseek-ai/dsh-valid-assertion', (_child, fail) => {
assertInvariant(fail, true, 'must stay true')
})
await valid()
const invalid = runtimeRegistration(ctx.invariants.register('@deepseek-ai/dsh-invalid-assertion', (_child, fail) => {
assertInvariant(fail, false, 'must stay true')
}))
await expect(Promise.resolve(invalid)).rejects.toThrow(/must stay true/)
})
it('accepts structural service implementations and test doubles', () => {
expect(serviceShapeViolation({ kind: 'probe', run() {} }, {
methods: ['run'],
stringProperties: ['kind'],
})).toBeUndefined()
expect(serviceShapeViolation(Object.assign(() => {}, { run() {} }), {
methods: ['run'],
})).toBeUndefined()
})
it.each([
{ value: null, message: 'service implementation must be an object' },
{ value: 42, message: 'service implementation must be an object' },
{ value: {}, message: 'service implementation must expose method "run"' },
{ value: { run() {}, kind: '' }, message: 'service implementation must expose non-empty string "kind"' },
])('rejects invalid structural service implementations: $message', ({ value, message }) => {
expect(serviceShapeViolation(value, {
methods: ['run'],
stringProperties: ['kind'],
})).toBe(message)
})
})

View File

@@ -1,30 +1,24 @@
/** Package-owned runtime contract checks for `@deepseek-ai/dsh-llm-replay`. @module @deepseek-ai/dsh-llm-replay/invariant */
/**
* Package-owned invariant companion for `@deepseek-ai/dsh-llm-replay`.
* @module @deepseek-ai/dsh-llm-replay/invariant
*/
/* jscpd:ignore-start */
import type { Context } from 'cordis'
import { observePluginInvariant, type InvariantInstaller } from '@deepseek-ai/dsh-invariants'
import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
const PACKAGE_NAME = '@deepseek-ai/dsh-llm-replay'
/** Cordis companion plugin name. */
export const name = 'llm-replay-invariant'
/** Services required before the companion can register. */
/** Service required before the companion can reserve package ownership. */
export const inject = ['invariants']
/** Install checks for this package's active plugin fibers. */
const install: InvariantInstaller = (ctx, fail) => {
observePluginInvariant(ctx, fail, {
name: 'llm-replay',
inject: [
'llm',
],
effects: [
[
'llm.registerAdapter()',
'ctx.on("llm/stream")',
],
],
})
}
/**
* No runtime invariant: this test-only adapter consumes a fixed replay script; its stream grammar
* is checked by the LLM companion and fixture derivation tests.
*/
const install: InvariantInstaller = () => {}
/**
* Register this package's invariant companion.
@@ -33,3 +27,4 @@ const install: InvariantInstaller = (ctx, fail) => {
*/
export const apply = (ctx: Context): Promise<() => void> =>
Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install))
/* jscpd:ignore-end */

View File

@@ -1,32 +1,24 @@
/** Package-owned runtime contracts for @deepseek-ai/dsh-loader-smoke. @module @deepseek-ai/dsh-loader-smoke/invariant */
/**
* Package-owned invariant companion for `@deepseek-ai/dsh-loader-smoke`.
* @module @deepseek-ai/dsh-loader-smoke/invariant
*/
/* jscpd:ignore-start */
import type { Context } from 'cordis'
import { assertInvariant, type InvariantInstaller } from '@deepseek-ai/dsh-invariants'
import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
const PACKAGE_NAME = '@deepseek-ai/dsh-loader-smoke'
/** Cordis companion plugin name. */
export const name = 'loader-smoke-invariant'
/** Services required before the companion can register. */
/** Service required before the companion can reserve package ownership. */
export const inject = ['invariants']
/** Assert default source mode and plain-Node built-artifact launch resolution. */
const install: InvariantInstaller = async (_ctx, fail) => {
const { resolveExampleLaunch, resolveExampleMode } = await import('./index.ts')
assertInvariant(fail, resolveExampleMode('') === 'src',
'an empty example-mode selection must preserve source-mode development')
const launch = resolveExampleLaunch({
srcBin: '/workspace/probe/src/bin.ts',
mode: 'lib',
})
assertInvariant(fail,
launch.command === process.execPath
&& launch.args.length === 1
&& launch.args[0] === '/workspace/probe/lib/bin.js'
&& launch.env.TSX_TSCONFIG_PATH === undefined,
'built example launches must use plain Node, the derived lib entry, and no tsx paths map')
}
/**
* No runtime invariant: this test-support package owns no production event stream or mutable data;
* consuming test suites exercise its behavior.
*/
const install: InvariantInstaller = () => {}
/**
* Register this package's invariant companion.