Fettl by Hard Mode Labs

Stop AI slop before review.

Fettl catches swallowed errors, dead scaffolding, duplicated logic, silent fallbacks, and structural shortcuts while the change is still in motion. Supported hooks and CI stop repeatable failures early, deterministic corrections run under policy, and only decisions that require intent reach a person.

hardmodelabs / payments · PR #184queuedinspecting diff…finding isolatedclassifiedpatch constrainedverifying…assessment complete
  1. 81fn reconcile_opening(account: &Account) -> Result<Entry> {
  2. 82 let balance = account.pending_balance();
  3. 83
  4. 84 let opening = balance.unwrap_or(0);
  5. let opening = balance.unwrap_or(0); let opening = balance.ok_or(MissingBalance)?;
  6. 85
  7. 86 Ok(Entry::new(account.id, opening))
  8. 87}
Local checks · supported hooks and CI · controlled correction167 public checks in the current engine

The gap

It passes lint.
It still makes the codebase worse.

Five findings from one investigation. The code is real, the reasoning differs per finding, and the response follows the evidence, not the agent’s confidence.

Prevented before mergeFETTL-S031FETTL-E014FETTL-D007FETTL-X002FETTL-A004
  1. 116try {
  2. 117 await provider.sync(customers);
  3. 118} catch (error) {
  4. 119 /* continue */
  5. 120}
  1. 83let balance = account.pending_balance();
  2. 84let opening = balance.unwrap_or(0);
  3. 85Ok(Entry::new(account.id, opening))
  1. 50pub async fn fetch_usage(&self) -> Result<Vec<UsageRow>> {
  2. 51 // TODO: wire up metering API
  3. 52 Ok(vec![])
  4. 53}
  1. 12export function normalizeUser(input: RawUser): User { … }
  2. 13// src/users/normalize.ts · original
  3. 14// src/api/serializers.ts · copy 2, diverged
  4. 15// src/billing/mapCustomer.ts · copy 3, diverged
  1. 7# This robust solution ensures optimal
  2. 8# performance across all edge cases.
  3. 9def rank(results):
  4. 10 return sorted(results, key=score)
Same syntax · different consequence
let opening = balance.unwrap_or(0);high · propose repair
label.unwrap_or("unknown")low · observe

Same syntax. Display code, no downstream decision; recorded, not repaired.

rule
SWALLOWED_ERROR
severity
medium
decision
warn
rule
SILENT_FALLBACK
severity
high
decision
propose repair
rule
INCOMPLETE_STUB
severity
medium
decision
warn
rule
DUPLICATED_LOGIC
severity
medium
decision
human decision
rule
NARRATIVE_ARTIFACT
severity
low
decision
deterministic fix
SWALLOWED_ERROR · src/providers/sync.ts:119

A failure disappears while the request keeps moving

The discard is deliberate-looking but erases the failure signal the retry logic depends on. Fettl flags the empty handler and the missing result.

signal
failure restored to the author
delivery
text finding + PR comment
edit
none; no automatic rewrite
SILENT_FALLBACK · src/ledger/reconcile.rs:84

Missing financial data becomes a valid-looking zero

Fettl compares the fallback against how the value is used. balance.unwrap_or(0) reaches a persisted entry and is high risk; label.unwrap_or("unknown") only reaches a card and is recorded, not repaired.

patch
constrained · approval required
verification
tests + rescan after approval
decides
human
INCOMPLETE_STUB · src/billing/usage.rs:52

A typed placeholder passes review without doing the work

The stub type-checks and the TODO comment reads as intent. Fettl treats a permanent empty return behind a complete signature as unfinished scaffolding.

signal
stub flagged with trusting call sites
delivery
text finding + score impact
edit
none
DUPLICATED_LOGIC · src/users/normalize.ts:12

Agent-made helpers drift across files instead of converging

Which copy is canonical, and whether unifying them changes public behavior, is a team decision. Fettl presents the divergence map and options; it does not pick one.

signal
divergence map of all four copies
delivery
PR thread evidence + options
decides
human
NARRATIVE_ARTIFACT · src/search/ranking.py:7

Generated prose explains confidence instead of intent

Narrative artifact with no coupled behavior. Removing the prose is a narrow, verifiable transformation at the safe end of the correction spectrum.

patch
comment prose removed
verification
tests + rescan pass
cost
no credits consumed

The control loop

Detect. Decide. Correct.

One finding, carried through the system. The rail below is the same FETTL-E014 from the assessment above; watch where it slows down.

DetectedClassifiedBoundedVerified

The diff is scanned. Source location and the exact expression become evidence.

src/ledger/reconcile.rs:84

Context, severity, and repairability attach to the finding. Financial persistence makes this one high.

severity high · approval required

The finding enters one of three permitted pathways: deterministic fix, approval-required patch, or human decision. The system pauses here and shows its authority.

pathway: propose repair

Relevant checks run, the result is rescanned, and the evidence is attached to the PR. Green appears only at completion.

tests pass · rescan clean
Deterministic fixnarrow, local, verifiable
Approval-required patchthis finding waits here
Human decisionevidence and options only

One engine, two stages

Start local.
Add control when the code becomes business.

The Free CLI proves the signal without an account or source upload. Pro surrounds the same finding with the commercial workflow. The finding does not change; the authority around it does.

fettl scan --stagedlocal · no account · no upload
highFETTL-E014src/ledger/reconcile.rs:84

Missing balance silently becomes zero

    let opening = balance.unwrap_or(0);

pending_balance() returns None when the upstream ledger has not settled. unwrap_or(0) converts that missing data into a valid-looking opening balance, and the reconciliation entry is written without any record of the fallback.

output

1 finding · score 82 (−7 from base)

scope

Changed and staged files, curated high-signal checks, text findings.

fixes

Limited deterministic safe fixes, applied locally.

access

No account or source upload required.

boundary

Personal, education, open source, and time-limited evaluation.

Repository scope

complete scan · ledger/** policy applied

Finding history

first seen in PR #184 · not in baseline

Structured output

JSON + SARIF available

Prevention

CI gate + supported local hooks

Repository settings

managed through the Fettl API path

Entitlement

ongoing commercial use

Free runs where the code lives. Commercial production use is outside the Free boundary.

Prevention path

Move the quality boundary left.

Fettl meets agent-written changes before they become review debt. The same policy starts with the changed files, runs through supported hooks, and holds the line in CI.

01 · CHANGE

Catch it while context is fresh

Changed and staged-file checks give the developer immediate evidence before low-quality patterns spread through the branch.

02 · HOOK

Stop repeatable mistakes automatically

Supported Pro hooks apply the entitled catalog and bounded corrections before the change is handed off for review.

03 · GATE

Escalate only what needs judgment

CI and structured evidence enforce the same policy, verify safe corrections, and surface the decisions that genuinely require intent.

Product evidence

When Fettl interrupts, it shows its work.

Most deterministic problems should be handled before review. When a finding crosses a policy boundary, select it to inspect the exact expression, evidence, proposed repair, and verification. Illustrative output using real finding types and workflow states.

hardmodelabs / payments · PR #184assessment complete
Fettl assessment

2 findings need attention

score82−7 from base
  1. 81fn reconcile_opening(account: &Account) -> Result<Entry> {
  2. 82 let balance = account.pending_balance();
  3. 83
  4. 84 let opening = balance.unwrap_or(0);
  5. 85
  6. 86 Ok(Entry::new(account.id, opening))
  7. 87}
why it matters

pending_balance() returns None when the upstream ledger has not settled. unwrap_or(0) converts that missing data into a valid-looking opening balance, and the reconciliation entry is written without any record of the fallback.

Compare display code: label.unwrap_or("unknown") at src/ui/account_card.rs:31; recorded as low, decision observe. Same syntax, different consequence.

rule
SILENT_FALLBACK
repairability
approval required
constrained diff
let opening = balance.unwrap_or(0);
let opening = balance.ok_or(MissingBalance)?;

Bounded by path, command, runtime, and budget; held for approval before any edit.

checks that ran
  1. reconcile::tests · pass
  2. clippy · clean
  3. rescan · no new high findings

No patch is applied before human review.

Every finding, patch, and check above is selectable text.

Controlled correction

Automation stops where intent begins.

Gate one shows deterministic Pro correction. Gates two and three document the boundary required for future Max repair; they are not available today.

01Safe deterministic correction
  1. ranking tests · pass
  2. rescan · resolved

Narrow. Deterministic. Verifiable.

Known transformations run locally. The diff is shown before application, and verification completes before the gate closes. No model or external agent is involved.

FETTL-A004 · narrative artifactcomment prose removedtests + rescan · pass
02Future Max approval
  1. reconcile::tests · pass
  2. rescan · clean

A constrained patch, never a blank check.

A future Max finding would become an isolated patch bounded by paths, commands, runtime, and budget. It waits at the hold line for a person.

  • paths: 1 file
  • commands: cargo test reconcile
  • runtime: capped per run
  • budget: capped per run
FETTL-E014 · silent fallbackpatch held for approvalbudget: capped per run
03Human decision required

Intent stays with a person.

Architecture, behavior, compatibility, public APIs, data models, and ambiguous tradeoffs stay in the PR thread with evidence and options.

FETTL-X002 · duplicated logicdivergence map attachedpick an option; it posts as a comment

Pricing

Useful free. Valuable when the work is commercial.

Pro is the only paid self-service launch plan. Pricing will be shown before activation and remains provisional during beta.

View pricing
private betaFettl Pro
Betapricing shown before activation
pricing remains provisional

Ongoing commercial use, the complete entitled deterministic catalog and fixes, full scans, structured CI, supported hooks, and the managed application path.

Request access

Data handling

Your source does not need a round trip to prove local value.

The Free CLI runs locally. No account or source upload is required. Running Free checks or resolving a local identity does not upload source code to Fettl.

Managed Pro workflows use explicit privacy modes and publish their data boundary before onboarding. LLM-assisted or external-agent repair automation is reserved for future Max plans and is unavailable in Pro.

Read Security & Data Handling

Private beta

Bring us the work your pipeline should prevent.

Fettl is looking for individual developers using coding agents in Rust, Python, JavaScript, or TypeScript who can bring an active GitHub repository, point to recurring agent-written failure patterns, and give direct product feedback.

01 Active GitHub repository02 Recurring agent failure patterns03 Direct beta feedback
Primary languages Choose at least one

No card. No newsletter opt-in. We’ll only contact you about Fettl.