Files
deepseek-harness/docs/rfc/proposed/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.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

3.4 KiB

RFC: Trim unreachable ACP bridge surface — the branding knobs and the kind-sniffing fallback

Status: proposed

Problem

Two pieces of dsh-acp surface are unreachable from any shipped configuration:

  1. AcpConfig.agentName / agentVersion (packages/ui/acp/src/index.ts). The shipped app package hands the bridge only { model, systemPrompt } (packages/ui/acp-agent/src/index.ts), so no leaf cordis.yml — the only production config surface — can set the knobs at all; they are settable solely by direct-mounting the bridge, which only a unit test does. Every snapshot golden — the hook-matrix scenarios included — pins the schema defaults (deepseek-harness-acp / 0.0.1). The pair also carries a live TODO(double-default): the literals exist twice (schema .default(...) plus ?? fallbacks), with the TODO asking to pick one home.
  2. The toolKindFor name heuristic (same file) special-cases bash*/read*/write/edit* tool names in the generic-fallback path. Since the render-intent union, every first-party tool those arms match ships its own presentCall carrying its kind, and the presenter-less production tools (subagent, subagent_fork) fall through to other anyway. The arms are production-reachable only when a tool's presentCall THROWS (the containment fallback) — and the bridge's own module doc states the design rule the heuristic violates: "the bridge never special-cases tool names".

Proposal

Hardcode agentInfo at the initialize site ({ name: 'deepseek-harness-acp', version: '0.0.1' }), deleting the two config fields, their schema defaults, the ?? fallbacks, and the TODO(double-default) whose subject vanishes; drop the knob half of the direct-mount config test, the two rows in packages/ui/acp/README.md, and the packages/ui/acp/acp-feature-support.md cell that cites the knobs. Zero golden churn — the emitted wire value is unchanged. Replace toolKindFor with the constant 'other' in both fallback sites (the presenter fallback and nullToolPresenter) and delete the heuristic with its test rows.

Why not keep them?

agentInfo is client-visible branding a deployment will eventually want configurable — but a knob no shipped config can reach is not configurability, it is drift surface (the double-default TODO is its symptom), and the honest re-add must include the dsh-acp-agent plumb-through that does not exist today either; both arrive together with the deployment that needs them. For the heuristic: a hypothetical third-party presenter-less tool named read_docs would lose its inferred read icon — but inferring kinds from unknown plugins' names is exactly the special-casing the render-intent design rejected. The behavior delta on shipped paths is confined to the presenter-throw fallback, where rendering kind other makes the client show the raw input instead of a masquerading first-party card — strictly better diagnostics for a broken presenter.

Acceptance criteria

  • agentName/agentVersion and toolKindFor appear only in this RFC; snapshot goldens are byte-identical; bridge tests are green with the constant fallback.
  • The initialize handshake continues to report deepseek-harness-acp/0.0.1 (pinned by the handshake snapshot).

Risks

None beyond the presenter-throw rendering delta described above — an error path whose new behavior is more diagnosable than the old.