@xlaunch/invariants 0.2.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Portions Copyright (c) 2026 Northlatch Labs LLC
4
+ Copyright (c) 2026 DeepSeek
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,163 @@
1
+ ---
2
+ description: "Runtime invariant checks for live compositions: the registry service that runs package-owned checks, for users and maintainers choosing, configuring, or debugging them."
3
+ kind: "package-reference"
4
+ ---
5
+
6
+ # @xlaunch/invariants
7
+
8
+ ## Summary
9
+
10
+ `xlaunch-invariants` runs package-owned runtime checks — invariants — inside a Xlaunch composition: any package can ship a `./invariant` companion that verifies its own durable relationships (authoritative event streams and mutable snapshots) while the composition runs. Checks run automatically, and a failed check reports an `InvariantError` attributed to the package that owns the violated relationship. Choose it for compositions that want self-checking diagnostics with a global switch and package-name filters; the standard agent composition already mounts it with the four core companions, and loading the service alone installs no checks.
11
+
12
+ ## Table of Contents
13
+
14
+ - [Use this package](#use-this-package)
15
+ - [Understand the implementation](#understand-the-implementation)
16
+ - [Further Exploration](#further-exploration)
17
+ - [Model Experience](#model-experience)
18
+ - [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
19
+ - [Dev Note](#dev-note)
20
+
21
+ -----
22
+
23
+ <a id="use-this-package"></a>
24
+ ## Use this package
25
+
26
+ Mount the registry when a composition should verify its own runtime contracts, then decide which packages' checks run. The service exposes `ctx.invariants`; companions register checks under their package's exact npm name, and every failure carries the owning package name.
27
+
28
+ ### When to use it
29
+
30
+ Use the registry for compositions that want live diagnostics. [`xlaunch-sdk-minimal`](../../bundle/sdk-minimal/README.md) mounts it with the four core stateful companions — `xlaunch-session`, `xlaunch-agent`, `xlaunch-scope`, and `xlaunch-agent-loop`; `xlaunch-base` deliberately omits runtime diagnostics. Custom compositions mount the registry and add companions for any other loaded package whose contracts they want checked. Loading the registry alone installs no checks: it ships no product checks of its own, so a composition that never mounts a companion observes no diagnostic behavior.
31
+
32
+ ### Enabling checks and selecting packages
33
+
34
+ The registry is enabled by default and checks every registered package unless filters say otherwise. Use `enabled` as a global switch, `package_allowlist` to admit only named packages, and `package_blocklist` to exclude packages after allowlist matching — a blocklist match overrides an allowlist match. Patterns are case-sensitive JavaScript regular-expression sources (unanchored unless they supply `^` and `$`), and an invalid, blank, or duplicate entry fails service startup instead of being skipped.
35
+
36
+ ```yaml
37
+ - name: '@xlaunch/invariants'
38
+ config:
39
+ enabled: true
40
+ package_allowlist:
41
+ - '^@xlaunch/'
42
+ ```
43
+
44
+ | Field | Default | Meaning |
45
+ |---|---|---|
46
+ | `enabled` | `true` | Global switch for all registered checks |
47
+ | `package_allowlist` | `[]` | Regex sources admitting package names; empty admits all |
48
+ | `package_blocklist` | `[]` | Regex sources excluding package names after allowlist matching |
49
+
50
+ The generated [configuration catalog](../../../docs/config-catalog.md#xlaunchinvariants) is the exhaustive source for every accepted field and its JSDoc.
51
+
52
+ ### Which checks run
53
+
54
+ Each companion protects relationships its package owns, and a companion installs a check only for an observable event or mutable-data relationship — never for a service or method presence. The shipped executable companions cover:
55
+
56
+ | Companion | Checks |
57
+ |---|---|
58
+ | `xlaunch-session`, `xlaunch-agent`, `xlaunch-scope`, `xlaunch-agent-loop` | Session log enclosure and call/result trace, agent-status transitions, scope-filtered dispatch subjects, loop-built request reconstruction |
59
+ | `xlaunch-llm`, `xlaunch-llm-retry`, `xlaunch-tools`, `xlaunch-system-prompt` | LLM stream grammar, retry-failure shape, tool-pipeline stage pairing and frozen results, prompt-assembly section names |
60
+ | `xlaunch-compaction`, `xlaunch-hook-protocol`, `xlaunch-sandbox-policy` | Compaction stream pairing, hook invocation/result pairing, sandbox mode values |
61
+ | `xlaunch-fs`, `xlaunch-subagent`, `xlaunch-workflow`, `xlaunch-tool-workflow` | Filesystem event identity, subagent provider and start/end pairing, workflow lifecycle identity, workflow record shape |
62
+ | `xlaunch-goal`, `xlaunch-goal-round-driver` | Durable goal-stream folds and reconstructed continuation prompts |
63
+ | `xlaunch-permission-presets`, `xlaunch-user-approval`, `xlaunch-commands` | Preset references to live presets, approval asked/decided pairing, command run/done pairing |
64
+ | `xlaunch-jobs`, `xlaunch-tool-todo`, `xlaunch-time-context` | Job snapshot field relationships, whole-list todo shape, durable clock readings |
65
+ | `xlaunch-credentials`, `xlaunch-settings`, `xlaunch-storage-domain`, `xlaunch-workspace` | Commit events against the live service or memory state, entity-cache mirroring |
66
+ | `xlaunch-agent-presets`, `xlaunch-session-title`, `xlaunch-plan-mode`, `xlaunch-schedule` | Preset mount placement, title source citation, plan-mode payload, schedule stream |
67
+ | `xlaunch-client-hmr`, `xlaunch-client-modules`, `xlaunch-client-runtime` | Browser/node-half stat-watcher lifecycle, boot entry graph, slot mutation versioning |
68
+
69
+ Every other workspace package omits the companion and states the package-specific reason in its README.
70
+
71
+ ### Adding a companion to a custom composition
72
+
73
+ A companion is a normal plugin you mount beside the registry. It declares any services it needs and registers under its package's exact npm name; the registry joins its setup before the registration completes.
74
+
75
+ ```ts
76
+ import type { Context } from '@xlaunch/cordis'
77
+ import InvariantRegistry from '@xlaunch/invariants'
78
+ import * as SessionInvariant from '@xlaunch/session/invariant'
79
+
80
+ declare const ctx: Context
81
+
82
+ ctx.plugin(InvariantRegistry, { enabled: true })
83
+ ctx.plugin(SessionInvariant)
84
+ ```
85
+
86
+ ### When a check fails
87
+
88
+ A violation throws an `InvariantError` from the context that reported it: it carries the stable code `INVARIANT`, the full npm `packageName` of the owning package, and a message prefixed `invariant violated by "<package>": …`. The failure is therefore attributable to a package without the registry importing any product code. A companion whose installer itself fails is disposed and its registration rolled back, so a broken check cannot leave partial listeners behind.
89
+
90
+ -----
91
+
92
+ <a id="understand-the-implementation"></a>
93
+ ## Understand the implementation
94
+
95
+ <details>
96
+ <summary>Implementation internals — click to expand</summary>
97
+
98
+ This section explains the design behind the registry; the observable behavior is covered in [Use this package](#use-this-package).
99
+
100
+ ### Design philosophy
101
+
102
+ - **Product-independent registry.** The service imports no session, agent, scope, or agent-loop package and contains none of their checks; companions carry checks next to their owners.
103
+ - **Real relationships, not synthetic assertions.** A companion checks an event-stream or mutable-data relationship its package owns; confirming a method, plugin name, injection, or fixed pure result is a type, load, or unit-test concern, never a runtime invariant.
104
+ - **Registration reserves ownership.** A package name is reserved even when filters keep its installer inactive, so two plugins can never silently claim the same name.
105
+ - **Companion wiring is mechanically enforced.** `pnpm run verify-package-invariants` rejects empty installers, installers that omit or ignore the reporter, wrong registration names, incomplete publication wiring, and stale wiring for omitted companions ([companion-omission note](../../../.agents/notes/implemented/simplification/2026-08-28-omit-unneeded-invariant-companions.md)).
106
+
107
+ ### Source map
108
+
109
+ | File | Role |
110
+ |---|---|
111
+ | [`src/index.ts`](src/index.ts) | Plugin entry: `Config` schema, `InvariantRegistry` service, selection, registration, `InvariantError` |
112
+ | — | No runtime invariant companion is published; registration ownership and child lifecycle are the service's mutation boundary itself; observing them from the same registry would only duplicate its implementation. |
113
+
114
+ ### Selection and registration lifecycle
115
+
116
+ `register(packageName, installer)` reserves the full npm name and returns an effect-scoped disposer. An enabled installer runs in a dedicated child fiber; `installer.inject` declares the services that fiber may access, and synchronous or asynchronous completion is joined before registration succeeds. Failure disposes the child and releases the reservation atomically. The service owns every registration fiber, while the returned disposer also belongs to the companion fiber, so unloading either side removes listeners, trace state, and the reservation — a companion can reload and register the same name again without retained state. Session-backed companions rebuild their baseline from durable events; live-only companions observe operations that begin after reload.
117
+
118
+ </details>
119
+
120
+ -----
121
+
122
+ <a id="further-exploration"></a>
123
+ ## Further Exploration
124
+
125
+ Read these pages when the package-level contract is not enough. They move from the generated service reference to the decision evidence and the group map.
126
+
127
+ - [Runtime invariants subsystem](../../../docs/subsystems/invariants.md) — the generated reference for `Config`, the installer, the service, and the companion contract.
128
+ - [Generated configuration catalog](../../../docs/config-catalog.md#xlaunchinvariants) — every accepted config field and its source declaration.
129
+ - [Invariant runtime contracts Agent Note](../../../.agents/notes/implemented/architecture/2026-07-19-package-invariant-runtime-contracts.md) — what a runtime invariant may assert and the mechanical gate that enforces companion wiring.
130
+ - [Runtime-diagnostics group map](../../README.md) — adjacent diagnostics packages.
131
+
132
+ -----
133
+
134
+ <a id="model-experience"></a>
135
+ ## Model Experience
136
+
137
+ None, as the observer validates requests but never rewrites their context.
138
+
139
+ #### KV Cache effect
140
+
141
+ Checks observe assembled requests and durable state without mutating request content, so provider cache reuse is exactly what the underlying composition produces.
142
+
143
+ ## Known Limitations and Deferred Work
144
+
145
+ <a id="known-limitations-and-deferred-work"></a>
146
+
147
+
148
+ These limits define when the registry is a poor fit or needs operational care. They are current package constraints, not a task backlog.
149
+
150
+ - **Filters are fixed for the service lifetime** — `enabled`, `package_allowlist`, and `package_blocklist` are compiled once at startup; changing them requires a Cordis plugin reload.
151
+ - **Live-only companions miss pre-reload operations** — a companion that only observes live operations cannot reconstruct operations that began before its own reload; session-backed companions rebuild their baseline from durable events.
152
+ - **Request reconstruction covers loop-built requests only** — the `xlaunch-agent-loop` companion reconstructs requests explicitly built by the loop; direct one-shot LLM calls remain outside that contract even when callers freeze them or attach a session id.
153
+ - **No checks without a companion** — the registry ships no product checks; a composition that mounts the service alone observes nothing.
154
+
155
+ <a id="dev-note"></a>
156
+ ### Dev Note
157
+
158
+ <details>
159
+ <summary>Working context for maintainers — click to expand</summary>
160
+
161
+ None.
162
+
163
+ </details>
package/lib/index.js ADDED
@@ -0,0 +1,123 @@
1
+ import { Service } from "@xlaunch/cordis";
2
+ import z from "@xlaunch/schemastery";
3
+ //#region lib/types/index.js
4
+ /**
5
+ * Configurable registry for package-owned runtime invariant contributions.
6
+ * Every workspace package registers checks from a `./invariant` companion;
7
+ * ordinary package entrypoints stay independent of diagnostics.
8
+ *
9
+ * @module @xlaunch/invariants
10
+ */
11
+ /** Thrown when a package-owned runtime invariant is violated. */
12
+ var InvariantError = class extends Error {
13
+ /** Stable machine-readable invariant failure code. */
14
+ code = "INVARIANT";
15
+ /** Full npm package name that owns the violated invariant. */
16
+ packageName;
17
+ /**
18
+ * Construct a package-attributed invariant failure.
19
+ * @param packageName - full npm package name that registered the check.
20
+ * @param message - violated contract, without the standard error prefix.
21
+ */
22
+ constructor(packageName, message) {
23
+ super(`invariant violated by "${packageName}": ${message}`);
24
+ this.name = "InvariantError";
25
+ this.packageName = packageName;
26
+ }
27
+ };
28
+ /** Compile and validate one package-filter list. */
29
+ function compilePatterns(field, values) {
30
+ const seen = /* @__PURE__ */ new Set();
31
+ return values.map((value) => {
32
+ if (value.length === 0 || value.trim() !== value) throw new Error(`invariants: ${field} entries must be non-blank and have no surrounding whitespace`);
33
+ if (seen.has(value)) throw new Error(`invariants: ${field} contains duplicate regex ${JSON.stringify(value)}`);
34
+ seen.add(value);
35
+ try {
36
+ return new RegExp(value);
37
+ } catch (cause) {
38
+ throw new Error(`invariants: ${field} contains invalid regex ${JSON.stringify(value)}`, { cause });
39
+ }
40
+ });
41
+ }
42
+ /** Package-owned invariant registry with global and regex-based selection. */
43
+ var InvariantRegistry = class extends Service {
44
+ static Config = z.object({
45
+ enabled: z.boolean().default(true),
46
+ package_allowlist: z.array(z.string()).default([]),
47
+ package_blocklist: z.array(z.string()).default([])
48
+ });
49
+ enabled;
50
+ ownerCtx;
51
+ packageAllowlist;
52
+ packageBlocklist;
53
+ registrations = /* @__PURE__ */ new Set();
54
+ /**
55
+ * Create and install the invariant registry.
56
+ * @param ctx - Cordis context that owns the service.
57
+ * @param config - global enablement and package-name regex filters.
58
+ */
59
+ constructor(ctx, config = {}) {
60
+ super(ctx, "invariants");
61
+ this.ownerCtx = ctx;
62
+ this.enabled = config.enabled ?? true;
63
+ this.packageAllowlist = compilePatterns("package_allowlist", config.package_allowlist ?? []);
64
+ this.packageBlocklist = compilePatterns("package_blocklist", config.package_blocklist ?? []);
65
+ }
66
+ /** Return whether one full package name passes the configured filters. */
67
+ selected(packageName) {
68
+ if (!this.enabled) return false;
69
+ if (this.packageAllowlist.length > 0 && !this.packageAllowlist.some((pattern) => pattern.test(packageName))) return false;
70
+ return !this.packageBlocklist.some((pattern) => pattern.test(packageName));
71
+ }
72
+ /**
73
+ * Register one package's invariant installer. The package name is reserved
74
+ * even when filtering disables its checks. Enabled installers run in a child
75
+ * fiber; failure disposes that fiber and releases the reservation.
76
+ * @param packageName - full npm package name that owns the contribution.
77
+ * @param installer - listener or startup-check installer for the child context.
78
+ * @returns an effect-scoped disposer for the registration.
79
+ */
80
+ register(packageName, installer) {
81
+ if (packageName.length === 0 || packageName.trim() !== packageName || /\s/.test(packageName)) throw new Error("invariants: packageName must be non-blank and contain no whitespace");
82
+ if (this.registrations.has(packageName)) throw new Error(`invariants: package "${packageName}" is already registered`);
83
+ const ctx = this.ownerCtx;
84
+ const registrations = this.registrations;
85
+ registrations.add(packageName);
86
+ let registration;
87
+ try {
88
+ registration = ctx.effect(async () => {
89
+ if (!this.selected(packageName)) return () => {
90
+ registrations.delete(packageName);
91
+ };
92
+ const installInvariant = (childCtx) => installer(childCtx, (message) => {
93
+ throw new InvariantError(packageName, message);
94
+ });
95
+ try {
96
+ const child = ctx.plugin(installer.inject === void 0 ? installInvariant : Object.assign(installInvariant, { inject: installer.inject }));
97
+ try {
98
+ await child;
99
+ } catch (error) {
100
+ await child.dispose();
101
+ throw error;
102
+ }
103
+ return async () => {
104
+ try {
105
+ await child.dispose();
106
+ } finally {
107
+ registrations.delete(packageName);
108
+ }
109
+ };
110
+ } catch (error) {
111
+ registrations.delete(packageName);
112
+ throw error;
113
+ }
114
+ }, `invariants.register(${JSON.stringify(packageName)})`);
115
+ } catch (error) {
116
+ registrations.delete(packageName);
117
+ throw error;
118
+ }
119
+ return registration;
120
+ }
121
+ };
122
+ //#endregion
123
+ export { InvariantError, InvariantRegistry, InvariantRegistry as default };
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Configurable registry for package-owned runtime invariant contributions.
3
+ * Every workspace package registers checks from a `./invariant` companion;
4
+ * ordinary package entrypoints stay independent of diagnostics.
5
+ *
6
+ * @module @xlaunch/invariants
7
+ */
8
+ import { Context, Service } from '@xlaunch/cordis';
9
+ import type { Inject } from '@xlaunch/cordis';
10
+ import type Schema from '@xlaunch/schemastery';
11
+ /** Runtime invariant selection configured on the service plugin. */
12
+ export interface Config {
13
+ /** Global switch; defaults to `true`. */
14
+ readonly enabled?: boolean;
15
+ /** Case-sensitive JavaScript regex sources that admit package names; empty admits all. */
16
+ readonly package_allowlist?: string[];
17
+ /** Case-sensitive JavaScript regex sources that exclude package names after allowlist matching. */
18
+ readonly package_blocklist?: string[];
19
+ }
20
+ /**
21
+ * Throw a package-attributed invariant failure.
22
+ * @param message - violated package contract without the standard prefix.
23
+ * @returns never because reporting a violation throws.
24
+ */
25
+ export type InvariantFailure = (message: string) => never;
26
+ /** Install one package's checks into the registration's child context. */
27
+ export interface InvariantInstaller {
28
+ /**
29
+ * Install the package contribution.
30
+ * @param ctx - child context owned by this invariant registration.
31
+ * @param fail - reporter bound to the registering package name.
32
+ * @returns nothing, or a promise settling after asynchronous checks finish.
33
+ */
34
+ (ctx: Context, fail: InvariantFailure): void | Promise<void>;
35
+ /** Services the child installer fiber may access. */
36
+ readonly inject?: Inject;
37
+ }
38
+ /** Thrown when a package-owned runtime invariant is violated. */
39
+ export declare class InvariantError extends Error {
40
+ /** Stable machine-readable invariant failure code. */
41
+ readonly code: "INVARIANT";
42
+ /** Full npm package name that owns the violated invariant. */
43
+ readonly packageName: string;
44
+ /**
45
+ * Construct a package-attributed invariant failure.
46
+ * @param packageName - full npm package name that registered the check.
47
+ * @param message - violated contract, without the standard error prefix.
48
+ */
49
+ constructor(packageName: string, message: string);
50
+ }
51
+ declare module '@xlaunch/cordis' {
52
+ interface Context {
53
+ invariants: InvariantRegistry;
54
+ }
55
+ }
56
+ /** Package-owned invariant registry with global and regex-based selection. */
57
+ export declare class InvariantRegistry extends Service {
58
+ static Config: Schema<Config>;
59
+ private readonly enabled;
60
+ private readonly ownerCtx;
61
+ private readonly packageAllowlist;
62
+ private readonly packageBlocklist;
63
+ private readonly registrations;
64
+ /**
65
+ * Create and install the invariant registry.
66
+ * @param ctx - Cordis context that owns the service.
67
+ * @param config - global enablement and package-name regex filters.
68
+ */
69
+ constructor(ctx: Context, config?: Config);
70
+ /** Return whether one full package name passes the configured filters. */
71
+ private selected;
72
+ /**
73
+ * Register one package's invariant installer. The package name is reserved
74
+ * even when filtering disables its checks. Enabled installers run in a child
75
+ * fiber; failure disposes that fiber and releases the reservation.
76
+ * @param packageName - full npm package name that owns the contribution.
77
+ * @param installer - listener or startup-check installer for the child context.
78
+ * @returns an effect-scoped disposer for the registration.
79
+ */
80
+ register(packageName: string, installer: InvariantInstaller): () => void;
81
+ }
82
+ export default InvariantRegistry;
83
+ //# sourceMappingURL=index.d.ts.map
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@xlaunch/invariants",
3
+ "description": "Registry service for package-owned Xlaunch runtime invariants",
4
+ "version": "0.2.0-beta.1",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/Northlatch-Labs-LLC/xlaunch-agent.git",
11
+ "directory": "packages/runtime-diagnostics/invariants"
12
+ },
13
+ "type": "module",
14
+ "main": "lib/index.js",
15
+ "types": "lib/types/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./lib/types/index.d.ts",
19
+ "default": "./lib/index.js"
20
+ },
21
+ "./src/*": "./src/*",
22
+ "./package.json": "./package.json"
23
+ },
24
+ "files": [
25
+ "lib/index.js",
26
+ "lib/types/**/*.d.ts"
27
+ ],
28
+ "license": "MIT",
29
+ "author": "Northlatch Labs LLC",
30
+ "peerDependencies": {
31
+ "@xlaunch/cordis": "^4.0.2"
32
+ },
33
+ "dependencies": {
34
+ "@xlaunch/schemastery": "^3.18.2"
35
+ },
36
+ "devDependencies": {
37
+ "@xlaunch/cordis": "^4.0.2"
38
+ }
39
+ }