pm-ai-shipping: code-review becomes the top-level skill; perf + security are sub-cases
Restructure, per the ask that code review be the parent and the other two dimensions its sub-cases: - SKILL.md gains a "one engine, three anchors" section. Correctness is the core and stays inline; performance and security move to their own reference files, loaded only when selected. - references/performance-review.md (new) — a universal, stack-agnostic core (repeated work, growth relationships, retention, copying, contention, amplification) plus the three-part bar for a performance finding. Defers the database/web checklist to /performance-audit-static instead of restating it. - references/security-review.md (new) — trust boundaries and sinks for code with no web surface, and the one rule that INVERTS relative to correctness: attacker-equals-victim refutes a security finding but never a correctness one. Defers the full procedure to /security-audit-static. - Both audit commands now say they are the specialisation behind their sub-case, so the narrow entry points still lead back to the skill. ship-check gains two stages it was missing: - Step 3, correctness review — the pass neither audit performs: logic and state defects that compile clean and pass the suite. - Step 6, independent unsteered review — a fresh session of a second model (Codex or equivalent), given no checklist and no prior findings, with the subject computed from a diff rather than described. Every finding is hand-verified against the code before it enters the packet, since an unsteered reviewer carries no refutation discipline of its own. The packet reports whether it ran clean or did not run at all - those are different signals. Also carries the working-tree edits already in progress: model-and-orchestration guidance on both audits, the OWASP A02/A06/A09 backstop, CSP in the output-encoding bullet, the prompt-injection/agent-abuse bullet, and the Audit Provenance section (now also naming the second model). No version bump - not tested against the benchmark yet. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01G42vsxSKL7je39AsHZ5aJm
This commit is contained in:
co-authored by
Claude Opus 5
parent
2e662ac04d
commit
18032bc9f7
@@ -1,5 +1,8 @@
|
||||
# Correctness taxonomy — twelve lenses, with detection tells
|
||||
|
||||
*Reference for the correctness sub-case — the core of the `code-review` skill. The performance and
|
||||
security sub-cases have their own files alongside this one.*
|
||||
|
||||
Overlapping diagnostic lenses, not a classification scheme and not a quota. Each entry says **how you
|
||||
detect it**, because a class name alone changes nothing about what a reviewer looks at.
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
# Sub-case: performance review
|
||||
|
||||
A specialisation of the parent engine. The anchor changes; the refutation discipline and the report
|
||||
contract do not.
|
||||
|
||||
**Anchor:** workload → resource demand → growth or contention → material consequence.
|
||||
|
||||
The agreement being tested is between what the code *assumes about its workload* and what the
|
||||
workload *will actually be*. Code written against seed data agrees with a world that will not exist
|
||||
in production. That is the same shape as any other broken agreement: two participants, each
|
||||
reasonable alone.
|
||||
|
||||
## The universal core
|
||||
|
||||
Language- and stack-agnostic. Apply before any technology-specific checklist.
|
||||
|
||||
- **Repeated work** — scans, parsing, serialisation, allocation, initialisation or I/O performed
|
||||
again where a single pass, a hoist or a reuse would do.
|
||||
- **Growth relationships** — how does resource use scale with input size, with concurrency, and with
|
||||
elapsed time? Superlinear growth in any of the three is the finding; the constant factor is not.
|
||||
- **Retention** — queues, buffers, caches and collections that grow without a bound, an eviction
|
||||
policy or backpressure. Unbounded retention is a failure with a delay on it.
|
||||
- **Copying and conversion** — data copied or converted between representations on a hot path,
|
||||
especially at a boundary where both sides could have agreed on one representation.
|
||||
- **Serialisation and contention** — lock duration and scope, single-threaded chokepoints,
|
||||
head-of-line blocking, and work held inside a critical section that did not need to be.
|
||||
- **Amplification** — retries, polling, fan-out and cache misses that multiply one logical request
|
||||
into many real ones. Check the multiplier under failure, not under success.
|
||||
|
||||
## Technology specialisations
|
||||
|
||||
Apply only where the underlying technology exists — do not report the absence of a database concept
|
||||
in a program that has no database. For data-backed applications (over-fetching, `SELECT *`, missing
|
||||
pagination, index definitions, caching layers), `/performance-audit-static` holds the detailed
|
||||
checklist; use it rather than restating it here.
|
||||
|
||||
## What makes a performance finding
|
||||
|
||||
All three, or it is not a finding:
|
||||
|
||||
1. **A reachable workload** — the input size, rate or concurrency is one the system will actually
|
||||
meet, established from the code and its context rather than assumed.
|
||||
2. **A resource cost or growth relationship** — what is consumed, and how it scales.
|
||||
3. **A material consequence** — latency a user feels, a cost that is paid, a limit that is hit, or a
|
||||
failure that results.
|
||||
|
||||
## Refutation
|
||||
|
||||
Refute against real bounds, amortisation, reuse, actual call frequency, and deliberate trade-offs. A
|
||||
nested loop over a collection with a hard bound of four is not a finding. A missing cache in code
|
||||
called once at startup is not a finding.
|
||||
|
||||
**Distinguish measurement from static deduction, and label which you did.** Never invent a timing.
|
||||
Never report absent caching, a nested loop, or a missing index as a finding on its own — without a
|
||||
workload, those are observations, not defects.
|
||||
@@ -0,0 +1,68 @@
|
||||
# Sub-case: security review
|
||||
|
||||
A specialisation of the parent engine. The anchor changes, and one refutation rule is **inverted**
|
||||
relative to correctness — read that section before running this sub-case alongside another.
|
||||
|
||||
**Anchor:** source → trust boundary → sink, with an attacker who controls the source.
|
||||
|
||||
The agreement being tested is between what a component *trusts* and what an attacker can *supply*.
|
||||
Where correctness asks "can this happen", security asks "can someone make this happen on purpose" —
|
||||
and an adversary will construct the unlikely execution deliberately.
|
||||
|
||||
## Where the procedure lives
|
||||
|
||||
`/security-audit-static` owns the full specialised procedure — entry-point mapping, the four
|
||||
high-value paths, the keep/drop rule with its attacker-and-victim test, the OWASP Top 10 coverage
|
||||
backstop, and the high-miss checklist. **Run it rather than restating it.** This file exists to say
|
||||
what changes when security is selected as a dimension of a code review, and to supply the part of the
|
||||
engine that survives when the application has no web surface at all.
|
||||
|
||||
## The universal core
|
||||
|
||||
Applies to a CLI, a library, a daemon, a build tool — anything without an HTTP handler in sight.
|
||||
|
||||
- **Trust boundaries** — every point where data crosses from a less-trusted origin into a
|
||||
more-trusted context: arguments, environment, config files, stdin, filenames, archive members,
|
||||
network responses, plugin and extension surfaces, deserialised state, and model output.
|
||||
- **Sinks** — where a value becomes an instruction rather than data: process execution, dynamic
|
||||
evaluation, query construction, path resolution, template rendering, deserialisation, outbound
|
||||
requests, permission and role writes, and logging.
|
||||
- **Injection by representation confusion** — a value interpreted in the syntax of the sink rather
|
||||
than as an opaque datum. Encode for the *sink*, not at the input. This is the same disagreement as
|
||||
correctness lens 10 (representation and information loss), with an adversary steering it.
|
||||
- **Validator/consumer differentials** — the check and the use disagree about what the value means:
|
||||
unanchored patterns, prefix allowlists, normalisation applied on one side only, validation on one
|
||||
representation and execution on another.
|
||||
- **Fail-open paths** — error, timeout, cancellation, cache-miss and boundary branches that default
|
||||
to *allow*. Correctness lens 12 finds these; security decides what they cost.
|
||||
- **Secrets and sensitive data in transit to the wrong place** — logs, traces, error bodies,
|
||||
temporary files, crash dumps, and anything an unprivileged local user can read.
|
||||
- **Privilege and identity** — which principal an operation runs as, whether the check and the action
|
||||
name the same object, and what happens when they do not.
|
||||
|
||||
## The inverted refutation rule
|
||||
|
||||
Under correctness, a defect that harms only the person who triggered it is still a defect. Under
|
||||
security it usually is **not** a finding: if the only victim is the attacker, on their own machine,
|
||||
account, tenant or data, and no shared system or privilege boundary is crossed, drop it.
|
||||
|
||||
The carve-outs where that refutation is **forbidden** — outbound-network sinks, shared billing or
|
||||
quota, data exposure, cross-tenant or cross-principal flows, and server-side execution or rendering —
|
||||
are listed in `/security-audit-static`. Use its list; do not reinvent one.
|
||||
|
||||
**Do not let the two rules leak into each other.** Running both dimensions in one review, keep the
|
||||
tests separate per finding: a defect dropped as a security finding may still be a correctness finding
|
||||
with a real consequence, and should be reported as one.
|
||||
|
||||
## What makes a security finding
|
||||
|
||||
The parent skill's five requirements, with the trigger read adversarially:
|
||||
|
||||
1. A supported obligation — the trust assumption, and what establishes it.
|
||||
2. A feasible execution — **including who the attacker is and what they control.**
|
||||
3. A concrete contradiction — the boundary that fails to hold.
|
||||
4. An observable consequence — **naming the victim**, who must not be only the attacker.
|
||||
5. An examined counterargument — a real check at the sink, an unreachable path, an upstream
|
||||
validator, or a non-dangerous sink.
|
||||
|
||||
Findings are code-review results, not confirmed exploits. Say so.
|
||||
Reference in New Issue
Block a user