build:artifacts produces every artifact, including the tsdown bundles,
the Desktop bundle, and Web, so naming it after sources undersold it;
build:check checks scripts, benchmarks, and website code besides tests.
The build.ts scopes, aggregate step ids, the Python builder flag
(--build-artifacts), workflows, callers, docs, and the build-split Agent
Note follow the new names. The note also records the naming
alternatives.
Refs #5852
pnpm run build ran every step in one serial chain, including the two
noEmit aggregate programs (tests, scripts, benchmarks, website) that no
artifact step consumes, so the Host aggregate check alone delayed tsdown by
about 66 s.
- build:src (scripts/build.ts --scope src) builds every artifact in the
existing order and writes the client build record; it replaces the
removed --artifacts-only flag and the libraries CLI mode.
- build:test (--scope test) type-checks only the Host and Client aggregate
programs with tsc -p, concurrently, without compiling references or
checking prerequisites.
- build runs both as one dependency graph through run-gates' new
runAggregate: each aggregate check starts once its face's packages are
compiled, and Client compilation stays after the Host bundle that writes
the Typert /remote declarations. DSH_GATE_CONCURRENCY=1 serializes it;
DSH_GATE_FAIL_FAST=1 stops the remaining steps at the first failure.
Passing steps print one PASS line (DSH_GATE_VERBOSE=1 shows their output).
- PR artifact builds (e2e, release, preview, Node 22 compatibility) and the
Python builder (--build-src) use build:src; dev:web and dev:desktop use
build:src. test:*, bench, typecheck and the required consumer/Windows
lanes keep the complete build.
- lint, lint:fix, doc-typecheck and the Typert contracts gate prepare with
host-libraries (Host package compilation + Host bundle) instead of
build:lib:host; their own checks never read the aggregate root or the
Desktop bundle.
Parallel and serial build produce byte-identical lib/, Web dist and client
build record; a test-only type error fails build and build:test while
build:src passes.
Refs #5852
Set DSH_E2E_MAX_WORKERS=4 for the credentialed e2e workflow and pin that environment contract in the workflow test. Profile-launched SDK and ACP scenarios each boot a complete subprocess tree, so the previous file-level fan-out could multiply process and provider pressure far beyond the runner's useful concurrency.
The bound changes scheduling only: every e2e file still runs, the Vitest configuration retains its explicit override knob, and local callers can choose a different positive worker count when their resources allow it.
apps/cli/cordis.yml now bakes in the production OTLP endpoint; CI boots of
the web composition (e2e, snapshots, built smokes) must not stream test
sessions there. DSH_TELEMETRY_DISABLED=1 at the workflow level disables
the telemetry row before its load-time url validation; the telemetry e2e
still runs — it overrides the variable to empty for its child process and
points DSH_TELEMETRY_OTLP_URL at its in-test collector.
Convert the hand-rolled corepack + store-path + actions/cache pnpm setups
to pnpm/action-setup@v4 + setup-node cache: pnpm (the landlock-run.yml
pattern) in e2e.yml, docs-pages.yml, pi-ai-provider-e2e.yml,
build-exe-for-python-sdk.yml, and ci.yml's node-compat and benchmark
jobs. The enterprise restore-only PR jobs and the Windows job keep their
documented asymmetries; serial-linux keeps its hand-rolled store cache
because it produces the exact key those restore-only jobs consume, and
only swaps corepack for the action.
Implements and moves the CI-caching Agent Note from PR #667 to
implemented/, recording the serial-linux producer exception and the
exact-key (no restore-keys prefix) behavior of setup-node's cache.
sandbox-acp-agent's whole surface moves into examples/acp-agent following
the example's existing multi-variant shape (the code-mode/both-mode
overlays): sandbox.cordis.yml + its replay overlay, the four snapshot
scenarios (config-options / mode-switching / escalation-approved /
escalation-rejected) as a 'sandbox' header class over per-scenario
configPath — goldens byte-identical, zero re-recording — and
escalation.e2e.ts unchanged apart from the config path. One ACP example
remains; demo:sandbox-acp keeps its name and boots the variant. References
(both RFCs, group/package READMEs, the examples table and test map, the
e2e workflow comment) now point at the variant.
The three-entry cordis.yml (dsh-sandbox-local + dsh-bash-sandbox at a
read-only default + dsh-approval) served over ACP: the first live approval
composition. Recorded snapshot scenarios pin the wire end to end —
config-options advertisement, the mode-switching arc as the suite pinned
header (both switches, the prompt-section delta, one changed-by-the-user
notice per knob, a confined write landing under the switched mode), and
both escalation branches over scripted permissionAnswers (a grant runs
confined under workspace-write; a rejection executes nothing and pins the
fail-closed text). The with-key escalation e2e drives a real model +
real runner + the real bridge answerer, world-verified; ci.yml snapshot
lane and e2e.yml install bubblewrap so the confined replays actually
execute.
Both RFCs move to implemented/ (Decision/Consequences form, deferred
phases tracked in their own sections), with every cross-reference flipped.
Add a second axis to every RFC — its class (feature, bug-fix,
simplification, architecture, process, testing) — encoded in the path
as docs/rfc/{lifecycle}/{class}/file.md. The folder is the label, so
the closed set is enforced by structure rather than a parsed field.
Two new doc-sync gates back it:
- verify-rfc-classification: every RFC sits in a valid class folder and
the README index lists it under the matching lifecycle→class heading.
- verify-doc-refs: every docs/*.md path cited in a packages|examples TS
comment resolves — closes a drift class verify-md-links can't see, and
catches the four comment refs this reorg moved.
The README gains a Classification section explaining the taxonomy and
per-class index sub-sections. A self-referential process RFC records why
the scheme is path-encoded and gated.
Adds docs/rfc/implemented/2026-06-19-real-api-e2e-ci.md covering the rationale
for running the real-API e2e suite in a separate secret-consuming workflow, the
fork/Dependabot/secret threat model, the residual exposure of the pull_request
trigger, and what changes when the repo goes public. Indexes it in the RFC
README.
Also adds a SECURITY comment on the pull_request trigger forbidding a switch to
pull_request_target (an untrusted-code-with-secrets leak vector, especially once
public), pointing at the RFC.
Adds .github/workflows/e2e.yml, which runs `pnpm run test:e2e` against the
external DeepSeek API (https://api.deepseek.com) using a DEEPSEEK_API_KEY repo
secret. ci.yml stays keyless/forkable; this is a separate, secret-consuming
workflow that fills the gap of nothing in CI exercising the with-key suites.
- Triggers: workflow_dispatch + push to main/master + nightly schedule +
pull_request. A job-level `if:` skips untrusted PRs (forks + Dependabot, both
keyless), keying the Dependabot test on the PR author (pull_request.user.login)
not github.actor. A job-level skip reports as success, so this is safe as a
required check.
- Unconditional preflight hard-fails on a missing secret so the self-skipping
suite can't report a false green when the key is misconfigured.
- Secret scoped to the preflight + e2e steps only; permissions: contents: read;
DEEPSEEK_BASE_URL pinned to the external API; single Node 24; timeout 45m;
cancel-in-progress only for PR runs.
Plan converged with Codex (gpt-5.5:xhigh) over 3 review rounds.