mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-13 16:54:48 +00:00
AI.md, AI_AUTONOMY.md and PULSE_PRO.md linked nine times into docs/architecture/, which .gitignore marks as not for public release. The targets were never missing, they were deliberately unpublished, so every one of those links was dead for anybody but the maintainer. Write the three promised documents against the code and publish them under docs/ where the rest of the shipped set lives. PATROL_ARCHITECTURE.md covers a run end to end. The interesting part is that deterministic signal detection runs after the model, not before, so unmatched signals catch what the model failed to file. Signal types, the thresholds those signals derive from your own alert settings, and every condition in Finding.ShouldInvestigate are documented from internal/ai/patrol_signals.go and internal/ai/findings.go. ASSISTANT_SAFETY.md documents the session state machine in internal/ai/chat/fsm.go, its four states, the tool classification it runs on, and its invariants. No write without a validated target, no second write before the first is verified, no final answer about an unverified change, and no attempt count that wears the gate down. ASSISTANT_ARCHITECTURE.md covers the agentic loop around that machine, the three-phase pipeline, why only execution parallelises and at what cap, the read-before-write batch that must stay ordered, the look-before-asking gate and its bound, and the stable error codes. Also removed two older pointers into the same private directory, in API.md and UPGRADE_v6.md, and the two references to ENTITLEMENT_MATRIX.md in PULSE_PRO.md. That file exists locally and is a monetization document, so publishing it is not a documentation decision. Unresolvable intra-doc links are now 2 of 218, both internal release-control documents deliberately withheld from the shipped set. Contract-Neutral: documentation only
100 lines
4.1 KiB
Markdown
100 lines
4.1 KiB
Markdown
# Pulse Assistant safety architecture
|
|
|
|
The state machine that governs what the Pulse Assistant is allowed to do
|
|
during a chat session, the tool classification it runs on, and the invariants
|
|
it holds.
|
|
|
|
The point of this machine is structural. Prompt wording can be argued with by
|
|
a model, and drifts as prompts are edited. These rules are enforced in code,
|
|
in `internal/ai/chat/fsm.go`, so neither a model nor a future prompt change
|
|
can talk its way past them.
|
|
|
|
## Tool kinds
|
|
|
|
Every tool call is classified before it runs.
|
|
|
|
| Kind | Meaning |
|
|
|---|---|
|
|
| `resolve` | Discovery and query tools that find resources |
|
|
| `read` | Read-only tools such as logs, metrics, status, and config |
|
|
| `write` | Mutating tools such as restart, stop, start, delete, and file write |
|
|
| `user_input` | Interactive tools that ask you something |
|
|
|
|
Classification is `ClassifyToolCall`, which delegates to the shared
|
|
`agentcapabilities` classifier so the Assistant and the rest of the agent
|
|
surface agree on what counts as a write.
|
|
|
|
## States
|
|
|
|
A session starts in `RESOLVING` and moves between four states.
|
|
|
|
| State | What it means |
|
|
|---|---|
|
|
| `RESOLVING` | No validated target yet, so resources must be discovered first |
|
|
| `READING` | A target is established and querying is allowed |
|
|
| `WRITING` | Transitional, entered around a mutation |
|
|
| `VERIFYING` | A write happened and evidence has not been gathered since |
|
|
|
|
Transitions on a successful tool call are as follows.
|
|
|
|
- A `resolve` or `read` in `RESOLVING` moves the session to `READING`.
|
|
- A `write` from any state moves the session to `VERIFYING`, records the tool
|
|
and timestamp, and clears the read-after-write flag.
|
|
- A `resolve` or `read` while in `VERIFYING` sets read-after-write, which is
|
|
what satisfies the verification requirement.
|
|
- A `user_input` call does not advance state at all, because asking you a
|
|
question is neither discovery nor verification.
|
|
|
|
`CompleteVerification` returns a verified session from `VERIFYING` to
|
|
`READING` so further writes become possible.
|
|
|
|
## The invariants
|
|
|
|
**No writing without a validated target.** A `write` attempted in `RESOLVING`
|
|
is blocked. The model must establish what it is acting on before it acts.
|
|
|
|
**No writing again until the last write is verified.** A `write` attempted in
|
|
`VERIFYING` is blocked until a read or resolve has run since the write.
|
|
|
|
**No final answer about an unverified change.** `CanFinalAnswer` refuses while
|
|
the session is in `VERIFYING` with no read-after-write. The Assistant cannot
|
|
tell you it restarted something and then decline to look at whether the
|
|
restart worked.
|
|
|
|
**Repeated attempts do not wear the gate down.** Consecutive blocked writes in
|
|
`VERIFYING` increment a counter, and that counter is telemetry only. There is
|
|
no attempt threshold after which the verification requirement is waived.
|
|
|
|
**Reads are never blocked.** No state blocks a `read`, `resolve`, or
|
|
`user_input`. The machine constrains mutation and the claims made about
|
|
mutation, not information gathering.
|
|
|
|
## Blocked calls and recovery
|
|
|
|
A blocked call returns an `FSMBlockedError` carrying the state, the tool, the
|
|
tool kind, a reason, and a recoverable flag. It surfaces to the model with the
|
|
stable code `ErrCodeFSMBlocked` rather than as prose, so the model can branch
|
|
on the code.
|
|
|
|
Blocks are recoverable rather than terminal. The session tracks a pending
|
|
recovery per blocked operation, and a later successful call of the same tool
|
|
clears it. Pending recoveries expire after ten minutes.
|
|
|
|
## Resetting
|
|
|
|
`Reset` returns the session to `RESOLVING` and clears all tracking, which is
|
|
what a full session clear does.
|
|
|
|
`ResetKeepProgress` is the softer variant used when context is cleared but
|
|
pinned items are kept. It drops verification tracking and moves a `VERIFYING`
|
|
session back to `READING`, without discarding that a target was established.
|
|
|
|
Note that `WroteThisEpisode` means "wrote at all during this session" rather
|
|
than "wrote during the current verification cycle", and `CompleteVerification`
|
|
deliberately leaves it set.
|
|
|
|
## Related reading
|
|
|
|
- [AI features](AI.md) for the overview and configuration.
|
|
- [Patrol deep dive](PATROL_ARCHITECTURE.md) for the scheduled analysis
|
|
runtime, which is a separate loop from the Assistant.
|