Delete @deepseek-ai/dsh-invariants, every package's ./invariant companion
and its tests, the invariant gates and Vitest setup, the scoped-event
resolver generator, and the INVARIANT-coded listener rethrow paths.
Update docs, READMEs, Agent Notes, and add an upgrade guide.
Review follow-ups: the Electron payload smoke allocates the way the product
does on Windows, so the packaged tree resolves the console host assets it now
depends on; the README states that dependency and its loud failure as a known
limitation; the terminal handle takes the platform this method already
resolved; and the note links the earlier tail-grace note, records why that
grace cannot cover a malformed tail, and drops the claim that the smoke
exercises the operating system host.
The per-platform case reads the third spawn argument to assert the console-host
option is absent on POSIX; an untyped vi.fn() declares no parameters, so the
indexed call argument fails typecheck.
The README, the Ctrl-C comment, and the bare-kill comment still described
Windows' own console host as the one backing the PTY. Name the host the code
now selects, record the exit-event behaviour of both teardown paths measured on
the pool machine, state that a missing conpty asset fails loud, and move the
note to the bug-fix class next to the other Windows console fix. The terminal
case now asserts the option key is absent on POSIX rather than not true.
The console host Windows provides, on the images the master standby pool runs
(Server 2022, Windows 10 22H2), replays a prompt line that scrolled out of the
viewport as `\ndsh>\x1b[1C`: the trailing space becomes a cursor move, so the
persistent-pwsh readiness path never sees its `dsh> ` tail and every send waits
out the silence tier. The same case passes on the Blacksmith Windows image,
whose console host emits the tail verbatim.
Allocate Windows PTYs with `useConptyDll: true`, so the PTY is backed by the
OpenConsole the node-pty package ships. The option is set only for `win32`;
the terminal spec pins it per platform.
Probing the pool machine with the bundled console host rendered the `dsh> `
tail for all seven prompts of the failing case's command sequence, and
`pty.pid` still resolves to `pwsh.exe` and equals the shell's own `$PID`.
* feat(i18n): key translation pairing records by heading section
Replace the whole-file blob hashes in *.i18n.yaml with one entry per
heading section that still holds language-specific content, keyed by the
English heading-slug path. Blocks identical across the pair (generated
table rows, code blocks, shared regions) stay out of the hash, so edits to
different sections and identical regenerations merge with Git's default
text merge, including on GitHub.
Remove the dsh-translation-pairing merge driver, its resolver command and
installer wiring; gen-translation-brief recovers last-confirmed text from
commit history. Migrate all active records, archive the superseded Agent
Note, and record the replayed conflict reduction in the new one.
* test(i18n): refresh translation prompt snapshot for the terminology note
* feat(i18n): exclude only code blocks and generated regions from pairing records
Replace byte-equality masking with an explicit rule: a record hash skips
fenced code blocks and BEGIN/END GENERATED regions, the two kinds of
content the pairing gate already requires to be identical on both sides.
Move generated data into regions written into both pages:
gen-config-catalog renders both languages and the record with per-package
regions labelled by code identifiers; gen-module-graph keeps its table in a
region; gen-doc-graphs splices the event matrix regions into the Chinese
page. Add a generic region splice beside the region grammar.
- Agent Notes: cross-link the new decision with the native fatal recovery
and fail-loud release notes both ways, rewrite the older note's
console-retention and dialog-detail facts in place, and state the report's
actual bounds.
- crash-report: cut the rendered error section at 256 KiB and prune only
files matching the generated crash-<time>-<source>.log syntax.
- main: backendReady follows the backend state except during shutdown, so a
failure while tearing down a ready backend still reads as running.
- subprocess-local: the temporary-file-cleaner hint is appended only for
ENOENT; other codes rely on the appended error.
- client-modules: describeError is module-private; BootModuleRow.url's
JSDoc names its fallback role.
client-modules: a batch that already executed is never requested again,
even when its first importer was a row it did register — every executed
batch URL is remembered and a still-missing row goes straight to its
one-resource URL. The in-process module system test in test-support is
updated to the aggregated arrival message. describeError replaces three
inline non-Error ternaries and is covered.
subprocess-local: the spill path is published only after the exclusive
open succeeds, so a failed open (EEXIST on a planted entry included) can no
longer unlink a path this process did not create; a reporter that throws is
contained and written to stderr; logSpillFailure builds the owner reporter
for both the runtime and the SSH helper so the logging path is exercised
once instead of duplicated. Tests cover the runtime logger, the bare-caller
stderr default, EEXIST, and a throwing reporter.
desktop: a fatal failure during shutdown still writes its report; the
report phase follows the backend state so a failure during a restart is
'startup' again; writeReport is a required recovery operation and the
dialog tests await the write; the shell pid is labelled; the withheld
response-header list states why set-cookie is dropped.
app-boot, READMEs, Agent Note: "never resumes" is restated as control never
returning to the failed operation while the loop runs until release
settles; inspect output is bounded; incident inferences (who removed the
spill directory, which batch failure occurred) are written as inferences.
OutputCollector.spillAll ran openSync/writeSync inside the stream 'data'
listener with no containment. When the private per-process spill directory
had been removed by a temporary-file cleaner, the first overflowing chunk
threw ENOENT from Pipe.onStreamRead, became an uncaught exception in the
Desktop Host, and the Electron shell reported it as a fatal failure.
Spilling is best-effort by contract (spillPath is optional; a failed final
close already withholds it). Every filesystem failure while opening or
appending the spill file now discards the spill, reports once through the
owner's logger, and leaves in-memory collection untouched. Spill inputs move
into one SpillOptions object with the reporter, so tail-only collectors no
longer pass an empty directory; prepareManagedProcessBinding is the explicit
resolve step for the directory and reporter defaults, and the runtime and
SSH helper supply their plugin loggers.
Tests cover ENOENT on open (removed directory), ENOTDIR on open, and ENOSPC
on append after the file exists, asserting the tail stays byte-exact, the
spill file is withdrawn, and the reporter fires once.
Merge master 62b700bba7bb71e66d2d5a3b850ba8f4dd0fd6b4 into release/session-log-v4 at 4825bc01a999f564e79172a6af28e34fc757c540. Preserve this pinned integration checkpoint before any later upstream movement so the dependent session-format repairs have an immutable rebase base.
Keep release projection-backed child catalogs, independent Session references, exact fork behavior, V4 writer, and existing migration data. Adapt the incoming subagent sidebar chat to refreshProjections rather than the removed dedicated catalog API, preserve title projections in complete projection fixtures, and retain both sidebar actions and release lineage/status behavior. Remove the duplicate SessionProjectionMap import introduced by automatic merging.
Preserve both disjoint archive seals without changing any existing hash. Regenerate current Cordis and documentation catalogs from the combined source, retaining release session methods plus master slot factories. The frozen V0-V3 runtime paths are unchanged. Initial validation passed the full build, 93 focused Client tests, and all 1905 archived artifact seals; remaining integration and snapshot checks follow on this checkpoint.