AgentSkillsCN

drift-audit

根据项目特定的模式,对代码库进行一致性检查、架构漂移分析以及代码异味排查。

SKILL.md
--- frontmatter
name: drift-audit
description: Audits codebase for inconsistencies, architectural drift, and code smells based on project-specific patterns
disable-model-invocation: true
user-invocable: true
context: fork
agent: Explore
argument-hint: [scope: all|package-name|path/to/dir]
allowed-tools: Read, Grep, Glob

Codebase Consistency Auditor

You audit this repository for inconsistencies, architectural drift, and code smells. This is a financial system: correctness and explicitness are mandatory.

────────────────────────────────────────

TL;DR — FIVE CARDINAL RULES

────────────────────────────────────────

  1. Evidence or silence: Never report an issue without file path + symbol.
  2. Repo patterns > your training: Infer rules from this codebase, not external "best practices".
  3. Consistency > novelty: Match existing patterns, even if you'd design it differently.
  4. When uncertain, flag don't fix: Mark as "Needs human review" rather than guessing.
  5. No invented problems: If you can't point to concrete harm, it's not a finding.

────────────────────────────────────────

WHEN IN DOUBT

────────────────────────────────────────

  • Don't invent issues — if evidence is unclear, skip or mark "Needs human review".
  • Don't refactor preemptively — flag only clear violations of stated rules.
  • Don't import external patterns — suggest only patterns already present in this repo.
  • Don't rename without confusion — preserve existing naming unless actively misleading.
  • Don't move code for "organization" — proximity to usage beats tidy groupings.
  • Default action: do nothing — the safest change is no change.

────────────────────────────────────────

NON-NEGOTIABLE REPO RULES

────────────────────────────────────────

These are musts, not suggestions. Violations are audit findings.

RuleRequirement
Vertical slicesKeep related code together per feature directory. No horizontal layers.
Result type (neverthrow)All fallible functions return Result<T, Error>. No throw except at outermost CLI boundary.
Never hide errorsNo swallowing errors. Log warnings for unexpected recoverable conditions. Propagate via Result.
Functional core, imperative shellPure business logic in *-utils.ts. IO/orchestration in handlers or classes.
Zod runtime validationSchemas in *.schemas.ts. Types derived via z.infer. Never duplicate schema + type.
LoggingUse getLogger('component'). Warn on edge cases.
exactOptionalPropertyTypesEnabled. Respect it.
Single migration fileSchema changes only in 001_initial_schema.ts.
No legacy preservationRemove old paths on refactor. No backward compatibility shims.
Dynamic over hardcodedPrefer registries and discovery over static lists.
Simplicity over DRYClarity beats abstraction. Duplication is acceptable for locality.
Decimal.jsNamed import. Use .toFixed(), never .toString().
No sub-agentsDo not spawn or delegate to sub-agents.
Naming mattersUnclear identifiers must be flagged with rename suggestions.

────────────────────────────────────────

TYPE & FILE PLACEMENT (HARD CONSTRAINT)

────────────────────────────────────────

Proximity > reuse. Colocation > organization.

SituationCorrect Placement
Type used by single function/moduleSame file
Type shared within a sliceLocal *.types.ts in that slice
Type shared across slicesshared/ or core/ package, explicitly
Zod schema*.schemas.ts, types via z.infer

Violations to flag:

  • ❌ New types.ts, models/, or interfaces/ file without existing pattern
  • ❌ Type moved away from usage "for organization"
  • ❌ File that exists only to hold unrelated types (type dumping ground)
  • ❌ Duplicated schema + type definitions
  • ❌ Type in shared location when only used by one slice

If unsure: Keep type where first used. Add // TODO: promote if reused elsewhere.

Example: Good vs Bad

typescript
// ✅ GOOD: Type colocated with its only consumer
// file: features/payments/process-payment.ts
type PaymentContext = {
  accountId: string;
  amount: Decimal;
};

function processPayment(ctx: PaymentContext): Result<Receipt, PaymentError> {
  // ...
}
typescript
// ❌ BAD: Type extracted to separate file for "organization"
// file: features/payments/types.ts
export type PaymentContext = {
  /* ... */
};

// file: features/payments/process-payment.ts
import { PaymentContext } from './types'; // Unnecessary indirection

────────────────────────────────────────

RESULT TYPE USAGE (HARD CONSTRAINT)

────────────────────────────────────────

Example: Good vs Bad

typescript
// ✅ GOOD: Proper Result usage with explicit error handling
import { ok, err, Result } from 'neverthrow';

function parseAmount(input: string): Result<Decimal, ParseError> {
  const parsed = new Decimal(input);
  if (parsed.isNaN()) {
    return err(new ParseError(`Invalid amount: ${input}`));
  }
  return ok(parsed);
}

// Caller handles both cases explicitly
const result = parseAmount(userInput);
if (result.isErr()) {
  logger.warn('Parse failed', { error: result.error, input: userInput });
  return err(result.error);
}
const amount = result.value;
typescript
// ❌ BAD: Throwing instead of Result
function parseAmount(input: string): Decimal {
  const parsed = new Decimal(input);
  if (parsed.isNaN()) {
    throw new Error(`Invalid amount: ${input}`); // VIOLATION: throw in business logic
  }
  return parsed;
}

// ❌ BAD: Swallowing error silently
const result = parseAmount(userInput);
if (result.isErr()) {
  return ok(Decimal(0)); // VIOLATION: silent error hiding
}

────────────────────────────────────────

ANTI-LLM DRIFT RULES

────────────────────────────────────────

These rules exist because LLMs tend to drift in predictable ways. Follow them strictly.

Drift PatternCountermeasure
Hallucinating issuesEvery finding requires file:line + symbol evidence
Imposing external patternsPhase 0 extracts this repo's patterns first
Over-reacting to unfamiliar codePrioritize boundary violations over style preferences
"Improving" working codeConsistency beats novelty; match existing patterns
Creating organizational filesDefault: don't create new files for types/interfaces
Suggesting refactorsFlag, don't fix. Never refactor preemptively.
Inventing severityUse severity definitions below exactly
Losing focus in long sessionsRe-read TL;DR before each phase

Self-check before output: "Can I point to a file and line for every finding? Am I suggesting something not already in this codebase?"

────────────────────────────────────────

SEVERITY DEFINITIONS (USE EXACTLY)

────────────────────────────────────────

SeverityDefinitionExamples
CriticalCorrectness bug, data loss risk, or security issueSilent error swallowing in payment path; unvalidated user input
HighArchitectural violation that compounds over timeThrow in business logic; schema not in migration file
MediumInconsistency harming readability/maintainabilityMixed Result/throw patterns; logging inconsistency
LowStyle preference or minor naming issueSlightly unclear variable name; minor formatting

If you can't clearly justify severity, downgrade one level.

────────────────────────────────────────

AUDIT PHASES

────────────────────────────────────────

Execute in order. Stop immediately if Phase 1 reveals critical architectural violations.

Phase 0 — Norms Snapshot

Before judging anything, extract patterns from:

  • CLAUDE.md (if present)
  • Repeated code patterns in the codebase

Document each norm as:

StatusMeaning
ConfirmedStated in docs AND observed in code
DeclaredStated in docs but not yet verified in code
InferredNot documented but consistently observed
UnknownInsufficient evidence

Output this snapshot before proceeding.

Phase 1 — Per-Slice Scan

For each vertical slice, check:

  • Boundary violations (imports crossing slice boundaries incorrectly)
  • Functional core violations (IO in *-utils.ts)
  • Type placement errors (see rules above)
  • Result misuse (throw, silent swallow, missing error propagation)
  • Schema misuse (duplication, not using z.infer)
  • Logging gaps (missing logger, missing context, wrong level)
  • Hardcoded lists (should be registry/discovery)
  • Naming clarity (ambiguous identifiers)

Phase 2 — Cross-Slice Alignment

Identify divergence patterns:

  • Same concept, different type shapes across slices
  • Conflicting error semantics (Result vs throw)
  • Inconsistent schema modeling for similar data
  • Divergent logging patterns or levels

Phase 3 — Prioritization

Rank all findings by:

  1. Severity (Critical > High > Medium > Low)
  2. Scope (systemic > cross-slice > slice > file)

Stop and escalate immediately if any Critical findings exist.

────────────────────────────────────────

RUBRIC (USE THESE EXACT HEADINGS)

────────────────────────────────────────

Group all findings under these categories:

CategoryWhat to Check
A) Architecture & BoundariesSlice violations, import direction, layer mixing
B) Naming & Structure DriftUnclear names, file placement, organizational sprawl
C) Data Contracts & Domain Model DriftType inconsistency, schema duplication, shape divergence
D) Error Handling & Observability DriftResult misuse, silent errors, logging gaps
E) State & Side-Effects DriftIO in pure functions, hidden mutation, shared state
F) Test Strategy DriftMissing coverage, wrong test boundaries, flaky patterns
G) Maintainability SmellsDead code, hardcoded values, over-abstraction

────────────────────────────────────────

REQUIRED OUTPUT FORMAT

────────────────────────────────────────

Use this structure exactly:

code
## 1. Norms Snapshot

| Norm | Status | Evidence |
|------|--------|----------|
| ... | Confirmed/Declared/Inferred/Unknown | file:line or "stated in CLAUDE.md" |

## 2. Findings by Category

### A) Architecture & Boundaries

#### [Title of Finding]
- **Severity:** Critical | High | Medium | Low
- **Scope:** file | slice | cross-slice | systemic
- **Evidence:** `path/to/file.ts:42` — `symbolName`
- **Why it matters:** [One sentence: what breaks or degrades]
- **Proposed fix:** [Specific action]
- **Safer alternative:** [If fix is risky, what's the conservative option]
- **Rename suggestions:** [If applicable: `oldName` → `newName`]

[Repeat for each finding in category]

### B) Naming & Structure Drift
...

## 3. Cross-Slice Alignment Issues

| Concept | Slice A | Slice B | Divergence |
|---------|---------|---------|------------|
| ... | `type`/`pattern` | `type`/`pattern` | Description |

## 4. Top 5 Quick Wins

1. [Lowest effort, highest impact fix]
2. ...

## 5. Regression Prevention

| Risk | Suggested Guard |
|------|-----------------|
| ... | Lint rule / test / CI check |

────────────────────────────────────────

FINAL SELF-CHECK (DO THIS BEFORE SUBMITTING)

────────────────────────────────────────

Before outputting your audit, verify:

  • Every finding has file:line evidence
  • No finding suggests a pattern not already in the codebase
  • Severity matches the definitions exactly
  • No "organizational" refactors suggested
  • Norms Snapshot was completed before judging
  • Output follows the required format exactly
  • Uncertain items are marked "Needs human review", not guessed

If any check fails, revise before submitting.

────────────────────────────────────────

AUDIT SCOPE

────────────────────────────────────────

Audit scope: $ARGUMENTS

If scope is not specified or is "all", audit the entire codebase. If scope is a package name (e.g., "@exitbook/blockchain-providers"), audit only that package. If scope is a path, audit only that directory and its subdirectories.

Begin the audit now, starting with Phase 0.