Commit Graph
11 Commits
Author SHA1 Message Date
Omar SobhandClaude Opus 5 0b4d91889a docs: hand-off refresh — container-tier work shipped, stale guidance corrected
deploy / test (push) Successful in 4m46s
deploy / build (push) Successful in 1m1s
TOOL-CALL-ARCHITECTURE.md said "switch claude_cli to stream-json" as the
cheapest fix. That was wrong and is now marked so, with what actually
happened: zero tool.call events with the parser working perfectly, because
TurnEvent::ToolCall only fires for tools ZeroClaw itself executes. Hooks
sidestep that entirely, and the doc now leads with the resolution rather
than the theory. A fresh session is pointed at this file, so leaving the
wrong recommendation on top would have sent it down the same path.

NEXT-SESSION.md: state header, and the ordered list rewritten — items 1-3
are done or superseded. "Give the direct-session tier a tap" is dropped with
its reason: that tier is dormant (CLAWMATES_MISSION_EXECUTOR unset), and
checking before building saved the work. New top item is watching the first
production mission, since the gate and tap are proven locally and unproven
in prod.

Added an operational section for the things that cost the most time: the
403 actions-log API, gw-04's legacy docker-compose, the socket proxy, disk
contention between manual builds and CI, and Clerk-only prod auth.

Also flagged that SKILL-USE-BASELINE.md's Trigger column is now stale in a
good way — tool calls are observable on the container tier, so Trigger can
be scored from behaviour instead of prose. That is the highest-value
follow-up.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-21 07:22:01 -07:00
Omar SobhandClaude Opus 5 5a11fae0d6 docs: container-tier gate and telemetry shipped; CI failures were disk
deploy / test (push) Successful in 4m39s
deploy / build (push) Successful in 1m0s
Records the verified result (10 tool.call, 4 file.touch on a real mission),
how hooks succeed where stream-json could not, the production state and its
rollback, and the three same-shaped bugs the live test found.

Also records that CI's build failures were disk pressure from my own manual
runtime builds on gw-04 — not code — and that a docs-only commit was the
first casualty, which made it look like a regression.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-21 07:11:02 -07:00
Omar SobhandClaude Opus 5 930c7e0b67 docs: the PreToolUse gate is verified end to end
deploy / test (push) Successful in 4m55s
deploy / build (push) Failing after 1m28s
Ran it against the real claude binary with the real settings document and
the real hook script. Both halves.

It blocks: asked to `curl -X POST`, the agent attempted the Bash call, the
hook fired FROM --settings, the call was refused, and denied.jsonl recorded
the payload with hook_event_name PreToolUse and the exact command. The agent
relayed the reason accurately — the text from vm_tool_gate::RULES reached
the model, which is the point of writing reasons rather than bare refusals.

It allows: `echo` and a harmless `rm -rf ./scratch-nonexistent` both ran and
denied.jsonl stayed empty. A gate that blocked everything would have passed
the first test; this is the half that rules that out — and two of this
gate's four bugs produced exactly that failure.

So the last unproven link in the chain is closed, and the gate is real in
production rather than plausibly real.

One finding worth keeping: asked to `git push --force`, the model refused on
its OWN before ever calling Bash, so the hook never fired and the test was
inconclusive. A gate test must use a command the model will actually attempt.
The model's judgement is not the gate, and testing against something it
already refuses measures nothing.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-21 00:19:37 -07:00
Omar SobhandClaude Opus 5 0be932fd83 test(gate): a fixture emitter for the live PreToolUse check, and what it proved
deploy / test (push) Successful in 4m41s
deploy / build (push) Successful in 5m46s
Tried to close the last open question — does the PreToolUse gate actually
fire in a guest — and got most of the way.

Established:
  - the generated script blocks and allows correctly under DASH, not just
    macOS sh: force-push and `cd /tmp && rm -rf /` return 2, while
    `grep -rn 'rm -rf /' docs/` and ordinary work return 0
  - without node it allows and writes the `inert` marker, so a gate that
    cannot parse is distinguishable from one that matched nothing
  - `claude` in the runtime image supports `--settings` (SETTINGS-OK)
  - PreToolUse DOES fire under `claude -p` in this image — measured by an
    earlier session and recorded in vm_stop_gate.rs:36

Unproven, and now precisely scoped: whether Claude Code honours a
PreToolUse hook supplied via `--settings <path>` specifically, with a real
agent turn. The live attempt hit the weekly subscription rate limit, and
`claude doctor` does not report hooks, so there is no non-LLM confirmation
available.

`emit_guest_assets` (ignored by default) writes the real hook script and the
real settings document to /tmp so the check can be run against the actual
binary in one docker command — no microVM, no fleet. The exact command is in
docs/NEXT-SESSION.md.

Worth stating plainly: if that link is broken, the gate is inert in
production and looks exactly like a gate that found nothing — which is the
failure mode this whole session has been about.

Full workspace suite green: 107 binaries.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 14:45:48 -07:00
Omar SobhandClaude Opus 5 afb1e29bf3 docs: streamjson2 built but deliberately not deployed
deploy / test (push) Successful in 4m31s
deploy / build (push) Successful in 57s
The corrected runtime image exists on gw-04 and stays there. It delivers no
observability until TurnEvent::ToolCall can be emitted for observed calls, so
deploying it alone would be a provider output-format change carrying risk for
no benefit. Production stays on the known-good :v084.

The harmful v1 image was deleted from both hosts so it cannot be redeployed
by accident.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 09:55:33 -07:00
Omar SobhandClaude Opus 5 536adddd0f docs: stream-json tested live — it does not deliver observability, and v1 was harmful
deploy / test (push) Successful in 4m52s
deploy / build (push) Successful in 59s
Deployed the amd64 build to gw-04 and drove a real mission. The agent used
Bash and the standard tools; no tool.call events appeared, and the gateway's
unmatched-frame histogram still showed only session_start.

The reason is structural: TurnEvent::ToolCall is emitted from
tool_execution.rs, only for tools ZeroClaw itself runs. Claude Code runs its
tools in its own subprocess, so the event never fires. A provider that knows
about the calls changes nothing by itself.

The first version was also harmful — it returned the observed calls as
tool_calls, so the loop tried to execute Claude Code's tool names and fed
"Unknown tool: Bash" back to the model. Fixed in the fork; both runtimes
rolled back to the known-good image in the meantime.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 09:47:05 -07:00
Omar SobhandClaude Opus 5 ac4fa0b8f7 docs: CI green and deployed — record the verified production state
deploy / test (push) Successful in 4m37s
deploy / build (push) Successful in 56s
Run 498 passed and deployed. Confirmed on gw-04: 53 skills, 11 templates,
zero unresolved bindings, self-authoring announced ENABLED, the new
gateway_preflight answering, and migration 0080 applied.

Also records that run 497 was cancelled by the concurrency guard rather
than failing, and that the stream-json runtime image is still NOT shipped by
this pipeline.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 08:06:24 -07:00
Omar SobhandClaude Opus 5 689a5e14a3 docs: CI root cause was an apostrophe, not any of the three theories
deploy / test (push) Successful in 4m31s
deploy / build (push) Successful in 6m4s
Records both real causes (run 490 stomped by an overlapping run; 491-496
killed by an apostrophe closing a single-quoted sh -c block), the guard that
now catches the second class locally, and what to check when the in-flight
run settles — including that a successful build is the FIRST time these
commits reach production.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 07:45:02 -07:00
Omar SobhandClaude Opus 5 d23f30e929 docs: record the CI investigation honestly, including what is still unknown
deploy / test (push) Failing after 7s
deploy / build (push) Skipped
Establishes what is verified (the code passes on the runner host, with
cargo's real exit code), what is narrowed (493/494 die inside the Rust step
before cargo starts; 495 died before step 1), the three theories that were
wrong, and the cheapest next experiment.

Also records the two things that made this expensive: the actions-log API
returns 403 for our token, and my first reproduction piped cargo into `tail`
and reported tail's exit code.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 07:33:10 -07:00
Omar SobhandClaude Opus 5 72ba4ba523 fix(ci): two runs stomped each other, and the logs blamed the tests
deploy / test (push) Failing after 8s
deploy / build (push) Skipped
Runs 490 and 491 both failed `test`. Neither failure was in the code.

Runs 490 and 491 started 16 minutes apart and a full suite takes longer
than that, so they overlapped. The first thing a run does is
`docker rm -fv cm-ci-pg` — a name every run shared — so the newer run
deleted the older run's database mid-suite. Both failed, and the failures
read as test failures.

Verified before changing anything: the exact CI command, on gw-04, against
the same warm cargo volumes and a Postgres started exactly as CI starts it,
passes on 128b423 — as do `npm ci`, `typecheck` and `vitest` on that host.
The code was never the problem.

  - `concurrency: deploy-${{ gitea.ref }}` with cancel-in-progress, so runs
    on a ref serialize. A superseded run tests a commit that is no longer
    the tip; finishing it costs 20 minutes to learn something that no longer
    matters.
  - the test Postgres is named per run, so overlap cannot corrupt a run even
    if the concurrency guard is later removed. Impossible rather than
    unlikely.
  - `--shm-size=1g` on it. Docker defaults /dev/shm to 64MB and cm-testkit
    creates a database per test; Postgres exhausts its parallel-query
    segments mid-run and reports `could not resize shared memory segment`
    DURING MIGRATIONS, which reads like a schema fault. Hit locally on
    2026-08-19; scripts/test-server.sh already carries the same flag.

The lesson is the session's own: I twice inferred a cause from a red build
without reading the failure — first node, then dash — and both were wrong.
The answer came from running the job on the runner's own host.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 07:00:10 -07:00
Omar SobhandClaude Opus 5 b653dbfe72 docs: hand-off note for the next session
deploy / test (push) Failing after 1m43s
deploy / build (push) Skipped
Records the state of the tree, the one step not taken (the stream-json
runtime image is built and never deployed, so no mission has confirmed
tool.call rows end to end), the ordered next steps, the decisions that are
the operator's, and what was deliberately left undone with reasons.

Also records the two corrections made this session — "missions can't call
tools" was wrong, and raw test counts are a bad coverage metric — because
both were confidently stated here before being checked.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 05:24:43 -07:00