CASE STUDY ONE COMMIT ERA 12 DECISIONS + 1 FIX

The case study: how this family got built.

The development story of the twelve packages, told as it happened - the phases, the misdiagnoses named before the fixes, and the decisions that survive in the shipped seams. Every challenge below is stated with what actually happened.

Overview

5 BUNDLES / 231 CHECKS -> 12 PACKAGES

The family grew from five bundles and 231 smoke checks to twelve packages across one commit era - the Oct 3–6, 2026 stretch that ends at 5982aa8 - with roughly 800 checks across twelve suites as the final count. Every step of the way, the smokes were the arbiter: zero assertion changes across refactors, renames and a framework port. And every real bug - the shadowed patch layers, the silent journal open, the version guard that could only succeed once - was found live, not by the smokes. That asymmetry is the story's spine, and the sections below keep it honest: what the suites caught, what only a restart could catch, and which two theories died on the way to the truth.

12 PACKAGES 12 SMOKE SUITES DUAL RELEASE CLASSIC + EFFECT-TS

Phase I - The boilerplate era

THE FACTORY + THE GOVERNANCE TRIO

The setup: three independent hooks - the package governor, the package pinner, the cargo governor - plus the dash normalizer, each carrying its own copy of the same machinery: ledgers, exclusion matching, policy loading, guarded writes, wiring, schemas. The decision (49e5b3d, 859f16a, 018919c): consolidate onto one factory service - 15 methods, one transform contract, and the ledger strings owned by the modules themselves. The technique: the Wire/Attach/ Continue seam trio, and a transform leaf the factory drives but never absorbs - each hook's transforms stay its identity. The outcome: five bundles green, 231 checks, and every ledger string byte-identical to pre-refactor behavior, smoke-asserted. The factory's page shows the seam table this era produced; it has since grown 15 → 16 → 17 methods as later phases moved machinery in.

dsh-plugin-factory SERVICE

The furnace: one service with 15 methods centralizing the machinery the hooks kept duplicating - the ledger, the gate, the guarded write, the wiring, the schema factory.

dsh-hook-package-governor HOOK

The package.json governor: chain-canonicalization plus the update stage, run as a detached, contained continuation.

dsh-hook-package-pinner HOOK

The static pinner: every ranged dependency version rewritten to its exact form, protected by a keep-list.

dsh-hook-cargo-governor HOOK

The Cargo.toml governor: surgical line rewrites on raw TOML and cargo upgrade driven through the subprocess seam.

dsh-hook-mdash NON-MANIFEST

The first stream normalizer: the dash family rewritten live in the model output, at the injection point a file hook does not have.

Two live-verified fixes from this era never regressed since: a hook's inject and Config must sit on the loader's default export object, and apply must return nothing - a returned value silently kills event delivery. Both are the kind of bug no type checker sees; both were found with a restart and a missing ledger line.

Phase II - The audit and the fixes

3 CRITICALS, THEN THE QUEUE

A confirmation agent re-verified all five bundles and found three things that rewrote the queue. Each is a finding with a fix; none was visible from the passing smokes alone.

TYPE-ONLY 28ebc30 + c6a72ce

The pinner's tsc went red - TS2339 four times plus TS2310, a type that recursively references itself as a base. The factory's built declarations shipped unresolved @Interface/* aliases; any consumer whose tsconfig maps the same paths resolves them to its own files. Runtime unaffected: the smoke still passed 28/28.

Fix. Relative specifiers everywhere and named type exports from the factory entry - then the type-import flip deleted the consumers' local structural mirrors outright (~208 lines). Type-only imports are erased, so the consumers' only-Config-imports-the-factory posture survives the flip untouched.

P0 28ebc30

The build was nondeterministic: the build tool's TypeScript hook ran tsc then tsc-alias through an exec() that was never awaited, so the emitted declaration specifier style depended on timing - rebuilding did not reproduce the committed state.

Fix. Each bundle's prepublishOnly now runs the build with the racy hook neutralized, then explicit sequential tsc && tsc-alias - and a red tsc fails the build instead of shipping. Rebuild twice, get an identical tree.

P1 1ed3564

The package governor still registered its in-flight key as the plain target key - the same key the factory's continuation uses. An update running under key K plus an external edit could orphan the update's controller. The cargo flavor had fixed the same collision locally a phase earlier.

Fix. The key helper moved factory-side as the 16th method - UpdateKey(target) yields update:<targetKey> - and both governors adopted it. Collision-window smoke cases went into the factory and governor suites the same day.

The rest of the queue executed in one session: the module terminology rename ( 3c29108 - mechanics only, the cargo flavor literal in the activation string stays), the standalone schema helper that deleted three config workarounds (060e3b6), the core extraction as a dependency-free pure package (1fef4ca), and the granularization splits (711d5b2 ). One operational beat worth keeping: the smoke suites lived in /tmp and were lost once - replayed from the session archives step by step, then archived to ~/.dsh/smokes/ forever after. The arbiter must not be disposable.

Phase III - Going live

THE JOURNAL SAGA

The first live battery exercised everything the smokes had proven: the governor + pinner interlock on one manifest write, the update stages as real jobs, the cargo's actual cargo upgrade with the full argv, the dash normalizer counting replacements in live streams. It also surfaced the first live-only failure: the harness's storage domain enforces one open per name, so the shared journal domain was single-winner per boot. At that boot only the pinner's records landed; the governor's and the cargo's silently never did - while the human ledger files remained the complete record, which is the only reason the loss was even noticed.

The fix, in two commits

The first successful open binds its handle on the factory instance ( 952eaa1), and every module's records route through it. The boot-window race came next (aa53c91): records journaled before any open completes now buffer in a capped, drop-when-full pre-bind queue and drain with their timestamps preserved - a three-stage routing of shared sink, pre-bind buffer, then per-state fallback. The third boot confirmed both live:

One boot's complete record set - the shared domain

16:44:43.232 activated | activated (pinner, ...) 16:44:43.301 activated | activated (anywhere mode, ...) <- the governor's (was missing) 16:44:43.302 activated | cargo <- the cargo's (was missing) 16:45:42.178 governed | <version token> <- the interlock cascade 16:45:42.196 dispatched | programmatic <- the update stage

Before the fix, that file showed one module's activations. After it, all four - and the interlock cascade and the dispatched update stage record themselves in the same place. The update stage's awaited promise resolves at the dispatch: the background job keeps running, and the caller never awaits the job.

Phase IV - The stream family

SIX FLAVORS + THE GATE

The dash normalizer generalized. The core took over the pure machinery - generic over structural shapes, with no dependency on the host's LLM types: a fragile cross-bundle symlink workaround for a nominal-type clash was replaced by a durable design (98be27b, c2beb06). Five sibling flavors followed on the same template - quotes, ellipsis, spaces, invisible, fullwidth - each with its own ledger, activation line and count line (ad4c2c3, 68afdcd). Then the tool-args gate (1d827ad), and its three-way refinement (9d6e195): edit calls pass by identity - the old-string must match the real file bytes - and a per-call marker lets a single call opt out entirely. The marker is honestly stated: smoke-verified, but not reachable from the structured tool interface at the time; the practical per-call raw route is the edit exemption.

The stream, before and after

text-delta in : “The refactor is complete — ranges 10–15 covered.” text-delta out: “The refactor is complete - ranges 10-15 covered.” tool-call-delta, name "edit" -> passes through BY IDENTITY arguments {"old": "a — b"} -> untouched: the old_string must match real bytes

One beat belongs to the family's self-awareness: the system normalizes itself. The agents building the family saw their own comment prose come out with ASCII hyphens, because their output streams run through the same flavors. The planned cosmetic pass was cancelled by the user - em-dashes live only in the README examples, never in code. The workbench and the matrix pages run exactly these flavors live, and the workbench lets you watch the gate make its per-call decisions.

Phase V - The raw-write saga, commonalization and granular control

THE DENSEST PHASE

The raw-write tool landed first (bb9a6fd): a write wrapper with an explicit normalize parameter, exempt from stream normalization by name like edit, mirroring the built-in write's filesystem path so the governance hooks see its writes. Then the live tests showed its writes never triggered the governance chain - and the diagnosis took three rounds, two of them wrong. The emit-context theory: the event must be scoped to the emitting plugin. The listener-scope theory: the listener must be registered at the wrong level. The delivery research refuted both with code, simulation and live policy evidence: the event is delivered; the gate rejects the actor. The shared event bus has no scope filter on plain emits - the root registration fix aimed at the misdiagnosis was harmless, and stayed.

The real blocker: the patch layers

The deployed mutationTools value of all three governance bundles was [write, edit, str_replace_editor] - no raw-write - even though the schema default included it. The bundles' own patch layers set mutationTools explicitly, and a patch layer's config replaces the entry config wholesale, shadowing the default. The inspection tooling projected the schema, so the projected list looked correct while the live value was not - the verification blind spot in one sentence. The fix (affa730) was one line in three patch files, and it became the family's standing lesson about verifying the live effective config.

The journal migration that failed silently

The journal domain bumped to v2 to carry the stream counts (4c0e83b) - and every boot after it landed zero records. The v2 open failed against the v1 file on an exact-equality version check; the open's catch swallowed it; every record drained into a never-drained buffer and died with the process. The fix ( 756d566): a per-record layout that auto-migrates the v1 records, backup-and-skip for invalid ones, and a loud failure line on any open failure - because the silence is what made it undiagnosable.

Commonalization: three executors become one

The write-path audit found the built-in write, the raw-write tool and the factory's guarded write all implementing the same five steps, three times. The merge ( 91293d2): the factory's Write becomes the shared executor - the guarded write lives on as its alias - with the update envelope and the activation composer folded into the core the same pass. Then the fine-grained control (e69c5d3): normalize selects the transforms, govern selects the chain steps through the factory's Govern- the 17th method - and a step registry the modules populate. The governance marker (2c8764e, 83ba8e5) inverts the event path into a direct path: the raw-write's actor carries the govern selection, so direct governance is the only channel and no flag means no chain - the escape hatch.

Shared stepBuilt-in writeraw-write (before)Factory guarded write (before)
1. resolvesession-aware resolve options (cwd, escalation root)same call, no cwd option - a real divergence, documentednone - the target arrives pre-resolved
2. fs/write-intentthe waterfall, next() -> voididentical waterfall, next() -> undefinedbuilds the intent inline: replaceIfVersion + version
3. sandbox policyfail-closed controller + standing session policyverbatim replica of the no-escalation branchthe per-call workspace-write fence at the target's own directory
4. writeTextthe five-argument call + denial remediationsame five arguments, no remediationsame five arguments, plus the stash pre-registration
5. fs/observedpresent emit with the written version, actor = the execbyte-identical emit shape, actor = the execdelegated to the same-actor refresh

The fold, and the guard that made it converge

The direct steps' detached chains raced - nondeterministic writes on the same file - so the fold awaits each step's chain before the next reads (d7a3c93, 140faa0). Then the deeper bug: every step wrote against the version observed at the triggering event, so only the first write could succeed and the later steps failed the stale-version check silently. The fix (5982aa8): the chain pass stats the target before its write and takes the fresh version, so the fold converges in any step order - which matters, because the pinner activated before the governor at the decisive boot. One more fix belongs to the Effect-TS port: the write executor originally mapped the caller's abort signal onto the run promise's options, so a pre-aborted signal interrupted the whole fiber and the caller saw all fibers interrupted without error instead of the Classic aborted-before-write behavior. The dash suite's pre-aborted-write scenario caught it; the fix drops the signal mapping - the signal forwards to the seams only, exactly the Classic semantics.

The final battery's outcomes, verbatim

raw-write, no govern flag -> NO chain (the escape hatch; the write still emits fs/observed) raw-write, govern: ["canonicalize","pin"] -> governed + pinned both land, the file canonical + pinned, NO update dispatch raw-write, govern: true -> governed -> update stage dispatched -> pinned (the full chain, any step order) built-in write / edit -> governed via the event path (the interlock as always)

Phase VI - The releases, the monorepo and the Site

BOILERPLATE -> SHIPPING

The completed codebase became the boilerplate for two official releases off one source: the Classic implementation stays live-first, and the Effect-TS port ships only after its smokes prove parity - the ledger strings remain the contract in both (register #13). The release prep anonymized and de-personalized every bundle and rebuilt the READMEs on a single skeleton borrowed heavily from the sibling project's conventions. The Effect-TS mapping planned the parallel-govern toggle in from the start - concurrency is different there, and designing the toggle first beats retrofitting it. The naming inverted ( register #15): packages read as @-sentences - Hook @ DSH @ Governor @ Package - and group alphabetically by kind, role and domain, at version 0.0.1, one repository per package under submodule structure. And the Site you are reading is the last item: the integration showcase, with the versions page carrying the two engines side by side.

The decision index

13 DECISIONS, WHERE THEY LIVE, WHAT PROVED THEM

Every decision below survives in a shipped seam. The technique column names where it lives; the evidence column links the narrative to the commit era.

DecisionRationaleTechnique / seamEvidence
Module-owned ledger strings; the smokes as the arbiterByte-identical strings make renames safe and behavior provable - the literal activated (cargo flavor, ...) survives every refactorThe transform contract + the smoke harness; renames change mechanics, never stringsthe handoff P2/P5; 3c29108, e106a98, 66bfd81
Stat-before-write version guardIn a multi-step fold every step wrote against the SAME observed version - only the first write could succeed; the fresh stat makes the fold converge in ANY step orderThe guarded write's replaceIfVersion intent + a fresh version before each write5982aa8
Wrapped-actor governance marker + the direct pathThe raw-write's actor carries {...exec, govern}; the gate's govern reason makes direct governance the only channel - the event path skips marked actors, so no flag means no chain (the escape hatch)The gate's actor step + the factory's Govern (the 17th method) + the step registry2c8764e, 83ba8e5, e69c5d3
The sequential fold; the parallel toggle designed but gatedDetached chains raced (nondeterministic writes); same-file steps - canonicalize + pin on one package.json - DO race, so parallel only when disjointness is provenThe direct-govern fold in the write executor's continuation; the per-call toggle rides the same govern flag shaped7a3c93, 140faa0
Per-record journal layout + the loud failure lineThe v2 open failed silently against the v1 file (an exact-equality version check) and buffered every record into a never-drained buffer; silence made it undiagnosablelayout: per-record, compatibleVersions: [1], invalidRecords: backup-and-skip - one ledger line on open failure4c0e83b, 756d566
Patch layers carry the live configA patch layer's config REPLACES the entry config wholesale, shadowing schema defaults; the schema projection alone is the verification blind spotThe three governance bundles' patch layers + the mutationTools gate inputaffa730
Explicit tools over background rewritersBackground rewriting breaks the edit old-string contract and interleaves with bounded passes; an explicit tool is visible, opt-in, and a no-op writes nothingThe tools seam (ctx.tools.register) + the stream gate's name-exemption48f9515
One shared write executor owned by the factoryThree executors duplicated the same five-step pipeline; the factory is the only home both tool-style and continuation-style writes already depend onThe factory's Write (the 16th method; the guarded write lives on as its alias)91293d2
The core as pure delegate; the stream dispatch dependency-freeA cross-bundle symlink workaround for a nominal-type clash was fragile; generic structural shapes survive every narrowingStream/Chunk + Stream/Block with no dsh-llm import anywhere98be27b, c2beb06
Host-era pins; verify from the installed app, never stale node_modulesThe @deepseek-ai family pins must match the running host; the registry's latest tag is stale and the profile's old links lieThe dependency-pin disciplinethe handoff P12
Dual release: Classic live-first, Effect-TS ships only after parityKeep the working implementation onboard; the ledger strings stay the contract in BOTH implementationsThe stream gate, the services + layers, the tracing spansthe monorepo plan; the versions page
Reversed hierarchical naming + version 0.0.1 + submodulesNames read as @-sentences and group alphabetically; one repository per packagePackage naming; the monorepo layoutthe branding brief
The abort signal forwards to the seams, never onto the fiberThe Effect-TS write executor originally mapped the caller's signal into the run promise's options; a pre-aborted signal interrupted the whole fiber - the caller saw All fibers interrupted without error instead of the Classic aborted-before-write semanticsThe Effect-TS Write executor with the signal mapping dropped - the signal rides the seams only, exactly the Classic mechanicsthe dash suite's pre-aborted-write scenario (the Effect-TS round)

The working lessons

THE HONEST CLOSE
The smoke/live fidelity gap

Every real bug - the patch layers, the v2 journal open, the version guard, the delivery puzzle - was found LIVE, not by the smokes. The smokes prove the mechanics; the live battery proves the wiring. Neither report is complete without the other.

Load order is not list order

The pinner activated before the governor at the decisive boot - never rely on the bundle-list order for step ordering. The fold plus the fresh-version writes make the order irrelevant.

Timestamps are epoch UTC

The storage timestamps are epoch milliseconds; the local display adds +03. The missing-records scares were filter mistakes, not lost data - one hour of arithmetic saved an hour of dread.

The subagent quirks

One file per response keeps agents alive; agents that batch die more often. Agents crash mid-flight without a closing message - recover from the on-disk state. And the subagents' own streams get normalized: their comment prose came out hyphenated.

Verify the live effective config

The meta-lesson of the patch-layer saga: a schema projection is not the truth. The patch layer replaces the entry config wholesale - read the composed layers, never just the defaults.

The state the era ended in: twelve packages, twelve green suites, a clean tree, the full live matrix passed - and a backlog of decisions already designed, waiting for the next era. The install command below is the whole family's front door.

START HERE COPIED
$ pnpm add @playform/hook-dsh-core