Commit Graph
176 Commits
Author SHA1 Message Date
Tianyi Cui d45e470192 fix: retarget the i18n pairing exclusions to the flattened catalog paths
The manifest excluded docs/tool-catalog/ and docs/persistence-catalog/ as
directories; the trailing slash is a deliberate path boundary, so the
flattened single files no longer matched and lost their generated-doc
classification — the gate would have accepted a hand-added .zh.md twin it
must reject. The entries now name the files.
2026-07-07 00:08:55 +08:00
Tianyi Cui 4e2da27201 Merge branch 'config-catalog' into catalog-flatten 2026-07-07 00:06:19 +08:00
Tianyi Cui f0ef280848 fix: identity-check name resolutions across the pasted closure; exclude the catalog from i18n pairing
Review findings on the config catalog:

The transitive-paste closure deduplicated by bare name, so two DIFFERENT
package-local declarations sharing a name would silently collapse to the
first one pasted — and a reference satisfied by the wrong declaration is a
wrong catalog, not just a thin one. Every resolution is now identity-checked
by source pointer: reaching the same declaration again is benign, while a
name that resolves to two distinct declarations, to conflicting imports, or
to a declaration in one file and an import in another is a violation — a
verbatim fence has a single flat namespace, so the fix is a rename at the
source. A spec case pins the two-declarations collision.

docs/config-catalog.md also joins the translation-pairing exclusions: it is
a generated English-only doc, and without the entry the gate would accept a
hand-added .zh.md twin it must reject.
2026-07-07 00:00:34 +08:00
Tianyi Cui 82dfc62620 Merge branch 'config-catalog' into catalog-flatten 2026-07-06 23:38:40 +08:00
Tianyi Cui fe815c9586 Merge remote-tracking branch 'origin/master' into config-catalog
# Conflicts:
#	docs/rfc/INDEX.md
2026-07-06 23:31:58 +08:00
Tianyi Cui 6d9a4f1258 Merge branch 'config-catalog' into catalog-flatten
# Conflicts:
#	docs/config-catalog.md
#	scripts/gen-config-catalog.ts
2026-07-06 23:16:29 +08:00
Tianyi Cui fb3f3a69ec fix: extend the schema cross-check to nested key paths; scope the catalog framing
Review findings on the config catalog:

The schema-subset check compared only top-level z.object keys against
top-level type members, so a nested loader-accepted key (agents[].id,
agentOptions.model, capabilities.*) missing from the declared type would
pass the gate unseen. The walk now collects nested object/array
compositions as key paths and resolves each against the declared config
type — through interfaces (heritage included), aliases, literals,
intersections, unions, arrays, indexed access, Partial-style wrappers, and
type references across package-local and workspace imports (re-export
chains included). The check stays presence-only and one-directional, and
only a definite miss is a violation: a path crossing a type the walk
cannot enumerate (an external package's) is skipped, never mis-reported.
The recursion guard applies at named declarations only — a structural
first child shares its span start with its parent, so a span-keyed guard
on every node mistakes ordinary descent for a cycle and silently turns
definite misses into unknowns.

The page and RFC framing also overstated the catalog as the exact
cordis.yml-settable surface: the paste is the plugin's full declared
config type, and a field the runtime schema deliberately excludes (the ACP
bridge's test-injected stream) is a runtime-only seam its own JSDoc marks.
Both now say so.

Five spec cases pin the new behavior: nested hidden key, workspace
intersection via star re-export, Partial wrapper, indexed-access
composition, and the external-type unknown path.
2026-07-06 23:06:03 +08:00
Tianyi Cui 116e2c45a8 docs: flatten single-file catalog dirs to docs/tool-catalog.md and docs/persistence-catalog.md
A directory holding exactly one file adds a path level for nothing;
cordis-catalog/ keeps its folder because it holds two sibling pages
(events.md + services.md), matching config-catalog.md which was born flat.

docs/tool-catalog/tools.md -> docs/tool-catalog.md and
docs/persistence-catalog/log-events.md -> docs/persistence-catalog.md; their
generators' OUT paths and in-page relative links drop one directory level,
and every citation repo-wide (docs, RFCs, package READMEs, generator
headers) is updated. graph-atlas.md, config-catalog.md, and the doc graphs
regenerate with the new paths.
2026-07-06 22:26:06 +08:00
Tianyi Cui b0c7eadd23 feat: generated plugin config catalog (docs/config-catalog.md)
scripts/gen-config-catalog.ts walks every packages/<group>/<pkg> entry with
the TypeScript compiler API and emits docs/config-catalog.md: per loadable
plugin, the verbatim config declaration (JSDoc included) its apply/constructor
receives in a ts config-catalog fence, the inject requirements, resolved links
for every referenced type (package-local types pasted transitively, other
plugins' config types as intra-page anchors, LINK_MAP names to
core-data-structures, workspace types to source), and terse classification
lists for config-free plugins, abstract seams, and libraries — classification
is total, so a new package cannot go undocumented.

The walk enforces per-field JSDoc prose on every pasted declaration and
statically cross-checks the schemastery schema (z.object keys, z.intersect
composition across packages): every schema-validated key must be a declared
member of the config type. One violation existed repo-wide — the agents[].id
field in dsh-agent-loop — fixed by adding its JSDoc (which shifts the
cordis-catalog services page's source pointers; regenerated).

verify-config-catalog (--check) joins doc-sync; doc-typecheck learns the
ts config-catalog fence; gen-cordis-catalog exports its JSDoc/pointer helpers
and LINK_MAP for reuse. Negative-path spec in
packages/core/agent-core/tests/gen-config-catalog.spec.ts mirrors the
gen-cordis-catalog spec. Decision record:
docs/rfc/implemented/process/2026-07-06-generated-config-catalog.md (includes
the deliberate acceptance of README ## Config overlap).
2026-07-06 21:57:17 +08:00
Tianyi Cui c57c7527a5 Merge branch 'master' into codex/parallelize-ci 2026-07-06 21:54:07 +08:00
Hypatia May 41e1955ace Clarify condensing in doc budget guidance 2026-07-06 16:31:18 +08:00
Tianyi Cui c0808d5126 docs: the governing principle — every LLM request is reconstructable from the session log
The reconstructability RFC is the principle's home: model-visible ⟺
logged in both forms, the mechanism (boundary derivation + header
fold), the enforcement (write-time round-trip guard, the dev
invariant), the corollaries ranked (prefix-cache stability first), the
MiniCode lineage with the provenance arrow inverted, and the
alternatives it beat — including the stateful transmission client
whose three-design archaeology lives in PR #162.

Placements per the one-home-per-fact taxonomy: a standing-order line in
root AGENTS.md (with displacement trims to stay inside the 1,575-word
ceiling), the principle statement in architecture.md § Session Log and
its Turn Flow lines (condensed to the ratcheted 1,630 ceiling), the
request-envelope section in core-data-structures/core.md with the
LlmCallConfig paste, both review-requested FIXMEs
(FIXME(call-config-shape) beside the type, FIXME(catalog-verbs) at the
catalog's drift-gate note), cookbook rows redirected off agent/request
(tool filtering → system-prompt/assemble, plan-mode prompt → sections/
inject()), and the llm/stream JSDoc stating the frozen-request
contract. RFC index and all generated catalogs regenerated.
2026-07-06 03:49:35 +08:00
Tianyi Cui 1b9408268b ci: cache eslint lane 2026-07-06 03:07:35 +08:00
Tianyi Cui 2093a8898b loop: every request is built from the log — boundary snapshot, header events, config-only waterfall
The loop is now transmission-stateless; a request is a pure function of
(session log, this step's rendered assembly, current AgentOptions):

- The reconstruction boundary is step/start: the messages snapshot is
  taken in the same synchronous frame immediately before the step/start
  append, so the request's messages are exactly the derivation over
  events[0..stepStartSeq) — an inject() from an agent/request listener
  (or any concurrent task) lands after the boundary and joins the NEXT
  request. This changes behavior for a synchronous step/start
  session/event listener that appends content (master derived after the
  append, so such a listener could reach the current request):
  agent/pre-step is the sanctioned seam for current-request content.
- agent/request is re-typed to config-only: (agent, turn, step,
  config: LlmCallConfig, next) → LlmCallConfig. The frozen seed comes
  from AgentOptions on a loop instance's first request (explicit options
  beat the logged baseline — fork overrides and resume reconfiguration
  stay correct) and from the log's folded header afterwards; listeners
  return a replacement to switch. Content shaping through the request is
  no longer expressible — model-visible content flows through the log
  channels.
- recordRequestHeader appends whatever header event the request owes the
  log before dispatch: an 'initial'/'resume' snapshot anchoring each
  loop instance, a round-trip-verified delta on change, a 'fallback'
  snapshot when the encoding cannot express it. Session.requestHeader()
  is the log's incrementally-folded baseline.
- Requests are deep-frozen before dispatch (deepFreeze exempts the
  AbortSignal — freezing one breaks AbortController.abort() outright);
  frozen + sessionId is the loop-built marker the dev invariant keys on.

Ported from #162 and re-anchored on the log: the append-extension /
frozen-end-to-end / compaction-resend / prompt-change property tests,
plus new specs for the boundary semantics, resume anchoring, and the
end-to-end theorem (every recorded request rebuilds byte-equal from the
log alone). Live cache-hit e2e (request-cache.e2e.ts) verified against
the real DeepSeek API. Snapshot goldens intentionally stale until the
single re-record after the compact/summary envelope lands.
2026-07-06 03:07:34 +08:00
Tianyi Cui d71c96a44c ci: keep lint lane serial 2026-07-06 02:59:50 +08:00
Tianyi Cui 09326fd84a ci: split lint lane internally 2026-07-06 02:56:23 +08:00
Tianyi Cui 5efc449af0 ci: keep static lane source-only 2026-07-06 02:43:42 +08:00
Tianyi Cui a7b569850b session: the request header becomes logged state — request/header events + fold/diff/apply
Every conversation request's non-content half (system prompt, tool
schemas, call config — the EpochHeader) is now recorded in the session
log: a 'request/header' full snapshot (reason 'initial' | 'resume' |
'fallback') anchors the fold at conversation birth and process
boundaries, and 'request/header-delta' events (system line-trim,
name-keyed tools delta, whole config) encode mid-run changes. The pure
trio — foldRequestHeader / diffHeader / applyHeaderDelta — reconstructs
the header any request was built under from the log alone; the writer
contract round-trip-verifies every delta with a 'fallback' snapshot
when the encoding cannot express a change (pure tool reordering), so a
well-formed log always folds cleanly. Canonical absence: empty system
and empty tools normalize to absent fields, matching request builds.

Persistence and cordis catalogs regenerated; SessionEventMap paste and
EpochHeader added to the core-data-structures session page.
2026-07-06 02:42:51 +08:00
Tianyi Cui 2d80d868be ci: isolate lint and tune coverage lane 2026-07-06 02:39:26 +08:00
Tianyi Cui 7cd4868056 ci: split primary gates into broad lanes 2026-07-06 02:22:22 +08:00
Tianyi Cui d9c401d27a Merge remote-tracking branch 'origin/master' into codex/parallelize-ci 2026-07-06 01:59:49 +08:00
Tianyi Cui 0452261b5b Merge parallel pre-push gates into CI scheduler 2026-07-06 01:47:13 +08:00
Tianyi Cui 5caceee380 Move ACP snapshot replay doc into package 2026-07-06 00:52:06 +08:00
Tianyi Cui 72c83c771a chore: parallelize pre-push gates 2026-07-06 00:52:00 +08:00
Tianyi Cui 0e29de459e docs(rfc): address Codex review — fence-aware format gate, exact corpus counts
Two findings from the pre-ready review, both verified:

- verify-rfc-format scanned raw lines, so an RFC quoting a Status line,
  a banned heading, or the grandfather comment inside a fenced example
  would false-positive. The content scans (duplicate Status, H2 headings,
  banned headings, grandfather, legacy marker) now ignore fenced blocks;
  the positional header-block checks stay raw. Verified: a fenced
  'Status: implemented' + '## Plan' + grandfather quote inside a walked
  RFC no longer trips the gate.

- The companion RFC's pre-format corpus counts were imprecise: 27
  distinct Status spellings (reasons collapsed), not 'some fifteen';
  nineteen implemented files carrying thirty proposal-era heading
  occurrences, not 'over twenty files'; three English files (plus one zh
  counterpart) with no status, not four.
2026-07-05 23:45:34 +08:00
Tianyi Cui e6fad266a6 docs(rfc): define and enforce a uniform RFC format; adopt it across the corpus
Define the in-file RFC contract in docs/rfc/README.md § The file format:
the header block (`# RFC: <title>` plus a dateless Status enum
cross-checked against the lifecycle folder), the per-lifecycle body
skeleton (a Problem opener everywhere; Proposal/Alternatives considered/
Acceptance criteria/Risks in proposed/; present-tense Decision/
Consequences with proposal-era headings banned in implemented/; the
frozen proposal shape in rejected/), and a mandatory Alternatives
considered section with a date-fenced grandfather comment for pre-format
RFCs whose alternatives are not reconstructible from the record.

Enforce it with a new doc-sync gate, scripts/verify-rfc-format.ts, and
normalize all 112 RFCs to it: ~15 Status-line spellings collapse to the
enum, 29 Context openers become Problem, the 39 legacy-format XXX debt
markers are resolved and banned from reappearing, proposal-era sections
in implemented RFCs are rewritten to shipped reality (including the
web/fs/subagent seam RFCs' migration plans and test checklists, closing
the doc-tiers deferred-work item on the web seam), every RFC gains an
Alternatives considered section or the grandfather comment, and the
bilingual pair is re-mirrored and re-recorded.

Move the generated index tables out of README.md into a fully generated
docs/rfc/INDEX.md — gen-rfc-index now writes the whole file, and
verify-rfc-classification checks its freshness and rejects index-shaped
rows in the curated README — which makes room for the format contract to
live in the README front door instead of a separate FORMAT.md.

The decision record, and the first RFC written in the new format, is
docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.md.
2026-07-05 22:58:25 +08:00
Tianyi Cui d899333cde docs: split cordis primer from architecture map 2026-07-05 19:07:34 +08:00
Tianyi Cui fdd65269f9 docs: synthesize architecture rewrite 2026-07-05 18:51:52 +08:00
Tianyi Cui 96055d1763 docs: rewrite architecture intro 2026-07-05 03:32:11 +08:00
Tianyi Cui a06e5f1c87 Merge remote-tracking branch 'origin/master' into codex/docs-graph-brainstorm
# Conflicts:
#	docs/architecture.md
2026-07-05 03:09:32 +08:00
Tianyi Cui 54a3c8b2a4 docs: address graph review placement 2026-07-05 02:54:01 +08:00
Tianyi Cui 8e70efcfcc Merge remote-tracking branch 'origin/master' into codex/docs-graph-brainstorm
# Conflicts:
#	docs/architecture.md
#	docs/development.i18n.yaml
#	docs/development.md
#	docs/development.zh.md
2026-07-05 02:16:26 +08:00
Tianyi Cui a1a660823f Merge remote-tracking branch 'origin/master' into worktree-arch-doc-drop-layering
Master split the cordis catalog (d55d4120) while this branch was in review.
Resolution: keep this branch's Service map restructure, adopt master's split
catalog link targets (events.md / services.md), and regenerate the catalog so
the waterfall-semantics anchor fix lands in the split output.
2026-07-05 02:15:30 +08:00
Tianyi Cui 5d97374a59 Merge remote-tracking branch 'origin/master' into codex/docs-graph-brainstorm
# Conflicts:
#	docs/module-graph.md
#	package.json
#	packages/core/tools/tests/gen-tool-catalog.spec.ts
2026-07-05 01:53:13 +08:00
Tianyi Cui 1316022cc8 docs: revise graph docs from review 2026-07-05 01:25:58 +08:00
Tianyi Cui 8dd8ce21db docs: make the service map the front door of architecture.md
The Layering ASCII diagram was cluttered, lumped THE concrete loop plugin
undifferentiated into a grab-bag plugins box, omitted dsh-agent-core and the
app packages, and restated the dependency rule that packages/README.md
already owns — while being the first thing a reader linked from README hits.

- Drop the Layering section; the tier story becomes one intro sentence and
  the dependency rule a one-line Service map footer linking
  packages/README.md#dependencies.
- Split the Service map into the spine (packages/core/) vs the swappable
  capability seams; annotate ctx.agentLoop as THE concrete loop plugin.
- Promote Cordis waterfall semantics to a top-level section placed before
  first waterfall use; drop '(important)' from the heading (anchor swept:
  AGENTS.md, gen-cordis-catalog.ts + regenerated catalog).
- Promote Event taxonomy to a top-level section (anchor unchanged).
- Retitle 'The vocabulary (dsh-llm)' to 'Content blocks and streaming
  (dsh-llm)' so the heading names its content (citation swept:
  llm-streaming.md).

Net -29 words (1851 -> 1822); the 1890 ceiling stands, keeping the
manifest's working margin.
2026-07-05 01:22:17 +08:00
Tianyi Cui 816a9f15f6 Merge remote-tracking branch 'origin/master' into split-cordis-catalog
# Conflicts:
#	docs/cordis-catalog/events.md
2026-07-05 01:22:05 +08:00
Tianyi Cui e06807ce0e Merge remote-tracking branch 'origin/master' into codex/app-attribution-rfc 2026-07-05 01:00:40 +08:00
Tianyi Cui b9e2d7ed85 Merge master into app attribution RFC 2026-07-05 00:45:39 +08:00
Tianyi Cui 25e02ae9a8 Split the cordis catalog into separate events and services documents
gen-cordis-catalog.ts now emits docs/cordis-catalog/events.md and
docs/cordis-catalog/services.md instead of the combined
events-and-services.md: a reader is either finding what to listen to or
what to call, and each axis now scans and deep-links as its own page.
Headings promote one level (scopes and ctx.<key> entries become H2), the
dispatch-mode legend lives on the events page, and the inherited tier
splits accordingly. --check verifies both files and names whichever is
stale.

Every reference updated in the same change (no compat redirects,
pre-release stance): architecture.md, AGENTS.md, docs/AGENTS.md tier row,
filesystem/subagent core-data-structures pages (the ctx.fs anchor
survives — slugs are heading-level-independent), fs README, four RFCs,
the tool-catalog and persistence-catalog generator intros (both
regenerated), and the bilingual development.md pair (re-recorded).
2026-07-05 00:45:06 +08:00
Tianyi Cui 2c9e5ee756 Merge remote-tracking branch 'origin/master' into persistence-log-catalog 2026-07-04 23:41:57 +08:00
Tianyi Cui 2728e3bd5b Close remaining keyof-join holes the review verification found
- The owning top-level interface SessionEventMap must now be the SINGLE
  EXPORTED declaration in @deepseek-ai/dsh-session: a non-exported local
  interface (even inside the owning package) and a second exported copy
  are hard errors, so a same-named helper can no longer be catalogued as
  the on-disk vocabulary.
- Any SessionEventMap declaration carrying an extends clause is a hard
  error: inherited keys join keyof SessionEventMap but have no catalog
  row, so heritage is a silent-skip path the gate must reject.

Three new spec cases; RFC and module doc updated to match.
2026-07-04 23:21:23 +08:00
Tianyi Cui c64cfbbe5d Merge remote-tracking branch 'origin/master' into simpl-a3-knobs
# Conflicts:
#	docs/rfc/README.md
2026-07-04 23:17:51 +08:00
Tianyi Cui 53dc3c8a28 Harden generator against Codex review findings
- A SessionEventMap member that is not a property signature with an
  explicit payload type is now a hard error instead of silently skipped —
  a method-form or type-less member joins keyof SessionEventMap and must
  not escape the catalog.
- A top-level interface SessionEventMap outside @deepseek-ai/dsh-session
  (ownership read from the package manifest) is now a hard error — an
  unrelated same-named local interface was previously catalogued as the
  on-disk vocabulary.
- JSDoc tag detection runs on the trimmed line, so an extra-indented
  '*  @mode' can no longer bypass the forbidden-tag check and leak into
  prose.

Four new spec cases cover these; RFC and module doc updated to describe
the enforced (not just assumed) invariants.
2026-07-04 23:11:42 +08:00
Tianyi Cui 232f314c3a Add generated persistence log event catalog with freshness + completeness gates
docs/persistence-catalog/log-events.md enumerates every SessionEventMap
member — the owning dsh-session vocabulary plus the dsh-compact and
dsh-hook-protocol declaration merges — with payload, surface/log-only badge,
JSDoc prose, and declaration site. scripts/gen-persistence-catalog.ts is a
pure AST pass in the gen-cordis-catalog mold: verify-persistence-catalog
(--check) joins doc-sync, so a stale committed catalog fails pre-push and CI.

The walk enforces JSDoc completeness (every member needs description prose;
@mode is rejected as a category error — log events do not dispatch on the
cordis bus), derives the surface badge from the SurfaceEventType union with a
stale-member cross-check, and hard-errors on duplicate declarations. Payloads
render through the TypeScript printer so newline-separated multi-line type
literals still emit valid one-line fragments.

Documented the five previously JSDoc-less core events (turn/step boundaries,
tool/call), removed the two stray @mode tags on the hook/* merges, and
replaced the hand-restated event enumerations (session.md hook/* table,
compact README table, hook-protocol README bullets, session README name-list
— whose merge note had already drifted) with links to the catalog. RFC:
docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.md.
2026-07-04 22:58:28 +08:00
Tianyi Cui 3977f1d63c Merge remote-tracking branch 'origin/master' into codex/docs-graph-brainstorm
# Conflicts:
#	docs/architecture.md
#	docs/development.i18n.yaml
#	docs/development.md
#	docs/development.zh.md
#	docs/rfc/README.md
#	package.json
2026-07-04 22:39:16 +08:00
Tianyi Cui 663e57c6d6 Merge branch 'simpl-a2-vocab' into simpl-a3-knobs
# Conflicts:
#	packages/core/tools/src/index.ts
2026-07-04 21:20:55 +08:00
Tianyi Cui 1905c809e3 Merge remote-tracking branch 'origin/master' into simpl-c-web-observation
# Conflicts:
#	docs/architecture.md
#	packages/web/web/src/index.ts
2026-07-04 20:54:42 +08:00
Tianyi Cui 3a66b336a2 Merge remote-tracking branch 'origin/master' into simpl-0-rfc-index
# Conflicts:
#	AGENTS.md
#	docs/rfc/README.md
2026-07-04 20:29:57 +08:00
Tianyi Cui a29bbe1453 Add JSDoc completeness gate for the cordis surface
gen-cordis-catalog now hard-errors (aggregated, not fail-fast) when an
event lacks description prose or a payload @param, or a public service
method lacks JSDoc, a @param per parameter, a @returns on a non-void
result, or an explicit return type annotation. The this receiver and the
trailing waterfall next are exempt on events (mode machinery owned by
@mode); a stale @param naming no real parameter errors, mirroring the
@mode contradiction check. parseJsDoc now ends prose at the first block
tag (standard JSDoc semantics), so the tags never change the rendered
catalog — only Source: line pointers moved.

Fills the ~139 gaps found across the 15 surface files, extends the spec
with negative-path fixtures for every new guard plus the exemptions,
records the decision as an implemented process RFC, and extends the
AGENTS.md typed-events bullet with the authoring rule. Runs inside
verify-cordis-catalog -> doc-sync, so CI and pre-push enforce it with
zero new wiring.
2026-07-04 19:06:35 +08:00