Technical debt seer tooling

Vølven sees the code that will hurt later.

A product family for finding future cost: hidden contracts, growing suppressions, brittle tests, upgrade friction, deploy friction, and the tiny assumptions that become expensive folklore.

The suite

One debt model. Different edges.

Vølven is split into focused tools so each one can stay useful instead of becoming another lint-shaped attic.

Core debt skill

The doctrine. It separates real debt from local mess, taste complaints, and deliberate strategic shortcuts.

PHP and Laravel skills

Weak arrays, stringly workflows, hidden Eloquent side effects, unsafe jobs, migration risk, and stale framework assumptions.

Python skill

Implicit schemas, mutable globals, swallowed exceptions, async failure paths, and scripts pretending to be architecture.

TypeScript and JavaScript skills

Runtime contracts, casts that silence uncertainty, duplicated state, unsafe API boundaries, and mock-heavy tests.

Pest plugin

Deterministic debt budgets for PHP projects. Old debt can be captured. New debt fails CI.

Debt signals

The things Vølven cares about have a bill attached.

Not every rough edge matters. Vølven looks for signals that change how expensive the next month, deploy, upgrade, or incident becomes.

Hidden contracts

Call order, magic names, lifecycle assumptions, and test fixtures that know more than production code.

Growing suppressions

Inline ignores and tolerated uncertainty that quietly become project policy because CI stopped asking questions.

Misleading tests

Mocks that assert choreography while the real behavior, boundary, queue, or integration path can still break.

Deploy and upgrade friction

Migrations, environment assumptions, stale adapters, and framework quirks that turn ordinary releases into archaeology.

Boundaries

Vølven does not cosplay as your existing tools.

Pint owns style. PHPStan and Psalm own type correctness. Rector owns mechanical fixes. Pest arch() owns architecture rules. ESLint, TypeScript, Ruff, mypy, and pyright already have jobs.

Vølven owns debt pressure: whether known debt is growing, whether hidden contracts are getting riskier, and whether maintenance cost is moving in the wrong direction.

Pint: style PHPStan: type correctness Rector: mechanical refactors Pest arch: structure rules Vølven: future cost

Pest plugin

Make debt growth fail loudly.

The plugin tracks deterministic debt signals, compares them to a committed baseline, and reports findings in the same shape as the Vølven doctrine.

Baseline old debt Block fresh debt Keep reasons attached

Read the full Pest plugin docs

debt()->budget()
    ->phpstanIgnores(max: 12)
    ->todoComments(max: 20)
    ->mixedTypes(max: 12)
    ->largeClasses(max: 5)
    ->mustNotGrow()
    ->requireReasons()
    ->assert();

PHPStan ignores

Counts suppression annotations only. Type-shaping annotations stay clean, because contracts are not debt.

TODO and FIXME

Tracks unowned work before it becomes “everybody knows why this is here” folklore.

Mixed types

Finds important unknowns crossing boundaries without a visible contract or validation point.

Large classes

Flags class-like files large enough to trap unrelated reasons to change.

Workflow

Legacy-friendly without pretending legacy is fine.

Vølven starts where the codebase is. Capture the existing debt, then stop the next commit from making the pile taller.

01

Scan

Find deterministic debt signals and format failures like useful review findings, not lint confetti.

02

Baseline

Commit .volven/debt-baseline.json so existing debt is visible without blocking all progress.

03

Ratchet

Use mustNotGrow() to fail CI when new debt appears outside the agreed budget.

04

Repay

Fix the smallest useful slice first. Large rewrites are usually procrastination with a cape.

Language variants

The same debt idea, translated into local failure modes.

Laravel

Model events hiding side effects, queued jobs without idempotency, production-lock migrations, config reads outside config files.

Read Laravel docs
Python

Dynamic dictionaries through core paths, swallowed exceptions, async code without cancellation discipline, implicit data-pipeline schemas.

Read Python docs
TypeScript

any, unsafe casts, runtime API trust, React components owning business rules, state split across URL, cache, store, and component.

Read TypeScript docs
JavaScript

Hidden object shapes, callback/promise mixing, mutable shared state, framework magic without local conventions.

Read JavaScript docs

Doctrine

Debt is future cost, not ugliness.

  1. Flag hidden coupling, brittle contracts, misleading tests, unsafe dynamic behavior, upgrade friction, deploy friction, and trapped knowledge.
  2. Do not flag style, generic smells, duplicate static-analysis findings, or broad refactor sermons.
  3. Every finding needs evidence, the smallest useful fix, and a reason it may be acceptable.
  4. Separate real debt from local mess, taste complaints, and deliberate strategic debt.
  5. Prioritize by risk, blast radius, change frequency, and fix cost. No fake debt scores. The world has enough pretend precision.