mirror of
https://github.com/ultraworkers/claw-code.git
synced 2026-04-27 15:10:54 +08:00
roadmap: #268 filed
This commit is contained in:
parent
d90b5f02ec
commit
62b20c7a46
20
ROADMAP.md
20
ROADMAP.md
@ -16972,3 +16972,23 @@ Gap. This is distinct from #262 but sibling-shaped. #262 filed the missing `--ma
|
|||||||
Required fix shape: (a) define a delimiter contract for `prompt TEXT`: either require all flags before `prompt` and reject any `rest[1..]` token that starts with `-` unless escaped via `--`, or parse `prompt` as consuming exactly one TEXT argv and then resume global flag parsing; (b) support `--` as an explicit literal-prompt delimiter so users can intentionally include flag-looking text (`claw prompt -- "explain --max-turns"`); (c) emit a typed `CliFlagWarning`/`cli_parse` JSON error when a flag-looking token appears after the prompt without `--`; (d) add parser tests for `prompt x --max-turns 0`, `prompt x --output-format json`, `prompt x --definitely-unknown`, `prompt -- "x --max-turns 0"`, and `--output-format json prompt x`. Acceptance: the documented `prompt TEXT` path no longer silently mutates trailing control tokens into model input; fixes for #262 cannot pass while leaving this long-form parser site greedy.
|
Required fix shape: (a) define a delimiter contract for `prompt TEXT`: either require all flags before `prompt` and reject any `rest[1..]` token that starts with `-` unless escaped via `--`, or parse `prompt` as consuming exactly one TEXT argv and then resume global flag parsing; (b) support `--` as an explicit literal-prompt delimiter so users can intentionally include flag-looking text (`claw prompt -- "explain --max-turns"`); (c) emit a typed `CliFlagWarning`/`cli_parse` JSON error when a flag-looking token appears after the prompt without `--`; (d) add parser tests for `prompt x --max-turns 0`, `prompt x --output-format json`, `prompt x --definitely-unknown`, `prompt -- "x --max-turns 0"`, and `--output-format json prompt x`. Acceptance: the documented `prompt TEXT` path no longer silently mutates trailing control tokens into model input; fixes for #262 cannot pass while leaving this long-form parser site greedy.
|
||||||
|
|
||||||
**Status:** Open. No source code changed. Filed 2026-04-26 14:02 KST. Branch: feat/jobdori-168c-emission-routing. HEAD: `fae9fd9` before filing. Cluster delta: position-sensitive-parse-asymmetry sub-shape +1 documented-subcommand member; sibling to #262, not duplicate. Concrete delta this cycle: ROADMAP-only pinpoint appended after source verification of the `prompt` arm.
|
**Status:** Open. No source code changed. Filed 2026-04-26 14:02 KST. Branch: feat/jobdori-168c-emission-routing. HEAD: `fae9fd9` before filing. Cluster delta: position-sensitive-parse-asymmetry sub-shape +1 documented-subcommand member; sibling to #262, not duplicate. Concrete delta this cycle: ROADMAP-only pinpoint appended after source verification of the `prompt` arm.
|
||||||
|
|
||||||
|
## Pinpoint #268 — MCP `tools/list` is never re-fetched on session resume: the runtime trusts the static `.claw.json` server list at `/mcp` time and the cached/qualified-name tool catalog at runtime build time, with zero staleness detection or live refresh path between server-restart events that change the tool catalog and the next `claw --resume` invocation
|
||||||
|
|
||||||
|
Dogfooded 2026-04-26 14:08 KST on `feat/jobdori-168c-emission-routing` at HEAD `d90b5f0` (post-rebase fast-forward onto gaebal-gajae's #267 `prompt TEXT` greedy-slurp pinpoint). #254 audited the **MCP Resources lifecycle** absence (`subscribe`/`list_changed`/`updated` for resources). #268 is the **sister pinpoint on the tool axis**: even the existing one-shot `tools/list` discovery is structurally bound to runtime startup and is never re-fetched on resume, so a session that restarts an MCP server (adding/removing/renaming tools) and then runs `claw --resume <session>` proceeds against the previous boot's stale tool catalog with no staleness signal. Founds the **NEW Session-resume-tool-catalog-staleness cluster** with #268 as solo founder, complementary to #254's resource-axis lifecycle gap.
|
||||||
|
|
||||||
|
Verified concrete surface (all paths absolute from `rust/crates/`): the resume entrypoint at `rusty-claude-cli/src/main.rs:2974` (`fn resume_session(session_path, commands, output_format)`) loads the persisted `Session` via `current_session_store().load_session(reference)` at `:5620-5634` (`fn load_session_reference`) and dispatches each `/<cmd>` through `run_resume_command(session_path, &session, &command)` at `:3467`. **The resume path never calls `build_runtime_mcp_state` and never instantiates `RuntimeMcpState::new` and never calls `manager.discover_tools_best_effort()`** — `rg "build_runtime_mcp_state|RuntimeMcpState::new" rust/crates/rusty-claude-cli/src/main.rs` returns the only two construction sites at `:7267` (`build_runtime_plugin_state_with_loader`) and `:4311` (the impl), and neither is reachable from `resume_session`. The resume-mode `/mcp` slash arm at `main.rs:3596-3613` calls `commands::handle_mcp_slash_command(args, &cwd)` which at `commands/src/lib.rs:2341-2347` calls `loader.load()` and then `render_mcp_summary_report(cwd, runtime_config.mcp().servers())` — i.e., it dumps the **configured-server list from `.claw.json`** without spawning any MCP process or issuing any `tools/list` request. The function never touches `McpServerManager`, never spawns stdio, never sends an `initialize` handshake, never sends `tools/list`. There is **zero** `tool_catalog`/`tool_snapshot`/`cached_tools`/`tool_list_at`/`tool_revision`/`tool_etag` field on `Session` at `runtime/src/session.rs:91-105` (the persisted struct fields are: `version`, `session_id`, `created_at_ms`, `updated_at_ms`, `messages`, `compaction`, `fork`, `workspace_root`, `prompt_history`, `last_health_check_ms`, `model`, `persistence`). The startup-time discovery report at `main.rs:4119-4205` (`impl RuntimeMcpState { fn new(...) }`) calls `runtime.block_on(manager.discover_tools_best_effort())` ONCE and stores the result in `RuntimeMcpState { runtime, manager, pending_servers, degraded_report }` — the in-memory snapshot is held for the lifetime of the process and never re-issued. There is **zero** `refresh_tools` / `reload_tools` / `refetch_catalog` / `recheck_servers` method on `RuntimeMcpState` or `McpServerManager`; `rg "refresh_tool|reload_tool|refetch|recheck_server" rust/crates/runtime/src/` returns no matches.
|
||||||
|
|
||||||
|
Downstream symptom matrix: (1) **Server tools changed between sessions** — user adds/removes a tool on an MCP server (e.g., `git`/`gh`/local-tooling MCP servers commonly add tools across versions). On `claw --resume <session>` the resumed `/mcp` view shows the old configured-server list with no tool count and no live `tools/list` cross-check; on continued prompts the tool registry built at runtime startup contains either the now-stale tool set OR the freshly-discovered set with no audit trail of which prompts ran against which catalog. (2) **MCP server replaced with a different binary at the same `command:` path** — the new binary advertises a different tool set; the resumed session has zero detection path. (3) **MCP server now-unavailable** — a server that was reachable at session-start but is offline at resume: there is no liveness probe in resume mode, only a configured-list dump, so `/mcp` reports the server as configured without flagging it as unreachable until a `tools/call` fails downstream. (4) **Tool descriptor drift** (description, JSON-schema input shape, qualified name): a tool that kept its name but changed its `input_schema` between server versions: the runtime tool registry built at the FIRST session start at `main.rs:4129-4133` (`mcp_runtime_tool_definition`) snapshots `tool.tool.input_schema.clone()` once; subsequent re-builds at the NEXT session start would pick up the new schema, but mid-session the agent is reasoning over the boot-time schema with no `version`/`etag`/`schema_revision` field on `ManagedMcpTool` to detect drift.
|
||||||
|
|
||||||
|
Gap. Three structural absences on the same axis: (a) **resume-mode tool-list refresh** — `run_resume_command` never instantiates `RuntimeMcpState`, so resumed sessions cannot even attempt a fresh `tools/list`; the resumed `/mcp` slash command at `main.rs:3596-3613` dispatches to a config-only renderer rather than a live-MCP renderer. (b) **mid-session tool-list refresh** — even the long-running session at first start instantiates `RuntimeMcpState` exactly once at `main.rs:7267` (`build_runtime_plugin_state_with_loader`) and never re-calls `discover_tools_best_effort()` afterwards; if the agent is alive when an MCP server's `tools/list_changed` notification fires (per the MCP spec's `notifications/tools/list_changed`), there is no notification-dispatch path on the JSON-RPC reader (the same notification-dispatch absence #254 catalogues for `notifications/resources/list_changed`). (c) **persisted tool-catalog snapshot** — the `Session` JSONL file at `.claw/sessions/<fingerprint>/<id>.jsonl` does not record which tool catalog was active when each turn ran, so post-hoc audit cannot tell which catalog version the assistant assumed. The composite gap means an MCP server that legitimately advertises `notifications/tools/list_changed` per the MCP 2025-03-26 spec is silently treated as having a frozen tool catalog from process boot.
|
||||||
|
|
||||||
|
Cluster shape novelty. Founds the **NEW Session-resume-tool-catalog-staleness cluster** with #268 as solo founder, distinct from #254's resource-axis lifecycle absence (which targets `resources/subscribe`+`resources/list_changed`+`resources/updated`+`ResourceRegistry` on the data-handle axis). #268 targets the **tool-handle axis**: `tools/list_changed` notification handler, `RuntimeMcpState::refresh_tool_catalog`, resume-mode `RuntimeMcpState` re-instantiation, persisted `tool_catalog_revision` on `Session`. #254 and #268 form the **fourth complementary-pinpoint-pair-bundle** in the dogfood corpus (after #245+#250 WebSearch, #262+#264 turn-budget, #264+#266 typed-error-axis), tracking the **two missing axes of MCP capability lifecycle** — resources and tools — that the spec advertises as live-subscribable but the runtime treats as one-shot-snapshot.
|
||||||
|
|
||||||
|
Distinct from #207/#208/#222/#231/#236/#246/#249/#258/#260/#262/#265 silent-fallback-input-mutation (those are CLI-layer prompt/output silent mutation; #268 is missing-refresh-of-discovery-data at the protocol-runtime layer). Distinct from #254 (resources axis vs tools axis). Distinct from #266 (typed-error enum vs missing-refresh primitive — orthogonal axes). Distinct from #259 session-state schema gaps (which catalogue what's in the JSONL; #268 catalogues what `Session` should have but does not — the tool-catalog-revision field). Distinct from #229/#238/#244 persistent-WebSocket-stream cluster (those are bidirectional client-driven streams; #268 is server-pushed-notification-handler absence on stdio JSON-RPC, structurally identical to #254's gap but on the tool axis).
|
||||||
|
|
||||||
|
Discovery-pattern continuation: this is the **fourth complementary-pinpoint-pair-bundle** (#245+#250, #262+#264, #264+#266, now #254+#268). #254 was filed earlier this dogfood-day at 11:02 KST; #268 closes the resources↔tools axis-pair as both being structurally one-shot. Pair-bundle ratio: 4 of 68 pinpoints in the #200-range (≈5.9%) bundled — confirms complementary-pair-bundles as a **stable discovery-pattern that systematically expands when an axis gap is filed and an orthogonal sister axis exists**. #268 also extends the **PURE-CLAWABILITY-FRICTION-FROM-DOGFOODING** discovery-pattern (#254's founding pattern) — the agent's own MCP runtime treats catalog discovery as boot-once rather than spec-compliant subscribe/refresh, so the agent silently reasons over a boot-time tool view that diverges from server reality across process lifetimes.
|
||||||
|
|
||||||
|
Required fix shape: (a) add `notifications/tools/list_changed` notification handler on the JSON-RPC stdio reader (parallel to #254's resources handler) routing to a per-server channel; (b) add `pub enum ToolCatalogLifecycleEvent { ToolListChanged | ToolAdded(McpTool) | ToolRemoved { qualified_name: String } | ToolSchemaChanged { qualified_name: String, old_schema: JsonValue, new_schema: JsonValue } }` typed event surfaced through `LaneEvents`; (c) add `RuntimeMcpState::refresh_tool_catalog(&mut self) -> Result<McpToolDiscoveryReport, ...>` that re-runs `manager.discover_tools_best_effort()` and diffs against the previous snapshot, emitting `ToolCatalogLifecycleEvent`s for the delta; (d) instrument the resume entrypoint at `main.rs:2974` (`resume_session`) to instantiate `RuntimeMcpState` (or a lightweight liveness-only variant) when the session has any MCP server configured, refresh the catalog, and surface the diff in the resume-mode `/mcp` output rather than dumping the static config; (e) add `revision: u64` and optional `etag: Option<String>` to `ManagedMcpTool`/`McpTool` so persisted session JSONL turns can record `tool_catalog_revision` per turn; (f) extend `Session` with `pub last_tool_catalog_revision: Option<u64>` (and bump `SESSION_VERSION` from `1` to `2` per #259); (g) advertise `tools.listChanged = true` in the initialize handshake at `mcp_stdio.rs:1400` when the runtime supports it; (h) expose `/mcp tools refresh` slash command and `claw mcp tools refresh` CLI subcommand; (i) emit a typed `mcp_tool_catalog_stale` warning to `--output-format json` when resume detects the catalog has diverged from the snapshot embedded in the last session turn. Acceptance: an MCP server that adds a tool between session-end and `claw --resume <session>` causes the resumed `/mcp` output to show `+1 tool added: srv__new_tool` rather than the static configured-server list with no live cross-check; an MCP server that emits `notifications/tools/list_changed` mid-session causes a `ToolListChanged` lane event and refreshes the tool registry rather than being silently dropped; the persisted session JSONL records `tool_catalog_revision` per turn so post-hoc audit can identify which catalog snapshot the assistant reasoned over.
|
||||||
|
|
||||||
|
**Status:** Open. No source code changed. Filed 2026-04-26 14:08 KST. Branch: feat/jobdori-168c-emission-routing. HEAD: `d90b5f0` before filing (post-rebase fast-forward onto gaebal-gajae's #267 `prompt TEXT` greedy-slurp pinpoint). Cluster delta: Session-resume-tool-catalog-staleness cluster 0→1 (founder, NEW SOLO CLUSTER); complementary-pinpoint-pair-bundle discovery-pattern extended to 4 bundles total (#245+#250 WebSearch, #262+#264 turn-budget, #264+#266 typed-error-axis, #254+#268 MCP-resources/tools-lifecycle-axis-pair). Sister: #254 (MCP Resources lifecycle on the data-handle axis; #268 is the tool-handle axis sister). Smaller-scope by design (matches #253/#254/#257/#258/#260/#261/#262/#263/#264/#265/#266/#267 context-budget discipline). Distinct from #266 (typed-error enum vs missing-refresh primitive — orthogonal axes). Distinct from #259 session-state schema gaps (#259 catalogues what's in JSONL; #268 catalogues what `Session` should have but does not — the `last_tool_catalog_revision` field). Concurrent-dogfood-rebase parity will be confirmed local==origin==fork at HEAD `d90b5f0+#268` after push.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user