Skip to content

fix: name join in YAML/LTL and ArgValue; host install names its binary and its mode - #197

Merged
yfxiao16 merged 1 commit into
mainfrom
fix/kta1kri-round3
Oct 14, 2026
Merged

yfxiao16 merged 1 commit into
mainfrom
fix/kta1kri-round3

Conversation

@yfxiao16

Copy link
Copy Markdown
Contributor

Three items left over from the kta1kri round-two review (#196). None was in his report; the first is the class he was probing (#2, the name join) on a surface the earlier fixes did not reach, and the other two came up while re-verifying a18 through the real install path.

The name join reaches YAML/LTL atoms, the ArgValue term, and loop detection

a17 canonicalised the tool argument inside the pattern factories, so must_precede("check_policy", "issue_refund") binds every spelling. A rule written as LTL in YAML did not go through a factory: called(Issue_Refund) and Var(count, Issue_Refund) keyed on that exact spelling and missed issue_refund, mcp__finance__issue_refund and finance__issue_refund. The ArgValue term (G(!Gt(ArgValue("issue_refund", "amount"), 10))) read arg_value(<exact tool>, field) while grounding wrote it under the raw event name only, so a cap written as a Term passed the MCP-prefixed call with the value unread.

The join now lives in pred_key / predKey, the one function both sides call: for called, count, consecutive_count and arg_value the tool position is canonicalised. Grounding writes arg_value under every alias and keys its counters canonically; keying them by raw spelling put two entries behind one key and the snapshot loop wrote whichever came last, which admitted a third rate_limit call under a new spelling. loop_detection now follows a tool across an MCP prefix (search, then mcp__web__search, used to reset the run) and still resets on a different tool. Two low-level test files that hand-wrote called(X) valuations now use lower-case names.

sponsio host install names its own binary

_resolve_binary accepted an already-absolute argv[0] and otherwise took whatever sponsio was first on PATH. A relative invocation (./venv/bin/sponsio host install) on a machine with a second install wrote the other binary into settings.json; on my machine that was a broken Homebrew install, and Claude Code treats a hook that exits non-zero as a non-blocking error and runs the tool. One resolve_binary in hosts.py serves both installers: argv[0] resolved against the working directory, python -m sponsio.cli for a module invocation, PATH last.

--mode on host install does what it says

It wrote defaults.mode into the host library, which the hook never reads (the hook takes SPONSIO_GUARD_MODE, then SPONSIO_MODE, then enforce), so a default install printed Runtime mode: observe and blocked anyway, and --mode enforce was a no-op. Rather than have the hook honour a file the agent can reach, the mode rides on the hook command: --mode observe writes env SPONSIO_GUARD_MODE=observe <binary> host guard … (works whether the host shells out or exec()s), enforce writes the plain command, and a reinstall switches. The installer's default is now enforce, which is what it always did; sponsio init / onboard keep observe for a project sponsio.yaml, where defaults.mode is honoured. The installer no longer stamps mode: into host buckets; an existing line is left alone and ignored, as it always was.

Tests

  • Python: 3141 passed, 44 skipped; ruff clean; check-ts-parity.sh in sync.
  • TS: 124 passed (empty HOME), parity 40 + 39 scenarios.
  • New: tests/test_host_install_mode.py (resolver, prefix on both installers, the hook honouring the prefix, defaults); tests/test_fail_open_layer.py (+8 YAML/LTL and ArgValue spellings, loop detection across a prefix, counter not overwritten); matching cases in fail-open-layer.test.ts.

No version bump; this can ride in a19 with whatever else lands.

🤖 Generated with Claude Code

…y and its mode

Three items left over from the kta1kri round-two review.

- A rule written as LTL in YAML (`called(Issue_Refund)`, `Var(count, …)`)
  and the `ArgValue` term keyed on the exact tool spelling, so they missed
  `issue_refund` and `mcp__finance__issue_refund` while the pattern
  factories had been canonicalised in a17. The join now lives in
  `pred_key` / `predKey` for the tool-keyed predicates (`called`, `count`,
  `consecutive_count`, `arg_value`); grounding writes `arg_value` under
  every alias and keys its counters canonically, so a stale spelling no
  longer overwrites a count. `loop_detection` follows a tool across an
  MCP prefix.
- `host install` resolved the hook binary from PATH when invoked by a
  relative path, which on a machine with a second install wrote that one
  into the hook; Claude Code runs the tool when a hook exits non-zero.
  One `resolve_binary` for both installers, resolving argv[0] against the
  working directory and using the interpreter for a module invocation.
- `--mode` wrote `defaults.mode` into the host library, which the hook
  never read: a default install printed `observe` and blocked anyway. The
  hook defaults to `enforce` openly; `--mode observe` rides on the hook
  command as `env SPONSIO_GUARD_MODE=observe …`, where the agent under
  guard cannot change it.

Tests: pytest 3141 passed; TS 124 passed, parity 40 + 39 scenarios.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
@yfxiao16
yfxiao16 merged commit 1e701b4 into main Oct 14, 2026
10 checks passed
@yfxiao16
yfxiao16 deleted the fix/kta1kri-round3 branch October 14, 2026 11:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant