The package-invariant spec built its fixture with the range the rule no longer
accepts. knip stopped needing the tar ignore entry once the tarball helpers
became the one place that spawns it.
The harness packages declare the vendored framework as a peer, so installing
only the dsh tarballs left npm resolving @deepseek-ai/cordis from a private
registry the credential-free pack job cannot reach. The verification now takes
several pack directories and installs every tarball in them, and the dsh
workflow packs the vendored family for that purpose while still publishing only
its own set.
The verification also reads what each tarball declares instead of what the
checkout says, which is what let the process and tarball helpers become one
home each - the three copies of a spawn wrapper were a duplication finding.
The invariant companion rule pinned @deepseek-ai/dsh-invariants to a ^0.0.1
peerDependency, which the workspace protocol replaces; it now requires
workspace:^ like every other workspace-internal reference.
The release note stated the provenance risk by naming the internal repository,
which the public-link gate rejects in tracked files. It now states the same
constraint without naming it.
release:dsh takes major, minor, patch, or an explicit version and writes one
version across the family; release:vendor takes none and increments each
package's own patch, but only for packages whose published payload changed since
their vendor-<package>-v* tag. That tag is the record of the commit a package
last published from, so the change judgement needs no state file, and the diff
is filtered through the manifest's files rules - editing a vendored comment does
not trigger a release.
Both refresh the lockfile, commit, and print the tag to create after the commit
merges. --dry-run reports the plan and writes nothing.
Incrementing the release numbers is also what drops an upstream prerelease
segment: cordis 4.0.0-rc.7 publishes as 4.0.1, because a prerelease version
would not satisfy a consumer's plain range.
A throwaway consumer outside the repository declares every member as a file:
dependency, installs, and runs the installed executable with plain Node,
asserting the version it reports. That is the check a workspace link or a stale
lib/ in the checkout cannot pass for: it reads only what files selected.
The family declares its executable, so the vendored family — libraries a
consumer imports, with no executable — states that it has none instead of
carrying a probe that would prove nothing.
Both pack workflows run it after packing, still without credentials.
1504 hand-written ranges pointing at workspace members become workspace:^, so
pnpm pack substitutes each member's real version at publication: sibling
peerDependencies follow the family version instead of being pinned at ^0.0.1,
and a reference to a vendored package follows that package's own line. Without
this, publishing 0.0.2 ships peer ranges naming a version that does not exist,
and 0.0.1-rc.1 does not satisfy ^0.0.1 either.
It also retires ranges that had gone stale against the workspace: ^4.0.0-rc.6
for a 4.0.0-rc.7 checkout, ^3.17.0 for schemastery 3.18.0.
workspace:* stays where an exact published version is the point, which is how
the Landlock entry pins its platform packages.
A workspace constraint now requires the protocol, so a new package cannot
reintroduce a hand-written range. The same constraint caught packages/boot/cmdline
arriving on master without the publishable trio, which this change completes.
Every package under packages/, apps/, and vendor/ drops "private": true and
declares publishConfig.access "restricted": the repository now states which
packages it publishes instead of deciding it at publish time. Each one also
declares its repository and directory, which is how a consumer of a private
package reaches its source.
The Landlock packages move to restricted with them. They have never been
published, so nothing anonymous depends on them today, and the whole
@deepseek-ai scope stays private.
The workspace constraint that required every package to be private now applies
to non-members only, and asserts the publishable trio on each release member.
A release family owns its member discovery, version baseline, tag naming, and
packed-payload rule; the dsh family shares one version across packages/ and
apps/, while every vendor/ package keeps its own version line. Publish order is
topological over runtime dependencies so no package reaches the registry before
one it depends on.
pack packs the whole family into one directory and records the upload order;
publish decides per package against the registry, skipping a version whose
published tarball has the same integrity and failing when it differs, which is
what makes re-running publish over one artifact safe.
The vendored packages keep upstream's payload: their manifests export ./src/*,
so the harness rule that rejects sources and declaration maps would publish an
export map pointing at absent files.
A launcher provides three values before the tree mounts: ctx.cmdlineArgs
(get() is the whole interface) carrying everything after its own flags,
ctx.appExit for a bounded exit, and ctx.appPatches for decisions a later
recomposition must keep. An app's startup row injects cmdlineArgs and calls
runStartup() with its own commander program.
Rows the app configures inject its startup service, so they wait until the
startup row has resolved their values and provided it; --help prints,
disables those rows, and exits without the app ever starting.
A changed row is recycled — disabled, then re-enabled with its new values —
because a row's config is resolved when the Loader creates its fiber, while
the row is still waiting. Recycling never touches inject: an inject update
restarts the row from its unwrapped callback and loses the plugin's own
static injections. A mount still in flight is allowed to settle first, so
the disable has a fiber to dispose instead of racing one into existence.
Machine-produced by `pnpm run rescope-vendor --apply` plus the regeneration it
prints: `pnpm install` for the lockfile, `pnpm run gen-third-party-notices`,
`verify-translation-pairing --write` for the touched bilingual pairs,
`gen-doc-graphs`, and one typert snapshot whose ids embed character offsets.
`pnpm run rescope-vendor --check` verifies the result.
Renames nine vendored packages (cordis, cosmokit, schemastery and the six
@cordisjs plugins) and every reference that resolves them: manifest names and
dependency keys, module specifiers including declare-module merges, cordis.yml
plugin names, tsconfig paths, every Markdown fence, and `docs/` prose.
Directory names, upstream versions, and dependency ranges are unchanged, so
vendor/README.md still reads as an upstream snapshot; its manifest table gains
an upstream-name column so THIRD_PARTY_NOTICES keeps MIT attribution pointed
at each fork's origin.
The tutorial tier follows the rename end to end: its yaml fences named plugins
the Loader can no longer resolve, its `ts ignore-check` fences disagreed with
the compiled fences beside them, and its prose quoted both. The contracts that
told readers to keep upstream names — the root convention and the vendoring
cookbook's tree comment and manifest invariant — now say to rescope instead.
Two rules read `@deepseek-ai/` as "another workspace plugin": the client bundle
purity gate now names the vendored libraries a browser bundle inlines, and the
files where a bare `cordis` is an agent-preset id keep that product data.
Every harness package declares cordis as a peer dependency, so publishing the
harness publishes the vendored framework layer too; under the upstream names
that publication would squat them on the registry.
scripts/rescope-vendor.ts owns the rename: the nine-package mapping, a
delimited-token rule that leaves cordis.yml, the Loader's cordis: builtins and
vendor directory names alone, per-file exemptions where a name is a directory
or an upstream runtime identifier, and the exact edits for sites a token rule
cannot express — dot-notation lookups, unquoted manifest keys, a regex literal
whose failure would make every Context-merge scan silently find nothing, the
vendored-manifest table, and the contracts that told readers vendored packages
keep their upstream names.
Markdown follows the rename inside every fence, because a fence is code a
reader copies or configuration they mount, and in `docs/` prose as well, where
a sentence quoting a name teaches something this repository no longer resolves.
Prose elsewhere records what was true when it was written, and the same
spelling can mean something else: the Python SDK's `cordis` option, or the
unvendored `@cordisjs/plugin-http`. `docs/rescope.md` states both names on
purpose and is exempt.
exactEditState() classifies every exact edit as pending, applied, or invalid.
An insertion keeps its anchor and a deletion keeps its remainder, so each side
counts the form that survives: a duplicated insertion, a half-applied
replacement, and a deletion whose remainder moved are all invalid. The run
classifies every edit before writing anything and aborts on the first invalid
one, so a disagreement between the mapping and the tree cannot leave a
half-rescoped checkout; each write re-reads its file, because two edits can
target one. rescope-vendor.spec.ts pins those rejections, and --check asserts
the whole post-state from the hygiene gate, so CI owns the invariant.
--reverse restores the upstream names, verified as a round trip: reverse, then
apply, reproduces this tree byte for byte.
docs/rescope.md is the consumer-facing reference: the old-name/new-name table
with each package's role, what the rename deliberately leaves alone, the sites
callers must change, and the commands to apply, verify, and revert. The Agent
Note carries the decision and its consequences.
The rename itself lands in the next commit, produced by running the script.
A delegated in-process child now acts only within the sandbox scope fixed
at delegation: captureDelegatedPolicyOverrides still snapshots the parent's
explicit sandbox override but pins the child approval policy to 'never'
(instead of inheriting the parent's), so every child ask — sandbox_permissions
escalations included — is rejected deterministically by ApprovalService
before any answerer, with the audit pair still logged. Every in-process
child additionally receives the scoped subagent:delegation runtime-context
statement telling it to report a scope limitation instead of retrying.
Supersedes the approval half of the policy-inheritance decision (new Agent
Note cross-linked from both prior notes and the approval-seam Q&A); refreshed
child snapshot fixtures carry the pinned event, and
subagent-published-run-failure now persists a one-event child log.
The generated matrix under-reports client-face listeners because the program
is seeded from the host aggregate alone, so `session/preset-changed` lists
`ui-command` without `ui-skill` — the same shape as the existing
`connection/reset` and `models/changed` rows. Record it where the collector
lives, with what closing it actually takes.
Presets own the rows that decide what a session's `/` menu contains, but
both browser catalogs cache per session and had no invalidation edge for a
recompose: `commands/changed` is registry-wide and recomposing registers
nothing, so the menu kept serving the composition the session no longer ran.
The host stream now frames the logged `agent-preset/selected` commit as
`host/session-preset-changed`; the runtime bridges it to the typed
`session/preset-changed` event, `ui-command` soft-refreshes that session's
directory key and `ui-skill` invalidates its catalog entry.
Reaching the host on a second switch was a separate defect: the list-row
identity guard compared every summary field except `agentPreset`, and the
merge keeps the row's `updatedAt`, so a switched row looked unchanged and
served its cached instance forever. The hero chip compares the pick against
that row, so switching back to the creation-time preset sent no RPC at all.