Skip to content
Back to skills

Assumption Ledger

ASecurity

Rank a plan's hidden assumptions by impact × uncertainty, each with its cheapest test, an expiry and a decision.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 20, 2026
ai-agentspythongobashgitapi

Works with

  • api

Security analysis

A100/100

Scanned October 20, 2026

npx -y skills add adnanmokhtar/refract --skill assumption-ledger --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Assumption Ledger?

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

Security grade badge for Assumption Ledger
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/adnanmokhtar-assumption-ledger/badge)](https://www.skillsdirectory.com/skills/adnanmokhtar-assumption-ledger)

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: assumption-ledger
description: "Rank a plan's hidden assumptions by impact × uncertainty, each with its cheapest test, an expiry and a decision."
kind: skill
pack: product
allowed-tools: [Read, Write, Edit, Grep, Glob, Bash]
---

# Skill: assumption-ledger

## Premise

Every plan rests on beliefs. The dangerous ones are not the beliefs that are wrong; they are the beliefs nobody noticed they were holding, because those are the ones that go untested for the whole project and are discovered at launch.

An assumption is not a defect. An *unexamined* one is. The output of this skill is a ranked list where the top rows are the cheapest things to find out this week, which is usually the most actionable artifact attached to any brief.

## Halt conditions

- **No plan, brief, or spec to read** — assumptions are extracted from a stated intention, not from a topic.
- **The plan is entirely evidence-backed and says so** — verify with `evidence-trace` before concluding this; it is rare, and usually means the assumptions are implicit rather than absent.
- **Ranking requested with no impact context** — impact means "impact on what". Without a stated success metric or objective, the ranking is arbitrary; get it or report the ledger unranked and say why.

## When to run

- Immediately after `/frame-problem`, as the brief's closing section.
- Before committing to work larger than a sprint.
- When a plan depends on beliefs about users, demand, capability, or timing that nobody has stated aloud.
- When a project keeps being extended — an unexamined assumption is usually why the finish line moves.
- After `evidence-trace` reports an unsourced set.

## Procedure

### 1. Extract, by category

Assumptions hide in confident sentences. Read the plan for each category and write what must be true for the sentence to hold:

| Category | The belief | Typical wording that hides it |
|---|---|---|
| **desirability** | someone wants this enough to change behaviour | "users will finally be able to…" |
| **prevalence** | enough people have this problem | "customers keep asking for…" |
| **willingness** | they will pay, switch, or migrate | "this unblocks the enterprise segment" |
| **feasibility** | it can be built at this cost, in this time | "straightforward once the schema is in place" |
| **viability** | the economics work | "at scale the cost per user is negligible" |
| **dependency** | something outside our control will hold | "the vendor's API supports this" |
| **timing** | the window is open, and staying open | "we need this before the competitor ships" |
| **capability** | the team can do this well | "we've done something similar" |
| **adoption path** | people will discover and reach it | "it'll be in the main navigation" |

The wording column is the practical part: these phrases are where an assumption is most often disguised as a fact.

### 2. State each as a falsifiable claim

Rewrite as something that could be shown false: *"at least 30% of accounts on the mid-tier plan perform this workflow monthly"* rather than *"lots of customers need this"*. An assumption that cannot be false cannot be tested, and it will be argued about instead.

### 3. Score impact and uncertainty

- **Impact** — if this is false, what happens? `fatal` (the plan does not work) / `major` (significant rework or a much smaller outcome) / `minor` (an adjustment).
- **Uncertainty** — how confident are we, and on what basis? `high` (nobody has checked) / `medium` (indirect or dated evidence) / `low` (direct current evidence, though it remains an assumption about the future).

Rank by impact × uncertainty. The `fatal` × `high` rows are the whole point of the ledger: they are what to find out before committing, and there are usually only two or three.

### 4. Attach the cheapest test

For each row, the cheapest thing that would meaningfully move the uncertainty — not the most rigorous. Rough ascending cost:

- Query existing data (often minutes; frequently sufficient for prevalence)
- Read existing tickets or call notes
- Ask five customers
- A concierge or manual version of the capability
- A landing page or interest-to-action measurement
- A prototype
- A limited build behind a flag

State the test, its cost, and **what result would change the decision**. A test whose outcome would not alter anything is not worth running, and saying so out loud saves more time than the test would have.

### 5. Set expiry and record the decision

Each row gets a date (`YYYY-MM-DD`) by which it must be tested or accepted. An assumption carried past its expiry without a decision has quietly become a fact, which is exactly the failure this ledger exists to prevent.

The `Decision` column holds `open`, `tested: <result> (<date>)` or `accepted: <named person>`; nothing else counts as decided. The `Feature` column holds the success-file slug the row belongs to (empty or `*` for every feature). `launch-readiness` reads these columns by header name (rule PRR-LR-6): at a feature's launch every `fatal × high` row for that feature must be decided, and at repo scope every one past its expiry.

### 6. Report

```
## assumption-ledger — <plan / brief> — <date>

Objective the impact is measured against: <success metric or goal>

| # | Assumption (falsifiable) | Category | Impact | Uncertainty | Rank | Cheapest test | Cost | Would change | Expiry | Owner | Decision | Feature |
|---|--------------------------|----------|--------|-------------|------|---------------|------|--------------|--------|-------|----------|---------|

Top rows (fatal × high): <n> — these block commitment
Tests runnable this week: <n>
Assumptions past expiry from prior ledgers: <n> (named)

Recommendation: <test before committing | commit and monitor | do not commit>
```

## Inputs

- The brief, spec, or plan.
- The declared success metric or objective, for the impact axis.
- `evidence-trace` output, where an unsourced set already exists.
- Prior ledgers in `ai/product/assumptions.md`, to carry forward unexpired rows.

## Outputs

- The ledger, appended to `ai/product/assumptions.md` and included as the closing section of the brief.
- The `fatal × high` rows, which `@product-strategist` treats as blocking commitment.
- The runnable-this-week set, which is the immediate research plan.

## False positives / gotchas

- **Listing everything.** A forty-row ledger is a document; a six-row ledger is a plan. Merge the minor rows or drop them.
- **Assumptions stated so they cannot be false** ("users value convenience"). Rewrite as a claim with a threshold.
- **Choosing the most rigorous test rather than the cheapest.** The goal is to move uncertainty, not to publish.
- **A test whose result would not change the decision.** Note it and skip it; that observation is itself valuable.
- **Scoring impact against an unstated objective**, so the ranking reflects the scorer's preference.
- **Never revisiting.** A ledger with no expiry dates becomes a list of things everyone once worried about.
- **Confusing a dependency with an assumption.** "The vendor's API supports this" is checkable in an afternoon — that is a task, not an assumption. Move it.

## Related

### Skills
- `evidence-trace` — supplies the unsourced set this skill ranks.
- `acceptance-criteria-check` — an assumption inside an acceptance criterion is a different defect; that skill catches it.
- `launch-readiness` — checks whether the fatal assumptions were ever tested.

### Agents
- `@product-strategist` — the brief closes with this ledger.
- `@scope-arbiter` — items flagged NO-EVIDENCE arrive here.
- `@user-research-synthesizer` — runs the tests this ledger names.

### Commands
- `/frame-problem` — dispatches this skill.
- `/audit-requirements` — converts UNSOURCED findings into rows here.

### Patterns
- `ai/patterns/problem-framing.md`, `ai/patterns/opportunity-sizing.md`

## Verify (postconditions)

Contract: [`templates/snippets/postcondition-check.md`](../../../../snippets/postcondition-check.md). This skill writes `ai/product/assumptions.md`; each check below is observed after the write, reported when it passes as well as when it fails, and `NOT RUN (<reason>)` where no signal is available. They are the gotchas above that this skill's own write can cause.

| # | Postcondition | How it is observed |
|---|---|---|
| P1 | The ledger was appended, not rewritten: every row present before the run is still present, unexpired rows carried forward | row count and `#` ids before vs after (`git diff --stat ai/product/assumptions.md`, or the file read before the write) |
| P2 | Every new row is falsifiable: a threshold or a countable outcome, no "users value …" | each `Assumption` cell holds a number, a percentage or a named observable; a row without one is listed |
| P3 | Every new row has `Impact` ∈ fatal / major / minor, `Uncertainty` ∈ high / medium / low, an ISO `Expiry` after today, a named `Owner` and a `Decision` (`open` is a value) | the columns read back by header name, the same way `readiness-score.py` reads them |
| P4 | The ledger is a plan, not a document: at most about ten rows per brief, the `fatal × high` rows first | count per brief; ranks in order |
| P5 | Every test names what result would change the decision | the `Would change` cell is non-empty and not a restatement of the test |
| P6 | Rows past expiry from earlier ledgers are listed by name in the report | the expired-and-open set computed from the file equals the report's list |
| P7 | No dependency is recorded as an assumption ("the vendor's API supports this" is a task) | `Category: dependency` rows are each checked: a one-afternoon check is moved to the task list |

`python3 -I .claude/skills/launch-readiness/scripts/readiness-score.py --repo=. --scope=repo --rule=PRR-LR-6` (when this pack's `launch-readiness` is installed) is the mechanical read of P3 and P6: it exits 2 while a `fatal × high` row is past its expiry and undecided.

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.