Skip to content
Back to skills

Plumb Line Remediate

ASecurity

Use when applying findings from a plumb-line audit report — the builder has a report (or pasted findings) and wants the fixes made. Opt-in and separate from the audit, which is read-only and never fixes.

  • 4 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 3, 2026
ai-agentspythonrustgoshellgit

Works with

  • cli

Security analysis

A100/100

Scanned October 1, 2026

npx -y skills add slopstopper/plumb-line --skill plumb-line-remediate --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Plumb Line Remediate?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Plumb Line Remediate
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/slopstopper-plumb-line-remediate/badge)](https://www.skillsdirectory.com/skills/slopstopper-plumb-line-remediate)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: plumb-line-remediate
description: Use when applying findings from a plumb-line audit report — the builder has a report (or pasted findings) and wants the fixes made. Opt-in and separate from the audit, which is read-only and never fixes.
---

# Remediate plumb-line audit findings

REQUIRED READING FIRST: `reference/portable-principles.md` (plugin root).
If this file cannot be read, stop immediately and report: "Cannot remediate:
`reference/portable-principles.md` is missing or unreadable. Do not proceed from
memory — the principles file is the source of truth for what a fix must honor."

The audit finds; this skill fixes. The two never blur: remediation runs only on
an explicit invitation, consumes a report the audit produced (any
`report-format: v1`+; v4 is current), and applies nothing the builder has not
seen. If there is no report, offer to run `plumb-line-audit` first, or accept
findings pasted in the findings-table shape (Path / Line / Function / Status /
Issue / Suggested Fix / Principle; a v3 or earlier table has no Status).

**Validate the report before consuming it.** This skill acts on a contracted
input, so check the contract. The checker ships inside this plugin
(`<plugin root>/scripts/check_report_format.py`; `scripts/check_report_format.py`
inside the plumb-line repo):

```
python3 <plugin root>/scripts/check_report_format.py <the report>
```

A violation is **not** a reason to refuse the run — it is a reason to say what is
wrong before acting on it. Report the violations, then ask whether to proceed;
the risk a malformed report carries is that a column means something other than
you assume, and the builder is the one who can tell. If the checker is
unavailable, say the input was not mechanically validated rather than staying
silent — the same honesty the audit owes its own output.

## The contract (what a remediation run IS)

A remediation run produces, in order:

1. a **fix plan** — every finding classified before any edit,
2. **per-finding diffs** — each shown before it is considered done,
3. a **remediation record** — the finding→change table that gives the
   remediation itself the lineage it demands of the code (P8 — State-first lineage),
4. a **verification step** — the project's own enforcement, run, with output.

Editing a file the builder never sees a diff for, or finishing without the
record, is a failed run — regardless of whether the fixes were correct.

## Step 1 — Classify every finding before touching anything

Read the whole findings table first and classify each row. Then, before anything
changes the tree under remediation, write the plan table (Finding / Path / Class
/ Intended action) to a file with a tool call of its own, and wait for it to
complete: no edit may be in the same call or the same step as the plan write.
A change to the tree is an edit, a write, a shell command that modifies a file
in it, or a git command that writes inside it, such as `git init` or `git
stash`; reading files, or copying them out to a snapshot elsewhere, is not. Put
the plan file outside the code under remediation, for example
`plumb-line-plan.md` in a temp directory, and show the table to the builder
too, before the first edit. Name each principle inline in the plan
(`P2 — One-way layering`), as in the record.

Repeat the same plan table in your final message, below the record, headed "Fix
plan", and give the plan file's path. Make no claim about when the plan was
printed or written: the order of your tool calls shows it, and a claim cannot.
The repeat is checked with the record (see "The message is the text the
checker passed", below).

Why: the plan is what lets a builder stop an edit before it happens, so it has
to exist before the first edit, where anyone can see it did. Four remediators
under the release harness's pressure protocol, told to print the plan first,
edited first; three of them then said in their final message that the plan had
come before the first edit, which their transcripts do not show (#589). A plan
file written by a tool call, completed before the first edit, is on the record;
a sentence about timing is not.

**Mechanical** — the principle determines the fix; no epistemic value must be
invented. Typical: remove an upward import (P2 — One-way layering); replace a
hardcoded constant with the already-existing injected config (P5 — Injectable
priors); add a version constant + validator to an uncontracted output (P7 —
Contracted outputs); record lineage fields that are computable from inputs in
scope (P8 — State-first lineage); relabel maturity to what the code already is
(P6 — Maturity vocabulary); wrap an untagged return in `mark`/`derive` where the
source is unambiguous (P3 — Confidence + provenance).

**Judgment** — the fix requires a claim only the builder can stand behind: which
confidence a value deserves, whether a stub should stay or become a real
integration, which layer a relocated piece of code belongs to, what a changed
baseline's explanation is (P9 — Golden baseline + explain-the-drift). For each
judgment finding, propose a concrete default and ask; apply only on a yes. When
the builder is not present to answer, apply the **conservative default** (below),
mark it `applied-conservative` in the record, and say it needs their review.

**The conservative default: claim nothing the code cannot support.** Where an
epistemic value must be supplied and nobody has answered, take the weakest
honest claim — a fabricated or stubbed value gets the floor: the lowest value in
the project's own confidence representation (in a plumb-line envelope the
`"none"` rung, plus `confidenceScore` `0` where scores are used; where the
project's confidence field is a number, `0`), a mock-labelled source
(`source: "mock"` in an envelope), and `derivedFromMock: true`. Match the field's
existing type; never write a rung string into a numeric field. An unverifiable origin is
labelled as what it is, not what it is hoped to be. Never pick a "reasonable
middle" (0.5-ish) for a value that is actually fake: an invented moderate
confidence is an invented fact. Two runs on the same input must produce the same
claim — the floor is deterministic; optimism is not.

## Step 2 — Apply one finding at a time, diff shown per finding

Work finding by finding, smallest first if order is free. For each: make the
edit, then show the diff (before/after or unified) labelled with the finding it
resolves, in the conversation, as you go — not a bulk dump at the end. The
builder must be able to stop a bad direction after finding 1, not discover it
after finding N.

**Scope discipline.** Touch only what the finding requires. Adjacent
improvements you notice — a stale comment, a string that could be richer, a
refactor begging to happen — go in the record's **Proposed (not applied)**
section, never into the working tree. One exception, because honesty beats
minimality: if your edit makes an existing statement in the same file false
(a comment or docstring naming a constant you just deleted, a doc line
describing behavior you just changed), correct that statement as part of the
finding's diff — a remediation must not manufacture a lie by omission. Note the
correction in the record.

If a fix for one finding would conflict with the fix for another, stop and
surface the conflict rather than picking silently.

## Step 3 — The honesty guardrail (what a fix may never do)

A remediation may never resolve a finding — or satisfy a gate, a test, a
deadline, or a re-audit — by making the code *less* honest. Concretely, never:

- clear or hand-set a taint flag (`derivedFromMock` and kin) on data that is
  still mock-derived;
- raise a confidence, or swap a source label for a cleaner one, so a check
  passes;
- delete or bypass a null-result / rejection branch so an output always
  succeeds;
- drop a provenance, confidence, or lineage field because its honest value
  is embarrassing;
- update a golden baseline without a recorded explanation of which input moved
  (P9 — Golden baseline + explain-the-drift: the explanation IS the fix; a
  silent update is the violation).

When the only change that would satisfy a finding, gate, or instruction is one
of these, the finding is **blocked**, not fixable: record it as `blocked` with
the honest paths out (implement the real thing, or obtain an explicit written
waiver that scopes the check), and leave the code truthful. A gate failing on
honest metadata is the gate working; the remediation's job was done when the
metadata became honest. This mirrors bootstrap's rule: if you cannot name a
source-truth layer, that absence is the finding — here, if you cannot fix it
honestly, that impossibility is the finding.

When the blocked item is a failing test whose requirement cannot be met yet,
there is one more honest path, besides implementing the real thing or a
written waiver: an honest deferral, on the four conditions in
`plumb-line-method`'s section **Mid-task: a test that cannot pass
honestly** (a strict expected-failure marker, the assertion unchanged, the
reason in the marker, the decision handed back). Offer it; apply it only with
the builder's yes, record that row as `applied-judgment`, and name the
deferral, with its reason, in the row's line below the table. Declined, the
row stays `blocked` and the test stays red.

## Step 4 — Verify with the project's own enforcement

After the last fix, run what the project already trusts, and show the output:

- plumb-line adapters if installed (boundary check, `no-provenance-bypass`
  lint, `require-provenance-output` if the project declared a surface,
  pre-commit gate);
- otherwise the project's own linters/tests that cover the touched files;
- at minimum, an import/load smoke check of every file changed.

Then offer — never auto-run — a re-audit scoped to the touched files, so
find-and-fix stay separate acts with separate records. On a yes, **invoke
`plumb-line-audit` directly** (via the host's skill mechanism) rather than
telling the builder to run it — the baton passes by invocation, not
instruction.

## Step 5 — The remediation record

End every run with the record, then offer — never auto-write — to save it as
`plumb-line-remediation.md` (same always-offer contract as the audit's report
file). The record has a header and a table:

```
remediation-format: v1
source-report:       <path or "pasted findings">
source-report-format: <its report-format version>
principles-revision: <from reference/portable-principles.md>
date:                <YYYY-MM-DD>
commit:              <git SHA before remediation, or "working tree (uncommitted)", or "no repository (not version-controlled)">
```

| Finding | Path | Class | Action | Change summary |
| ------- | ---- | ----- | ------ | -------------- |
| *example — replace with real rows* | `src/foo.py` | Judgment | applied-conservative | tagged `derivedFromMock`, confidence at the floor — needs builder review (P3 — Confidence + provenance) |

The row above is an **example**: delete it and emit your own findings. It is here
only to show the Action cell's form — the **bare verb**, no backticks. Everywhere
else this file names the vocabulary in prose it renders as `applied-conservative`,
which is markdown inline-code formatting, not part of the value.

- **Action** is one of: `applied-mechanical`, `applied-judgment` (builder said
  yes), `applied-conservative` (default taken, needs review), `proposed`
  (suggested, not applied), `blocked` (honest fix impossible — reason given),
  `skipped` (builder said no).
- Below the table: the **Proposed (not applied)** list, and one line per
  `blocked`/`applied-conservative` row saying what the builder must decide,
  and per `applied-judgment` row that applied an honest deferral, naming the
  test, the reason, and that the requirement is still not met.
- Principle references render inline-named (`P3 — Confidence + provenance`),
  never bare codes, exactly as in the audit report.

A run where every finding lands as `applied-mechanical` still emits the full
record — the record is the lineage of the remediation, not a summary of its
difficulties.

**Validate the record against its own contract before emitting it.** The same
check this skill runs on its input applies to its output: `remediation-format`
has a version, a key list, and a validator, and a contract enforced only on the
way in is half a contract. Run the checker that ships in this plugin
(`python3 <plugin root>/scripts/check_report_format.py`) on the record — writing it to a temp file if it has not been saved — and
fix any violation before printing:

```
python3 <plugin root>/scripts/check_report_format.py <the record>
```

Only when it genuinely cannot run (no shell, no Python, the plugin root
unknown, a host rule forbidding it), say so in one line rather than implying
the record was mechanically checked:

Emit **one** of these lines, never both:

```
format-validation: scripts/check_report_format.py v<N> — clean
```

`<N>` is the checker version the checker prints on its first line (`check_report_format v<N> — ...`); copy it, so a stored "clean" says which rule set it was earned under. The checker judges every `format-validation:` line: an unfilled `v<N>`, a stamp newer than the checker, or a line in any other form (a different dash, trailing text, a list bullet) is rejected; an unstamped clean line passes with a "checker version unrecorded" note.

```
format-validation: not run (checker unavailable in this repo)
```

**The message is the text the checker passed.** Write the record to a
temp file, run the checker on that file, then print the file's text as your
message, unchanged: nothing above the header (no summary, heading or
preamble), and no edit between the check and the message. If you change
anything after the check, however small, re-run the checker on the changed
text before printing it. Anything else you want to say (the repeated plan, a
summary, the next step) goes below the record, after its last line, in the same
file, before you run the checker: the whole delivered message is what gets
checked, so a bare principle code below the record fails it as surely as one
inside it. A saved `plumb-line-remediation.md` holds the record alone, not
what you say below it. A `— clean` stamp is true only of
the exact text it was run on: two 2026-09-30 eval audits delivered a
message that opens with a prose summary above the header, one whose body
also fails, under a `— clean` stamp, and the checker names both stamps as
not earned (#581).

Never drop or soften a row to make the record validate — the contract describes
the record's *shape*, and a shape violation is fixed by fixing the shape.

## Quick reference

| Situation | Action |
| --------- | ------ |
| No audit report exists | Offer `plumb-line-audit` first, or accept pasted findings |
| Fix needs an epistemic value nobody supplied | Conservative floor, `applied-conservative`, flag for review |
| Only a dishonest edit would satisfy the finding/gate | `blocked` + honest paths out; leave code truthful |
| A failing test's requirement cannot be met yet | Offer an honest deferral (method skill's four conditions); builder's yes → `applied-judgment`, else `blocked` |
| Noticed an improvement no finding asked for | Record under Proposed (not applied) |
| Your edit made a nearby comment/doc false | Correct it within the finding's diff; note in record |
| Two findings' fixes conflict | Stop; surface the conflict |
| All fixes applied | Run project enforcement, show output below the record, offer re-audit |

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.