Skip to content

feat(critic): manifesto compliance check gates auto-merge (#133)#141

Merged
hadamrd merged 1 commit into
trunkfrom
loop/133-feat-manifestos-critic-compliance-check
May 28, 2026
Merged

feat(critic): manifesto compliance check gates auto-merge (#133)#141
hadamrd merged 1 commit into
trunkfrom
loop/133-feat-manifestos-critic-compliance-check

Conversation

@hadamrd
Copy link
Copy Markdown
Owner

@hadamrd hadamrd commented May 28, 2026

Closes #133.

Summary

  • _critic_sdk.load_manifestos_text reads every file under docs/manifestos/ (overridable via LOOP_MANIFESTOS_DIR) and renders them into the critic prompt via a new {manifestos} placeholder in briefs/critic.md.tmpl.
  • CriticReport gains manifesto_violations: list[ManifestoViolation] — typed dataclass with rule_id, manifesto, quote, suggested_fix, severity.
  • _coerce_report parses the new field with full back-compat (missing → []), drops malformed entries, defensively defaults unknown severities to sev3, and forces overall = "request_changes" whenever any sev1 manifesto violation is present — even if the model emitted approve.
  • critic_actions.plan_actions blocks auto-merge on any sev1 manifesto violation and labels the PR critic:manifesto-violation in addition to critic:blocking. apply_critic_report posts a manifesto-violation summary comment.
  • Two seed manifestos shipped (docs/manifestos/error-handling.md, testing.md) so the feature is operative immediately.

Acceptance criteria mapping

  • _critic_sdk.py loads every manifesto + renders into prompt via critic.md.tmplload_manifestos_text + new {manifestos} placeholder.
  • CriticReport.manifesto_violations: list[ManifestoViolation] with full field set.
  • Parser populates new field, defaults to [] for back-compat.
  • sev1 violation forces request_changes and blocks auto-merge.
  • sev2/sev3 violations reported but non-blocking.
  • All new + existing critic tests pass.

Test plan

  • tests/test_critic_manifesto_check.py — happy + adversarial + gate (12 cases).
  • tests/test_critic.py — existing critic suite still green.
  • tests/test_briefs.py — updated for new required manifestos kwarg.

🤖 Generated with Claude Code

The critic could rubber-stamp PRs that compiled and passed tests but
visibly violated project quality rules (e.g. `except Exception: pass`,
weak assertions). With nothing teaching the critic about the
manifestos, auto-merge shipped drift.

This wires the critic into the manifestos:

- `docs/manifestos/` is now the canonical home for project rules. Two
  seed manifestos (error-handling, testing) ship with the repo so the
  feature is operative on day one.
- `_critic_sdk.load_manifestos_text` reads every `*.md`/`*.txt` file
  under the canonical dir (overridable via `LOOP_MANIFESTOS_DIR`) and
  renders one block per file. `critic.review_pr` interpolates that
  block into `briefs/critic.md.tmpl` via a new `{manifestos}` slot.
- `CriticReport` gains a `manifesto_violations: list[ManifestoViolation]`
  field. `ManifestoViolation` is a typed dataclass with rule_id,
  manifesto, quote, suggested_fix, severity. Back-compat: JSON without
  the field still parses (defaults to `[]`).
- `_coerce_report` drops malformed entries (missing rule_id/manifesto),
  treats unknown severities as sev3 (defensive default), and forces
  `overall = "request_changes"` whenever any sev1 violation appears —
  even if the model emitted `approve`.
- `critic_actions.plan_actions` blocks auto-merge on any sev1 manifesto
  violation, labels the PR `critic:blocking` + `critic:manifesto-violation`,
  and posts a manifesto-violation summary comment via the gh client.
  sev2/sev3 violations are reported but not blocking.
- Prompt template now teaches the model to scan for manifesto rule
  violations and emit the new JSON shape.

Tests (`tests/test_critic_manifesto_check.py`):
- happy-path: manifesto text rendered into prompt; violations field
  parses; back-compat with absent field; sev1 flips overall;
  sev2 leaves it alone.
- adversarial: malformed entry skipped; unknown severity → sev3;
  wrong-type field ignored.
- gate: sev1 violation blocks; sev2-only does not.

Existing `tests/test_briefs.py::test_render_critic_brief_*` adjusted to
pass the new required `manifestos` kwarg.
@hadamrd hadamrd merged commit 3496e23 into trunk May 28, 2026
2 checks passed
@hadamrd
Copy link
Copy Markdown
Owner Author

hadamrd commented May 28, 2026

Source issue #133 was closed mid-flight (state: closed). Loop refusing auto-merge. Reopen the issue OR merge manually.

@hadamrd hadamrd deleted the loop/133-feat-manifestos-critic-compliance-check branch May 28, 2026 18:10
hadamrd added a commit that referenced this pull request May 28, 2026
…loop) (#149)

Closes the feedback loop the CTO described: every bug we fix becomes a
permanent gate. Today's PR #147 (critic SDK event-capture mismatch)
exposed a 4-PR train of bugs with the same shape — #97, #120, #128,
#147 — all driven by string-literal discriminators that didn't match
across module boundaries.

The critic (PR #141) reads the quality manifesto + flags sev1
violations. This rule + the critic infrastructure together mean the
next worker that writes ``event["type"] == "result"`` (or similar
cross-module string-comparison) gets the PR auto-blocked with the
manifesto rationale.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(manifestos): critic compliance check — manifesto violations gate auto-merge

1 participant