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.
4.8 KiB
RFC: Drop the unconsumed web observation surface — the providers-change event and the status methods
Status: implemented
Problem
WebService exposes an observation surface no production code observes:
web/providers-change(packages/web/web/src/index.ts) is declared and emitted on every provider registration and disposal, and each registration effect's rollback yield is ordered BEFORE the emit solely so a throwing change listener unwinds the registration. No listener exists outside the package's own two unit tests (one of which exists to pin that rollback ordering).searchStatus()/fetchStatus()and theWebCapabilityStatusunion (same package) have zero production callers:dsh-tool-webexecutes directly throughctx.web.search()/fetch()and surfaces unavailability as the structuredWebErrorcodes the seam throws at execution time (packages/web/tool-web/src/search.ts,packages/web/tool-web/src/fetch.ts); the only status callers are the web packages' own tests. The prose inpackages/web/tool-web/README.mdand architecture.md claims the tool "reads only the aggregatedsearchStatus()/fetchStatus()" — drift that survives only because nothing checks prose against call sites.
The seam's own design starves both surfaces of consumers: tool registration follows product ENABLEMENT, not provider availability (packages/web/tool-web/src/index.ts), and provider selection resolves at execution time, never cached — so there is no cache to invalidate, no registration set to recompute, and no caller that needs an availability probe distinct from executing and routing the structured error. HMR cleanup is carried by the effect disposers themselves.
This mirrors drop the unconsumed llm/adapter-change event, which removed the same notification shape, the same rollback-before-emit machinery, and the same listener-throw test from LlmService. That RFC's keep/cut criterion — keep tools/change for its plausible user-facing tool-list consumer, cut the boot-time backend-registry signal — puts a web-provider registry squarely on the cut side; the status methods are the same judgment applied to a pull surface instead of a push one.
Decision
The event declaration, both emits, and the rollback-before-emit ordering are deleted (the plain ctx.effect disposer carries HMR cleanup). searchStatus()/fetchStatus()/WebCapabilityStatus are deleted — the provider-private status() stays, since it feeds execution-time selection. The listener-throw rollback test that existed solely for the removed event is gone, and the emission assertions and every status-based assertion are rewritten onto the behavior a real caller observes: a successful search()/fetch(), or the structured WebError codes for unavailable/ambiguous/misconfigured provider sets. The cordis catalog is regenerated; packages/web/web/README.md, packages/web/tool-web/README.md (the drifted reads-status sentence), web.md, and the web paragraph in architecture.md describe the shipped contract; the web capability seam RFC's facts (it specified the event and the status aggregation) are amended per implemented/AGENTS.md.
Alternatives considered
Why not keep it?
The web seam RFC specified both deliberately — the event as a minimal HMR-visibility signal, the status methods as the tool's aggregated diagnostics — and a future provider-status panel is imaginable. But the same RFC's other choices starved them: derived-on-call selection and enablement-based registration leave no consumer that CAN need either, the shipped tool demonstrates the real pattern (execute and route the structured error), and the drifted README sentence shows the promised consumer never materialized. Per AGENTS.md "RFCs are proposals, not golden truth", these are the parts of that proposal the code has since shown to over-reach; a future observer reintroduces the smallest signal or query it actually consumes, shaped by that consumer.
Verification
No providers-change, searchStatus, fetchStatus, or WebCapabilityStatus spelling survives outside RFC history; the catalog is fresh (verify-cordis-catalog green); registration/disposal HMR-safety tests prove cleanup through execution behavior; and the tool-web README plus the architecture paragraph describe the execution-time error-routing contract the tool actually has.
Consequences
A future provider-picker UI or diagnostics panel that wants change notifications or a status query re-adds the smallest surface it consumes; the identical judgment, and its reversal condition, is already recorded on the llm precedent.