Files
deepseek-harness/docs/rfc/proposed/process/2026-06-20-discover-package-inventory.md
T
Tianyi Cui 9ebc38badf docs(rfc): revise the batch for the hooks-stack base; add three post-stack RFCs
The branch now bases on the hooks stack (PR #138's head), so every
'in-flight' reference to stack content became a current-state fact.
Audited all nine RFCs + three supplements claim-by-claim against the
merged tree (none invalidated; several strengthened):

- prune-dead-core-spine-surface: describe the landed tools/pre-execute →
  dispatch → tools/post-execute pipeline — listeners return Decisions,
  the registry builds every result and snapshots it to protect callId,
  and a second (mutation-guard) test pins the field; drop the resolved
  wait-for-interception hedge; scope the additionalContext ferry out.
- prune-producerless-vocabulary-variants: the ui-stdio fixture migrated
  off the continuation trigger (llm-replay is the sole writer now); the
  stack's own additions (rejected, prompt/blocked, hook/invoked+result)
  all arrived with producers — the admission policy demonstrated live.
- prune-unimplemented-subagent-vocabulary: enrichment landed as
  lastAssistantMessage only (agentType was dropped in the stack's own
  review — the same judgment this RFC extends); the seam RFC now names
  tools/pre-execute deny, which exists, sharpening the re-add path.
- drop-inert-request-knobs / drop-image-content-block /
  trim-acp-bridge-unreachable-surface: current-state rewordings (shipped
  bridges set no request fields; only compact-basic has explicit image
  arms; 13 hook goldens also pin agentInfo).
- generic-long-running-tool-runtime census: second production seam
  consumer (hook-protocol runHook: resolve+run, stdin/env, foreground
  only — background machinery stays single-consumer); scrub-duplication
  blast radius.
- discover-package-inventory: identical 54-entry tsconfig reference
  sets; the comparesLog scenario knob (fixture-derivable, like recorded).
- unify-agent-and-session-id: third divergence site (in-process subagent
  children mint two UUIDs), the hooks bridge id-lookups, and ui-stdio's
  labelBySession map as a consumer that deletes under unification.

New RFCs from the post-stack survey:
- remove-agent-steering-mirror: the last mirror-of-durable event; zero
  production listeners; both retention RFCs deferred its fate, and the
  'no durable twin' rationale is contradicted by the adjacent append.
- tighten-hook-protocol-contract: producer-less 'native' dialect,
  parsed-and-discarded suppressOutput, and hook/result semantics
  (truncation + decision-string) defined twice in the bridges instead
  of the lib that owns the event.
- single-source-acp-replay-config: cordis.yml/cordis.snapshot.yml differ
  by exactly one plugin entry, with no gate on the forced symmetry.
2026-07-04 11:24:44 +08:00

4.6 KiB

RFC: Discover package inventories instead of maintaining static lists

Status: proposed

Problem

Package and gate inventories are repeated by hand. The package cookbook tells authors to update several files. The package README carries a hand-written dependency graph. CI and development docs can drift from the actual doc-sync subcommands when new gates are added. tsconfig.build.json and the root tsconfig.json each hand-list every package as explicit project references — two identical sets that grow in lockstep, so a single generator can emit both — and tsconfig.base.json's paths map hand-lists the per-group glob fan-out. knip.json restates a per-package entry stanza for each package that gains an *.e2e.ts suite — byte-identical overrides that exist only because the shared packages/*/* stanza omits the e2e glob (an entry glob matching no files is inert, so the default stanza could carry it for every package). The ACP snapshot suite's scenario table (examples/acp-agent/tests/acp.snapshot.ts) hand-maintains a childSessions count per scenario that duplicates the number of session.<n>.jsonl fixture siblings on disk. These lists are small today, but every new package or scenario class creates another manual synchronization point.

The package hierarchy already removed several of these by hand: scripts/publint-all.ts now derives its list from the packages/<group>/<pkg> layout, and the two tsconfig paths maps collapsed to one @deepseek-ai/dsh-* wildcard. What remains is the inventory that cannot be globbed away — chiefly tsconfig.build.json's project references, which TypeScript requires as an explicit array (no wildcard form).

Static lists are appropriate when they encode policy; they are needless friction when they duplicate manifest data or layout facts that already exist in package.json, workspace globs, or the package hierarchy.

Proposal

Make the remaining package/gate inventories discoverable. A single canonical source — the packages/<group>/<pkg> hierarchy plus package manifests — should drive tsconfig.build.json's references, the module graph, and any other full-package list, with a generate-and-verify step (the existing gen-module-graph / gen-cordis-catalog pattern: a generator writes the artifact, a --check mode in hygiene/doc-sync fails on a stale committed copy). Module graph generation already reads package manifests. doc-sync should be the one command that defines and prints its sub-gates, with docs linking to that command rather than restating a second list.

The hierarchy does not need to encode every fact about a package, but it should encode the broad maintenance policy: core/product packages, integrations, capability seams, and support/test/example packages should not all require a hand-maintained exception list before scripts can tell them apart.

Two of the cataloged items need no generator at all: folding the e2e entry glob into knip's default stanza deletes the per-package restatements outright, and childSessions can be discovered from each scenario's fixture directory, leaving the scenario table to declare only policy (recorded, hasModelTurn, comparesLog) — and even those track fixture-derivable facts today (comparesLog ⟺ the committed log has entries beyond its header line; recorded ⟺ hasModelTurn with no replay.override.json sibling), so each new scenario class keeps adding knobs the fixture directory already answers.

Acceptance criteria

  • tsconfig.build.json project references are generated from the hierarchy (a generator emits them; a --check gate fails when the committed copy is stale), rather than hand-maintained.
  • Adding a package does not require editing a static package list for any gate.
  • Docs describe the source of truth rather than repeating generated inventories.
  • CI invokes the aggregate commands and lets those commands own their sub-gate lists.
  • knip.json carries a per-package override only where it encodes real information (an extra entry file, an ignored dependency), never a restatement of the default stanza.
  • Snapshot scenarios declare policy, not facts discoverable from their fixture directories.

What we give up

Discovery scripts can become too clever. The implementation should stay boring: read manifests, filter on explicit fields, print the resolved list, and fail loud. The payoff is removing manual inventory drift, not inventing a build system.