/**
 * Package-owned invariant companion for `@deepseek-ai/dsh-agent-presets`.
 * @module @deepseek-ai/dsh-agent-presets/invariant
 */
// Imported through the package name, not `./mount.ts`: a module shared between
// the two build entry points becomes a third chunk that the published `files`
// list does not carry, which `verify-built-package-invariants` rejects.
import { leakedServices, livePresetMounts } from '@deepseek-ai/dsh-agent-presets';
const PACKAGE_NAME = '@deepseek-ai/dsh-agent-presets';
/** Cordis companion plugin name. */
export const name = 'agent-presets-invariant';
/** Service required before the companion can reserve package ownership. */
export const inject = ['invariants'];
/**
 * Assert that no installed preset composition reaches the root service realm,
 * and that a deployment configuring a roster composes every agent from it.
 *
 * `mountPreset` proves the first once, when the subtree settles. A row that
 * publishes later — from a timer, or an asynchronous continuation after its
 * plugin returned — would escape that one-shot audit, so re-check every live
 * mount whenever a service registration changes.
 */
const install = (ctx, fail) => {
    ctx.on('internal/service', function (name) {
        for (const mount of livePresetMounts()) {
            const leaked = leakedServices(ctx, mount.fiber);
            if (leaked.length === 0)
                continue;
            fail(`preset "${mount.presetId}" published process-global service(s) [${leaked.join(', ')}] `
                + `after its mount was audited (observed while notifying "${name}") — `
                + 'a preset service must sit behind an `isolate` realm or move to the host composition');
        }
    }, { global: true });
    // An agent that joined no preset resolves `tools`, `system-prompt`, and
    // `skill` against the empty global layer, so the model receives nothing.
    // `composedPreset()` is the roster's own answer to "did this agent join",
    // read from the live scope chain — see the [Agent
    // Note](../../../../.agents/notes/implemented/architecture/2026-08-10-host-plane-ownership-after-presets.md)
    // for why the warning beside it is advisory while this one fails.
    //
    // Two conditions, each load-bearing. `context.agent` is what makes this an
    // AGENT assembly: a scope-only assembly — a cold read resolving presenters
    // in a standing key, a diagnostic — is not an agent and must not be judged
    // on whether it joined anything. And assembly rather than publication is the
    // moment that matters, because an unjoined agent is legal until it addresses
    // a model: `recompose` binds a bare agent as its first link, and that agent
    // is unjoined for its whole life up to the switch.
    ctx.on('system-prompt/assemble', (_assembly, context, next) => {
        const presets = ctx.get('agentPresets');
        const agent = context.agent;
        if (presets !== undefined && presets.roots.length > 0
            && agent !== undefined && presets.composedPreset(agent.ctx) === undefined) {
            fail(`agent "${agent.id}" addressed a model without joining any agent preset while a roster is `
                + 'composed; its tools, prompt sections, and skill catalog resolve against the empty global layer');
        }
        return next();
    });
};
/**
 * 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) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
//# sourceMappingURL=invariant.js.map