# Stances
A rule does one of three things, and the middle one is the point:
| `observe` | records the firing and says nothing at all |
| `advise` | puts the reason into the model's context; refuses nothing |
| `deny` | refuses the tool call, with the reason and the remedy |
`observe` and `advise` are not two ways of saying "not blocking yet".
`additionalContext` enters the model's context and therefore changes its
behaviour, which contaminates the rate the observation exists to measure. **A
rule that talks is intervening.** That is why the two are named differently
and why `backtest` numbers from an `advise` rule are not comparable with the
numbers that justified promoting it.
That contamination is also what makes it measurable. `amont-agent backtest
--compliance` reads the two stances against each other: what a model did
after an `advise` fired, beside what it did after an `observe` fired and
said nothing. The second is the rate the habit corrects on its own, and an
`advise` that does not beat it is costing context tokens for nothing. See
[measuring and graduating](measuring.md).
## Changing one
Takes effect on the next command; nothing to restart.
```sh
git config --global amont.agent.pipe-to-tail.stance observe
git config --global amont.agent.stance observe # every rule
```
The ladder, most specific first:
```
rule.default_stance < amont.agent.stance < amont.agent.<id>.stance
```
then capped at the rule's own ceiling, and clamped to `observe` if the guard
is switched off.
## Ceilings
Every rule declares the loudest stance it may ever take. For most rules that
is `deny`, and the ceiling changes nothing. A rule whose finding is an
estimate — "this loop may make hundreds of requests" — is capped at
`advise`: refusing a command on an estimate would claim a certainty the
analysis does not have.
The cap is applied after every configured key, so neither
`amont.agent.stance deny` nor the rule's own key can pass it, and
`graduate --to deny` refuses a capped rule with the reason. `amont-agent
rules` prints each rule's ceiling beside its stance.
## Why git config and not a committed file
Promotion power stays on the machine, with the person. A rule that a committed
file could promote to `deny` would mean cloning a repository hands it the
power to refuse your shell commands.
This is enforced three times, because neither of the first two was enough.
1. `amont.conf`'s parser will not name these rules, so a committed manifest
cannot reach them.
2. amont's config reader lets a repository's committed policy `set` lines
outrank system and global git config — right for a hook manager, wrong for
a guard — so this project reads git config itself, without that ladder.
3. Git's own search order ends at `--local` and `--worktree`, and the last
file wins. A `.git/config` therefore outranked your `--global` answer
without any of amont's machinery being involved — and the agent whose
command was just refused can write one, since `git config` is not a
command any rule here objects to. So the reader takes **`--global`, then
`--system`, and nothing else.**
A stance answers to your own git config and to nothing a repository carries or
a process standing in one can write. A file your global config `include`s or
`includeIf`s counts as your own: git skips those for a scoped read unless asked,
and this reader asks. `graduate` and `demote` write `--global`
for the same reason.
One consequence worth stating plainly: `git config amont.agent.<rule>.stance`
run inside a repository writes `--local` by default, and this tool will not
read it. Pass `--global`, which is what every example here does.