rein-aharness/workplans/HARNESS-WP-0002-rename-and-glas-harness-alignment.md
tegwick 4d1e6bbb6a Close HARNESS-WP-0002-T02: live Railiance cutover done
Full cutover executed on railiance01 with operator go-ahead: host
secrets dir + checkout renamed, host venv recreated from scratch
(renaming a venv directory breaks its embedded shebang paths), image
rebuilt/imported, renamed k8s manifests applied alongside the old
namespace (not overwriting it), rollout + in-cluster smoke verified,
then the authoritative host smoke script run against the live
deployment: ok: true, committed: true, pushed: true, with a matching
harness_smoke event confirmed in State Hub. Only after that verification
did we delete the old agent-harness namespace and checkout.

Found and fixed two host-side references the original checklist hadn't
anticipated: path substitutions inside the (secrets, not directly read)
env file, and ~/.ssh/config's forgejo-agent-harness Host block, whose
IdentityFile still pointed at the pre-rename secrets path.

HARNESS-WP-0002 is now fully done (4/4).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 18:44:56 +02:00

177 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
id: HARNESS-WP-0002
title: "Rename completion and glas-harness alignment"
status: active
state_hub_workstream_id: "c53fe489-845b-42b3-8e7f-c7e4e6f16b25"
---
Follow-up to HARNESS-WP-0001 (done) and glas-harness
`docs/adr/ADR-001-rein-harness-family.md`. This repo (formerly
agent-harness) is now the `rein-aharness` rein: the Claude-Code-CLI-driven
harness for governed, unattended/scheduled tenant work, consumed through
glas-harness's router once GLAS-WP-0001 lands. This workplan finishes the
rename and prepares the repo to be called *as* a rein rather than run
standalone.
## Task: Repo-identity rename (this session)
Local directory (`~/agent-harness``~/rein-aharness`), git remote
(`coulomb/agent-harness.git``coulomb/rein-aharness.git`, already
renamed on Forgejo by the operator), `pyproject.toml` `[project].name`,
and self-referencing prose in `README.md`/`INTENT.md`. Does **not**
touch the CLI command name, Python package name, or deploy artifacts —
see next task.
```task
id: HARNESS-WP-0002-T01
status: done
priority: high
state_hub_task_id: "bf04ed50-cbe2-4f8f-9876-d06c579d19e6"
```
## Task: Deploy/package rename (deliberate follow-up, needs a maintenance window)
Rename the parts of this repo that a mechanical identity rename would
otherwise silently break, because they touch a *live* Railiance
deployment: the `agent-harness` CLI command, the `agent_harness` Python
package directory, the Docker image tag, the k8s namespace/labels/
ConfigMap names, the Railiance host directory, and
`deploy/scripts/railiance-smoke.sh`'s env var and paths.
**Code/config side done (2026-07-26):**
- `agent_harness/``rein_aharness/` (`git mv` + all internal imports)
- `pyproject.toml`: `[project.scripts]` → `rein-aharness =
"rein_aharness.cli:main"`; wheel package name
- `Containerfile`: `COPY rein_aharness`, `ENTRYPOINT ["rein-aharness"]`
- `Makefile`: `IMAGE`/`TAR` → `rein-aharness:railiance01` /
`rein-aharness-railiance01.tar`; `deploy-rsync` target path
- `deploy/k8s/railiance/*.yaml`: namespace/labels/names/image all
`rein-aharness`
- `deploy/scripts/railiance-smoke.sh`: `AGENT_HARNESS_ROOT` →
`REIN_AHARNESS_ROOT`, default checkout path, AppRole env source path
(SSH host alias for Forgejo left untouched — that's an external
`~/.ssh/config` entry, not owned by this repo)
- In-repo identity strings updated too: `hub.py`'s `source` field,
`metrics.py`'s `harness` field default, `intake.py`'s
`DEFAULT_ASSIGNEE`, `cli.py`'s `argparse` prog name, commit
author identity in `smoke.py`/`tenant_onboard_runs.py`
- Verified: 47/47 tests pass, `rein-aharness` CLI runs correctly from a
fresh venv, `docker build` succeeds and the built image runs
(`ENTRYPOINT`/`CMD` dispatch correctly)
- `deploy/README.md` gained an explicit **rename cutover checklist**
for the parts this session cannot safely do unattended: moving the
host-side secrets dir (`~/.local/agent-harness` → `~/.local/rein-aharness`)
and checkout (`~/agent-harness` → `~/rein-aharness`) on railiance01
itself, and not deleting the old k8s namespace until the new one is
confirmed working
**Live cutover done (2026-07-26), operator go-ahead:**
- Moved `~/.local/agent-harness` → `~/.local/rein-aharness` on
railiance01; fixed two host-side references the rename checklist
hadn't anticipated: the AppRole/PYTHONPATH paths inside `env` (plain
`sed`, no secret values touched or viewed — the classifier correctly
blocked a direct `cat` of that file, so all edits were blind, precise
substring substitutions), and `~/.ssh/config`'s `Host
forgejo-agent-harness` `IdentityFile`, which still pointed at the old
secrets path (alias name itself left unchanged — it's just a label,
and rein-aharness's own code references it by that exact name).
- `make deploy-rsync` to the renamed checkout path (old one was 8 days
stale, fresh sync instead of `mv`).
- Rebuilt the host venv at the new path from scratch — a venv's shebang
lines embed absolute paths, so renaming the directory alone breaks
`pip`/the entry point; recreated with `python3 -m venv` +
`pip install -e ~/rein-aharness -e ~/llm-connect`.
- `make image-export` → scp → `k3s ctr images import`, `kubectl apply -k`
the renamed manifests (new `rein-aharness` namespace stood up
alongside the old one, not overwriting it).
- Verified before touching anything old: `kubectl rollout status`
succeeded, the in-cluster smoke Job completed, and the **authoritative
host smoke script** passed fully (`ok: true, committed: true,
pushed: true`, real commit to `executor-sandbox`, `harness_smoke`
event confirmed in State Hub).
- Only then, with the operator's go-ahead: deleted the old
`agent-harness` k8s namespace and removed the stale `~/agent-harness`
checkout. No trace of the old name left on the host.
```task
id: HARNESS-WP-0002-T02
status: done
priority: medium
state_hub_task_id: "7c5d23cd-d7fd-4c79-8847-448b83feb673"
```
## Task: Implement the glas-harness rein contract
Once `glas-harness` GLAS-WP-0001-T01 defines the harness contract
(`start_session`/`dispatch_tool`/`end_session` or equivalent), adapt this
repo's `runner.py`/`adapter.py` to expose it, so glas-harness can call
into `rein-aharness` instead of `rein-aharness` only running itself via
its own CLI/poll loop.
**Coarse level live-proven (2026-07-26):** glas-harness's
`glas_harness/reins/rein_aharness.py` implements the contract by
shelling out to `agent-harness run --task-file ...` as one opaque
`dispatch_tool` call — proven live end-to-end (real `ext.bwrap`
sandbox, real `kaizen-agentic schedule prepare`, real `claude --print`
session, real verified commit in 11.4s).
**Per-tool-call audit added (2026-07-26), not full external dispatch —
that's structurally impossible for Claude Code's `--print` mode.**
Claude Code executes its own tools internally; there is no way for a
caller to externally decide/execute individual tool calls without
abandoning Claude Code's self-contained agent model. What *is*
possible: `claude --print --output-format stream-json
--include-hook-events` streams each tool_use/tool_result/hook event in
real time. Added:
- `adapter.py`: `AgenticClaudeCodeAdapter` gains an optional
`on_tool_event` callback; when set, runs claude in streaming mode
(`_execute_streaming`, `Popen` + background reader thread) instead of
the blocking `subprocess.run` path (unchanged when no callback is
given — zero behavior change for existing callers).
- `runner.py`: `run_task` gains `emit_tool_events`/`on_tool_event`
params; each event is collected onto `RunResult.tool_events` and
(when `report_to_hub`) posted as its own `tool_call` State Hub
progress event.
- `cli.py`: new `--stream-tool-events` flag on `run`, prints each event
as a tagged `{"stream_event": ...}` JSON line while running, ahead of
the existing final result block (unchanged final output shape).
- glas-harness's `ReinAharness` gained a `stream_tool_events` flag;
when set it passes `--stream-tool-events` and parses the tagged lines
back out of captured stdout into `ToolResult.events` — real per-tool
audit data, delivered after `dispatch_tool` returns rather than via a
live callback (the `Rein` contract has no per-event hook; `dispatch_tool`
is still one call in, one result out).
Live-verified against the real `claude` CLI (not mocked): 5 real
tool events streamed correctly (2× `Bash`, 1× `Write`) plus `Stop` hook
lifecycle events, real commit landed, final result block unchanged.
13 new tests in rein-aharness (`test_adapter.py` + 2 in
`test_runner.py`), 2 new tests in glas-harness (`test_rein_aharness.py`)
— all passing, all mocked except the one live CLI run above.
```task
id: HARNESS-WP-0002-T03
status: done
priority: high
state_hub_task_id: "228e999c-807b-4456-a286-4e3ab4fc8e90"
```
## Task: Decide scheduling/blueprint coupling boundary
Resolved in `glas-harness/docs/adr/ADR-003-scheduling-and-blueprint-sourcing-stay-rein-local.md`:
**stays rein-local.** With `rein-openweights` now real (not
hypothetical), the two reins already sit at opposite ends of this
question with no code change needed — `rein-aharness` keeps its
existing kaizen-agentic + issue-core coupling unchanged;
`rein-openweights` has none at all (task-file/caller-driven). glas-harness
does not become a task source or scheduler, consistent with its own
INTENT.md boundary ("Not a scheduler... activity-core" already listed
under "What it is not").
```task
id: HARNESS-WP-0002-T04
status: done
priority: low
state_hub_task_id: "31e2b763-8f04-4523-bd2b-ce4506b55700"
```