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: syncint host::execute(...), constructsapplication(std_output, cfg.database)(not default-constructed), plus a pre-applicationcfg.ore_roundtripDB-free interception branch with its own try/catch before the main block.ores.shell: syncint host::execute(...), constructsapplication(cfg.connection, cfg.login, cfg.script_path), callsapp.run()with no arguments (noio_ctx, nocfg) — 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'shost.cppbespoke, do not force either ontorun_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 forores.cli(a mandatory reference member) but not forores.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: syncint host::execute(...), constructsapplication(std_output, cfg.database)(not default-constructed), plus a pre-applicationcfg.ore_roundtripDB-free interception branch with its own try/catch before the main block.ores.shell: syncint host::execute(...), constructsapplication(cfg.connection, cfg.login, cfg.script_path), callsapp.run()with no arguments (noio_ctx, nocfg) — 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
- Unify application.cpp and service initialisation across services — the task that surfaced this