export const Config = Schema({ logFile: ... }, { myField: ... }) via the standalone named Schema export - usable at module-evaluation time, before any service instance exists; shared: false emits the minimal block for non-manifest modules.
plugin-dsh-factory
Plugin @ DSH @ Factory • _The DeepSeek Harness Plugin Family for PlayForm._ The furnace of the DSH governance family - the first service-provider bundle in the DeepSeek Harness plugin family. Loading it registers one class plugin (export default class PluginFactory extends Service, super(ctx, "pluginFactory"), static inject = ["fs"]) that exposes ctx.pluginFactory: a single service holding every piece of common machinery the family's hooks used to duplicate. One service. Nineteen methods (the direct-govern pair RegisterGovern + Govern and the GovernSteps registry among them). The hooks bring their own metal; the factory pours the mold.
$ pnpm add @playform/plugin-dsh-factory The profile wiring for this plugin - the bundles list, the patch entry and the restart - is on the setup page.
Where It Fits
Family position (the @-sentence Plugin @ DSH @ Factory): the family's parent service - every other package consumes it (the three governance hooks inject the service; the six normalize flavors consume State/Append and the Schema helper); its own parent is the filesystem service (inject: ["fs"]).
| Consumer | Injects | Uses |
|---|---|---|
| hook-dsh-governor-package | ["fs", "pluginFactory"] | Gate, Discover/Parse, Continue, GuardedWrite, Refresh, State, Wire, Attach, Journal, Append, UpdateKey |
| hook-dsh-pinner-package | ["fs", "pluginFactory"] | Gate, Discover, Continue (pin pass), State, Wire, Attach, Journal, Append |
| hook-dsh-governor-cargo | ["fs", "pluginFactory"] | Gate, Discover/Parse, Continue (TOML surgery), State, Wire, Attach, Journal, Append, UpdateKey, Seam |
| hook-dsh-normalize-dash + the five hook-dsh-normalize-* flavors | ["pluginFactory"] | State, Append - plus the named Schema export (shared: false) for their config |
The pure layer it deliberately does not re-export is hook-dsh-core (its service surface stays stable); the hooks import the core's helpers directly. The DSH plugin family is the DeepSeek Harness plugin layer of the PlayForm ecosystem: TypeScript-first Source/ → Target/, the deterministic @playform build, prepublishOnly-only - the same conventions as every other @playform package.
In the DeepSeek Harness
The factory is the family's bridge into the harness internals - it sits under every consumer and drives the actual facilities:
| Seam | What the plugin does there | What you can observe |
|---|---|---|
| The tool layer (write / edit / str_replace_editor) | The fs/observed events the governance hooks react to are fired by the tool layer only, for every harness write or edit; GuardedWrite and Refresh keep the author's next guarded write from ever failing a stale-version check. | One trigger law for the whole machine, any agent, any thread. |
| ctx.fs - the filesystem service (dsh-fs) | Every write of a GOVERNED file goes through ctx.fs (the fs/write-intent waterfall, the standing sandbox policy, the fs/observed emit); only the ledger append and auxiliary discovery reads are plain-fs exemptions, documented. | Writes that the observation policy and the sandbox see like built-in writes. |
| ctx.jobs - the jobs facility | Attach registers the root's job controller (which serves every owner) and runs the update stages inside the jobs envelope (kind governor-update, unowned), with the detached contained continuation as the probed fallback. | Update stages that never block or abort the author's session. |
| The storage domain | Journal writes the package_governance v2 records when the storage facility is present (probed, graceful): the queue drains, or the records buffer/drop and the human ledger stays the complete record. | A machine-readable governance history beside the human ledger. |
| Sessions / the ledger | Append composes the two wrappers - <State.Module>: <message> on the logger and [<ISO>] <message> in the durable ledger file - around every consumer message. | "Did it activate / what happened" is answerable from the ledger alone. |
The Problem
Three independent consumers of the same machinery already existed. The governor, the pinner and the cargo governor each maintained their own copy of: the ledger (Append), the exclusion match (Match), the registry / policy walk-up discovery (Discover/Parse), the union keep-list resolution with the P3 chain-keys interlock, the g1 gate set, the version-guarded write with the P4 sandbox fence, the P3/U2 observation-policy refresh, the detached contained continuation scaffolding, the State construction with defensive cell unwrap, the ctx.on wiring, the P1/P2/P5 lifecycle effects, the Schemastery schema shape, and the probe-once optional-service accessor. Every bug fix or hardening pass - the sandbox fence, the stale-version leak, the in-flight disposal - had to be applied three times. The factory makes it apply once.
How It Works
A consumer never re-implements the mold - it injects the service (inject: ["pluginFactory"], the loader holds it PENDING until the factory exists) and supplies only its own three parts:
The pure (current, section, keep) => { next, count, message? } | null function. current is the RAW file text (null when the read failed); the consumer decodes, applies its logic, logs its own no-op/refusal lines and returns null for every no-op path.
ncu/cargo dispatch, cooldowns, circuit breakers, the first-wins update-policy path pick: model logic, built on GuardedWrite/Refresh/Seam/Journal/UpdateKey.
What the factory deliberately does NOT own: the consumer ledger strings (every message a hook logs - "skipped (excluded) ...", "observed non-JSON package.json ... - skipped", "REFUSED rewrite ...", "pinned ...", "governed ... → ...", the activated (...) proof - is composed and logged by the hook through the factory's Append), the transforms (the consumer supplies the pure function; the factory only drives it inside Continue), and the update engines (the factory gives them GuardedWrite/Refresh/Seam/Journal/UpdateKey to build with). Full contract: SCHEME.md.
Verification. tsc --noEmit - zero errors; pnpm run prepublishOnly - minified Target/ (+ .d.ts twins); node factory-smoke.mjs (in the family's smokes/ directory) - 30 checks, ALL PASS, covering every primitive, the Gate matrix, both GuardedWrite postures, the full Continue lifecycle, State defaults + cell unwrap, Attach's three effects, Journal's queue/drain/silent-skip, Schema's volatile cells and Seam's probe-once caching.
The Config
The factory registers no Config schema of its own - it is the config machinery. Its Schema(shared?, m) instance method is the Schemastery schema factory every consumer builds its schema with, and the standalone named Schema export makes the same factory usable at module-evaluation time, before any service instance exists (the loader needs Config at load). shared: false emits the minimal block (no logFile/updateCooldownMs/ mutationTools/policyFile/exclude) for non-manifest modules like the normalize flavors; the shared defaults carry the family's block. Volatile cells (log, logFile and any consumer's own hot fields) commit without remounting the plugin; the factory's State builder unwraps them defensively.
In Action
The consumer supplies the transform - the only code in the chain it writes
After - the write the factory performed, as the author and the ledger see it
The factory's part of that one pass: Gate decided the actor and the path, Discover found the nearest registry.json, Continue ran the transform detached and contained, GuardedWrite carried replaceIfVersion past the P4 sandbox fence, Refresh re-emitted the fresh version with the same actor, and Append composed the logger's line from the module's message. The consumer composed the only string in the chain.
The Ledger
The factory registers no activation line and owns no ledger strings - it is a service, not a module. Its Append(state, message) is the family's one ledger mechanism, and it composes exactly two wrappers around the CONSUMER's message:
Every string a hook logs - "skipped (excluded) ...", "governed <path> → <version>", "pinned <path> (N versions)", the activated (...) proof - is composed and logged by the hook, through the factory's Append. The factory's own composed strings are parameterized machinery (the unreadable-policy line takes the policy file name; the suppressed-error lines take state.Module as the prefix) and stay byte-identical when a consumer keeps its historical name.
Related plugins
The pure layer the factory deliberately does not re-export - the hooks import the core's helpers directly.
A governance hook child: injects the service and supplies its own transform, update engine and ledger strings.
The factory's first NON-MANIFEST module: injects only the service and uses State/Append and the named Schema export.
License: MIT. The published artifact contains only the built output - files whitelists Target/, cordis.patch.yml and the docs; Source/ never ships. There are no build/watch npm scripts: the only npm script is prepublishOnly.