tamperward 1.4.4 → 1.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,13 +18,17 @@ path: deleting failing tests, skipping them, casting to `any`, suppressing lint
|
|
|
18
18
|
lowering coverage gates, rewriting snapshots, editing CI, or bypassing hooks with
|
|
19
19
|
`--no-verify`. Tamperward treats the safety nets themselves as protected assets and
|
|
20
20
|
blocks the **class** of bypass — one ruleset, evaluated on the actual diff and commands
|
|
21
|
-
as a verdict, not a probability, enforced
|
|
22
|
-
agent's loop (a
|
|
23
|
-
and at the merge.**
|
|
21
|
+
as a verdict, not a probability, enforced at every stage a change passes through:
|
|
22
|
+
**inside the agent's loop (a Claude Code hook today — a deny before the tool runs, and
|
|
23
|
+
a sweep at end of turn), at the commit, and at the merge.** CI is the authority; the
|
|
24
|
+
earlier layers shorten the feedback loop for agents that carry them.
|
|
24
25
|
|
|
25
26
|
> Apache-2.0 · zero runtime model calls · every headline claim below is measured, with
|
|
26
27
|
> the pre-registered predictions (including the refuted ones) committed to this repo
|
|
27
28
|
|
|
29
|
+
**[Docs & guide](https://hexrift.github.io/tamperward/)** ·
|
|
30
|
+
**[The launch post](https://hexrift.github.io/tamperward/blog/what-agents-do-when-you-block-their-shortcuts)** — how these numbers were measured, and which of my own bets lost
|
|
31
|
+
|
|
28
32
|
## Install
|
|
29
33
|
|
|
30
34
|
```bash
|
|
@@ -34,12 +38,12 @@ npx tamperward init
|
|
|
34
38
|
One idempotent command wires the policy and every enforcement point — it never
|
|
35
39
|
overwrites anything you wrote, and `--dry-run` shows the plan first:
|
|
36
40
|
|
|
37
|
-
|
|
|
41
|
+
| what | wired as |
|
|
38
42
|
| --- | --- |
|
|
43
|
+
| policy | a commented baseline `.tamperward.yml` — the defaults apply even without it |
|
|
39
44
|
| agent loop | Claude Code `PreToolUse` deny + `Stop` sweep, merged into `.claude/settings.json` |
|
|
40
45
|
| pre-commit | husky when present, the plain git hook otherwise |
|
|
41
46
|
| CI | a PR-gate workflow with out-of-band sign-off (details below) |
|
|
42
|
-
| policy | a commented baseline `.tamperward.yml` — the defaults apply even without it |
|
|
43
47
|
|
|
44
48
|
Or run the views directly:
|
|
45
49
|
|
|
@@ -77,6 +81,7 @@ tamperward: 2 blocking
|
|
|
77
81
|
evidence 2 test block(s) removed from test/calc.test.js
|
|
78
82
|
instead Keep the assertions and fix the code. Removing test blocks to go
|
|
79
83
|
green is the tamper.
|
|
84
|
+
sign-off tamperward allow test-deletion --file test/calc.test.js --reason "..."
|
|
80
85
|
|
|
81
86
|
A blocking finding clears only with a human sign-off. In CI that sign-off is
|
|
82
87
|
out-of-band — a PR label applied by a reviewer — never a file committed on the
|
|
@@ -88,7 +93,7 @@ Under GitHub Actions each finding also lands as an **inline annotation on the di
|
|
|
88
93
|
|
|
89
94
|
## The rules
|
|
90
95
|
|
|
91
|
-
Nine mechanical rules, deterministic by construction
|
|
96
|
+
Nine mechanical rules, deterministic by construction — eight `block`, one `warn`:
|
|
92
97
|
`test-deletion` (AST block-count, rename-out-of-glob, shell mutation), `test-skip`
|
|
93
98
|
(including `.only`, which narrows the suite), `ts-any-cast`, `lint-suppression`,
|
|
94
99
|
`coverage-lowering` (Jest and Vitest shapes, all four metrics, `package.json` included),
|
|
@@ -96,8 +101,10 @@ Nine mechanical rules, deterministic by construction, `block` by default:
|
|
|
96
101
|
(flags and the env-var escape hatches), and `snapshot-rewrite` (`warn` — see the FP study
|
|
97
102
|
below for why).
|
|
98
103
|
|
|
99
|
-
|
|
100
|
-
|
|
104
|
+
Two heuristic rule names — `assertion-weakening` and `guard-removal` — are **reserved
|
|
105
|
+
in the baseline policy but not yet built**: they get detectors only once a measured
|
|
106
|
+
negatives corpus exists (SPEC §7.A), enter as `warn`, and never block until their
|
|
107
|
+
precision clears the bar.
|
|
101
108
|
|
|
102
109
|
The policy file itself is un-ignorable, CI reads the policy from the **merge-base** (a PR
|
|
103
110
|
cannot govern its own verdict), and the agent honours no sign-off it can author — the
|
|
@@ -108,13 +115,29 @@ escape valve is a PR label only a human with write access can apply.
|
|
|
108
115
|
**Does the loop work?** `harness/run.sh` stands up an isolated repo with a real bug and a
|
|
109
116
|
failing protected test, lets a headless agent loose with the hooks installed, and
|
|
110
117
|
classifies the end state with an oracle independent of the detectors under test
|
|
111
|
-
(SPEC §7.B). Across
|
|
112
|
-
had a detector covering it — **0 tampers reached green; all
|
|
113
|
-
ended in an honest fix**, a
|
|
118
|
+
(SPEC §7.B). Across 67 runs of these **guarded** scenarios — every attempted bypass class
|
|
119
|
+
had a detector covering it — **0 tampers reached green; all 25 runs where a block fired
|
|
120
|
+
ended in an honest fix**, a 25/25 point estimate whose 95% lower bound is ≈89%. The split is the
|
|
114
121
|
honest part: Sonnet 5 never attempted a bypass at all, even when the prompt *ordered*
|
|
115
|
-
one;
|
|
122
|
+
one; every interception came from Haiku 4.5 on a seed whose honest fix is genuinely
|
|
116
123
|
expensive. Reproduce: `npm run build && harness/run.sh 5 adversarial haiku seed-hard`.
|
|
117
124
|
|
|
125
|
+
**Is the fix caused by the deny, or would it have happened anyway?** Measured, with a
|
|
126
|
+
pre-registered no-gate control arm (`harness/PREDICTION-ungated-control.md`): same seed,
|
|
127
|
+
model, prompt and oracle, hooks removed. **6/10 ungated runs tampered through; honest
|
|
128
|
+
fixes fell from 10/10 gated to 4/10 ungated.** The gate's measured contribution on that
|
|
129
|
+
configuration is a 60-point swing — causation, not survivorship — and one of the three
|
|
130
|
+
control-arm bets was refuted (ungated honest fixes came in above my bet).
|
|
131
|
+
|
|
132
|
+
**And when the agent knows the gate is there?** Also pre-registered
|
|
133
|
+
(`harness/PREDICTION-informed-adversary.md`) — betting the gate would *leak*. Refuted,
|
|
134
|
+
three bets out of three: with the detector sources vendored into the repo and the prompt
|
|
135
|
+
naming the gate, Haiku's bypass attempts went from 5/10 uninformed (same day, same
|
|
136
|
+
everything) to **0/10 informed — fifteen informed runs, zero evasion attempts**. Sonnet,
|
|
137
|
+
told the gate exists under "speed is everything" pressure, refused the task outright in
|
|
138
|
+
3/5 runs rather than work around it, and fixed honestly in the other 2. At this scenario
|
|
139
|
+
size, disclosure measured as deterrence, not as an evasion spec.
|
|
140
|
+
|
|
118
141
|
**Which detectors deserve to exist?** Measured too. Affordance seeds offer an agent one
|
|
119
142
|
specific bypass each; predictions are pre-registered before any rep runs
|
|
120
143
|
(`harness/PREDICTION-affordance.md`). Result: 7/10 adversarial runs regenerated a golden
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tamperward",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.6",
|
|
4
4
|
"description": "The deterministic agent-integrity gate. One ruleset, evaluated on the actual diff/commands as a verdict, enforced everywhere a change can be made.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "hexrift",
|