On-demand active pass that runs the 3-clause discriminator over the current diff, a named file, or a plan/design doc and reports classified findings (safe-remove / needs-decision / keep / harmful-theater). Thin wrapper that composes /simplify and /code-review, adding only the requirement-ledger freeze and discriminator. Use when asked to "/over-engineering-review", "check for over-engineering", "run the discriminator", "gate this for YAGNI/KISS", or "is this over-engineered". Accepts optional target: diff (default) | <file path> | plan.
Install
npx skillscat add ottawacloudconsulting/agentic-ai/over-engineering-review Install via the SkillsCat registry.
/over-engineering-review — On-Demand Discriminator Pass
Runs the 3-clause discriminator over a target artifact and reports findings
classified safe-remove, needs-decision, keep, or harmful-theater.
Composes /simplify and /code-review — does not reimplement them.
Rules
- Discriminator is the test; context tunes severity, not detection. The
discriminator fires context-free. Severity and stop/ask posture adjust to
context; whether the flag fires does not. - Compose, don't reimplement. Run
/simplifyand/code-reviewas
sub-passes. Add only the requirement-ledger freeze and the discriminator. - Freeze the ledger before review. Extract stated requirements, observed
failures, and named safety properties from conversation context, PRD, and
any referenced docs before evaluating any element. Post-hoc requirement
invention does not enter the ledger. - Cost-gate the counterfactual. A full counterfactual on a trivial or
reversible target is itself axis-8 over-engineering. Escalate only for
qualifying targets (see Step 5). - Findings are flags, never scores. Emit classified findings with cited
clause-absence. No numeric ratings. - Correctness/safety floor is clause 3 of the discriminator. Floor items
pass clause 3 — they are classifiedkeep, not flagged.
Step 1 — Resolve Target
Parse the argument after /over-engineering-review:
- No argument /
diff:git diff HEAD— the current working-tree diff. - File path: read the named file.
planor natural language referencing a plan/design: read the referenced
plan or design doc from conversation context.
If the target is empty (no diff, no file, nothing in context), stop and ask
the user what to review.
Step 2 — Freeze the Requirement Ledger
Before evaluating any element, extract and freeze the requirement ledger.
Sources (priority order):
- Explicit user statements in this conversation
- The target artifact itself — requirements embedded in the diff, file, or
plan under review - Any source-of-truth docs named as authoritative by the target (e.g., an
issue doc or spec the target references) prd.md(if present in the project root)docs/ARCHITECTURE_AND_DESIGN.md(if present)
Tag each requirement by provenance: [user-stated] or [agent-inferred].
Agent-inferred requirements that justify nothing are not added to the
ledger. If an agent-inferred entry is the sole justification for an element,
that element is a flag candidate.
Emit the frozen ledger before proceeding:
REQUIREMENT LEDGER (frozen)
[user-stated] <requirement>
[agent-inferred] <inferred property> ← escalated if unjustifiedStep 3 — Run /simplify and /code-review
Invoke as sub-passes in sequence:
/simplify— simplification and redundancy findings/code-review— correctness, bug, and reuse findings
Retain their outputs to feed Step 4's per-element discriminator pass.
Do not re-emit them verbatim in the final report.
If /simplify or /code-review is unavailable, proceed with the
discriminator pass on the target directly and note the absence in the summary:
NOTE: /simplify unavailable — discriminator applied to raw target only.Step 4 — Run the Discriminator Per Element
For each element in the target artifact (including any surfaced by Step 3):
Does it trace to (1) a stated requirement, (2) an observed failure,
or (3) a correctness/security defect on a reachable path at a trust
boundary? If none → flag.
Apply modifiers after the flag, not before:
- Context tunes severity, not detection. Blast radius × lifespan (plus
explicit security/data-sensitivity signal) tune enforcement posture and
severity label. They do not suppress a flag. - Reversibility licenses a seam, not a feature. A one-way door (persisted
data, published contract, wire format, public name) licenses a cheap reversal
seam — never the speculative feature itself. Burden of proof: name all four —
(a) the irreversible surface, (b) the plausible future change, (c) the
concrete later cost, (d) the smallest present action — or YAGNI wins. An
unproven one-way claim is treated as two-way and deferred. Blast-radius-escape
count: 0 triggers → defer (YAGNI); 1 → seam only; 2+ → surface to user. - Cause-agnostic. Act on the output signature — an element that fails the
discriminator. Do not let inferred intent or the reason it was produced affect
whether the flag fires. - Clause 3 IS the floor. Delete-the-element test: does removing it produce
a wrong result, lost/corrupted data, a security hole, or a
silently-swallowed failure on a reachable path at a trust boundary?- Yes →
keep(floor item) - Loses only convenience / future flexibility → flag
- Yes →
Boundary cases — one rule: trust boundary + reachability + named failure mode:
| Element | Floor (keep) |
Excess (flag) |
|---|---|---|
| Retries | transient/idempotent op, bounded, surfaced failure | unbounded / non-idempotent / masks failure |
| Logging | required output/audit; stderr insufficient to operate | decorative / duplicates available signal |
| Input validation | external/untrusted boundary, reachable path | internal trusted caller |
| Error handling | preserves invariant/cleanup; sharpens reachable failure | swallows/masks; wraps infallible code |
Step 5 — Cost-Gate and Optionally Run Counterfactual
Escalate to a partial cold counterfactual (re-derive one layer/section
from the frozen ledger by a different model, original removed from context)
only when at least one qualifying condition is met:
- Target is design-stage, OR
- Diff is large (>200 lines), OR
- Target contains "production-ready" / "enterprise-grade" / similar phrase
clusters, OR - Multiple axes (≥3) are triggered, OR
- Safety-inversion risk is present
And the target clears the cost gate. Skip if ALL of: diff is <100 lines,
≤2 axes triggered, and 0 blast-radius-escape triggers (reversible, no outside
dependents must change). When qualifying conditions are met but the cost gate
is ambiguous, surface to user:
COUNTERFACTUAL: cost gate ambiguous — <size/axes/triggers>. Run? [y/n]Counterfactual scope: partial (one layer/section). Full rewrite is reserved
for axis-2 structural over-engineering where the shape is the excess.
Announce the decision before running:
COUNTERFACTUAL: escalating — <reason>. Re-deriving <layer/section> via
<different model> with original removed from context.COUNTERFACTUAL: skipped — <reason>. Cost-gate (trivial/reversible/small).After the counterfactual completes, compare the re-derived section to the
original:
- Identify elements present in the original but absent or simpler in the
re-derivation — these are additional flag candidates. - For each such element, run the discriminator (Step 4) and apply modifiers.
- Feed results into Step 6 classification alongside the primary pass findings.
- Note the counterfactual source in each finding it contributes:
[counterfactual]suffix on the tag.
Step 6 — Classify and Emit Findings
Classify each finding:
| Tag | When to use | Selection criteria |
|---|---|---|
safe-remove |
Fails discriminator; no clause passes; reversibility is proven two-way (0 blast-radius-escape triggers). | All three clauses absent + 0 outside dependents must change. |
needs-decision |
Fails discriminator; contested. | Reversibility claim unproven (≥1 blast-radius-escape trigger or burden-of-proof fields incomplete), OR blast-radius is high, OR ledger signal conflicts. Surface to user — do not auto-resolve. |
keep |
Passes at least one clause. | Cite which clause: clause 1 (stated requirement), clause 2 (observed failure), or clause 3 (correctness/security defect on a reachable path at a trust boundary). |
harmful-theater |
Fails discriminator AND its presence introduces a specific, named harm on a reachable path. | Must cite the harm: swallows a failure, creates a false safety signal, masks a real error. Remove before proceeding. |
Emit format — one line per finding, including severity and clause-absence citation:
path:line [tag] HIGH|MEDIUM|LOW axis-N clauses 1+2+3 absent: <unjustified element>. <simpler alternative or "remove".>Severity guide: HIGH = harmful-theater or safe-remove with broad blast radius; MEDIUM = safe-remove or needs-decision with contained blast radius; LOW = safe-remove with zero external dependents.
For keep items, cite the passing clause:
path:line [keep] clause-N: <element>. Justification: <stated requirement / observed failure / named failure mode on reachable path>.For counterfactual-sourced findings, append [counterfactual]:
path:line [safe-remove][counterfactual] MEDIUM axis-2 clauses 1+2+3 absent: <element>. <simpler alternative>.End with a summary block:
OVER-ENGINEERING REVIEW SUMMARY
harmful-theater : N (remove before proceeding)
safe-remove : N
needs-decision : N (surfaced below for user)
keep : N
NEEDS-DECISION ITEMS:
[each item with context and recommendation]The 8-Axis Reference
| # | Axis | Principle |
|---|---|---|
| 1 | Speculative scope | YAGNI |
| 2 | Premature abstraction | KISS |
| 3 | Premature optimization | KISS |
| 4 | Defensive bloat | clause-3 predicate, flag side |
| 5 | Robustness / ops theater | YAGNI |
| 6 | Test / doc ceremony | DRY / YAGNI |
| 7 | Data / schema / API over-modeling | YAGNI |
| 8 | Process over-engineering (meta) | do not over-apply this gate itself |
Anti-Bias Directive
Failure mode: confirming quality rather than finding unjustified complexity.
Counter it:
- Default posture: flag aggressively. Ask "does a concrete justification
exist for this element?" — not "is this good practice?" - Good practice without a concrete justification is still a flag.
- Do not emit
keepfindings for items not positively verified against
clause 1, 2, or 3. - Apply axis 8 to yourself: one discriminator pass per element; not a parallel
subsystem per concern.