The dispatched nightly came back with one regression: dsh-liangshen functions
80.64 here against 80.07 on the runner, 0.57 over the gate's half-point
tolerance. The gap is not noise. benchmark-live-run.test.ts guards two cases
with it.runIf(harnessInstallAvailable()), so a machine that has the harness
installed covers functions a Linux runner never runs, and recording from here
puts the baseline above what CI can reach.
Record the four liangshen metrics at the runner's values, which is what the
ratchet has to hold on, and say so where the test rules live: when the two
sides disagree, the CI value is the one to record.
The shared setup now carries the storage repair Node 25 needs, so a package
whose own setup skips it runs its DOM tests on the degraded path and measures
lower coverage than the same tree does on Node 22. Name the three ways to pick
it up where the test rules live.
The reviewer's only e2e step was the skin preview lane, so the header, the --workdir help and the worktree-root comment no longer promise e2e artifacts beside the worktrees; docs/development.md loses the same phrase. The workspace keeps its ~/remote-e2e name.
capture-previews writes previews into the dsh-skins working tree, so market:fetch --force does not pick them up: --force only re-materializes an input whose worktree already sits on the pinned commit, and a worktree elsewhere is ignored in favour of the pinned tarball. The header now names the local-content mode for looking at fresh previews before the commit is pinned (and that the resulting market/dist must not be committed), and the pinned flow for the copy that ships. docs/development.md's skin section carried the same --force step.
The three developer skills described the pre-split layout: asset
directories under `packages/skins/skin-center`, `packages/dsh-pet` and
`packages/dsh-community-plugins`, plus commands such as
`pnpm skin-center:check` that exist only in the satellite repositories.
Each skill now names the owning repository, the commands that exist
there, and the side that stays here, and links the contracts instead of
restating them.
The same stale references are gone from the release and pre-push skills,
`docs/architecture.md` (which counted a fourth `lib/`-committing package
and listed `skins/skin-center` as a package directory), `docs/development.md`
(a skin-PR review lane for pull requests this repository rejects) and
`docs/plugins.md`; root `AGENTS.md` no longer mentions a skin registry
that lives elsewhere.
capture-previews still wrote preview/{light,dark}.jpg under packages/skins/skin-center, which the skin collection left when it moved to dsh-skins. The previews now land in the satellite checkout at satellites/dsh-skins/skins/<id>/preview/, the same working tree the pinned market input is copied from, and the script fails with an explicit message when that submodule is missing or sits on another commit. The hook-scene imports use the market layout the static server actually serves (/assets/skins/<id>/) instead of the removed monorepo path.
docs/development.md's 新增皮肤 section documents the new output location, the market:fetch --force step that local edits require (the gitlink is unchanged, so the input cache is not considered stale), and the current skin distribution facts.
The extraction moved the skin collection, the pet plugin and the
community plugin index into their own repositories, but the documents
that tell people where to submit those contributions still described
this repository's paths and scripts.
Skin, pet and community-index contributions now name the satellite
repository and its real entry points: skins/<id>/ with
scripts/dsh-skin-new.cjs and the skin-center catalog gate, assets/<id>/
with the pet CLI, and the community index's root community.json with
pnpm community:check. The gate lists in AGENTS.md, CONTRIBUTING.md,
docs/development.md and the architecture diagram no longer mention the
removed pnpm skin-center:check, and the artifact note now names the
three packages that still commit lib/.
The skin center, pet and community-index plugins now live in their own
repositories and are consumed as published npm packages, so this tree drops
them and everything that only existed to serve them in-repo.
Removed: packages/dsh-pet, packages/dsh-community-plugins and
packages/skins/skin-center (history stays in this repository), plus the root
scripts that moved with them (skin center catalog check, the reviewed-hooks
registry, the skin and pet authoring CLIs and their tests, community-index).
scripts/skins-montage.mjs stays: it renders the root README collage from
market/dist, which is this repository's tooling.
Decoupled:
- scripts/sync-shared.mjs no longer mirrors the settings trio, host helpers or
http/mount-once copies into the three packages (114 copies -> 99);
- lib-artifact-fingerprints.json tracks three committed lib/ packages now that
skin-center left;
- packages/dsh-usage drops an unused @linxin666/dsh-pet devDependency;
- the skin/pet/community gates leave ci.yml and the root scripts (they run in
the satellite repositories' own CI);
- scripts/i18n-audit.mjs no longer reads pet's client locale file, and the
test-standards and emoji audits skip .market-inputs (fetched content is not
ours to audit);
- the market build pins the community index in market-inputs.lock.json like the
skin and pet content, so the plugin list the site serves is reproducible from
a commit instead of following whatever npm resolves, and the catalog's skin
repo URLs point at dsh-skins;
- docs (root AGENTS.md, architecture, plugins, development, publish-prep) and
CONTRIBUTING point at the new repositories.
Gated by: aggregate:check, libs:check, runtime-deps:check, market:check,
sync-shared:check, test:standards, docs:check, i18n:check, emoji:check,
typecheck and 307/307 script tests.
Not yet safe to merge: the aggregate's three dependencies resolve from npm,
and the published 0.3.24 still injects the retired settingsScope service, so
the mount smoke stays red until the satellite repositories publish a build
containing the migration.
Turn the repository's test conventions into machine-enforced gates and close
three holes in the CI/CD set.
- scripts/test-standards.mjs: six business test rules (no-arbitrary-sleep,
no-ad-hoc-mock, bdd-title, given-when-then, call-count-only-assertion,
tautological-assertion) with a per-file, per-rule baseline in
scripts/test-standards-baseline.json, so new debt is blocked while the
existing 367-file backlog ratchets down. Rule scope follows the lane:
business tests under packages/, tests/ and desktop/ carry the full
contract, repository tooling under scripts/ only the mechanical rules.
- scripts/emoji-audit.mjs: replaces the inline ci.yml Python emoji step with a
reviewed, unit-tested gate; same ranges and out-of-scope trees, plus a
strict-UTF-8 skip and file:line:column reporting.
- scripts/coverage-gate.mjs with scripts/coverage-baseline.json: a per-package
v8 coverage ratchet (21 packages; repository totals 56.64% lines, 67.74%
branches) with a half-point tolerance for instrumentation noise. The
provider is declared per vitest major: the six 3.x packages carry
@vitest/coverage-v8@^3.2.7 and the root devDependency serves the 4.x fleet.
- ci.yml now runs the previously unenforced pnpm i18n:check, the new
pnpm test:standards, and pnpm emoji:check; nightly.yml is the Tier-2 lane:
both its jobs build before they test, exactly as ci.yml does, then run the
coverage ratchet and three consecutive full-suite runs for flake detection.
- scripts/pr-review.mjs keeps its gate sequence aligned with ci.yml.
- docs/development.md owns the rules, baselines, tiering and the failure-path
audit checklist. Decision recorded in
.agents/notes/implemented/testing/2026-09-16-business-test-discipline-gates.md.
Verified: pnpm test:scripts (three new specifications), pnpm test:standards
(clean baseline; a probe spec fails with three groups), emoji:check parity with
the Python step it replaces, coverage:check over the full fleet, pnpm
typecheck, pnpm test, docs:check, i18n:check, libs:check, aggregate:check,
actionlint, and pnpm install --frozen-lockfile.
Skins are one plugin in the family, not a peer pillar: the root README
pair demotes the skins chapter to a subsection of feature plugins, the
tagline and intro describe an aggregate plugin ecosystem distributed
through the Workshop, and the display name is simply skins (皮肤) —
Skin Center survives only in frozen technical identifiers (npm package,
directory, bundle id, wallpapers path). GitHub About and homepage match;
AGENTS.md and docs/development.md state the same hierarchy.
Decision record: .agents/notes/implemented/architecture/2026-08-24-plugin-aggregate-positioning.md
Display and source layers rename to dsh-web: GitHub slug, docs and prose,
aggregate package dir packages/dsh-web-all with npm name
@linxin666/dsh-web-all, settings package dir packages/dsh-web-settings,
private shared package dsh-web-shared, repo-local skill dirs, and the
docs banner asset.
Runtime, wire, and storage identifiers are frozen byte-identical so
installed profiles keep resolving with zero migration: web-ui-* bundle
ids, the dsh-web-ui-market settings section id, /api/dsh-web-ui-settings
and its proxy-token header, and the dsh-web-ui-telemetry-* storage keys.
Frozen history (docs/archive, docs/release-notes, archived notes), the
JAVA-LW fork reference, and local filesystem paths keep the old name.
npm migration: the next tag release dual-publishes @linxin666/dsh-web-all
alongside the final @linxin666/dsh-web-ui-all version, then the old name
is deprecated with a pointer; dual-publish lasts two releases.
Decision record: .agents/notes/implemented/architecture/2026-08-24-product-rename-dsh-web.md
Root and package instruction layers now describe shared/ as the single
source of truth for cross-package runtime modules and the sync-shared.mjs
generated copies as no-edit artifacts; development.md gains the edit loop;
the plugins.md budget figure now matches the manifest gate.