GLAS-WP-0002 is now fully done (4/4): formalize the CLI as the first Channel extension (contract + refactor + tests + second-channel documentation), not building a second channel yet -- same generalize-from-a-real-second-example discipline as ADR-002/ADR-004. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
86 lines
2.8 KiB
Markdown
86 lines
2.8 KiB
Markdown
---
|
|
id: GLAS-WP-0003
|
|
title: "First channel extension: formalize the CLI channel contract"
|
|
status: proposed
|
|
---
|
|
|
|
Scoped by `GLAS-WP-0002-T04`: of glas-harness's four charter pillars
|
|
(unified API, profile catalog, extension platform, observability),
|
|
"extension platform" is entirely unbuilt for channels — `glas_harness.cli`
|
|
is a channel in substance (a way a caller invokes a harness session) but
|
|
not in form (no `Channel` contract exists; it's just a CLI module).
|
|
|
|
This workplan does **one thing**: formalize the CLI as the first
|
|
channel extension, so the *contract* exists before a second channel
|
|
(Slack, HTTP, whatever) is attempted — not build a second channel now.
|
|
Same discipline as ADR-002/ADR-004: generalize from a real second
|
|
example, not in anticipation of one.
|
|
|
|
## Task: Define the Channel contract
|
|
|
|
A `Channel` mirrors `Rein`'s shape at a different layer: it turns an
|
|
external invocation (CLI args, a Slack message, an HTTP request) into
|
|
the `sandbox_profile`/`repo`/`title`/`description`/`rein` inputs
|
|
`run_task_through_rein` needs, and turns its `dict[str, Any]` result back
|
|
into whatever the invocation medium expects (stdout JSON for CLI, a
|
|
Slack reply, an HTTP response body). Minimal ABC:
|
|
|
|
```python
|
|
class Channel(ABC):
|
|
@abstractmethod
|
|
def parse_invocation(self, raw: Any) -> GatewayInvocation: ...
|
|
|
|
@abstractmethod
|
|
def render_result(self, result: dict[str, Any]) -> Any: ...
|
|
```
|
|
|
|
Document in `docs/channel-contract.md`, parallel to
|
|
`docs/harness-contract.md`.
|
|
|
|
```task
|
|
id: GLAS-WP-0003-T01
|
|
status: todo
|
|
priority: medium
|
|
```
|
|
|
|
## Task: Refactor glas_harness.cli into a CLIChannel
|
|
|
|
`src/glas_harness/channels/cli_channel.py`: `CLIChannel(Channel)`
|
|
implementing `parse_invocation` (argparse → `GatewayInvocation`) and
|
|
`render_result` (→ `json.dumps(..., indent=2)`, matching today's output
|
|
exactly — this is a refactor, not a behavior change). `cli.py` becomes a
|
|
thin `main()` that constructs a `CLIChannel` and calls it; existing CLI
|
|
usage and output are unchanged.
|
|
|
|
```task
|
|
id: GLAS-WP-0003-T02
|
|
status: todo
|
|
priority: medium
|
|
```
|
|
|
|
## Task: Tests + verify no behavior change
|
|
|
|
Unit tests for `CLIChannel.parse_invocation`/`render_result` in
|
|
isolation, plus re-running the existing live-proof commands (both
|
|
reins) to confirm identical CLI output before/after the refactor.
|
|
|
|
```task
|
|
id: GLAS-WP-0003-T03
|
|
status: todo
|
|
priority: medium
|
|
```
|
|
|
|
## Task: Document the pattern for a second channel
|
|
|
|
A short section in `docs/channel-contract.md` sketching what a second
|
|
channel (e.g. a Slack or HTTP channel) would need to implement,
|
|
without building one — this workplan stops at "the contract exists and
|
|
one real implementation proves it," matching the discipline applied
|
|
throughout this session's other deferred-until-a-second-example
|
|
decisions.
|
|
|
|
```task
|
|
id: GLAS-WP-0003-T04
|
|
status: todo
|
|
priority: low
|
|
```
|