Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
7f25b51
ci: enforce completed step attestations
Blakeolson21 Aug 23, 2026
d729ed5
fix(review): carry unresolved findings across rounds
Blakeolson21 Aug 23, 2026
7921793
no-mistakes(review): Fix carried findings and refresh CI attestations
Blakeolson21 Aug 23, 2026
5753610
no-mistakes(review): Harden carried finding persistence, identity, ri…
Blakeolson21 Aug 23, 2026
57a1225
no-mistakes(review): Preserve stable IDs and atomic review truth
Blakeolson21 Aug 23, 2026
ebb9aee
no-mistakes(review): Bind gate evidence and harden finding continuity
Blakeolson21 Aug 23, 2026
722c051
no-mistakes(review): Park stale gates and corroborate finding identity
Blakeolson21 Aug 23, 2026
0c094a1
no-mistakes(review): Rerun stale gates and preserve finding lineage
Blakeolson21 Aug 23, 2026
c2a0487
no-mistakes(review): Harden attestations and finding lineage continuity
Blakeolson21 Aug 23, 2026
281fc3f
no-mistakes(review): Harden CI attestation tracking and finding conti…
Blakeolson21 Aug 23, 2026
cacf520
no-mistakes(review): Preserve published CI heads and reap PR updates
Blakeolson21 Aug 23, 2026
e29c2aa
no-mistakes(review): Harden ambiguous CI pushes and lineage continuity
Blakeolson21 Aug 24, 2026
68c099e
no-mistakes(document): Document durable findings and attestation gates
Blakeolson21 Aug 24, 2026
086954e
test(ci): align repair expectations after rebase
Blakeolson21 Aug 24, 2026
7f53747
no-mistakes: apply CI fixes
Blakeolson21 Aug 24, 2026
69007e6
ci: accept attested historical pipeline marker
Blakeolson21 Aug 24, 2026
9433cbd
no-slop(review): Rerun stale gates and persist CI attestations
Blakeolson21 Aug 24, 2026
75c6465
no-slop(review): Preserve review truth and arm PR attestations
Blakeolson21 Aug 24, 2026
16203d1
no-slop(review): Corroborate finding lineage and bound stale CI attempts
Blakeolson21 Aug 24, 2026
39805cb
no-slop(review): Harden review lineage, recovery, risk, and CI bounda…
Blakeolson21 Aug 24, 2026
d667a70
no-slop(review): Harden finding recovery and CI attestation publication
Blakeolson21 Aug 24, 2026
95b431b
no-slop(review): Harden recovery truth and attestation publication
Blakeolson21 Aug 24, 2026
27e79ce
no-slop(review): Preserve review semantics and order attestation atte…
Blakeolson21 Aug 24, 2026
4dde9f5
no-slop(review): Preserve post-review truth and bind attestation runs
Blakeolson21 Aug 24, 2026
28ec2a7
no-slop(review): Restore attestation identity and review lineage orde…
Blakeolson21 Aug 24, 2026
b3014b5
no-slop(review): Harden review lineage recovery and CI publication or…
Blakeolson21 Aug 24, 2026
50d09df
no-slop(review): Align reconciled evidence and user finding statistics
Blakeolson21 Aug 24, 2026
09285fc
no-slop(review): Preserve lineage evidence and harden CI publication …
Blakeolson21 Aug 24, 2026
e1a6d28
no-slop(review): Fix finding statistics and atomic review certification
Blakeolson21 Aug 24, 2026
7ad67b5
no-slop(review): Harden finding occurrence recovery and statistics
Blakeolson21 Aug 24, 2026
3768216
no-slop(review): Preserve shared evidence and occurrence history
Blakeolson21 Aug 24, 2026
548f910
no-slop(review): Harden evidence, publication, recovery, and history …
Blakeolson21 Aug 24, 2026
623d4bd
no-slop(review): Order attestation events and restore legacy stats
Blakeolson21 Aug 24, 2026
bb518c9
no-slop(document): Document attestation and review recovery contracts
Blakeolson21 Aug 24, 2026
b6cead4
no-slop: apply CI fixes
Blakeolson21 Aug 24, 2026
6825c18
no-slop: apply CI fixes
Blakeolson21 Aug 24, 2026
88dd688
no-slop: apply CI fixes
Blakeolson21 Aug 24, 2026
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
135 changes: 112 additions & 23 deletions .github/workflows/no-slop-required.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: Require no-slop
run-name: "PR #${{ github.event.pull_request.number }} body compliance - ${{ github.event.action }} - event ${{ github.run_number }} (run ${{ github.run_id }})"
run-name: "no-slop-required|${{ github.event.action }}|PR #${{ github.event.pull_request.number }} event ${{ github.run_number }} (run ${{ github.run_id }})|${{ github.event.pull_request.body }}"

on:
pull_request:
Expand Down Expand Up @@ -40,29 +40,118 @@ jobs:
- name: Verify no-slop signature in PR body
env:
PR_BODY: ${{ github.event.pull_request.body }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
PR_ACTION: ${{ github.event.action }}
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
set -eu
canonical_marker='Updates from [git push no-slop](https://github.com/Blakeolson21/no-slop)'
legacy_marker='Updates from [git push no-mistakes](https://github.com/Blakeolson21/no-slop)'
if printf '%s' "${PR_BODY:-}" | grep -qF -- "$canonical_marker" ||
printf '%s' "${PR_BODY:-}" | grep -qF -- "$legacy_marker"; then
echo "Found no-slop signature in PR #${PR_NUMBER} body."
exit 0
fi
{
echo "::error::This PR was not raised through no-slop."
echo
echo "Contributions to this repository must be submitted via 'git push no-slop'."
echo "That pipeline runs the required review/test/lint/CI steps and writes a"
echo "deterministic '## Pipeline' section into the PR body containing one of:"
echo
echo " $canonical_marker"
echo " $legacy_marker"
echo
echo "See CONTRIBUTING.md for setup and the full workflow."
echo
echo "PR author: ${PR_AUTHOR}"
} >&2
exit 1
python3 <<'PY'
import json
import os
import re
import sys

body = os.environ.get("PR_BODY") or ""
pr_head_sha = os.environ.get("PR_HEAD_SHA") or ""
pr_action = os.environ.get("PR_ACTION") or ""
pr_author = os.environ.get("PR_AUTHOR") or ""
pr_number = os.environ.get("PR_NUMBER") or ""
prefix = "<!-- no-slop-pipeline-attestation:v1 "
closing = " -->"
required_steps = ("review", "test", "document")

pipeline_heading = "## Pipeline\n\n"
owned_markers = (
"Updates from [git push no-slop](https://github.com/Blakeolson21/no-slop)",
"Updates from [git push no-mistakes](https://github.com/Blakeolson21/no-slop)",
"Updates from [git push no-mistakes](https://github.com/kunchenguid/no-mistakes)",
)

def fail(message):
sys.stderr.write(f"::error::{message}\n")
raise SystemExit(1)

if not any(marker in body for marker in owned_markers):
fail(
"This PR was not raised through no-slop. Contributions must be submitted via "
f"'git push no-slop' (PR author: {pr_author})."
)
print(f"Found no-slop signature in PR #{pr_number} body.")

publication = re.match(r"\A<!-- no-slop-publication:v1 ([0-9a-f]{32}) -->(?:\r?\n){2}", body)
legacy_initial_publication = publication is None and pr_action in ("opened", "synchronize")
if publication is None and not legacy_initial_publication:
fail("This PR has no valid no-slop publication identity. Re-run 'git push no-slop'.")
expected_publication_nonce = publication.group(1) if publication is not None else None

def is_compliant_attestation(parsed, marker):
if not isinstance(parsed, dict):
return False
if legacy_initial_publication:
# Bootstrap only the canonical original-v1 body emitted by
# an installed pre-nonce binary opening or synchronizing the
# PR that adds publication nonces. Body edits and renamed
# historical markers must use the nonce-bearing format.
if marker != owned_markers[0] or "publication_nonce" in parsed:
return False
elif parsed.get("publication_nonce") != expected_publication_nonce:
return False
if not isinstance(parsed.get("steps"), list):
return False
# An installed pre-nonce daemon cannot republish the PR body
# after committing a CI repair. Permit that legacy tuple only
# on the resulting synchronize event; opened events must still
# describe their current head, and every nonce-bearing body is
# always bound to the current head below.
stale_legacy_repair = (
legacy_initial_publication
and pr_action == "synchronize"
and parsed.get("head_sha") != pr_head_sha
and re.fullmatch(r"[0-9a-f]{40}", parsed.get("head_sha", "")) is not None
)
if parsed.get("head_sha") != pr_head_sha and not stale_legacy_repair:
return False
statuses = {}
for item in parsed["steps"]:
if not isinstance(item, dict):
return False
name, status, certified_head = item.get("step"), item.get("status"), item.get("head_sha", "")
if not isinstance(name, str) or not isinstance(status, str) or not isinstance(certified_head, str):
return False
if name in statuses:
return False
statuses[name] = (status, certified_head)
if legacy_initial_publication:
return all(statuses.get(name, (None,))[0] == "completed" for name in required_steps)
return all(statuses.get(name) == ("completed", pr_head_sha) for name in required_steps)

candidates = []
for marker in owned_markers:
structural_prefix = pipeline_heading + marker + "\n\n" + prefix
search_from = 0
while True:
tuple_start = body.find(structural_prefix, search_from)
if tuple_start < 0:
break
start = tuple_start + len(structural_prefix)
end = body.find(closing, start)
if end >= 0:
try:
parsed = json.loads(body[start:end])
except json.JSONDecodeError:
parsed = None
if is_compliant_attestation(parsed, marker):
candidates.append(parsed)
search_from = tuple_start + 1

if len(candidates) != 1:
fail("This PR must contain one unambiguous owned no-slop v1 pipeline attestation. Re-run 'git push no-slop'.")
attestation = candidates[0]

publication_nonce = attestation.get("publication_nonce")
if publication_nonce is not None:
print(f"NO_SLOP_PUBLICATION_NONCE={publication_nonce}")

print("Found compliant no-slop pipeline attestation.")
PY
10 changes: 6 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ Thanks for wanting to contribute. One rule up front:
**All pull requests to this repository must be raised through `no-slop`.**

This repo _is_ no-slop. Contributions should be done using the tool itself, which reduces the maintainer's burden of reviewing and merging contributions.
The `Require no-slop` GitHub Actions workflow runs on every PR and fails if the body is missing the deterministic signature that no-slop writes. PRs without it will not be reviewed or merged.
For every relevant non-automation PR event, the `Require no-slop` GitHub Actions workflow fails unless the body begins with a valid publication identity and contains exactly one owned `## Pipeline` tuple: a recognized no-slop signature immediately followed by a parseable v1 pipeline attestation carrying the same publication nonce. The attestation must be bound to the current PR head and record `review`, `test`, and `document` exactly once as `completed` and individually certified against that head; skipped, failed, pending, running, stale, duplicated, or missing required steps are not merge authority.
Current no-slop and no-mistakes compatibility signatures are recognized. The historical `Updates from [git push no-mistakes](https://github.com/kunchenguid/no-mistakes)` signature is accepted only inside that fully valid current tuple; the historical signature by itself grants no authority.
During the publication-nonce rollout, an `opened` or `synchronize` event may instead carry the canonical pre-nonce v1 tuple emitted by an installed older no-slop binary. That narrow bootstrap requires completed review, test, and document statuses. An `opened` event must still attest its current head; a `synchronize` event may carry the pre-repair head because an older daemon cannot republish after committing its CI repair. Body edits and historical signatures do not qualify, and every nonce-bearing publication remains bound to the current head.

Every `opened` or `edited` event gets an independent run, including first-time-fork runs that become actionable through GitHub's normal approval process. The integration contract for consumers such as Wheelhouse is:
Every checked `opened` or `edited` event gets an independent run, including first-time-fork runs that become actionable through GitHub's normal approval process. The integration contract for consumers such as Wheelhouse is:

- The stable check name is `PR must be raised via no-slop`.
- The workflow run's `display_title` identifies the PR number, event action, `run_number`, and immutable `run_id`. For a PR, increasing `run_number` orders distinct events; a re-run retains that event identity and increments `run_attempt`.
- The run's `head_sha` binds the evidence to the reviewed commit. After the latest `opened` or `edited` run reaches `status: completed`, `conclusion: success` means that event's body contained the signature and `conclusion: failure` means it did not. `action_required` or `cancelled` is not compliance evidence and must be handled conservatively.
- The workflow run's `display_title` starts with `no-slop-required|<action>|PR #<number> event <run_number> (run <run_id>)|`, followed by the event body. A generated body begins with the publication identity, allowing no-slop to bind that publication to immutable Actions metadata without trusting job output. For a PR, increasing `run_number` orders distinct events; a re-run retains that event identity and increments `run_attempt`.
- The run's `head_sha` binds the evidence to the reviewed commit. After the latest `opened` or `edited` run reaches `status: completed`, `conclusion: success` means that event's body contained the signature and a current v1 attestation with review, test, and document each completed against that same head. `conclusion: failure`, `action_required`, or `cancelled` is not compliance evidence and must be handled conservatively.
- Fork runs stay on the `pull_request` boundary with read-only contents permission, no repository secrets, and no checkout or execution of fork code. Approval permits only this body check; it does not grant write authority.

## Workflow
Expand Down
5 changes: 2 additions & 3 deletions docs/src/content/docs/concepts/auto-fix.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ When the pipeline pauses for approval, you can manually trigger a fix from the T

The agent receives the merged fix payload for that round: the selected agent findings, any per-finding user notes, any selected user-authored findings added from the TUI or AXI interface, and a sanitized history of previous rounds for that step.
That history includes which finding IDs were selected for a prior fix attempt, which findings were left unselected by the user, and any one-line summaries from earlier fix commits.
On follow-up review passes, that history tells the agent not to re-report user-ignored findings unless the code now presents a materially different issue.
Review adds continuity rules to this generic history. The [Review step reference](/no-slop/reference/pipeline-steps/#review) owns how unresolved findings survive rereviews and how a later selection supersedes an earlier non-selection.

After a user-triggered fix, the step re-runs and pauses again to show you the results (`fix_review` status). You can then approve, fix again, skip, or abort.
TUI yolo mode approves the fix review automatically after its one fix round. AXI `--yes` funds up to 3 fix rounds per step and approves a fix review only when it is clean or contains only `no-op` findings. If an actionable finding cannot be selected or survives that budget, it leaves the run parked for explicit adjudication instead of silently approving it. An explicit approval can accept remaining actionable findings; the [step log](/no-slop/reference/cli/#no-slop-axi-logs) records that adjudication.
Expand All @@ -111,8 +111,7 @@ The Push step uses `no-slop: apply agent fixes` for remaining uncommitted change
## Step rounds

Each execution of a step (initial run or follow-up auto-fix run) is recorded as a "round" in the database.
A round stores its findings, duration, any selected finding IDs and whether that selection came from the user or auto-fix filtering, the merged finding payload actually sent to the fix agent for that round, and any one-line fix summary from that execution.
That merged payload can include per-finding user notes and user-authored findings added from the TUI or AXI interface.
The [database model](/no-slop/concepts/gate-model/#database) owns the persisted round fields, including Review's effective carried gate and the merged payload sent to a fix agent.
AXI status uses the same round history and the persisted auto-fix limit to show the active fix attempt, for example `auto-fix 1/3` or `fix 2`.
The step log records a marker when each automatic or user-triggered fix round starts.
The full round history remains available in the run log. The generated PR keeps earlier evidence step-scoped and shows only compact step status in its Pipeline section; the [pipeline steps reference](/no-slop/reference/pipeline-steps/#pr) owns the PR body and size-limit contract.
Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/concepts/gate-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ Communication between the CLI and daemon uses JSON-RPC 2.0 over the Unix socket.
### Database

SQLite at `~/.no-mistakes/state.sqlite` tracks repos, runs, step results, step rounds, derived intent summaries, local agent invocation performance, and the minimum session metadata needed to resume review-loop roles.
Step rounds record each execution attempt (initial, auto-fix) with its own findings and duration, plus selected finding IDs, whether the selection came from the user or auto-fix filtering, the merged finding payload actually sent to the fix agent for that round, and the one-line fix summary for fix rounds.
Step rounds record each execution attempt (initial, auto-fix) with its duration and the findings shown at that round's effective gate. Review rounds include unresolved findings carried from earlier gates even when the fresh rereviewer is silent; other steps retain their existing per-execution finding semantics. A round also stores selected finding IDs, whether the selection came from the user or auto-fix filtering, the merged finding payload actually sent to the fix agent, and the one-line fix summary for fix rounds.
Step results also store the last active timestamp, last activity text, native agent PID while a subprocess is active, and the effective auto-fix limit used by AXI status.
That merged payload can include per-finding user notes and user-authored findings from the TUI or AXI interface.
Intent stores the summary, source, session ID, and match score on each run when transcript matching is used, plus cached summaries for matching transcript sessions.
Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/concepts/pipeline.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ The pipeline is opinionated so that "passed the gate" has a stable meaning:
It also stops when the branch would silently bundle commits from a local default branch that were never pushed to `origin/<default_branch>`.
If there's no diff left after the rebase, the pipeline skips the rest.
- **Review before test** so the agent reads fresh code, not code it may have touched during fixes.
A later run's initial review also receives fix-round provenance for any uncertified pipeline-authored commits left on the branch when a previous run's re-review did not complete.
A later run's initial review also restores the unresolved review truth and provenance for pipeline-authored commits that reached the branch without a completed certifying review; the [Review step reference](/no-slop/reference/pipeline-steps/#review) owns the exact recovery contract.
- **Document after test** so docs are updated against code that's known to work.
- **Lint last among local checks** so it doesn't churn over code that may still change.
- **Push → PR → CI** happens after all local checks pass.
Expand Down
Loading
Loading