Skip to content

refactor: simplify the operations/command layer (#49, #43)#53

Open
kfastov wants to merge 1 commit into
mainfrom
refactor/ops-command-layer
Open

refactor: simplify the operations/command layer (#49, #43)#53
kfastov wants to merge 1 commit into
mainfrom
refactor/ops-command-layer

Conversation

@kfastov
Copy link
Copy Markdown
Owner

@kfastov kfastov commented Jun 4, 2026

Cleanup of the operations/command layer the warm-backend work produced — no user-visible behavior change (same output incl --json, same errors/exit codes). Addresses #49 and #43.

Changes

  • Invoke-first (perf). runOperation now calls invoke directly (one loopback round-trip on the warm path instead of ping+invoke). Only a ServerUnavailableError (no control.json / refused loopback connection — detected via isFetchConnectionFailure) triggers ensureServer + a single retry. A 4xx/5xx op error, a relayed sendError, and a request timeout/abort are NOT connection failures and never spawn a server (preserves the send-timeout contract).
  • Source-resolution dedup. resolveFromSource({ source, fetchLive, fetchArchive }) and selectMessageResults(...) collapse the duplicated live/both/archive/live-fallback logic across messagesGet/messagesContext/messagesList/messagesSearch. Identical behavior.
  • Generic passthrough + thinner handlers (subsumes Extract a reusable 'run a server task, follow progress, print' primitive to keep CLI handlers thin #43). A small PASSTHROUGHS table generates 16 one-line ops via buildPassthroughOps; only composite ops stay hand-written. All 44 ops and their result shapes are preserved (the MCP tools and /control/invoke depend on them). The three send* handlers share buildCommonSendArgs instead of each rebuilding the flag map (same validation order → same first-error).
  • Audits. Source consistency: every single-source result comes wholly from one source; both merges via mergeMessageSets preserving each row's source; archive→live fallback surfaces usedLiveFallback. No mixing found. TG calls: one follow-up reported (not changed, since it affects which labels appear) — resolveLiveMetadata issues an extra getPeerMetadata when username isn't cached even though the fetch already returns peerTitle; candidate to cache/skip later.

Tests

npm test349 passing (336 + 13 new: invoke-first vs spawn-on-connection-failure incl. op-error-does-not-spawn, the source-resolution helper across all source modes, the generic passthrough forwarding, handlers passing args through). No node_modules committed; comments behavioral.

Note

#49's "minimize TG API calls" is covered except the one reported resolveLiveMetadata round-trip (a safe-to-defer follow-up). #43 (thin handlers) is addressed via the passthrough + shared send args.

Internal cleanup of the op/command layer the warm-backend work produced;
no change to user-visible output, errors, or exit codes.

- runOperation invokes the op directly and only starts a server (then
  retries once) when the call fails because the server is unreachable.
  invoke now raises ServerUnavailableError for a missing control.json or a
  refused loopback connection, distinct from an op that ran and failed (a
  4xx/5xx/send error) or a request timeout, neither of which spawns a
  server. The warm path drops from two loopback round-trips to one.

- Extract one source-resolution helper for the single-result message ops
  (messagesGet/messagesContext): live / both / archive-then-live-fallback,
  whole result from a single source. Extract one result-selection helper
  for the list/search ops. Behavior identical.

- Forward the ~16 one-line passthrough ops through a small declaration
  table; only composite ops (message ops, sends, anything reshaping a
  result or calling more than one method) stay hand-written.

- Build the send args shared by send text/photo/file once instead of
  repeating the per-handler flag map, keeping the same validation order.

- Tests: invoke-first then start-on-connection-failure (and that an op
  error does not spawn a server); the shared source resolution across all
  four source modes (no source mixing); a generic passthrough forwarding.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant