ets-hook-dsh-cargo-governor
Verified@playform/ets-hook-dsh-cargo-governor · v0.0.1 · CC0-1.0
Silent Cargo.toml governor — the RUST-SIDED FLAVOR of the package.json governor (@playform/hook-dsh-package-governor): same architecture, same API-awareness discipline, same PlayForm TypeScript layout — but for Rust manifests. Hooks fs/observed — the cord
Install
dsh plugin add @playform/ets-hook-dsh-cargo-governor Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Creators
Readme
@playform/ets-hook-dsh-cargo-governor
The DeepSeek Harness Plugin Family for PlayForm.
[!NOTE]
The Cargo.toml flavor of the silent package.json governor - the same architecture, the same API-awareness discipline, the same silence toward the author, but for RUST manifests, with the update stage driven by the RUST-SIDE CLI (
cargo upgrade, from cargo-edit): Rust does not co-opt into the TypeScript ecosystem, so there is no npm-library equivalent - the update stage operates at the exclusionary level through the cargo CLI.A factory flavor: chain canonicalization + full-version normalization + surgical TOML rewriting +
cargo upgrade --exclude- comments survive.The @-sentence identity: Hook @ DSH @ Governor @ Cargo.
Every claim below is live-verified (2026-10-03, live).
Where It Fits
Family position (the @-sentence Hook @ DSH @ Governor @ Cargo): a hook child of the
ets-plugin-dsh-factory service and the ets-hook-dsh-core
helpers; the Rust-sided sibling of the two npm governance hooks on the same
fs/observed seam.
One of three governance hooks sharing the
fs/observed seam, each gating on its own basename and
writing its own ledger:
| plugin | basename gate | ledger | pass |
|---|---|---|---|
ets-hook-dsh-package-governor |
package.json |
ets-hook-dsh-package-governor.log |
chain pass (→ ^resolved) + update stage (ncu) |
ets-hook-dsh-package-pinner |
package.json |
ets-hook-dsh-package-pinner.log |
pin pass (^0.3.4 → 0.3.4; keep-list wins) |
| ets-hook-dsh-cargo-governor (this bundle) | Cargo.toml |
ets-hook-dsh-cargo-governor.log |
chain pass (bare caret / =exact) + cargo upgrade |
The basenames are disjoint: the cargo module never sees a package.json event and the npm plugins
never see a Cargo.toml event.
Composition semantics: chain > strip > normalize (this module's precedence), keep-list wins over normalization - never over the chain.
The ledgers are separate; activating one never implies another.
Machinery-wise it is a factory flavor: inject: ["fs", "pluginFactory"]
- gates, discovery, the guarded write, the refresh, the continuation, the effects, the schema and
the namespaced
UpdateKeycome fromets-plugin-dsh-factory; the policy loader and the suppression composer come fromets-hook-dsh-core. This bundle keeps the Cargo-specific residue: the TOML identification, the surgical pin, the full-version directive, and thecargo upgradebridge. Besides thefs/observedevent path, its two steps are registered with the factory's direct-govern registry at apply (Factory.RegisterGovern("Cargo.toml", "cargo" | "update", …)— factory SCHEME.md §2.16), so theraw-writetool's per-callgovernselection can drive the same chain + normalization pass and update stage directly through Factory.Govern (Function/Direct — same machinery, same ledger strings).
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.
Install
- Remote / dependency install (auto-activation):
pnpm add @playform/ets-hook-dsh-cargo-governorin the profile dir (+ the package name indsh.profile.bundles, ordsh plugin add). - Local git clone: clone →
pnpm install --ignore-workspace(the bundle carries its own node_modules - smol-toml) →npx Build 'Source/**/*.ts' --ESBuild Configuration/ESBuild.ts→dsh plugin --profile <name> add <this directory>. - Native dsh install:
dsh plugin --profile <name> add ./local-ets-hook-dsh-cargo-governor-<v>.tgz.
All three end the same way: the loader activates the entry from Target/, cordis.patch.yml
inserts the ets-hook-dsh-cargo-governor row, and the ledger logs activated (cargo flavor, ...) at
the next host start.
Usage
The bundle is configured through its cordis.patch.yml row (or the profile's dsh.bundle
manifest) - the full config table is in The Config:
- insert:
- id: ets-hook-dsh-cargo-governor
name: "@playform/ets-hook-dsh-cargo-governor"
config:
log: true
logFile: ~/.dsh/ets-hook-dsh-cargo-governor.log
updateMode: cargo
The shared Effect-TS plumbing - the runtime wiring, the stream machinery and the hook contract types - comes from the base ets-base-dsh package.
The Problem
Rust manifests drift the same way npm manifests do - but Cargo.toml is a TOML document people
decorate with comments, and there is no in-process library path: the only update tool is the cargo
CLI.
A governor for Cargo.toml must therefore rewrite surgically (never a TOML stringify) and
delegate its update stage across the Rust/TS boundary - while still hooking the same
fs/observed
event the npm hooks use, so one trigger law covers the whole machine.
How It Works
The pipeline G = U ∘ P
fs/observed (target, {kind:"present", version}, actor)
── fired by the TOOL LAYER ONLY, for every harness write/edit, any thread ──►
│
▼
G1 Factory.Gate ── displayPath → actor ∈ mutationTools → kind "present" →
│ Stash idempotence → basename "Cargo.toml" → excluded?
│ excluded ──► ledger `skipped (excluded) <path>` (every other gate
▼ outcome is silent) outcome proceeds)
G2 Factory.Discover + Factory.Parse ── nearest registry.json walk-up
│ (THE USER'S OWN registry - the same discovery as the npm governor;
│ none / unreadable ──► ledger line, chain canonicalization skipped)
▼
Stash seed (targetKey, version) ── our own re-emits re-enter as no-ops
│
▼ detached, contained (Factory.Continue - the listener never awaits)
G3 CHAIN PASS (the pure transform) ── ParseToml (smol-toml, IDENTIFICATION
│ ONLY) → Satisfy (the plan): 1. CHAIN - dep ∈ registry.effectiveLatest
│ → the bare resolved version (Cargo's implicit caret) or `=resolved`
│ with pinStyle "exact", always the FULL form (shorthand padded);
│ 2. STRIP - strict-mode unknown deps (whole `name = "..."` entry gone,
│ only with a registry); 3. NORMALIZE - every other simple version
│ (full-version directive below; the keep-list wins → byte-identical)
│ → Pin (SURGICAL LINE REWRITE on the raw text - comments, inline
│ comments, blank lines and spacing survive byte-for-byte) →
│ GuardedWrite (replaceIfVersion + the P4 fence) → ledger
│ `governed <path> → <version>` → Refresh (P3 re-emit, same actor)
▼ chained off the settled continuation (Function/Follow)
G4 UPDATE STAGE (the Rust/TS boundary) ── breaker → in-flight → cooldown →
│ the jobs envelope (kind "governor-update", unowned) or the detached
│ fallback → Policy loader → Upgrade via ctx.subprocess (fully-specified
│ argv, collect-mode output piped to the job ring + the ledger):
│ cargo upgrade --manifest-path <Cargo.toml>
│ --exclude <crate> ... (ONE flag per crate - the comma
│ form is silently IGNORED)
│ [-p <crate> ...] [--compatible/--incompatible/--pinned ...]
│ exclude = policy.reject ∪ chain deps (the cordis-trap guard:
│ cargo upgrade must never bump a chain-governed pin)
│ → Verify (verifyCommand via /bin/sh -c, exit 127 non-fatal) →
│ Settle → Refresh (U2: re-stat + re-emit the fresh version)
▼
SILENCE: the tool result shows exactly what the author wrote.
The governed state is discoverable only by a subsequent read - or in
the ledger.
The G4 update-stage envelope - the Dispatch/Settle pair of the diagram above (the gates, the jobs
envelope, the breaker update, the U2 refresh) - lives in the core (@playform/ets-hook-dsh-core's
Function/Update); this module is a thin delegate that injects its own collections, the cargo child
runner and its ledger strings, so the flow is not forked per governance module.
The full-version normalization directive
The user prefers full versions - no shorthand like "1.0" may remain in a governed Cargo.toml; every dependency version is expanded to its MOST SPECIFIC form:
| Written | Governed |
|---|---|
1.0 |
1.0.0 |
1 |
1.0.0 |
0.1 |
0.1.0 |
=1.0 |
=1.0.0 (the exact form keeps its = prefix) |
1.2-rc.1 |
1.2.0-rc.1 (padded BEFORE the prerelease) |
1.2.3-rc.1 |
unchanged (prerelease preserved as authored) |
1.2.3+build |
unchanged (build metadata preserved) |
>=1.2, ~0.3, >1.0, 1.0, 2.0 |
unchanged (complex ranges left as-is) |
Precedence, in order: (1) chain - a dep in registry.effectiveLatest is canonicalized to the
FULL resolved form (even a shorthand registry entry yields a full output); (2) strip -
strict-mode unknown deps; (3) normalize - every other simple version, UNLESS the name is in the
keep-list (pin-policy.json via keepFile - the same sidecar the pinner uses; discovery:
global keepFile → the file's own directory → registry-adjacent, the union).
The keep-list wins over normalization; the chain is never suppressed.
Cargo semantics are unchanged: a bare full version is still Cargo's implicit caret.
The TOML rewrite (why comments survive)
smol-toml (the one non-@playform tool dependency, carried by the bundle's own node_modules) is used for
PARSING ONLY - identification of the dep entries in [dependencies], [dev-dependencies],
[build-dependencies], [target.'cfg(...)'.dependencies] (and its dev/build variants), and
[workspace.dependencies] (the shared dep table - handled natively).
The rewrite itself (Function/Pin) is surgical line-level string manipulation on the raw text - so comments, inline comments, blank lines, and spacing survive byte-for-byte.
Handled entry shapes: name = "0.3.4",
name = { version = "0.3.4", ... } (single line or pretty-printed), [dependencies.name] table
style.
Never rewritten: path = "...", git = "...", and inherited entries (workspace = true -
the version lives in the workspace table, walked separately).
Non-dependency sections are NEVER
touched: the refusal guard refuses any plan entry outside an identified dependency table
(REFUSED rewrite of ...: non-dependency section "..." would change), and Pin aborts (never a
partial rewrite) if a planned entry cannot be located in the text.
The Rust side (live-verified)
cargo1.100.0-nightly + cargo-edit 0.13.13, resolved throughcargoBin(the schema default is the barecargo, found via the subprocess seam'sresolveExecutable; set an absolute path when the host PATH is not the shell PATH).--excludeis ONE flag per crate - the comma form is silently IGNORED (--exclude a,bexcludes nothing), the exact inverse of ncu's one-comma-argument reject list, which is why this module cannot reuse the parent's argv builder.- There is NO
--exactflag in cargo-edit 0.13.13 - exact pins are enforced at the manifest level by the chain pass (pinStyle: "exact"→=resolved). cargo upgradepreserves comments and formatting (it edits viatoml_edit), rewrites every dependency table, and exits 0 on success / 1 on errors.- If cargo-edit is NOT installed,
cargo upgradeexits 101 withno such command: upgrade- the module logsupdate: cargo-edit unavailable: ...and fails gracefully (the breaker counts it; the manifest is untouched).
Update-stage policy mapping
update-policy.json (same discovery as the npm governor: global policyFile → the file's own
directory → registry-adjacent → built-in default):
| Policy field | cargo-edit mapping (0.13.13) |
|---|---|
reject |
--exclude <crate> - ONE flag per crate (comma form ignored) |
allow |
-p <crate> - repeatable |
incompatible / pinned / compatible |
--incompatible / --pinned / --compatible <allow|ignore> |
pinStyle |
NO CLI equivalent (no --exact exists) - manifest-level via the chain pass |
depGroups / targets / concurrency |
NO equivalent |
verifyCommand |
run after the upgrade via ctx.subprocess (/bin/sh -c ...), exit 127 non-fatal |
The built-in default mirrors cargo upgrade's own semantics: no rejects, incompatible: "ignore",
pinned: "ignore", pinStyle: "caret", no verifyCommand (never install implicitly).
The Source Layout
TypeScript-first, built with @playform/build (ESBuild + tsc type-check):
ets-hook-dsh-cargo-governor/
├── Source/ ← TypeScript (NOT shipped)
│ ├── Library.ts ← entry: name / apply / Config / inject
│ │ + default { name, apply, Config, inject }
│ ├── Function/ ← Apply.ts (thin wire-up), Observe.ts,
│ │ │ Transform.ts (the TOML pipeline leaf),
│ │ │ Direct.ts (the direct-govern driver), Transform/Guard.ts,
│ │ │ Transform/Keep.ts, ParseToml.ts, Pin.ts (+ Pin/KeyOf, Name,
│ │ │ SpliceVersion, SplitPath), Normalize.ts,
│ │ │ Satisfy.ts, Filter.ts, Resolve.ts, Run.ts,
│ │ │ Dispatch.ts, Verify.ts, Settle.ts, Decode.ts
│ │ └── Update/ ← Policy.ts, Upgrade.ts (the Rust/TS bridge,
│ │ + Upgrade/Child, Collect, Seam, Unavailable)
│ ├── Interface/ ← typed contracts (State, Factory, Plan, ...)
│ └── Variable/ ← constants, defaults, the Config schema
├── Configuration/
│ └── ESBuild.ts ← the @playform/build custom config (+ .js twin)
├── Target/ ← built output (SHIPPED: .js + .d.ts)
├── cordis.patch.yml ← the loader row (id: ets-hook-dsh-cargo-governor)
├── package.json ← main → Target/Library.js
└── README.md / SCHEME.md ← usage + the design document
The published artifact contains only the built output; the only npm script is prepublishOnly
(Build 'Source/**/*.ts' --ESBuild Configuration/ESBuild.ts --TypeScript Configuration/TypeScript.noemit.json && tsc -p tsconfig.json && tsc-alias -f -p tsconfig.json).
The Hard Lessons
injectandConfigmust sit on the DEFAULT export object - named- only exports are shadowed and service accessors throw.applymust return nothing - a returned value silently kills event delivery. Test probes useContext.__cargoGovernorState.- The update stage runs in the jobs envelope when a controller serves the context, with the
detached contained continuation as the probed fallback - the earlier "ctx.jobs is agent-scoped"
premise was refuted live: a root plugin's controller (attached by the factory's
Attach) serves every owner. ctx.fs.writeTextfrom a root plugin needs an explicit sandbox policy- this module passes
{ mode: "danger-full-access" }because its own exclude list IS its fence.
- this module passes
- cargo-edit's
--excludeis one flag per crate - the comma form is silently ignored (the inverse of ncu's one-comma argument). - cargo-edit has no
--exact- exact pins are a manifest-level concern (the chain pass'spinStyle: "exact").
The Config
The exported Config schema validates and fills every default at load; new patch entries are
declared with insert:.
- insert:
- id: ets-hook-dsh-cargo-governor
name: "@playform/ets-hook-dsh-cargo-governor"
config:
log: true
logFile: ~/.dsh/ets-hook-dsh-cargo-governor.log # SEPARATE ledger - never the npm ledgers
updateCooldownMs: 3000
strict: false # strip unknown deps - explicit only, never a default
mutationTools: [write, edit, str_replace_editor, raw-write]
maxUpdateFailures: 3 # circuit breaker: pause a dir's update stage
cargoBin: /usr/local/bin/cargo # the update-stage binary; the schema default is the bare
# "cargo" (resolveExecutable) - an absolute path when the host PATH lacks it
updateMode: cargo # the ONLY mode (the Rust-side CLI)
policyFile: "" # optional global update-policy.json
keepFile: "" # optional global pin-policy.json (the keep-list)
exclude: [node_modules, .git, .dsh, .pnpm, .store, DeepSeek Harness.app]
In Action
One governed write.
The author saves a Cargo.toml with comments, a shorthand version, and a
chain-governed dep:
[dependencies]
# the engine — keep the comment alive
serde = "1.0" # shorthand: must become 1.0.0
tokio = { version = "0.4.1", features = ["full"] } # chain-governed
With the nearest registry.json resolving tokio to 0.4.5, the surgical rewrite produces (same text,
same comments, same inline spacing):
[dependencies]
# the engine — keep the comment alive
serde = "1.0.0" # shorthand: must become 1.0.0
tokio = { version = "0.4.5", features = ["full"] } # chain-governed
The transcript shows only what the author wrote; the ledger shows the pass:
[2026-10-03T09:15:22.411Z] activated (cargo flavor, logFile=~/.dsh/ets-hook-dsh-cargo-governor.log, updateMode=cargo, cargoBin=/usr/local/bin/cargo, exclude=[node_modules, .git, .dsh, .pnpm, .store, DeepSeek Harness.app], policyFile=(discovery), keepFile=(discovery))
[2026-10-03T09:16:01.880Z] governed ~/Projects/acme/engine/Cargo.toml → 42
[2026-10-03T09:16:34.120Z] update stage dispatched for ~/Projects/acme/engine (cargo via /usr/local/bin/cargo, built-in default policy)
[2026-10-03T09:16:41.502Z] update: cargo upgrade --manifest-path ~/Projects/acme/engine/Cargo.toml --exclude serde tokio → {"exitCode":0}
[2026-10-03T09:16:41.503Z] update: DONE — pins bumped per policy
(Here the policy's chain deps plus rejects became one --exclude flag per crate; serde and
tokio are protected from the CLI bump - tokio by the chain, serde by the normalization pass
already writing its full form.)
Read the file back to see the governed state; write it again
immediately and nothing complains - no FS_STALE_VERSION.
Write inside node_modules/.git/.dsh
and the ledger gains skipped (excluded) ... while the file stays untouched.
Remove cargo-edit and
the pass fails gracefully: update: cargo-edit unavailable: ..., the manifest untouched, the
breaker counting the failure.
The Ledger
One global log (logFile, default ~/.dsh/ets-hook-dsh-cargo-governor.log - SEPARATE from the npm
ledgers) records activation, exclusions, chain-pass results, refusals, and every update-stage
dispatch.
The strings this module composes (the ets-hook-dsh-cargo-governor: logger prefix is the
factory's Append; each line is [<ISO>] <message> in the file):
activated (cargo flavor, logFile=..., updateMode=cargo, cargoBin=..., exclude=[...], policyFile=(discovery), keepFile=(discovery))
skipped (excluded) <path>
no registry.json found for <path>
governed <path> → <version>
update stage dispatched for <dir> (cargo via ..., policy ...)
update: cargo upgrade <argv> → {"exitCode":0}
update: DONE / update: FAILED
unreadable registry.json at <found> — chain pass skipped for <path>
observed non-JSON/TOML Cargo.toml <path> — skipped
REFUSED rewrite of <path>: non-dependency section "<name>" would change
REFUSED rewrite of <path>: dependency "<key>" in section "<section>" has an unsupported value shape — rewrite aborted
REFUSED rewrite of <path>: dependency "<name>" in section "<section>" not found in text — rewrite aborted
update stage paused for <dir> (N consecutive failures ≥ limit)
update stage skipped for <dir> (in-flight)
update stage skipped for <dir> (cooldown)
update stage FAILED (<code>) for <dir>; consecutive=N
update: cargo upgrade failed (<label>) status N
update: running verifyCommand: <command>
update: verifyCommand ok
update: verifyCommand failed (status N)
update: verifyCommand runner unavailable (exit 127) — skipped, non-fatal
unreadable pin-policy.json at <keepFile> — using built-in default
(The registry-miss line, the three REFUSED forms, the runner-unavailable line and the
unreadable-policy line end with em dashes; the DONE line is update: DONE + em dash + reason -
byte-exact forms are in the In Action excerpt above.
Those em dashes are part of the literal ledger strings, so they live only in the example block.)
The activation line is written by apply() - "did it activate" must be answerable from the ledger
alone.
License 📜
CC0-1.0.