Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# Changelog

## 1.0.7-beta.0 — 2026-09-22

### Added

- `fp issues` gains `close`, `archive`, `unarchive` and `clear`. `close` is the second terminal state — "we're done with it", not "we fixed it" — and the difference is what happens next: a **resolved** issue reopens when its audit finding recurs, a **closed** one does not. `archive`/`unarchive` toggle a flag that is orthogonal to state, so taking an issue off the board never overwrites how it ended. `clear` is the bulk operation behind "we changed our agents, give us a fresh board": it resolves every open issue in a scope (`--audit <id>`, `--all-audits`, or `--everything` — exactly one required, no default) plus the audit findings behind them, needs `issues:close` **and** `audits:write`, and previews with `--dry-run` from the same server-side scope predicate the write uses. It writes **no** suppression, so a pattern that survived the agent changes reopens its issue on the next run rather than staying hidden. `--state closed` is accepted by `issues list`, and `Incident` carries `closed_at` / `archived_at`. (#815)
- **`fp-cloud-cli` cuts its first stable release, `0.0.1`.** The commands above drive server endpoints that are being deployed to FailproofAI Cloud, so the CLI half stops being a pre-release: the `0.0.1b3` line the `bump` job opened is cut stable rather than published, `Development Status` moves to `5 - Production/Stable` so the classifier agrees with the one string pip reads, and `0.0.2b0` opens the next beta line. Nothing about the command surface changes at the cut — `pipx install fp-cloud-cli` already resolved the betas, because they were the only releases; now it resolves a version that says so. This is the PyPI package's own line and does not move the npm version, which stays at `1.0.7-beta.0`. (#815)

### Fixes

- **One event, two answers: "a recurring finding reopens the resolved issue" and "it opens a new one" were both written down, four lines apart.** `fp audits resolve --help`'s confirm line said `a genuine recurrence re-opens as new`, the skill and its command reference said the same, and the new `clear` text inherited it — while `issues close --help`, the audits guide's own table and the Cloud CLI reference all said the issue **reopens**. Only the second reading makes the rest coherent: a recurrence that opened a different issue would leave `close` with nothing to stay closed *through*, and could not un-archive "a live issue" the way archiving documents. The recurrence sentence now says `reopens` everywhere it appears, in the confirm text a user reads before resolving and in the skill a model reads before acting. (#815)
- **`clear`'s help promised the preview count could not disagree with the write, which nothing enforces.** The dry run and the write share a scope predicate, not a row set: the write re-runs it, so an issue that enters the scope in between is cleared without being in the number the user confirmed. That is the right behaviour for a command whose argument is a *scope* — but the guarantee as written was a stronger one than the two requests can make. The help now says what holds (the count is the real size of the scope, taken server-side) and what does not (it is a count, not a lease), and points at the closing line, which reports what actually changed. (#815)
- **The skill mapped "clear all our issues" to `--all-audits`, which is not all issues.** `--all-audits` leaves alert-born and hand-opened issues on the board, so a model following that row would clear part of it and report a fresh start. Both the intent table and the workflow note now make settling the scope the first step, with what each flag does and does not cover. (#815)

### Docs

- Document ending an issue three ways (resolve / close / archive) and clearing a board after an agent change, in the audits guide and the Cloud CLI reference. (#815)

## 1.0.6 — 2026-09-16

Stable native Hermes policy-enforcement release, validated across CLI and
Expand Down
58 changes: 58 additions & 0 deletions docs/audits/findings-and-issues.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ A finding is the audit's evidence-backed statement about a failure. An issue is
fp issues assign <issue-id> --assignee engineer@example.com
fp issues comment-add <issue-id> --body "policy is in observe mode"
fp issues resolve <issue-id> --yes
fp issues close <issue-id> --yes
fp issues archive <issue-id>
```

Use `fp issues subscribe <issue-id>`, `fp issues unsubscribe <issue-id>`, and `fp issues subscribers <issue-id>` to manage watchers.
Expand All @@ -67,6 +69,62 @@ Create or link an issue when the finding needs assignment, discussion, status ch

Resolve the issue when remediation is deployed and verified. Resolve the finding when the failure mode has been addressed for the audit population. Those moments may differ.

## End an issue: resolve, close, or archive

An issue ends once, and how you end it decides what happens the next time the audit
sees the same pattern.

| Action | Means | If the pattern comes back |
| --- | --- | --- |
| **Resolve** | You fixed it. | The issue **reopens**, so you find out the fix did not hold. |
| **Close** | You are done with it: won't fix, not a problem, or no longer relevant. | It **stays closed**. |
| **Archive** | Take it off the board. Says nothing about how it ended. | A live issue returns to the board automatically. |

Resolve and close are both final and neither can overwrite the other, so an issue
someone resolved keeps that record. Archiving is separate from both: you can archive
an issue in any state, and it keeps whatever state it ended in. If an archived issue
is still live and the problem recurs, it comes back to the board on its own — archive
hides history, it cannot hide an active problem.

Closing an issue that came from an audit also dismisses the finding behind it. It
does not silence that pattern in your other audits; for that, mute or dismiss the
finding itself.

## Start fresh after changing your agents

When you ship a round of changes to your agents, the issues already on the board
describe the behavior you just replaced. Clearing resolves them in one step, along
with the audit findings behind them.

<Tabs>
<Tab title="Dashboard">
1. Go to **Analyze → Issues** and select **clear**, or open a single audit and select **clear issues** to limit it to that audit's work.
2. Choose the scope. Each one shows how many issues it covers before you commit to it.
3. Confirm. The issues are resolved, and so are the audit findings behind them.
</Tab>
<Tab title="CLI">
```bash
fp issues clear --all-audits --dry-run
fp issues clear --all-audits --yes

fp issues clear --audit <audit-id> --yes
fp issues clear --everything --yes
```

`--dry-run` reports what would change without changing it. Exactly one of
`--audit`, `--all-audits`, and `--everything` is required.
</Tab>
</Tabs>

**Clearing suppresses nothing.** A pattern your changes genuinely fixed stays gone. A
pattern that survived them **reopens** its issue on the next audit run — the same thing
resolving one by hand does — so a fresh start cannot quietly hide a problem you still
have. When you do want a pattern
silenced for good, mute or dismiss the finding instead.

Clearing needs permission to both close issues and write audits, because it resolves
the findings as well as the issues.

## Turn an issue into a policy draft

<Tabs>
Expand Down
8 changes: 6 additions & 2 deletions docs/reference/cloud-cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -291,13 +291,17 @@ Include context during creation when the first run needs it. Creation commits th

| Command | Purpose | Options |
| --- | --- | --- |
| `fp issues list` | List issues. | `--state`; `--alert-id`; `--limit`, `-n`; `--show-id` |
| `fp issues list` | List issues. Archived issues are hidden. | `--state`; `--alert-id`; `--limit`, `-n`; `--show-id` |
| `fp issues count` | Count open or selected issue states. | `--state` |
| `fp issues show INCIDENT_ID` | Show issue details, comments, subscribers, and activity. | — |
| `fp issues open` | Open a manual or alert-linked issue. | required `--summary`; optional `--title`, `--alert-id`, `--severity` |
| `fp issues ack INCIDENT_ID` | Acknowledge an issue. | — |
| `fp issues assign INCIDENT_ID` | Replace assignees; omit the option to clear them. | repeatable `--assignee` |
| `fp issues resolve INCIDENT_ID` | Resolve an issue. | `--yes`, `-y` |
| `fp issues resolve INCIDENT_ID` | Resolve an issue: the problem is fixed. A recurring audit finding reopens it. | `--yes`, `-y` |
| `fp issues close INCIDENT_ID` | Close an issue: you are done with it, fixed or not. A recurrence does not reopen it. | `--yes`, `-y` |
| `fp issues archive INCIDENT_ID` | Take an issue off the board without changing how it ended. | — |
| `fp issues unarchive INCIDENT_ID` | Put an archived issue back on the board. | — |
| `fp issues clear` | Resolve every open issue in a scope, plus the audit findings behind them. Requires exactly one scope flag. | one of `--audit`, `--all-audits`, `--everything`; `--dry-run`; `--yes`, `-y` |
| `fp issues comment-list INCIDENT_ID` | List comments. | — |
| `fp issues comment-add INCIDENT_ID` | Add a comment. | exactly one of `--body`, `--file` |
| `fp issues comment-delete INCIDENT_ID COMMENT_ID` | Delete a comment. | `--yes`, `-y` |
Expand Down
51 changes: 46 additions & 5 deletions fp-cloud-cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,52 @@
# Changelog — `fp` CLI

## 0.0.1b3 — 2026-09-12
## 0.0.1 — 2026-09-22

**First stable release.** `0.0.1b1` and `0.0.1b2` are the two betas behind it; the
`0.0.1b3` line the `bump` job opened is cut stable here rather than published, because
the server endpoints these commands drive are deployed to FailproofAI Cloud and the
CLI half should not stay a pre-release behind them. Until now `pipx install
fp-cloud-cli` resolved a beta only because no stable existed — a default that would
have silently changed the day one did. `Development Status` moves to
`5 - Production/Stable` with the version, so the classifier and the one string pip
reads say the same thing.

Nothing about the command surface changes at the cut: the entries below are the
entire diff from `0.0.1b2`, and `0.0.2b0` opens the next beta line.

### Added

- `fp issues close <id>` — end an issue as won't-fix. Distinct from `resolve`: a
recurring audit finding reopens a **resolved** issue and leaves a **closed** one
alone. On an audit issue it marks the finding `dismissed`, without writing the
org-wide fingerprint suppression that `fp audits dismiss` writes. Exit 9 if the
issue already ended. (#815)
- `fp issues archive <id>` / `unarchive <id>` — take an issue off the board and put
it back. Orthogonal to state, allowed in any state, no confirmation prompt. (#815)
- `fp issues clear (--audit <id> | --all-audits | --everything) [--dry-run]` — resolve
every open issue in a scope plus the audit findings behind them, in one server-side
transaction. Exactly one scope flag is required. Needs `issues:close` **and**
`audits:write`. Writes no suppression, so anything still broken reopens its issue
on the next run. The confirm names the count from a dry run that shares its
scope predicate with the write. (#815)
- `issues list --state closed` is accepted, and `Incident` carries `closed_at` and
`archived_at`. (#815)

Open for the next release. `0.0.1b2` published on 2026-09-12 and the `bump` job
moved the version here automatically; nothing has landed against `0.0.1b3` yet.
Add entries as changes merge — this section becomes the GitHub Release body when
it ships.
### Fixes

- The recurrence sentence said two different things in one release. `audits resolve`'s
confirm line (`a genuine recurrence re-opens as new`), the skill and the command
reference implied a recurrence opens a **different** issue; `issues close --help`, the
audits guide and the CLI reference said the resolved issue **reopens**. The second is
the one the rest of the model needs — a `closed` issue has to have something to stay
closed through — so `reopens` is now what every surface says. (#815)
- `issues clear --help` claimed the `--dry-run` count "cannot disagree" with the write.
The two requests share a scope predicate, not a row set, so an issue entering the scope
between them is cleared without being in the confirmed number — correct for a scoped
clear, but not the guarantee that was written. The help now states the real one, and
names the closing line as the count of what changed. (#815)
- The skill answered "clear all our issues" with `--all-audits`, which leaves alert-born
and hand-opened issues untouched. Settling the scope is now the first step. (#815)

## 0.0.1b2 — 2026-08-25

Expand Down
2 changes: 1 addition & 1 deletion fp-cloud-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ fp keys list|show|create|update|disable|regenerate # API keys (secret shown
fp users list|show|create|update|disable|enable
fp settings list|schema|set
fp alerts list|show|create|update|delete|test
fp issues list|count|show|ack|assign|resolve|comment-add|comment-list|comment-delete|subscribe|subscribers|unsubscribe|open
fp issues list|count|show|ack|assign|resolve|close|archive|unarchive|clear|comment-add|comment-list|comment-delete|subscribe|subscribers|unsubscribe|open
fp audits list|show|create|edit|delete|run|runs|findings|finding # scheduled audits
fp audits ack|assign|resolve|dismiss|mute|reopen # triage a finding
fp audits context-show|context-set|context-refresh # reference context
Expand Down
2 changes: 1 addition & 1 deletion fp-cloud-cli/fp_cli/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.0.1b3"
__version__ = "0.0.1"
44 changes: 44 additions & 0 deletions fp-cloud-cli/fp_cli/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1161,6 +1161,50 @@ def resolve_incident(ctx: ClientContext, incident_id: str) -> None:
_post_json(ctx, f"/api/issues/{incident_id}/resolve")


def close_incident(ctx: ClientContext, incident_id: str) -> None:
"""POST /api/issues/{id}/close — end the issue as won't-fix.

The sibling of ``resolve_incident``, and the difference is what happens next:
a resolved issue REOPENS if its audit finding recurs, a closed one does not.
409 if the issue already ended.
"""
_post_json(ctx, f"/api/issues/{incident_id}/close")


def set_incident_archived(ctx: ClientContext, incident_id: str, archived: bool) -> None:
"""POST /api/issues/{id}/archive or /unarchive — hide from the board, or restore.

Does not change ``state``: an issue ends once, and archiving says nothing
about how. Idempotent on both sides, so a caller never has to read the
current value first.
"""
verb = "archive" if archived else "unarchive"
_post_json(ctx, f"/api/issues/{incident_id}/{verb}")


def clear_issues(
ctx: ClientContext,
*,
scope: str,
audit_id: Optional[str] = None,
dry_run: bool = False,
) -> Dict[str, Any]:
"""POST /api/issues/bulk-clear — resolve every live issue in a scope.

``scope`` is ``audit`` (with ``audit_id``), ``all_audits`` or ``everything``.
Returns ``{issues, findings, dry_run, scope}``.

Needs ``issues:close`` AND ``audits:write`` — clearing resolves the audit
findings behind the issues, and the second grant is what stops a key that
cannot touch one finding from resolving all of them at once.
"""
body: Dict[str, Any] = {"scope": scope, "dry_run": dry_run}
if audit_id:
body["audit_id"] = audit_id
data = _post_json(ctx, "/api/issues/bulk-clear", body)
return data if isinstance(data, dict) else {}


def list_incident_comments(ctx: ClientContext, incident_id: str) -> List[IncidentComment]:
data = _get_json(ctx, f"/api/issues/{incident_id}/comments")
return [IncidentComment.from_dict(c) for c in (data if isinstance(data, list) else [])]
Expand Down
Loading
Loading