feat(invariants): require package-owned companions

This commit is contained in:
Tianyi Cui
2026-07-19 22:13:50 +08:00
parent 2c7822ddee
commit 433670a754
316 changed files with 5348 additions and 646 deletions

View File

@@ -11,11 +11,16 @@
"types": "./lib/types/index.d.ts",
"default": "./lib/index.js"
},
"./invariant": {
"types": "./lib/types/invariant.d.ts",
"default": "./lib/invariant.js"
},
"./src/*": "./src/*",
"./package.json": "./package.json"
},
"files": [
"lib/index.js",
"lib/invariant.js",
"lib/types/**/*.d.ts",
"lib/types/**/*.d.ts.map",
"src"
@@ -27,9 +32,11 @@
"vitest": "^4.1.8"
},
"peerDependencies": {
"@deepseek-ai/dsh-invariants": "^0.0.1",
"cordis": "^4.0.0-rc.7"
},
"devDependencies": {
"@deepseek-ai/dsh-invariants": "workspace:^",
"cordis": "^4.0.0-rc.7"
}
}

View File

@@ -0,0 +1,30 @@
/**
* Generated invariant ownership companion for `@deepseek-ai/dsh-acp-snapshot`.
* Replace this file with package-owned checks while preserving its registration.
*
* @generated scripts/gen-package-invariants.ts
* @module @deepseek-ai/dsh-acp-snapshot/invariant
*/
/* jscpd:ignore-start */
import type { Context } from 'cordis'
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. */
export const inject = ['invariants']
/** Reserve this package's invariant ownership until it adds relational checks. */
const install: InvariantInstaller = () => {}
/**
* Register this package's invariant companion.
* @param ctx - Cordis context carrying the invariant service.
* @returns the installed registration's disposer after setup succeeds.
*/
export const apply = (ctx: Context): Promise<() => void> =>
Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install))
/* jscpd:ignore-end */

View File

@@ -8,6 +8,11 @@
"src"
],
"references": [
{ "path": "../loader-smoke" }
{
"path": "../loader-smoke"
},
{
"path": "../../support/invariants"
}
]
}

View File

@@ -11,11 +11,16 @@
"types": "./lib/types/index.d.ts",
"default": "./lib/index.js"
},
"./invariant": {
"types": "./lib/types/invariant.d.ts",
"default": "./lib/invariant.js"
},
"./src/*": "./src/*",
"./package.json": "./package.json"
},
"files": [
"lib/index.js",
"lib/invariant.js",
"lib/types/**/*.d.ts",
"lib/types/**/*.d.ts.map",
"src"
@@ -23,6 +28,7 @@
"license": "BSD-3-Clause",
"peerDependencies": {
"@deepseek-ai/dsh-agent": "^0.0.1",
"@deepseek-ai/dsh-invariants": "^0.0.1",
"@deepseek-ai/dsh-llm": "^0.0.1",
"@deepseek-ai/dsh-session": "^0.0.1",
"@deepseek-ai/dsh-system-prompt": "^0.0.1",
@@ -32,6 +38,7 @@
"devDependencies": {
"@deepseek-ai/dsh-agent": "workspace:^",
"@deepseek-ai/dsh-agent-loop": "workspace:^",
"@deepseek-ai/dsh-invariants": "workspace:^",
"@deepseek-ai/dsh-llm": "workspace:^",
"@deepseek-ai/dsh-session": "workspace:^",
"@deepseek-ai/dsh-system-prompt": "workspace:^",

View File

@@ -0,0 +1,30 @@
/**
* Generated invariant ownership companion for `@deepseek-ai/dsh-agent-loop-testkit`.
* Replace this file with package-owned checks while preserving its registration.
*
* @generated scripts/gen-package-invariants.ts
* @module @deepseek-ai/dsh-agent-loop-testkit/invariant
*/
/* jscpd:ignore-start */
import type { Context } from 'cordis'
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. */
export const inject = ['invariants']
/** Reserve this package's invariant ownership until it adds relational checks. */
const install: InvariantInstaller = () => {}
/**
* Register this package's invariant companion.
* @param ctx - Cordis context carrying the invariant service.
* @returns the installed registration's disposer after setup succeeds.
*/
export const apply = (ctx: Context): Promise<() => void> =>
Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install))
/* jscpd:ignore-end */

View File

@@ -28,6 +28,9 @@
},
{
"path": "../../core/tools"
},
{
"path": "../../support/invariants"
}
]
}

View File

@@ -1,6 +1,6 @@
# dsh-invariants
Configurable registry service for package-owned runtime invariant checks. The root plugin registers `ctx.invariants`; it contains no product checks or product-package imports. Packages publish optional `./invariant` companion plugins that contribute their own assertions.
Configurable registry service for package-owned runtime invariant checks. The root plugin registers `ctx.invariants`; it contains no product checks or product-package imports. Every workspace package publishes a `./invariant` companion that registers its exact npm package name.
## Service: `InvariantService` (`ctx.invariants`)
@@ -24,6 +24,10 @@ The service owns every registration fiber, while the returned disposer also belo
## Package companions
An ownership-only generated baseline installs no listeners but still reserves its package name through the real service boundary. A package replaces that marked file when it gains a relational check, retaining the same registration. `pnpm run verify-package-invariants` checks every package's source registration, export, published files, dependencies, TypeScript reference, and bundle entry.
Four companions currently install stateful checks:
| Companion | Registration | Checks |
|---|---|---|
| `@deepseek-ai/dsh-session/invariant` | `@deepseek-ai/dsh-session` | sequence, turn/step enclosure, and same-step tool call/result trace |
@@ -50,7 +54,7 @@ ctx.plugin(InvariantService, {
ctx.plugin(SessionInvariant)
```
The standard agent spine mounts the service and all four companions. Custom compositions choose the companions they want and may disable or filter them without changing package entrypoints.
The standard agent spine mounts the service and the four stateful companions. Custom compositions choose the companions they want and may disable or filter them without changing package entrypoints. Vitest mounts every package companion against an explicitly enabled service for ordinary Cordis roots, so baseline ownership and stateful checks execute across unit, snapshot, and e2e suites; focused invariant-service tests construct their own topology to exercise filtering and lifecycle behavior.
## Model Experience
@@ -58,6 +62,6 @@ None, as the service and companions observe runtime events and requests but neve
## Known Limitations and Deferred Work
- The shipped checks cover only the four listed package contracts; a merge-extended event family has no family-specific assertion until its owner publishes one.
- Stateful checks cover only the four listed package contracts; other companions reserve ownership but add no listeners until their packages gain relational assertions.
- Request reconstruction covers frozen loop-built requests with a live session id; direct one-shot calls remain outside that companion's marker contract.
- Regular-expression filters are fixed for the service lifetime; changing them requires ordinary Cordis plugin reload.

View File

@@ -11,11 +11,16 @@
"types": "./lib/types/index.d.ts",
"default": "./lib/index.js"
},
"./invariant": {
"types": "./lib/types/invariant.d.ts",
"default": "./lib/invariant.js"
},
"./src/*": "./src/*",
"./package.json": "./package.json"
},
"files": [
"lib/index.js",
"lib/invariant.js",
"lib/types/**/*.d.ts",
"lib/types/**/*.d.ts.map",
"src"

View File

@@ -1,7 +1,8 @@
/**
* Configurable registry for package-owned runtime invariant contributions.
* Packages register checks from optional `./invariant` companion plugins;
* ordinary package entrypoints stay independent of diagnostics.
* Every workspace package registers its name from a `./invariant` companion;
* ordinary package entrypoints stay independent of diagnostics, and packages
* without relational checks use an ownership-only installer.
*
* @module @deepseek-ai/dsh-invariants
*/

View File

@@ -0,0 +1,30 @@
/**
* Generated invariant ownership companion for `@deepseek-ai/dsh-invariants`.
* Replace this file with package-owned checks while preserving its registration.
*
* @generated scripts/gen-package-invariants.ts
* @module @deepseek-ai/dsh-invariants/invariant
*/
/* jscpd:ignore-start */
import type { Context } from 'cordis'
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. */
export const inject = ['invariants']
/** Reserve this package's invariant ownership until it adds relational checks. */
const install: InvariantInstaller = () => {}
/**
* Register this package's invariant companion.
* @param ctx - Cordis context carrying the invariant service.
* @returns the installed registration's disposer after setup succeeds.
*/
export const apply = (ctx: Context): Promise<() => void> =>
Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install))
/* jscpd:ignore-end */

View File

@@ -11,22 +11,29 @@
"types": "./lib/types/index.d.ts",
"default": "./lib/index.js"
},
"./invariant": {
"types": "./lib/types/invariant.d.ts",
"default": "./lib/invariant.js"
},
"./src/*": "./src/*",
"./package.json": "./package.json"
},
"files": [
"lib/index.js",
"lib/invariant.js",
"lib/types/**/*.d.ts",
"lib/types/**/*.d.ts.map",
"src"
],
"license": "BSD-3-Clause",
"peerDependencies": {
"@deepseek-ai/dsh-invariants": "^0.0.1",
"@deepseek-ai/dsh-llm": "^0.0.1",
"@deepseek-ai/dsh-session": "^0.0.1",
"cordis": "^4.0.0-rc.7"
},
"devDependencies": {
"@deepseek-ai/dsh-invariants": "workspace:^",
"@deepseek-ai/dsh-llm": "workspace:^",
"@deepseek-ai/dsh-session": "workspace:^",
"cordis": "^4.0.0-rc.7"

View File

@@ -0,0 +1,30 @@
/**
* Generated invariant ownership companion for `@deepseek-ai/dsh-llm-replay`.
* Replace this file with package-owned checks while preserving its registration.
*
* @generated scripts/gen-package-invariants.ts
* @module @deepseek-ai/dsh-llm-replay/invariant
*/
/* jscpd:ignore-start */
import type { Context } from 'cordis'
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. */
export const inject = ['invariants']
/** Reserve this package's invariant ownership until it adds relational checks. */
const install: InvariantInstaller = () => {}
/**
* Register this package's invariant companion.
* @param ctx - Cordis context carrying the invariant service.
* @returns the installed registration's disposer after setup succeeds.
*/
export const apply = (ctx: Context): Promise<() => void> =>
Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install))
/* jscpd:ignore-end */

View File

@@ -19,6 +19,9 @@
},
{
"path": "../../core/session"
},
{
"path": "../../support/invariants"
}
]
}

View File

@@ -11,11 +11,16 @@
"types": "./lib/types/index.d.ts",
"default": "./lib/index.js"
},
"./invariant": {
"types": "./lib/types/invariant.d.ts",
"default": "./lib/invariant.js"
},
"./src/*": "./src/*",
"./package.json": "./package.json"
},
"files": [
"lib/index.js",
"lib/invariant.js",
"lib/types/**/*.d.ts",
"lib/types/**/*.d.ts.map",
"src"
@@ -25,9 +30,11 @@
"tsx": "^4.22.4"
},
"peerDependencies": {
"@deepseek-ai/dsh-invariants": "^0.0.1",
"cordis": "^4.0.0-rc.6"
},
"devDependencies": {
"@deepseek-ai/dsh-invariants": "workspace:^",
"cordis": "^4.0.0-rc.6"
}
}

View File

@@ -0,0 +1,30 @@
/**
* Generated invariant ownership companion for `@deepseek-ai/dsh-loader-smoke`.
* Replace this file with package-owned checks while preserving its registration.
*
* @generated scripts/gen-package-invariants.ts
* @module @deepseek-ai/dsh-loader-smoke/invariant
*/
/* jscpd:ignore-start */
import type { Context } from 'cordis'
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. */
export const inject = ['invariants']
/** Reserve this package's invariant ownership until it adds relational checks. */
const install: InvariantInstaller = () => {}
/**
* Register this package's invariant companion.
* @param ctx - Cordis context carrying the invariant service.
* @returns the installed registration's disposer after setup succeeds.
*/
export const apply = (ctx: Context): Promise<() => void> =>
Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install))
/* jscpd:ignore-end */

View File

@@ -7,5 +7,9 @@
"include": [
"src"
],
"references": []
"references": [
{
"path": "../../support/invariants"
}
]
}