Story: Review whether ores.cli/ores.shell's host.cpp divergence is load-bearing or historical

Table of Contents

This page documents a story in Sprint 25. It captures the goal, current status, acceptance criteria, and the tasks that compose it.

Goal

After extracting ores::service::run_host_async() and migrating all 17 domain services + ores.http.server + ores.compute/wrapper onto it, ores.cli and ores.shell are the only two tools left with hand-written host.cpp. Do a proper side-by-side review of both: what's genuinely common between them (both are sync, console-facing tools, unlike the NATS-service fleet), what's different, and — critically — whether their divergence from the shared async shape is load-bearing (a real product requirement) or just historical (nobody has revisited it since they were first written, and a sync wrapper over run_host_async or a dedicated sync sibling helper could actually fit).

Specifically examine:

  • ores.cli: sync int host::execute(...), constructs application(std_output, cfg.database) (not default-constructed), plus a pre-application cfg.ore_roundtrip DB-free interception branch with its own try/catch before the main block.
  • ores.shell: sync int host::execute(...), constructs application(cfg.connection, cfg.login, cfg.script_path), calls app.run() with no arguments (no io_ctx, no cfg) — REPL/ interactive, not request-driven like the others.

Status

Field Value
State DONE
Parent sprint Sprint 25
Now Nothing.
Waiting on Nothing.
Next Nothing.
Last touched 2026-08-05

Acceptance

Tasks

Task State Start End Description
Investigate whether ores.cli/ores.shell's host.cpp divergence is load-bearing DONE 2026-08-05 2026-08-05 Side-by-side review of ores.cli and ores.shell's host.cpp/application shape against the shared run_host_async helper, to determine whether their sync execution model and custom application constructors are genuine requirements or just historical.

Decisions

  • Keep ores.cli=/=ores.shell's host.cpp bespoke, do not force either onto run_host_async — sync-vs-async is the one real, load-bearing distinction for both from the daemon fleet (ores.cli: no concurrency to gain from a batch tool; ores.shell: REPL semantics, blocks on stdin). The "custom constructor" objection held up for ores.cli (a mandatory reference member) but not for ores.shell (already all-default-optional, so already default-constructible) — the original task's framing had conflated the two tools' reasons. Filed Extract a sync sibling of run_host_async for ores.cli/ores.shell for the real remaining duplication between just these two, rather than implementing it as part of this investigation (later done as its own story).

Out of scope

Promoted from capture

Captured 2026-08-05 in the product backlog; promoted preserving the UUID.

What

After extracting ores::service::run_host_async() and migrating all 17 domain services + ores.http.server + ores.compute/wrapper onto it, ores.cli and ores.shell are the only two tools left with hand-written host.cpp. Do a proper side-by-side review of both: what's genuinely common between them (both are sync, console-facing tools, unlike the NATS-service fleet), what's different, and — critically — whether their divergence from the shared async shape is load-bearing (a real product requirement) or just historical (nobody has revisited it since they were first written, and a sync wrapper over run_host_async or a dedicated sync sibling helper could actually fit).

Specifically examine:

  • ores.cli: sync int host::execute(...), constructs application(std_output, cfg.database) (not default-constructed), plus a pre-application cfg.ore_roundtrip DB-free interception branch with its own try/catch before the main block.
  • ores.shell: sync int host::execute(...), constructs application(cfg.connection, cfg.login, cfg.script_path), calls app.run() with no arguments (no io_ctx, no cfg) — REPL/ interactive, not request-driven like the others.

Why

task_unify_application_cpp_shape.org (story Reduce and configure per-service DB connection pool size) originally scoped ores.compute/wrapper alongside ores.cli=/=ores.shell as "real behavioural divergence" without actually checking — PR #1855 review caught that ores.compute/wrapper in fact matched the uniform shape and migrated cleanly. That's a signal the "these two are special" judgment for ores.cli=/=ores.shell was made by pattern-matching against their obviously-different signatures, not by seriously asking whether the divergence is necessary. A dedicated pass — reading both tools' actual runtime requirements, not just their current code shape — would either confirm they genuinely need to stay bespoke (sync CLI/REPL tools are a fundamentally different product shape from a NATS daemon) or find that some of the "differences" (e.g. the constructor args) are removable with a small, deliberate change rather than assumed permanent.

References

  • projects/ores.cli/src/app/host.cpp
  • projects/ores.shell/src/app/host.cpp
  • projects/ores.service/include/ores.service/service/host_runner.hpp

See also

Emacs 29.3 (Org mode 9.6.15)