Files
nanoclaw/container
Gabi Simons 49ef2ef24e fix(harness): address code-review findings (correctness, security honesty, altitude)
Correctness:
- reconciler + PreCompact hook unified into one read-modify-write with a
  single atomic write, and the parsed value is shape-validated: a settings.json
  holding valid-JSON-non-object (null, a scalar, {"env":"bad"}) no longer
  throws a TypeError that bricked the group — it warns and skips, like the old
  hook. Fixes divergent atomic/non-atomic writers and a double read per spawn.
- config update wraps both DB writes in one transaction — a failing scalar
  update can no longer leave the harness override half-applied.
- parseHarnessCapabilitiesArg returns a single key->directive map, so a repeated
  key resolves last-wins (was: clears always beat sets regardless of order).
- validation uses Object.hasOwn, not `key in` — inherited names like
  `constructor`/`toString` are no longer accepted as capabilities.
- createContainerConfig now binds cli_scope + harness_capabilities (were
  silently dropped to the column default).

Security honesty:
- agent-teams=off is documented as spawn-time hygiene, not a hard in-container
  boundary: settings.json is RW-mounted so an agent can rewrite it for the
  container lifetime. workflow=off keeps its disallowedTools backstop. Follow-up
  filed to mount the managed settings source read-only.
- dispatch escalation gate protects canonical field names and normalizes each
  incoming arg key — no spelling-variant bypass.

Altitude / cleanup:
- capabilities carry their host mechanism in the registry; the reconciler
  iterates it, so adding a key is one registry entry (+ one runner map line if
  it blocks a tool). Runner unknown-key lockstep + warning loop deleted (host
  drops unknown keys at resolve; warns once per distinct problem, not per spawn).
- resolved view is structured {state, source}; source is 'override' only for a
  VALID stored override (an invalid value reports 'default', not a lie).
- ReportFindings joins the fixed disallow list (headless has no UI to receive
  it; ~1.9KB/turn). PreToolUse hook built once in the constructor with a Set.
- drift guard: assert the installed SDK version too (SDK now pinned exactly),
  and dual-capture the fixture (tools vs toolsBare). This EMPIRICALLY corrected
  a prior claim: allowedTools is fully inert here (surfaces are byte-identical),
  it does not promote Glob/Grep — comment fixed to match.

Host 663 + container 125 green; wire re-probed (default drops
Workflow/DesignSync/ReportFindings; workflow=on restores only Workflow).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 14:45:38 +03:00
..