From 8aa5bd255ddcda0abf7a9ea3840379b21688ef87 Mon Sep 17 00:00:00 2001 From: Jothi Mani Rajendran <250249270+jothimani-rajendran@users.noreply.github.com> Date: Mon, 19 Oct 2026 00:28:03 +0000 Subject: [PATCH 1/3] feat(labels): plain-sentence policy labels, install warnings and witness notes (VOICE-3a) Rewrites the label text chock install prints and the catalog registry reads (bundle_grade grade texts, the Devin and tier-table prefixes, the unasked note), the client warnings in install/data/warnings.json, the Claude Code plugin offer text, and the plugin-hook witness notes, per the org-plan voice style guide: no semicolon chains, no "judged" or "fails open". No label claims more than before and every caveat stays. Tests asserting exact copy move to the new text; plugin_targets goldens regenerated with CHOCK_REGEN_GOLDENS=1 on Python 3.13. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Jothi Mani Rajendran <250249270+jothimani-rajendran@users.noreply.github.com> --- changelog.d/voice-3a-plain-labels.md | 7 ++++ src/chock/data/witnesses.json | 12 +++---- src/chock/install/data/claude_plugin.json | 12 +++---- src/chock/install/data/install.json | 8 ++++- src/chock/install/data/warnings.json | 30 ++++++++-------- src/chock/install/package.py | 10 ++++-- src/chock/plugin/bundle_build.py | 2 +- src/chock/plugin/bundle_grade.py | 8 +++-- .../fixtures/plugin_targets/antigravity.json | 2 +- tests/fixtures/plugin_targets/droid.json | 2 +- tests/fixtures/plugin_targets/kimi.json | 2 +- tests/fixtures/plugin_targets/openhands.json | 2 +- tests/test_install_clients.py | 10 +++--- tests/test_install_coexist.py | 2 +- tests/test_plugin_guard_plus_gate.py | 6 ++-- tests/test_plugin_guard_plus_gate_claims.py | 4 +-- tests/test_plugin_install_targets.py | 36 ++++++++++++++----- .../test_plugin_install_targets_kimi_droid.py | 8 ++--- tests/test_witness_ledger.py | 4 +-- 19 files changed, 105 insertions(+), 62 deletions(-) create mode 100644 changelog.d/voice-3a-plain-labels.md diff --git a/changelog.d/voice-3a-plain-labels.md b/changelog.d/voice-3a-plain-labels.md new file mode 100644 index 00000000..289add28 --- /dev/null +++ b/changelog.d/voice-3a-plain-labels.md @@ -0,0 +1,7 @@ +- **Policy labels, install warnings and witness notes now use short plain sentences (VOICE-3a).** The grade text + that `chock install` prints and the catalog's registry reads no longer chains clauses with semicolons, and no + longer says "judged" or "fails open". A gate that runs only at turn end now reads "blocks at turn end only. It + does not check a file write when it happens". Devin's label and the labels of clients graded from agentseam's + tier table say "a hook error lets the action through" where they said "fails open" or "fail mode open". No + label claims more than before, and every caveat is kept. Code that matches the old wording, such as the + catalog's `tools/label_honesty.py`, needs the new text. diff --git a/src/chock/data/witnesses.json b/src/chock/data/witnesses.json index 9298dbac..16f05d48 100644 --- a/src/chock/data/witnesses.json +++ b/src/chock/data/witnesses.json @@ -25,42 +25,42 @@ "surface": "plugin-hook", "client": "GitHub Copilot CLI 1.0.94, Windows", "date": "2026-10-11", - "method": "live probe of the chock plugin: pin-github-actions refused a create write at preToolUse, before the file landed, and chock-guardrails-protect refused a shell write to .chock/guardrails.json at preToolUse; VS Code agent mode, a toggle-file write through the edit tool and a delete-only apply_patch not covered (org-plan witness/results/witness-copilot-2026-10-11.md, 83f636d)" + "method": "live probe of the chock plugin. `pin-github-actions` refused a create write at preToolUse, before the file landed. `chock-guardrails-protect` refused a shell write to `.chock/guardrails.json` at preToolUse. Not covered: VS Code agent mode, a toggle-file write through the edit tool, and a delete-only apply_patch (org-plan witness/results/witness-copilot-2026-10-11.md, 83f636d)" }, { "agent": "claude_code", "surface": "plugin-hook", "client": "Claude Code 2.1.283, Windows", "date": "2026-10-12", - "method": "live probe of the chock plugin, every other chock plugin disabled: block-no-verify refused a Bash call and pin-github-actions refused a Write at PreToolUse, before either ran; Stop not exercised (org-plan witness/results/witness-claude-code-2026-10-12.md, 198694b)" + "method": "live probe of the chock plugin, with every other chock plugin disabled. `block-no-verify` refused a Bash call and `pin-github-actions` refused a Write at PreToolUse, before either ran. Stop was not exercised (org-plan witness/results/witness-claude-code-2026-10-12.md, 198694b)" }, { "agent": "devin", "surface": "plugin-hook", "client": "Devin CLI 3000.11.3 (local session), Windows", "date": "2026-10-08", - "method": "live probe of a chock plugin installed with `devin plugins install --local`: block-no-verify and chock-guardrails-protect refused a shell command before it ran; pin-github-actions did not refuse the write, only at turn end (stop); self-protection held (org-plan witness/results/witness-devin-2026-10-08.md, 0f06113)" + "method": "live probe of a chock plugin installed with `devin plugins install --local`. `block-no-verify` and `chock-guardrails-protect` refused a shell command before it ran. `pin-github-actions` did not refuse the write itself. It refused only at turn end (stop). Chock's protection of its own files held (org-plan witness/results/witness-devin-2026-10-08.md, 0f06113)" }, { "agent": "grok", "surface": "plugin-hook", "client": "Grok Build 1.0.62, Windows 11", "date": "2026-10-17", - "method": "live probe of a chock plugin installed with `grok plugin install --trust` (no hook trust prompt) and enabled under Grok's generated name c--users---chock-marketplace-grok-chock-witness-481da8d4 (username redacted as ), not chock-witness: block-no-verify refused a `git commit --no-verify` shell command before it ran (\"`run_terminal_command` blocked by plugin/c--users---chock-marketplace-grok-chock-witness-481da8d4/hooks: Blocked by chock policy: block-no-verify\"); pin-github-actions is advisory on Grok and the workflow write landed, as labelled, so no gate refusal is claimed (org-plan witness/results/witness-grok-2026-10-17.md, f52c055)" + "method": "live probe of a chock plugin installed with `grok plugin install --trust` (no hook trust prompt). It was enabled under the name Grok generated, c--users---chock-marketplace-grok-chock-witness-481da8d4 (username redacted as ), instead of chock-witness. `block-no-verify` refused a `git commit --no-verify` shell command before it ran (\"`run_terminal_command` blocked by plugin/c--users---chock-marketplace-grok-chock-witness-481da8d4/hooks: Blocked by chock policy: block-no-verify\"). `pin-github-actions` is advisory on Grok and the workflow write landed, as labelled, so no gate refusal is claimed (org-plan witness/results/witness-grok-2026-10-17.md, f52c055)" }, { "agent": "goose", "surface": "plugin-hook", "client": "goose 1.55.0 CLI, Windows 11", "date": "2026-10-18", - "method": "live probe of a chock plugin auto-discovered from ~/.agents/plugins/chock-witness, with Git for Windows' sh on PATH (goose runs every hook with `sh -c`; without sh every tool call, a benign `git status` too, was denied with \"the hook command failed to run\", on_failure: block): block-no-verify refused a `git commit --no-verify` shell command before it ran (\"Tool call denied by policy hook `chock-witness`: Blocked by chock policy: block-no-verify\") and pin-github-actions refused a write to .github/workflows/witness.yml at the write (\"Unpinned GitHub Action detected\"); a benign `git status` ran (org-plan witness/results/witness-goose-2026-10-18.md, 6316fd3)" + "method": "live probe of a chock plugin auto-discovered from `~/.agents/plugins/chock-witness`, with Git for Windows' sh on PATH. goose runs every hook with `sh -c`. Without sh, every tool call was denied, even a harmless `git status`, with \"the hook command failed to run\" (`on_failure: block`). `block-no-verify` refused a `git commit --no-verify` shell command before it ran (\"Tool call denied by policy hook `chock-witness`: Blocked by chock policy: block-no-verify\"). `pin-github-actions` refused a write to `.github/workflows/witness.yml` at the write (\"Unpinned GitHub Action detected\"). A harmless `git status` ran (org-plan witness/results/witness-goose-2026-10-18.md, 6316fd3)" }, { "agent": "antigravity", "surface": "plugin-hook", "client": "Antigravity IDE (version not recorded), Windows 11", "date": "2026-10-18", - "method": "live probe of chock's shipped plugin built on Windows (store windows_hook_command: quote_free, so the hooks.json command carries no quotes), copied to ~/.gemini/config/plugins/chock-witness, no hand edits: block-no-verify refused the witness kit's GUARD shell command before it ran (\"tool call denied by pre-tool hook: Blocked by chock policy: block-no-verify\"; `git status` then showed \"No commits yet\"); pin-github-actions let a write of .github/workflows/witness.yml with actions/checkout@v4 land and refused at turn end (\"Stop hook blocked termination: Unpinned GitHub Action det…\"), not at the write, and the agent then pinned the action by commit SHA; a benign `git status` ran. The claim is for a Windows build only (org-plan witness/results/witness-antigravity-2026-10-18.md, section \"Re-run on chock's shipped build\", 11121b3)" + "method": "live probe of chock's shipped plugin, built on Windows and copied to `~/.gemini/config/plugins/chock-witness` with no hand edits. The store sets `windows_hook_command: quote_free`, so the hooks.json command has no quotes. `block-no-verify` refused the witness kit's GUARD shell command before it ran (\"tool call denied by pre-tool hook: Blocked by chock policy: block-no-verify\"). Then `git status` showed \"No commits yet\". `pin-github-actions` let a write of `.github/workflows/witness.yml` with `actions/checkout@v4` land. It did not refuse the write itself. It refused at turn end (\"Stop hook blocked termination: Unpinned GitHub Action det…\"), and the agent then pinned the action by commit SHA. A harmless `git status` ran. The claim is for a Windows build only (org-plan witness/results/witness-antigravity-2026-10-18.md, section \"Re-run on chock's shipped build\", 11121b3)" }, { "agent": "claude_code", diff --git a/src/chock/install/data/claude_plugin.json b/src/chock/install/data/claude_plugin.json index 0ad48b95..e9b52bdd 100644 --- a/src/chock/install/data/claude_plugin.json +++ b/src/chock/install/data/claude_plugin.json @@ -1,11 +1,11 @@ { "build_client": "claude-code", "offer_when": {"deny_reply": ["yes", "partial"]}, - "heading": "Also works: the Claude Code plugin (agentseam loads_claude_plugins, witnessed):", - "listing": "This build also runs in other agents (agentseam loads_claude_plugins, witnessed):", + "heading": "This agent can also run the Claude Code plugin (agentseam loads_claude_plugins, seen in a live run):", + "listing": "This build also runs in other agents (agentseam loads_claude_plugins, seen in a live run):", "build": "Build it: chock install --selection __SELECTION__ --client __BUILD_CLIENT__ (then, in __WHERE__:)", "warnings": [ - "Install one build per agent, not both: the agent's own chock plugin and the Claude Code plugin would each check every action.", + "Install one build per agent. If you install both the agent's own chock plugin and the Claude Code plugin, each one checks every action.", "When another agent runs the Claude Code plugin, chock logs its events as claude_code (~/.chock/log/claude_code/), not under that agent." ], "clients": { @@ -54,7 +54,7 @@ { "where": "VS Code", "witness": "an Agents-window session bound to a repo (Copilot SDK) ran no hooks", - "label": "Chat panel only; an Agents-window repo session ran no hooks", + "label": "Chat panel only. An Agents-window repo session ran no hooks", "steps": [ {"note": "Add to your VS Code user settings (chock does not edit them), then use the Chat panel with the folder open:"}, {"settings": {"chat.plugins.enabled": true, "chat.pluginLocations": {"__PLUGIN_DIR__": true}}} @@ -68,7 +68,7 @@ { "where": "Devin", "witness": "turn-end gate only", - "label": "turn end only; the shell guard and the write gate did not run", + "label": "turn end only. The shell guard and the write gate did not run", "prefer_native": "Devin's own chock plugin (chock install --client devin) is the better install here.", "steps": [ {"note": "On Windows, `devin plugins install --local` creates a symbolic link, so it needs Developer Mode (Settings > System > For developers) or an elevated shell."}, @@ -79,7 +79,7 @@ }, "cursor": { "agent": "cursor", - "not_offered": "Not offered for Cursor: with Include Third-Party Plugins on, Cursor imports an enabled Claude Code plugin and calls its hooks, but in the witness run chock never ran and nothing was refused; do not rely on that import to enforce chock's policies.", + "not_offered": "Not offered for Cursor. With Include Third-Party Plugins on, Cursor imports an enabled Claude Code plugin and calls its hooks. But in the live test, chock never ran and nothing was refused. Do not rely on that import to enforce chock's policies.", "routes": [] } } diff --git a/src/chock/install/data/install.json b/src/chock/install/data/install.json index 51f80e34..792349aa 100644 --- a/src/chock/install/data/install.json +++ b/src/chock/install/data/install.json @@ -5,6 +5,12 @@ "origin": { "custom": "custom, not reviewed" }, + "tier_prefix": "__GRADE__, and __FAIL__ (agentseam __BASIS__): ", + "tier_fail_mode": { + "open": "a hook error lets the action through", + "closed": "a hook error blocks the action", + "configurable": "what a hook error does is configurable" + }, "labels": { "block": "blocks", "ask": "asks", @@ -87,7 +93,7 @@ "dest": "~/.chock/marketplace/devin", "binary": "devin", "index": [], - "label_prefix": "best-effort, fails open: ", + "label_prefix": "best-effort, and a hook error lets the action through: ", "gate_turn_end_only": true, "steps": [ {"note": "On Windows, `devin plugins install --local` creates a symbolic link, so it needs Developer Mode (Settings > System > For developers) or an elevated shell; otherwise it fails with \"os error 1314: A required privilege is not held by the client\"."}, diff --git a/src/chock/install/data/warnings.json b/src/chock/install/data/warnings.json index b3f1eaa1..553db238 100644 --- a/src/chock/install/data/warnings.json +++ b/src/chock/install/data/warnings.json @@ -6,7 +6,7 @@ "block-wildcard-agent-permissions", "agent-permissions-scan" ], - "says": "__PRESENT__ is selected without its twin __ABSENT__: the two cover one rule by different means; select both." + "says": "__PRESENT__ is selected without its twin __ABSENT__. The two cover one rule in different ways, so select both." }, { "kind": "all_present", @@ -14,7 +14,7 @@ "rtk-dangerous-actions-blocker", "block-destructive-commands" ], - "says": "__PRESENT__ judge the same commands from one shared table: keep one, or a command is judged twice." + "says": "__PRESENT__ check the same commands from one shared table. Keep one, or a command is checked twice." }, { "kind": "file_absent", @@ -22,7 +22,7 @@ "verify-dependency-exists" ], "file": ".chock/dependency-allowlist.txt", - "says": "__PRESENT__ refuses every new dependency until __FILE__ exists (not found in the current directory); create it first." + "says": "__PRESENT__ refuses every new dependency until __FILE__ exists (not found in the current directory). Create it first." }, { "kind": "file_absent", @@ -30,7 +30,7 @@ "verify-mcp-allowlist" ], "file": ".chock/mcp-allowlist.json", - "says": "__PRESENT__ refuses every MCP server until __FILE__ exists (not found in the current directory); create it first." + "says": "__PRESENT__ refuses every MCP server until __FILE__ exists (not found in the current directory). Create it first." }, { "kind": "grade", @@ -44,7 +44,7 @@ }, { "kind": "overlap", - "says": "__PRESENT__ is also in the chock plugin __PLUGIN__ (__PATH__): both copies fire; remove it from one of the two selections." + "says": "__PRESENT__ is also in the chock plugin __PLUGIN__ (__PATH__), so both copies fire. Remove it from one of the two selections." }, { "kind": "client", @@ -58,21 +58,21 @@ "clients": [ "devin" ], - "says": "Devin runs plugin hooks best-effort and fails open: a hook that errors or times out lets the action through." + "says": "Devin runs plugin hooks on a best-effort basis. A hook that errors or times out lets the action through." }, { "kind": "client", "clients": [ "devin" ], - "says": "This client names no file-write tool a hook can match, so a gate judges what a turn wrote only at turn end; the write itself is not held." + "says": "This client names no file-write tool a hook can match. So a gate checks what a turn wrote only at turn end, and it does not stop the write when it happens." }, { "kind": "client", "clients": [ "copilot" ], - "says": "A gate judges the write before it lands in Copilot CLI (witnessed 2026-10-11, CLI 1.0.94 on Windows); in VS Code agent mode that is unmeasured." + "says": "In Copilot CLI, a gate checks the write before it lands (seen in a live run on 2026-10-11, CLI 1.0.94 on Windows). In VS Code agent mode that is unmeasured." }, { "kind": "client", @@ -86,28 +86,28 @@ "clients": [ "goose" ], - "says": "goose denies a PreToolUse call whose hook fails, because every entry sets on_failure: block; its Stop hooks stay fail-open, so a gate that fails at turn end lets the turn finish." + "says": "goose denies a PreToolUse call when its hook fails, because every entry sets `on_failure: block`. Its Stop hooks keep the default, so if a gate fails at turn end, the turn still finishes." }, { "kind": "client", "clients": [ "grok" ], - "says": "Grok's hooks fail open: a timeout, a crash or malformed output lets the action through, only an explicit deny blocks, and an allowManagedHooksOnly policy skips plugin hooks. No gate runs here: agentseam records neither a write-tool vocabulary nor a blocking Stop for grok." + "says": "If a Grok hook times out, crashes or returns malformed output, the action goes through. Only an explicit deny blocks, and an allowManagedHooksOnly policy skips plugin hooks. No gate runs here, because agentseam records neither a write-tool vocabulary nor a blocking Stop for grok." }, { "kind": "client", "clients": [ "antigravity" ], - "says": "Antigravity documents no fail mode for a hook and no plugin-root variable: the hooks name the plugin folder by absolute path, and a gate judges what a turn wrote only at turn end." + "says": "Antigravity documents no fail mode for a hook and no plugin-root variable. The hooks name the plugin folder by absolute path, and a gate checks what a turn wrote only at turn end." }, { "kind": "client", "clients": [ "goose" ], - "says": "On Windows, goose runs every hook with `sh -c`, so Git for Windows' sh must be on PATH; without it every tool call is denied, a harmless one too, because the hook cannot start (on_failure: block)." + "says": "On Windows, goose runs every hook with `sh -c`, so Git for Windows' sh must be on PATH. Without it, every tool call is denied, even a harmless one, because the hook cannot start (`on_failure: block`)." }, { "kind": "client", @@ -128,14 +128,14 @@ "clients": [ "kimi-code" ], - "says": "Kimi Code lets a call through when a hook errors, times out or exits with any code other than 2, cannot prompt (an ask is not enforced there), and applies a plugin to every project you open; it installs from its TUI only, and runs a copy, so reinstall after a rebuild." + "says": "Kimi Code lets a call through when a hook errors, times out or exits with any code other than 2. It cannot prompt, so an ask is not enforced there. It applies a plugin to every project you open. It installs from its TUI only and runs a copy, so reinstall after a rebuild." }, { "kind": "client", "clients": [ "kimi-code" ], - "says": "On Windows, the shell Kimi Code runs hook commands with is unmeasured, and the hooks read ${KIMI_PLUGIN_ROOT}; this path is not tested there." + "says": "On Windows, the shell Kimi Code runs hook commands with is unmeasured, and the hooks read ${KIMI_PLUGIN_ROOT}. This path is not tested there." }, { "kind": "client", @@ -165,7 +165,7 @@ "kimi-code", "factory-droid" ], - "says": "Untested: chock has not witnessed an install in this client. Its steps, its hooks and the plugin version string (+) are unmeasured there." + "says": "Untested: no live run has shown a chock install working in this client. Its steps, its hooks and the plugin version string (+) are unmeasured there." } ] } diff --git a/src/chock/install/package.py b/src/chock/install/package.py index 59e6d369..61acc08c 100644 --- a/src/chock/install/package.py +++ b/src/chock/install/package.py @@ -61,7 +61,13 @@ def _prefix(data: dict[str, Any]) -> str: return str(data["label_prefix"]) agent = bundle_build.CLIENTS[data["format"]].agent row = next(r for r in tier_table.rows() if r["agent"] == agent) - return f"{row['grade']}, fail mode {row['fail_mode']} (agentseam {row['basis']}): " + words = settings() + return ( + words["tier_prefix"] + .replace("__GRADE__", row["grade"]) + .replace("__FAIL__", words["tier_fail_mode"][row["fail_mode"]]) + .replace("__BASIS__", row["basis"]) + ) def _unasked(data: dict[str, Any], level: int) -> str: @@ -70,7 +76,7 @@ def _unasked(data: dict[str, Any], level: int) -> str: if not data.get("tier_label") or level != bundle_grade.ASKS or any(runtime_bundle.pre_tool_can_ask(agent).values()): return "" why = vendors.entry(agent)["verdicts"]["degrade_notes"]["escalate"] - return f"; the ask is not enforced here: {why}" + return f". The ask is not enforced here ({why})" def labels(members: list[Member], catalog: Path, client_id: str, custom: frozenset[str] = frozenset()) -> list[Label]: diff --git a/src/chock/plugin/bundle_build.py b/src/chock/plugin/bundle_build.py index b3775f0d..9412a362 100644 --- a/src/chock/plugin/bundle_build.py +++ b/src/chock/plugin/bundle_build.py @@ -92,7 +92,7 @@ def member_grades( #: Devin's own docs call plugin hooks best-effort and fail-open, so no member line may say it "refuses" flatly. -_QUALIFIER = {"devin": "best-effort, fails open: "} +_QUALIFIER = {"devin": "best-effort, and a hook error lets the action through: "} def _describe(client: Client, bundle: dict[str, Any], packages: list, note: str) -> tuple[str, int]: diff --git a/src/chock/plugin/bundle_grade.py b/src/chock/plugin/bundle_grade.py index af0a660c..58a46cb4 100644 --- a/src/chock/plugin/bundle_grade.py +++ b/src/chock/plugin/bundle_grade.py @@ -20,7 +20,7 @@ ADVISORY, WARNS, ASKS, STOP_ONLY, BLOCKS = range(5) #: Keyword a bundle's weakest member lends it, in the manifest's own `enforcement` vocabulary. _ENFORCEMENT = {ADVISORY: "advise", WARNS: "warn", ASKS: "ask", STOP_ONLY: "block", BLOCKS: "block"} -ADVISORY_SAYS = "advisory only: skill text, nothing stops a violation" +ADVISORY_SAYS = "advisory only. It is skill text, and nothing stops a violation" _GUARD_SAYS = "refuses a matched shell command before it runs" _GATE_ACTION_GRADE = {"warn": WARNS, "ask": ASKS} _GATE_VERBS = {"block": "blocks", "ask": "asks", "warn": "warns"} @@ -72,12 +72,14 @@ def grade_of( reach = ( "on an agent's file writes and at turn end" if writes - else "at turn end only; the write itself is not judged" + else "at turn end only. It does not check a file write when it happens" ) grade = _GATE_ACTION_GRADE.get(action, BLOCKS if writes else STOP_ONLY) gate_says = f"{_GATE_VERBS.get(action, 'blocks')} {reach}" # A guard beside the gate blocks outright, so the gate's grade stays the package's floor. - return grade, f"{_GUARD_SAYS}; {gate_says}" if any(_GUARD_FLAG in c for c in commands) else gate_says + if any(_GUARD_FLAG in c for c in commands): + return grade, f"{_GUARD_SAYS}. {gate_says[:1].upper()}{gate_says[1:]}" + return grade, gate_says if any(_GUARD_FLAG in c for c in commands): return BLOCKS, _GUARD_SAYS return ADVISORY, ADVISORY_SAYS diff --git a/tests/fixtures/plugin_targets/antigravity.json b/tests/fixtures/plugin_targets/antigravity.json index 95d77532..313a3d70 100644 --- a/tests/fixtures/plugin_targets/antigravity.json +++ b/tests/fixtures/plugin_targets/antigravity.json @@ -29,7 +29,7 @@ ], "manifest": { "name": "demo-bundle", - "description": "Two demo policies. Members: demo-write-gate: blocks at turn end only; the write itself is not judged; demo-shell-guard: refuses a matched shell command before it runs; demo-advice: advisory only: skill text, nothing stops a violation. [Advisory skill only; enforcement needs chock installed in the repo.]" + "description": "Two demo policies. Members: demo-write-gate: blocks at turn end only. It does not check a file write when it happens; demo-shell-guard: refuses a matched shell command before it runs; demo-advice: advisory only. It is skill text, and nothing stops a violation. [Advisory skill only; enforcement needs chock installed in the repo.]" }, "hooks": { "agentseam": { diff --git a/tests/fixtures/plugin_targets/droid.json b/tests/fixtures/plugin_targets/droid.json index e8a0357a..fa03d105 100644 --- a/tests/fixtures/plugin_targets/droid.json +++ b/tests/fixtures/plugin_targets/droid.json @@ -30,7 +30,7 @@ "manifest": { "name": "demo-bundle", "version": "0.1.0", - "description": "Two demo policies. Members: demo-write-gate: blocks on an agent's file writes and at turn end; demo-shell-guard: refuses a matched shell command before it runs; demo-advice: advisory only: skill text, nothing stops a violation. [Advisory skill only; enforcement needs chock installed in the repo.]" + "description": "Two demo policies. Members: demo-write-gate: blocks on an agent's file writes and at turn end; demo-shell-guard: refuses a matched shell command before it runs; demo-advice: advisory only. It is skill text, and nothing stops a violation. [Advisory skill only; enforcement needs chock installed in the repo.]" }, "hooks": { "PreToolUse": [ diff --git a/tests/fixtures/plugin_targets/kimi.json b/tests/fixtures/plugin_targets/kimi.json index 5d5e2993..ee6580cc 100644 --- a/tests/fixtures/plugin_targets/kimi.json +++ b/tests/fixtures/plugin_targets/kimi.json @@ -29,7 +29,7 @@ "manifest": { "name": "demo-bundle", "version": "0.1.0", - "description": "Two demo policies. Members: demo-write-gate: blocks at turn end only; the write itself is not judged; demo-shell-guard: refuses a matched shell command before it runs; demo-advice: advisory only: skill text, nothing stops a violation. [Advisory skill only; enforcement needs chock installed in the repo.]", + "description": "Two demo policies. Members: demo-write-gate: blocks at turn end only. It does not check a file write when it happens; demo-shell-guard: refuses a matched shell command before it runs; demo-advice: advisory only. It is skill text, and nothing stops a violation. [Advisory skill only; enforcement needs chock installed in the repo.]", "skills": "./skills/", "hooks": [ { diff --git a/tests/fixtures/plugin_targets/openhands.json b/tests/fixtures/plugin_targets/openhands.json index 3413d2b2..98465b64 100644 --- a/tests/fixtures/plugin_targets/openhands.json +++ b/tests/fixtures/plugin_targets/openhands.json @@ -30,7 +30,7 @@ "manifest": { "name": "demo-bundle", "version": "0.1.0", - "description": "Two demo policies. Members: demo-write-gate: blocks on an agent's file writes and at turn end; demo-shell-guard: refuses a matched shell command before it runs; demo-advice: advisory only: skill text, nothing stops a violation. [Advisory skill only; enforcement needs chock installed in the repo.]" + "description": "Two demo policies. Members: demo-write-gate: blocks on an agent's file writes and at turn end; demo-shell-guard: refuses a matched shell command before it runs; demo-advice: advisory only. It is skill text, and nothing stops a violation. [Advisory skill only; enforcement needs chock installed in the repo.]" }, "hooks": { "hooks": { diff --git a/tests/test_install_clients.py b/tests/test_install_clients.py index 53085b3d..73911372 100644 --- a/tests/test_install_clients.py +++ b/tests/test_install_clients.py @@ -132,8 +132,8 @@ def test_the_flag_overrides_the_selections_client_and_the_marker_records_it(cata ("copilot", "refuses a matched shell command", "blocks on an agent's file writes and at turn end"), ( "devin", - "best-effort, fails open: refuses a matched shell command", - "best-effort, fails open: blocks at turn end only", + "best-effort, and a hook error lets the action through: refuses a matched shell command", + "best-effort, and a hook error lets the action through: blocks at turn end only", ), ], ) @@ -155,11 +155,11 @@ def test_client_warnings_say_untested_for_every_unwitnessed_client(catalog, tmp_ root, ref = catalog assert _run(tmp_path, v2(root, ref, client)) == 0 out = capsys.readouterr().out - assert ("warning: Untested: chock has not witnessed an install" in out) == (client in UNWITNESSED) + assert ("warning: Untested: no live run has shown a chock install working" in out) == (client in UNWITNESSED) assert ("trust them in /hooks" in out) == (client == "codex") - assert ("fails open: a hook that errors" in out) == (client == "devin") + assert ("A hook that errors or times out lets the action through" in out) == (client == "devin") assert ("only at turn end" in out) == (client == "devin") - assert ("in VS Code agent mode that is unmeasured" in out) == (client == "copilot") + assert ("In VS Code agent mode that is unmeasured" in out) == (client == "copilot") assert ("Allow Local Plugin Imports" in out) == (client == "cursor") diff --git a/tests/test_install_coexist.py b/tests/test_install_coexist.py index 9e14764c..cf079c3b 100644 --- a/tests/test_install_coexist.py +++ b/tests/test_install_coexist.py @@ -84,7 +84,7 @@ def test_overlap_with_another_chock_plugin_for_the_client_is_warned(catalog, tmp assert _run(tmp_path, v2(root, ref, "codex", (GATE_ID, ADVISORY_ID), name="set-two")) == 0 folder = place.default_dest("codex").resolve() / "codex" / "set-one" out = capsys.readouterr().out - assert f"warning: {GATE_ID} is also in the chock plugin set-one ({folder}): both copies fire" in out + assert f"warning: {GATE_ID} is also in the chock plugin set-one ({folder}), so both copies fire" in out assert GUARD_ID not in out.split("warning:", 1)[1].split("\n", 1)[0] assert _run(tmp_path, v2(root, ref, "claude-code", (GATE_ID,), name="set-three")) == 0 assert "is also in the chock plugin" not in capsys.readouterr().out, "another client's plugin never overlaps" diff --git a/tests/test_plugin_guard_plus_gate.py b/tests/test_plugin_guard_plus_gate.py index 6577b7db..9d3d37a9 100644 --- a/tests/test_plugin_guard_plus_gate.py +++ b/tests/test_plugin_guard_plus_gate.py @@ -44,8 +44,10 @@ def test_both_halves_ship_in_every_store(tmp_path: Path, store: str) -> None: gate_events = bundle_grade.events_for(doc, "--gate") assert (len(gate_events) == 2) == (matcher is not None and stop) grade, says = bundle_grade.grade_of_files(files, hooks_rel, agent) - assert says.startswith("refuses a matched shell command before it runs; blocks ") - assert ("the write itself is not judged" in says) == (matcher is None), "a Stop-only gate never claims the write" + assert says.startswith("refuses a matched shell command before it runs. Blocks ") + assert ("It does not check a file write when it happens" in says) == (matcher is None), ( + "a Stop-only gate never claims the write" + ) assert grade == (bundle_grade.BLOCKS if matcher else bundle_grade.STOP_ONLY) diff --git a/tests/test_plugin_guard_plus_gate_claims.py b/tests/test_plugin_guard_plus_gate_claims.py index fbee84fe..baf670a0 100644 --- a/tests/test_plugin_guard_plus_gate_claims.py +++ b/tests/test_plugin_guard_plus_gate_claims.py @@ -29,7 +29,7 @@ def test_a_merged_bundle_carries_and_states_both_halves(tmp_path: Path, client: assert any("--guard" in c for c in commands) and any("--gate" in c for c in commands) description = json.loads(files[Path(manifest_rel)])["description"] assert "Shell guard:" in description and "Write gate:" in description - assert "refuses a matched shell command before it runs; blocks" in description + assert "refuses a matched shell command before it runs. Blocks" in description def test_a_stop_only_gate_beside_a_guard_never_reads_as_judging_the_write(tmp_path: Path) -> None: @@ -38,7 +38,7 @@ def test_a_stop_only_gate_beside_a_guard_never_reads_as_judging_the_write(tmp_pa members = [Member(pack, data)] files = merged_files("copilot", _bundle(), members, tmp_path) description = json.loads(files[Path("plugin.json")])["description"] - assert "at turn end only; the write itself is not judged" in description + assert "at turn end only. It does not check a file write when it happens" in description def test_the_catalog_page_counts_each_half_and_says_some_ship_both(tmp_path: Path) -> None: diff --git a/tests/test_plugin_install_targets.py b/tests/test_plugin_install_targets.py index 84427939..afc89fc1 100644 --- a/tests/test_plugin_install_targets.py +++ b/tests/test_plugin_install_targets.py @@ -255,10 +255,26 @@ def test_antigravity_install_names_its_final_folder_not_the_staging_one(catalog, @pytest.mark.parametrize( ("client", "prefix", "evidence"), [ - ("goose", "best-effort, fail mode configurable (agentseam vendor-docs): ", "agentseam/issues/177"), - ("grok", "best-effort, fail mode open (agentseam vendor-docs): ", "agentseam/issues/188"), - ("antigravity", "best-effort, fail mode open (agentseam vendor-docs): ", "agentseam/issues/129"), - ("openhands", "best-effort, fail mode open (agentseam vendor-docs): ", "agentseam/issues/181"), + ( + "goose", + "best-effort, and what a hook error does is configurable (agentseam vendor-docs): ", + "agentseam/issues/177", + ), + ( + "grok", + "best-effort, and a hook error lets the action through (agentseam vendor-docs): ", + "agentseam/issues/188", + ), + ( + "antigravity", + "best-effort, and a hook error lets the action through (agentseam vendor-docs): ", + "agentseam/issues/129", + ), + ( + "openhands", + "best-effort, and a hook error lets the action through (agentseam vendor-docs): ", + "agentseam/issues/181", + ), ], ) def test_labels_come_from_the_tier_table_and_warnings_link_the_evidence_issue( @@ -270,9 +286,13 @@ def test_labels_come_from_the_tier_table_and_warnings_link_the_evidence_issue( lines = {line.split()[0]: line for line in out.splitlines() if line.startswith(" demo-")} assert f"{prefix}refuses a matched shell command" in lines[GUARD_ID] assert "advisory only" in lines[ADVISORY_ID] and prefix not in lines[ADVISORY_ID] - kept = {"goose": "sh must be on PATH", "grok": "Grok's hooks fail open", "antigravity": "only at turn end"} + kept = { + "goose": "sh must be on PATH", + "grok": "If a Grok hook times out, crashes or returns malformed output, the action goes through", + "antigravity": "only at turn end", + } witnessed = client in kept - assert ("warning: Untested: chock has not witnessed an install in this client" in out) != witnessed + assert ("warning: Untested: no live run has shown a chock install working in this client" in out) != witnessed assert {"Evidence wanted" in out, evidence in out} == {not witnessed} assert kept.get(client, "") in out @@ -283,10 +303,10 @@ def test_an_ask_gate_is_labelled_not_enforced_where_the_client_cannot_ask(catalo gate.manifest["hook"]["gate"]["action"] = "ask" (gate.policy_dir / "manifest.yaml").write_text(yaml.safe_dump(gate.manifest), encoding="utf-8") labels = {label.policy_id: label.says for label in package.labels(members, tmp_path / "m", "goose")} - assert labels[GATE_ID].endswith("; the ask is not enforced here: goose cannot prompt for confirmation") + assert labels[GATE_ID].endswith(". The ask is not enforced here (goose cannot prompt for confirmation)") # Antigravity's gate runs at Stop only, where agentseam records it cannot prompt either. labels = {label.policy_id: label.says for label in package.labels(members, tmp_path / "m", "antigravity")} - assert labels[GATE_ID].endswith("; the ask is not enforced here: Antigravity cannot prompt at Stop") + assert labels[GATE_ID].endswith(". The ask is not enforced here (Antigravity cannot prompt at Stop)") def test_the_toggle_lookup_reads_goose_and_antigravity_folders(tmp_path: Path) -> None: diff --git a/tests/test_plugin_install_targets_kimi_droid.py b/tests/test_plugin_install_targets_kimi_droid.py index eb519963..9acd3981 100644 --- a/tests/test_plugin_install_targets_kimi_droid.py +++ b/tests/test_plugin_install_targets_kimi_droid.py @@ -245,10 +245,10 @@ def test_labels_come_from_the_tier_table_and_warnings_link_the_evidence_issue( assert _install(tmp_path, root, ref, client) == 0 out = capsys.readouterr().out lines = {line.split()[0]: line for line in out.splitlines() if line.startswith(" demo-")} - prefix = "best-effort, fail mode open (agentseam vendor-docs): " + prefix = "best-effort, and a hook error lets the action through (agentseam vendor-docs): " assert f"{prefix}refuses a matched shell command" in lines[GUARD_ID] assert "advisory only" in lines[ADVISORY_ID] and prefix not in lines[ADVISORY_ID] - assert "warning: Untested: chock has not witnessed an install in this client" in out + assert "warning: Untested: no live run has shown a chock install working in this client" in out assert evidence in out @@ -258,8 +258,8 @@ def test_an_ask_gate_is_labelled_not_enforced_in_kimi_and_droid(tmp_path: Path) gate.manifest["hook"]["gate"]["action"] = "ask" (gate.policy_dir / "manifest.yaml").write_text(yaml.safe_dump(gate.manifest), encoding="utf-8") kimi = {label.policy_id: label.says for label in package.labels(members, tmp_path / "m", "kimi-code")} - assert kimi[GATE_ID].endswith("; the ask is not enforced here: Kimi Code cannot prompt for confirmation") + assert kimi[GATE_ID].endswith(". The ask is not enforced here (Kimi Code cannot prompt for confirmation)") droid = {label.policy_id: label.says for label in package.labels(members, tmp_path / "m", "factory-droid")} assert droid[GATE_ID].endswith( - "; the ask is not enforced here: Droid's ask does not force a prompt, so this is a block" + ". The ask is not enforced here (Droid's ask does not force a prompt, so this is a block)" ) diff --git a/tests/test_witness_ledger.py b/tests/test_witness_ledger.py index b4ce6998..3cf50e07 100644 --- a/tests/test_witness_ledger.py +++ b/tests/test_witness_ledger.py @@ -191,7 +191,7 @@ def test_copilots_plugin_witness_cites_its_record_and_names_what_it_did_not_cove assert evidence.witness("vscode_copilot", Surface.AGENT_HOOKS.value) is not None assert "witness/results/witness-copilot-2026-10-11.md" in row.method assert "83f636d" in row.method - assert "VS Code agent mode" in row.method and "not covered" in row.method + assert "Not covered: VS Code agent mode" in row.method assert "VS Code" not in row.client @@ -230,7 +230,7 @@ def test_antigravitys_plugin_witness_cites_its_record_and_the_turn_end_gate() -> assert "11121b3" in row.method assert "Blocked by chock policy: block-no-verify" in row.method assert "Stop hook blocked termination: Unpinned GitHub Action det" in row.method - assert "at turn end" in row.method and "not at the write" in row.method + assert "It refused at turn end" in row.method and "did not refuse the write itself" in row.method assert "quote_free" in row.method and "Windows build only" in row.method assert evidence.witness("antigravity", Surface.PRE_TOOL_USE.value) is None From 133099aff73f73c6fc8272f8340af02feebe8415 Mon Sep 17 00:00:00 2001 From: Jothi Mani Rajendran <250249270+jothimani-rajendran@users.noreply.github.com> Date: Mon, 19 Oct 2026 00:39:43 +0000 Subject: [PATCH 2/3] test: keep test_plugin_install_targets.py within the 300-line budget (VOICE-3a) Co-Authored-By: Claude Opus 5.5 Signed-off-by: Jothi Mani Rajendran <250249270+jothimani-rajendran@users.noreply.github.com> --- tests/test_plugin_install_targets.py | 34 ++++++++-------------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/tests/test_plugin_install_targets.py b/tests/test_plugin_install_targets.py index afc89fc1..78796855 100644 --- a/tests/test_plugin_install_targets.py +++ b/tests/test_plugin_install_targets.py @@ -252,29 +252,17 @@ def test_antigravity_install_names_its_final_folder_not_the_staging_one(catalog, assert commands and all(f'"{folder.as_posix()}/scripts/' in c for c in commands) +THROUGH = "best-effort, and a hook error lets the action through (agentseam vendor-docs): " +CONFIGURABLE = "best-effort, and what a hook error does is configurable (agentseam vendor-docs): " + + @pytest.mark.parametrize( ("client", "prefix", "evidence"), [ - ( - "goose", - "best-effort, and what a hook error does is configurable (agentseam vendor-docs): ", - "agentseam/issues/177", - ), - ( - "grok", - "best-effort, and a hook error lets the action through (agentseam vendor-docs): ", - "agentseam/issues/188", - ), - ( - "antigravity", - "best-effort, and a hook error lets the action through (agentseam vendor-docs): ", - "agentseam/issues/129", - ), - ( - "openhands", - "best-effort, and a hook error lets the action through (agentseam vendor-docs): ", - "agentseam/issues/181", - ), + ("goose", CONFIGURABLE, "agentseam/issues/177"), + ("grok", THROUGH, "agentseam/issues/188"), + ("antigravity", THROUGH, "agentseam/issues/129"), + ("openhands", THROUGH, "agentseam/issues/181"), ], ) def test_labels_come_from_the_tier_table_and_warnings_link_the_evidence_issue( @@ -286,11 +274,7 @@ def test_labels_come_from_the_tier_table_and_warnings_link_the_evidence_issue( lines = {line.split()[0]: line for line in out.splitlines() if line.startswith(" demo-")} assert f"{prefix}refuses a matched shell command" in lines[GUARD_ID] assert "advisory only" in lines[ADVISORY_ID] and prefix not in lines[ADVISORY_ID] - kept = { - "goose": "sh must be on PATH", - "grok": "If a Grok hook times out, crashes or returns malformed output, the action goes through", - "antigravity": "only at turn end", - } + kept = {"goose": "sh must be on PATH", "grok": "returns malformed output", "antigravity": "only at turn end"} witnessed = client in kept assert ("warning: Untested: no live run has shown a chock install working in this client" in out) != witnessed assert {"Evidence wanted" in out, evidence in out} == {not witnessed} From ec8a452da21dbf7320b4e5490d2995cb62f4319a Mon Sep 17 00:00:00 2001 From: Jothi Mani Rajendran <250249270+jothimani-rajendran@users.noreply.github.com> Date: Mon, 19 Oct 2026 00:57:47 +0000 Subject: [PATCH 3/3] fix(install): untested-client warning says what chock has not seen (VOICE-3a review) "no live run has shown a chock install working" claimed more than the original "chock has not witnessed"; it now reads "chock has not seen an install work in this client in a live run". Co-Authored-By: Claude Opus 5.5 Signed-off-by: Jothi Mani Rajendran <250249270+jothimani-rajendran@users.noreply.github.com> --- src/chock/install/data/warnings.json | 2 +- tests/test_install_clients.py | 2 +- tests/test_plugin_install_targets.py | 2 +- tests/test_plugin_install_targets_kimi_droid.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/chock/install/data/warnings.json b/src/chock/install/data/warnings.json index 553db238..269e9838 100644 --- a/src/chock/install/data/warnings.json +++ b/src/chock/install/data/warnings.json @@ -165,7 +165,7 @@ "kimi-code", "factory-droid" ], - "says": "Untested: no live run has shown a chock install working in this client. Its steps, its hooks and the plugin version string (+) are unmeasured there." + "says": "Untested: chock has not seen an install work in this client in a live run. Its steps, its hooks and the plugin version string (+) are unmeasured there." } ] } diff --git a/tests/test_install_clients.py b/tests/test_install_clients.py index 73911372..c1650f0a 100644 --- a/tests/test_install_clients.py +++ b/tests/test_install_clients.py @@ -155,7 +155,7 @@ def test_client_warnings_say_untested_for_every_unwitnessed_client(catalog, tmp_ root, ref = catalog assert _run(tmp_path, v2(root, ref, client)) == 0 out = capsys.readouterr().out - assert ("warning: Untested: no live run has shown a chock install working" in out) == (client in UNWITNESSED) + assert ("warning: Untested: chock has not seen an install work in this client" in out) == (client in UNWITNESSED) assert ("trust them in /hooks" in out) == (client == "codex") assert ("A hook that errors or times out lets the action through" in out) == (client == "devin") assert ("only at turn end" in out) == (client == "devin") diff --git a/tests/test_plugin_install_targets.py b/tests/test_plugin_install_targets.py index 78796855..9c99d19c 100644 --- a/tests/test_plugin_install_targets.py +++ b/tests/test_plugin_install_targets.py @@ -276,7 +276,7 @@ def test_labels_come_from_the_tier_table_and_warnings_link_the_evidence_issue( assert "advisory only" in lines[ADVISORY_ID] and prefix not in lines[ADVISORY_ID] kept = {"goose": "sh must be on PATH", "grok": "returns malformed output", "antigravity": "only at turn end"} witnessed = client in kept - assert ("warning: Untested: no live run has shown a chock install working in this client" in out) != witnessed + assert ("warning: Untested: chock has not seen an install work in this client in a live run" in out) != witnessed assert {"Evidence wanted" in out, evidence in out} == {not witnessed} assert kept.get(client, "") in out diff --git a/tests/test_plugin_install_targets_kimi_droid.py b/tests/test_plugin_install_targets_kimi_droid.py index 9acd3981..2ff3a60b 100644 --- a/tests/test_plugin_install_targets_kimi_droid.py +++ b/tests/test_plugin_install_targets_kimi_droid.py @@ -248,7 +248,7 @@ def test_labels_come_from_the_tier_table_and_warnings_link_the_evidence_issue( prefix = "best-effort, and a hook error lets the action through (agentseam vendor-docs): " assert f"{prefix}refuses a matched shell command" in lines[GUARD_ID] assert "advisory only" in lines[ADVISORY_ID] and prefix not in lines[ADVISORY_ID] - assert "warning: Untested: no live run has shown a chock install working in this client" in out + assert "warning: Untested: chock has not seen an install work in this client in a live run" in out assert evidence in out