The loader's entry store is a plain object, so an auto-generated all-digit
id is reordered ahead of its siblings by integer-key semantics and the
previous ordered assertion flipped on roughly one in fifteen runs. Row
ordering belongs to loader.entries(), not to this projection; the spec now
asserts each row by its id.
CI's coverage lane runs on a clean tree where workspace imports resolve
through tsconfig paths to src; the value import of
@deepseek-ai/dsh-agent-presets/display therefore needs its own paths row
beside ./types. Locally the built lib masked the gap; reproduced by moving
lib aside, fixed, and re-run green under the same condition.
Review round on #3316: the composition inventory answers from a standing
mount before the broken verdict (a file corrupted after mounting no longer
hides the running composition), livePresetMounts filters by the caller's
root fiber so a second Cordis runtime in one process never answers for it,
compositions carry trust and the plugin list resolves shipped preset names
through the shared dsh-agent-presets/display fold over ui-agent-preset's
dictionaries (INLINE_SAFE inline import; no cross-plugin runtime import),
the condition detail label reads Disabled when/禁用条件, and the stale
four-surfaces comment says three.
Reconciled with the scope-grouped plugin list: compositionInventory keeps
its additive block over master's RemoteError refactor; the slimmed
settings-store keeps ctx-based signatures while staying a display-only
roster store (no describeFace, no select); dead transport-rejection tests
dropped with the wire that no longer rejects; module graph, catalogs, and
harnesses regenerated against the merged tree.
Both scope groups drop their boxed chrome for the General-settings row
idiom: a title row (session-plugins title with the right-aligned preset
selector pill; global-plugins title), a grey subtitle line carrying the
count, a hairline divider between groups, and the cards grid below.
Counts ride the subtitle as text while the data attributes keep the raw
numbers for tests.
Review-driven refinements to the scope-grouped plugin list:
- The preset switcher becomes the General-settings selector pill over the
shared Menu primitive instead of a native select, and the preset group
is collapsible like the global one (search still forces both open).
- The session-plugins drawer is removed: rows the presets took over sit
inline in the global list with the preset-provided tag and per-preset
details, since the preset group above already shows those compositions.
- The status dot renders only for a live root fiber, so file-state rows
of an unmounted preset carry their enablement tag alone instead of a
column of grey dots.
- PresetTree reclaims the owning entry's subtree slot: EntryTree's
constructor filed the standing mount under the roster's own Loader row,
so after the first session composed a preset the whole composition
leaked into root loader.entries() as host rows (each preset overwriting
the last). A regression test holds the root entry list identical across
a mount.
The settings plugin list projected ctx.loader.entries() alone, hiding the
plugins sessions actually run and rendering the web overlay's deliberate
disabled tombstones (tool-bash, tool-fs, ...) as two dozen plainly disabled
rows while the same modules ran in every standard-preset session.
- dsh-agent-presets: compositionInventory() answers flattened rows per
preset — newest live standing generation when mounted, composition file
otherwise with !!js disabled gates evaluated against the Loader context;
reading never mounts (regression-tested), refusal stays 'conditional',
raced files report broken with the reason.
- dsh-host-plugin-inventory: list() gains an optional agentPresets block,
resolving the roster as an optional peer and mapping fiber states to the
public phase vocabulary.
- ui-settings-plugin-inventory: preset group first behind a display-only
switcher opening on the default preset; global group collapsed with
failures floated; host-disabled modules enabled by >=1 preset fold into a
session-plugins drawer naming providers; search spans scopes and points
at matches in unselected presets.
- ui-agent-preset: the General-settings default-preset row is deleted — the
roster section's make-default and the new-session chip keep the field —
and the settings store slims to the display roster the header label reads.
Docs, catalogs, module graph, settings-chrome goldens, and the bilingual
Agent Note ride along.
A pointer drill in the @ menu left no breadcrumb and a crumb click dropped
the header, while the keyboard drill worked. InputTriggerController.settle
assigned `drilled` after execute() returned, but a pointer mousedown runs
outside any Lexical update, so the descent edit commits discretely and
re-enters track() during execute() — where refreshHeaders and
fetchCandidates both read the claim while it was still clear.
settle now claims the drill before dispatching the edit and withdraws it
only when the edit is refused, which mutates nothing and so drives no
re-entrant track().
The skill carries the reliability rules, but nothing an agent loads by default
said that specs run concurrently at all. The testing policy described tiers and
evidence without ever stating how a spec is executed, and neither subtree
AGENTS.md mentioned it — including scripts/, where the two suites that recently
failed on unrelated branches live.
docs/testing.md gains the execution model as the one home for the fact: forked
workers, concurrent coverage partitions beside other gates, and self-hosted
runners sharing a host and volume, with the rule that a spec passing only when
run alone is a defect in the spec. It links the skill for the detailed rules.
packages/AGENTS.md and scripts/AGENTS.md carry the short actionable form and
link that section, so the rule is present in the context loaded while a test in
either subtree is being written.
Both ceilings are raised for the added words and the targets in docs/AGENTS.md
move with them: docs/testing.md 1150 to 1300 (now 1237) and packages/AGENTS.md
675 to 750 (now 712), each keeping the 5% headroom the standard requires.
The 'Test strength' bullet carried assertion strength, external-state
verification, the reliability reference, and the coverage caveat at once.
Splitting the reference into an adjacent entry matches how the orientation
list above names the same skill, and restores 'Test strength' to one subject.
The new entry also names the platform and timeout-budget rules the skill now
carries, so the checklist covers what a reviewer is being pointed at.
Two failure classes the repository paid for are not covered by the isolation,
synchronization, and teardown rules already in the skill.
A value the operating system owns is not guaranteed to return as written. A
test may write one back only where the assertion tolerates that write-back
failing; where the assertion depends on it, the expected value comes from a
fresh read. NTFS truncating a fractional-millisecond mtime and Windows folding
environment variable name case are the two instances seen so far.
A describe or case timeout overrides the runner's --testTimeout rather than
yielding to it, so a value below the lane budget lowers what CI granted, while
the same literal reads as a widening where the host default is smaller. The
hook budget travels with the test budget, and a case asserting a timeout keeps
its outer wait far larger than the timeout under test. Restoring a granted
budget, or sizing a bounded retry to measured contention, is named as distinct
from the masking fixes the skill rejects.
The diagnosis reference gains the platform differences under its platform
class, a classification path for self-hosted pools that expose no host metrics,
and the stopping rule for a signature no available host can reproduce.