Chapter 10 — Style Deep-Dive: Lean
A Lean Requirement is not a promise to the system — it is a hypothesis about value, tied to a measured gap. The Style refuses anything softer.
Chapter 08 introduced Style pluralism: one Requirement, many registers. Chapter 09 took the IndustrialStyle deep — IEC 61508, SIL 1–4, 13-state heavy-gate lifecycle, Nuclear-grade bookkeeping. This chapter takes the opposite register with the same depth: LeanStyle, the Toyota-tradition Style that rewires the whole Requirements vocabulary around A3, PDCA, Gemba, VSM, and Kaizen.
The canonical source is packages/requirements/src/styles/lean.ts — 460 lines of TypeScript declaring one StyleVocabulary, one StyleValidators object with four Toyota-shaped rules, a StyleTemplates list of five templates, and a RequirementReporter that emits A3 one-page Markdown. The pitch under docs/pitches/lean.md is the audience-facing argument; this chapter is the dog-food-facing walk-through.
The structural question this chapter answers: what does it mean, inside a typed DSL, to model a requirement as a measured gap rather than as a promised behaviour?
Lean, TPS, and the Requirement register
Lean vocabulary targets a specific audience. Not lawyers, not EN 61508 safety engineers, not scrum teams with INVEST acceptance criteria — although the Style can coexist with all of those. Lean vocabulary targets the continuous-improvement team: the CI lead on the shop floor, the value-stream manager tracing a flow, the Kaizen facilitator running a two-day event, the Lean-Six-Sigma Black Belt scoping an A3 project, the Toyota-Kata coach working one-on-one with a learner. Their job, as a trade, is to observe a value stream and remove waste.
What does "a requirement" mean to that audience?
It does not mean "the system shall, when the user presses X, display Y" — that is a delivery contract, a future-tense promise. A Lean requirement is a past-tense observation plus a future-tense target plus a present-tense gap between them. "Changeover currently takes 90 minutes. Hoshin target is 30 minutes. The gap is 60 minutes, dominated by waiting (22 min) and motion (~18 min)." That is a requirement in the Lean register. Every element of it is measured; every element is observed; none of it is a promise about the system.
Writing a requirement in the Lean register, therefore, means embedding four things in the type itself:
- The waste category it removes. Transport, inventory, motion, waiting, overproduction, over-processing, defects, unused-talent — the TIMWOODS octet, encoded at the type level, not in the prose.
- The current-state metric. What the value stream measures right now, before any change. Timed, counted, with units.
- The ideal-state metric. What the value stream would measure if the countermeasure landed. Same units, directly comparable.
- The improvement cadence. How long the team will run the experiment before reading the result — the Kaizen validation window, the time-box that prevents indefinite measurement without a decision.
Each of these four becomes a typed slot on the Requirement. A Lean requirement with no wasteCategory is a type error. A Lean requirement whose currentStateMetric and idealStateMetric carry different units is a type error. A Lean requirement whose validationWindow is empty is a type error. The Style's job is to make "we had a Kaizen" verifiable at compile-time, not at retrospective time.
The audience, if they are going to write down a requirement at all, already speaks this language. The job of LeanStyle is not to teach them a new vocabulary. The job is to give their vocabulary a type system — so the A3 sheet in the drawer becomes a typed JSON spec in Git, moving through a PDCA status FSM, refusing to sit in Standardized without an upstream Experimenting → Validated transition to back it up.
This chapter walks that Style from its vocabulary down through its validators, through a worked example, through the TIMWOODS encoding and the flow-metrics embedding, and finishes on a structural comparison between the Kaizen loop and the dog-food loop that drives this very package.
The LeanStyle type
The Style is one file. Its exports are five things: the vocabulary, the validators, the templates, the reporter, and the aggregated LeanStyle object that binds them. Each deserves its own look.
StyleVocabulary — what the Style says exists
The vocabulary is where the Style names its world. Opening src/styles/lean.ts and reading the top of the LEAN_VOCABULARY export:
export const LEAN_VOCABULARY: StyleVocabulary = {
requirementKinds: [
'ValueAdding',
'NonValueAddingButNecessary',
'Waste-Elimination',
'Flow-Improvement',
'Quality-BuiltIn',
'Customer-Pull',
'Standardization',
'Kaizen-Experiment',
'Respect-for-People',
],export const LEAN_VOCABULARY: StyleVocabulary = {
requirementKinds: [
'ValueAdding',
'NonValueAddingButNecessary',
'Waste-Elimination',
'Flow-Improvement',
'Quality-BuiltIn',
'Customer-Pull',
'Standardization',
'Kaizen-Experiment',
'Respect-for-People',
],Nine kinds. Not Functional/Non-Functional, not Quality/Constraint — those are the Default and Industrial taxonomies. The Lean taxonomy is value-centric. Every kind is a classification of how this requirement relates to the customer-pulled value stream:
ValueAdding— the work directly creates what the customer pulls.NonValueAddingButNecessary— needed under current constraints (regulatory, setup, cycle-time safeguard), but a candidate for future reduction.Waste-Elimination— a direct attack on observed muda. This kind carries a hard validator rule we will come back to.Flow-Improvement— reduces batch size, queue depth, or handoff count. Improves end-to-end flow without removing a specific waste outright.Quality-BuiltIn— jidoka. Stop-the-line, poka-yoke, built-in inspection. Quality is not inspected-in; it is built-in at the process step.Customer-Pull— increment pulled by an articulated customer need. The most Lean-Startup-flavoured of the nine.Standardization— codifies the current best-known method. Requires thestandard-workstatement pattern (enforced).Kaizen-Experiment— a time-boxed PDCA hypothesis. Requires thekaizen-hypothesispattern +PDCAverification (both enforced).Respect-for-People— organisational change touching how people are trusted and developed. The softest of the nine; rarely needs a metric, often needs a cultural narrative.
Contrast this against Default's Functional | NonFunctional | Constraint | Assumption | Risk. A Default requirement classifies what the system obligation is. A Lean requirement classifies where on the value stream the obligation lives. These are orthogonal taxonomies — you can say the same underlying fact in both registers, but you will say it in different words.
Moving down, the status workflow:
statusWorkflow: {
states: [
'ProblemStated',
'CurrentStateMapped',
'TargetStateDefined',
'CountermeasureProposed',
'Experimenting',
'Validated',
'Standardized',
'Deprecated',
],
initial: 'ProblemStated',
transitions: [
{ from: 'ProblemStated', to: 'CurrentStateMapped' },
{ from: 'CurrentStateMapped', to: 'TargetStateDefined' },
{ from: 'TargetStateDefined', to: 'CountermeasureProposed' },
{ from: 'CountermeasureProposed', to: 'Experimenting' },
{ from: 'Experimenting', to: 'Validated' },
{ from: 'Validated', to: 'Standardized' },
{ from: 'Standardized', to: 'Deprecated' },
{ from: 'Experimenting', to: 'CountermeasureProposed' },
{ from: 'Validated', to: 'TargetStateDefined' },
{ from: 'Standardized', to: 'ProblemStated' },
],
terminal: ['Deprecated'],
}, statusWorkflow: {
states: [
'ProblemStated',
'CurrentStateMapped',
'TargetStateDefined',
'CountermeasureProposed',
'Experimenting',
'Validated',
'Standardized',
'Deprecated',
],
initial: 'ProblemStated',
transitions: [
{ from: 'ProblemStated', to: 'CurrentStateMapped' },
{ from: 'CurrentStateMapped', to: 'TargetStateDefined' },
{ from: 'TargetStateDefined', to: 'CountermeasureProposed' },
{ from: 'CountermeasureProposed', to: 'Experimenting' },
{ from: 'Experimenting', to: 'Validated' },
{ from: 'Validated', to: 'Standardized' },
{ from: 'Standardized', to: 'Deprecated' },
{ from: 'Experimenting', to: 'CountermeasureProposed' },
{ from: 'Validated', to: 'TargetStateDefined' },
{ from: 'Standardized', to: 'ProblemStated' },
],
terminal: ['Deprecated'],
},Eight states. Seven forward transitions. Three rework transitions. The workflow is a PDCA cycle made explicit: Plan (ProblemStated → CurrentStateMapped → TargetStateDefined → CountermeasureProposed), Do (Experimenting), Check (Validated), Act (Standardized). The three rework edges encode a truth that most status FSMs refuse to name:
Experimenting → CountermeasureProposed— the experiment failed; the countermeasure was wrong; back to the drawing board with what we learned.Validated → TargetStateDefined— worse, the target itself was wrong; the experiment succeeded against its hypothesis but the hypothesis was addressing the wrong gap.Standardized → ProblemStated— the standing standard has been superseded; a new problem emerges; a new PDCA cycle begins.
This is Toyota Kata honesty about what learning does. Learning can invalidate your countermeasure. Learning can invalidate your target. The status machine must have edges for both. A requirements DSL that only allows monotonic progress (Draft → Approved → Done, never backward) cannot model Lean honestly. The Lean register needs these backward edges because its entire epistemology is we might be wrong about the hypothesis and we might be wrong about the target.
Next in the vocabulary, the risk taxonomy:
riskTaxonomy: {
levels: [
'HighImpactLowEffort',
'HighImpactHighEffort',
'LowImpactLowEffort',
'LowImpactHighEffort',
],
// ... matrix maps the likelihood×impact grid to these four levels
}, riskTaxonomy: {
levels: [
'HighImpactLowEffort',
'HighImpactHighEffort',
'LowImpactLowEffort',
'LowImpactHighEffort',
],
// ... matrix maps the likelihood×impact grid to these four levels
},Four levels. Not SIL 1–4, not Low/Medium/High likelihood × severity — Impact × Effort, ICE-style. The header comment in src/styles/lean.ts is explicit about why:
Impact × Effort (ICE-style). Likelihood is unused in Lean prioritisation — we do not play probabilities, we go see and act on what is in front of us.
Lean does not prioritise by probability of harm. It prioritises by what is observable now, what would the fix cost, what would the fix return. The HighImpactLowEffort quadrant is the just-do-it quadrant; the LowImpactHighEffort is the avoid quadrant (classic muda). This reuses the generic likelihood/impact matrix but repurposes the likelihood axis as effort — a pragmatic fit into the shared riskTaxonomy shape without forcing every Style to have its own risk type.
Verification methods:
verificationMethods: [
'GembaWalk',
'A3Review',
'FiveWhys',
'PDCA',
'VSM',
'Kaizen',
'StandardWork',
'TaktTimeCheck',
], verificationMethods: [
'GembaWalk',
'A3Review',
'FiveWhys',
'PDCA',
'VSM',
'Kaizen',
'StandardWork',
'TaktTimeCheck',
],Eight, all Lean-native. Note what is absent: no UnitTest, no IntegrationTest, no FormalProof, no Inspection. That is deliberate — a Lean requirement is not verified by a test in the software-engineering sense. It is verified by going back to the floor and re-measuring. If you need to verify a Lean requirement with a unit test, you are probably not writing a Lean requirement; you are writing an Agile or Default requirement that happens to borrow Lean vocabulary for marketing.
Rationale kinds:
rationaleKinds: [
'waste-observed',
'customer-complaint',
'takt-time-deviation',
'defect-metric',
'flow-impediment',
'standard-work-gap',
'kata-learning',
'hoshin-alignment',
], rationaleKinds: [
'waste-observed',
'customer-complaint',
'takt-time-deviation',
'defect-metric',
'flow-impediment',
'standard-work-gap',
'kata-learning',
'hoshin-alignment',
],Eight, again all evidence-flavoured. No generic "because we think so", no "product-vision-alignment". Every rationale kind commits to a category of evidence the requirement claims to rest on. waste-observed pledges a Gemba walk; defect-metric pledges a counted defect rate; takt-time-deviation pledges a measured takt violation. The rationale kind is a type-level promise about what evidence the Rationale.evidence[] array should carry.
Source kinds — this is where Lean's evidence discipline becomes a typed schema:
sourceKinds: [
{ kind: 'gemba-walk', label: 'Gemba walk — go see', slots: [
{ name: 'location', type: 'string', required: true, hint: 'shop floor / cell / queue / service desk' },
{ name: 'date', type: 'iso-date', required: true },
{ name: 'observer', type: 'string', required: true },
]},
// ... customer-feedback, process-measurement, a3-analysis, kaizen-event
{ kind: 'vsm', label: 'Value-stream map', slots: [
{ name: 'streamName', type: 'string', required: true },
{ name: 'mappedAt', type: 'iso-date', required: true },
{ name: 'wasteCategory', type: 'string', required: true,
hint: 'transport | inventory | motion | waiting | overproduction | over-processing | defects | unused-talent' },
]},
// ... hoshin-plan, kata-coaching
], sourceKinds: [
{ kind: 'gemba-walk', label: 'Gemba walk — go see', slots: [
{ name: 'location', type: 'string', required: true, hint: 'shop floor / cell / queue / service desk' },
{ name: 'date', type: 'iso-date', required: true },
{ name: 'observer', type: 'string', required: true },
]},
// ... customer-feedback, process-measurement, a3-analysis, kaizen-event
{ kind: 'vsm', label: 'Value-stream map', slots: [
{ name: 'streamName', type: 'string', required: true },
{ name: 'mappedAt', type: 'iso-date', required: true },
{ name: 'wasteCategory', type: 'string', required: true,
hint: 'transport | inventory | motion | waiting | overproduction | over-processing | defects | unused-talent' },
]},
// ... hoshin-plan, kata-coaching
],Eight source kinds. Each one is a typed sub-record with required slots. gemba-walk cannot be filed without a location, a date, and an observer's name. vsm cannot be filed without a stream name, a mapping date, and a TIMWOODS waste category. kata-coaching cannot be filed without a coach, a learner, and a session date. The hint strings in the slot definitions are what drive the interactive wizard — when a user runs npx requirements new --style lean, the prompt for source.type shows these eight kinds, and selecting vsm unfolds the three required slots.
This is the mechanism by which genchi genbutsu — the Toyota principle of "go see for yourself" — becomes a type discipline. You cannot file a Waste-Elimination requirement with a source of hoshin-plan or customer-feedback; the validator will reject it. You must cite a gemba-walk or a vsm. The hunger for first-hand observation is enforced by the type system, not by a code-review norm.
And the statement patterns — the Style's answer to EARS:
statementPatterns: [
{ pattern: 'problem-statement',
label: 'A3 problem statement',
template: 'Problem: {problem}. Current: {currentState}. Target: {targetState}. Gap: {gap}.',
slots: [
{ name: 'problem', required: true },
{ name: 'currentState', required: true, hint: 'measured, not guessed' },
{ name: 'targetState', required: true, hint: 'measurable target condition' },
{ name: 'gap', required: true, hint: 'the delta — what must close' },
] },
// ... countermeasure, standard-work, value-proposition
{ pattern: 'kaizen-hypothesis',
label: 'Kaizen / Lean Startup hypothesis',
template: 'If we {change}, then {expectedOutcome}, because {reasoning}. ' +
'We will know within {validationWindow} by observing {metric}.',
slots: [
{ name: 'change', required: true },
{ name: 'expectedOutcome', required: true },
{ name: 'reasoning', required: true },
{ name: 'validationWindow', required: true, hint: 'time-box for the experiment — build-measure-learn' },
{ name: 'metric', required: true, hint: 'the actionable metric (Ries)' },
] },
{ pattern: 'natural', label: 'Natural language (fallback — generates warning)',
template: '{text}', slots: [ { name: 'text', required: true } ] },
], statementPatterns: [
{ pattern: 'problem-statement',
label: 'A3 problem statement',
template: 'Problem: {problem}. Current: {currentState}. Target: {targetState}. Gap: {gap}.',
slots: [
{ name: 'problem', required: true },
{ name: 'currentState', required: true, hint: 'measured, not guessed' },
{ name: 'targetState', required: true, hint: 'measurable target condition' },
{ name: 'gap', required: true, hint: 'the delta — what must close' },
] },
// ... countermeasure, standard-work, value-proposition
{ pattern: 'kaizen-hypothesis',
label: 'Kaizen / Lean Startup hypothesis',
template: 'If we {change}, then {expectedOutcome}, because {reasoning}. ' +
'We will know within {validationWindow} by observing {metric}.',
slots: [
{ name: 'change', required: true },
{ name: 'expectedOutcome', required: true },
{ name: 'reasoning', required: true },
{ name: 'validationWindow', required: true, hint: 'time-box for the experiment — build-measure-learn' },
{ name: 'metric', required: true, hint: 'the actionable metric (Ries)' },
] },
{ pattern: 'natural', label: 'Natural language (fallback — generates warning)',
template: '{text}', slots: [ { name: 'text', required: true } ] },
],Five Lean-specific patterns plus the natural fallback. Each one makes an explicit current→target→gap or hypothesis→outcome shape mandatory. The kaizen-hypothesis pattern is the Style's centre of gravity — its five slots (change, expectedOutcome, reasoning, validationWindow, metric) are all required, and the validator refuses a Kaizen-Experiment requirement whose statement uses any other pattern.
StyleValidators — the four Toyota rules
The validators are where the Style earns its teeth. From the same file, LEAN_VALIDATORS.validateSpec hard-codes four rules:
validateSpec(spec: unknown): ValidationResult {
// ... kind and status checks elided
const statement = s.statement as Record<string, unknown> | undefined;
// Rule 1 — Kaizen-Experiment requires kaizen-hypothesis + PDCA
if (s.requirementKind === 'Kaizen-Experiment') {
if (statement?.pattern !== 'kaizen-hypothesis') {
errors.push({ path: 'statement.pattern',
message: 'Kaizen-Experiment requirements must use the kaizen-hypothesis pattern' });
}
const vm = s.verificationMethod as string | undefined;
if (vm !== 'PDCA') {
errors.push({ path: 'verificationMethod',
message: 'Kaizen-Experiment requirements must be verified by PDCA (got ' + String(vm) + ')' });
}
}
// Rule 2 — Standardization requires standard-work pattern
if (s.requirementKind === 'Standardization') {
if (statement?.pattern !== 'standard-work') {
errors.push({ path: 'statement.pattern',
message: 'Standardization requirements must use the standard-work pattern' });
}
}
// Rule 3 — problem-statement requires non-empty gap
if (statement?.pattern === 'problem-statement') {
const gap = statement.gap as string | undefined;
if (typeof gap !== 'string' || gap.length === 0) {
errors.push({ path: 'statement.gap',
message: 'problem-statement requires a non-empty gap (the measurable delta current→target)' });
}
}
// Rule 4 — genchi genbutsu: Waste-Elimination requires gemba or vsm source
if (s.requirementKind === 'Waste-Elimination') {
const source = s.source as Record<string, unknown> | undefined;
const t = source?.type as string | undefined;
if (t !== 'gemba-walk' && t !== 'vsm') {
errors.push({ path: 'source.type',
message: 'Waste-Elimination requirements must cite a gemba-walk or vsm source (genchi genbutsu — go see)' });
}
}
// ...
}, validateSpec(spec: unknown): ValidationResult {
// ... kind and status checks elided
const statement = s.statement as Record<string, unknown> | undefined;
// Rule 1 — Kaizen-Experiment requires kaizen-hypothesis + PDCA
if (s.requirementKind === 'Kaizen-Experiment') {
if (statement?.pattern !== 'kaizen-hypothesis') {
errors.push({ path: 'statement.pattern',
message: 'Kaizen-Experiment requirements must use the kaizen-hypothesis pattern' });
}
const vm = s.verificationMethod as string | undefined;
if (vm !== 'PDCA') {
errors.push({ path: 'verificationMethod',
message: 'Kaizen-Experiment requirements must be verified by PDCA (got ' + String(vm) + ')' });
}
}
// Rule 2 — Standardization requires standard-work pattern
if (s.requirementKind === 'Standardization') {
if (statement?.pattern !== 'standard-work') {
errors.push({ path: 'statement.pattern',
message: 'Standardization requirements must use the standard-work pattern' });
}
}
// Rule 3 — problem-statement requires non-empty gap
if (statement?.pattern === 'problem-statement') {
const gap = statement.gap as string | undefined;
if (typeof gap !== 'string' || gap.length === 0) {
errors.push({ path: 'statement.gap',
message: 'problem-statement requires a non-empty gap (the measurable delta current→target)' });
}
}
// Rule 4 — genchi genbutsu: Waste-Elimination requires gemba or vsm source
if (s.requirementKind === 'Waste-Elimination') {
const source = s.source as Record<string, unknown> | undefined;
const t = source?.type as string | undefined;
if (t !== 'gemba-walk' && t !== 'vsm') {
errors.push({ path: 'source.type',
message: 'Waste-Elimination requirements must cite a gemba-walk or vsm source (genchi genbutsu — go see)' });
}
}
// ...
},Four rules, each one a Toyota principle encoded as a boolean check:
- Rule 1 enforces that a Kaizen is a time-boxed hypothesis verified by PDCA. A kaizen without a validation window is a wish. The validator will not let you file a wish.
- Rule 2 enforces that a Standard carries steps, takt, and checkpoint. Ohno's dictum: "without standards, there can be no improvement." A standard without the shape of a standard is folklore.
- Rule 3 enforces that a problem has a measurable gap. "We have a problem with X" is not a problem; it is a complaint. A problem, in the A3 sense, is a measurable delta. No delta, no problem.
- Rule 4 enforces genchi genbutsu — you do not eliminate waste from a conference room. Either you saw it, or you mapped it. No third option.
These rules live in 40 lines of TypeScript. They replace what, in most Lean organisations, is a decade of cultural enforcement. Not because 40 lines are better than culture — they are not — but because 40 lines compose with culture. The validator catches the armchair A3 at commit time, before it reaches the board. The board, freed from rejecting shape errors, can spend its attention on substance.
StyleTemplates — five scaffolds
Templates are the opinionated seeds. Each one pre-fills the requirement kind, statement pattern, priority, rationale kind, default fit-criterion kind, and verification method, so the author only supplies content:
a3-problem— Frame a problem in the A3 shape. Starting point of any PDCA cycle.kaizen-experiment— A time-boxed hypothesis with a leading metric. Build-measure-learn on the shop floor.standard-work-definition— Codify the current best-known way to do the work.waste-elimination— Eliminate an observed waste (TIMWOODS). Requires Gemba walk or VSM as source — the validator will enforce it.customer-value-increment— A small increment pulled by an articulated customer need.
Invoked via npx requirements new --style lean --template kaizen-experiment, each template drops the user into a wizard with the right slots pre-wired. The mechanism is identical across Styles; what varies is the set of templates — IndustrialStyle ships its own (e.g., sil3-safety-function, functional-safety-assessment), AgileStyle ships user-story shapes, KanbanStyle ships class-of-service scaffolds. Chapter 13 takes the wizard apart end-to-end; the templates are its seed data.
RequirementReporter — A3 Markdown
The reporter takes a typed requirement and emits human-readable prose. For LeanStyle, the headline output is an A3 one-pager:
renderMarkdown(spec: unknown): string {
// ...
lines.push(`# A3 — ${s.id}: ${s.title}`);
lines.push('');
lines.push('## Context');
lines.push('');
lines.push('| Field | Value |');
lines.push('|---|---|');
lines.push(`| Kind | ${s.requirementKind} |`);
lines.push(`| Status (PDCA) | ${s.status} |`);
lines.push(`| Impact × Effort | ${risk?.level ?? '—'} |`);
lines.push(`| Source | ${source?.type ?? '—'} (${...}) |`);
lines.push(`| Verification | ${s.verificationMethod} |`);
lines.push('');
lines.push('## Problem statement');
lines.push('');
lines.push(`> ${this.renderStatement(s.statement)}`);
lines.push('');
lines.push('## Fit criteria');
// ...
}, renderMarkdown(spec: unknown): string {
// ...
lines.push(`# A3 — ${s.id}: ${s.title}`);
lines.push('');
lines.push('## Context');
lines.push('');
lines.push('| Field | Value |');
lines.push('|---|---|');
lines.push(`| Kind | ${s.requirementKind} |`);
lines.push(`| Status (PDCA) | ${s.status} |`);
lines.push(`| Impact × Effort | ${risk?.level ?? '—'} |`);
lines.push(`| Source | ${source?.type ?? '—'} (${...}) |`);
lines.push(`| Verification | ${s.verificationMethod} |`);
lines.push('');
lines.push('## Problem statement');
lines.push('');
lines.push(`> ${this.renderStatement(s.statement)}`);
lines.push('');
lines.push('## Fit criteria');
// ...
},One page. Printable. Version-controlled. Traceable. This is what an A3 becomes when you type it — the same artefact a Kaizen team has pinned to the wall for forty years, but emitted from a typed spec that can be compliance-checked, refined, and referenced from Features via @Satisfies. The artefact did not change shape. What changed is that it now has a machine-readable source.
A worked Lean Requirement
The running example of this series is FEATURE-TRACE-EXPLORER-TUI. It is a good Feature but a poor Lean specimen — an interactive TUI browser over a traceability graph is not natively a value-stream object. For the Lean walk, the running example needs a process whose wait-time matters. The site's own build pipeline is the obvious candidate.
Here is a Lean requirement against the build pipeline. Call it REQ-BUILD-WAIT: the observation that npm run build has grown from 2 min to 8.2 min over six months, driven almost entirely by serial steps that could be parallelised. In Default style this would read as "the build shall complete in under X minutes", a promise. In Lean style it reads as a measured gap — let us write it out as a subclass of Requirement<LeanStyleType>:
import {
Requirement,
Priority,
LeanStyle,
type LeanStyleType,
type Rationale,
type RequirementSource,
type RiskStatement,
type VerificationMethod,
type HistoryEntry,
} from '@frenchexdev/requirements';
export abstract class MyBuildWaitRequirement extends Requirement<LeanStyleType> {
readonly id = 'REQ-BUILD-WAIT';
readonly title = 'npm run build exceeds developer-flow window';
readonly priority = Priority.High;
readonly status = 'CurrentStateMapped' as const;
readonly kind = 'Waste-Elimination' as const;
readonly statement = {
pattern: 'problem-statement' as const,
problem: 'npm run build has crept from 2 min to 8.2 min; developers context-switch mid-build, losing flow.',
currentState: '8.2 min median over 40 builds (Apr 01–14, 2026, all contributors, warm cache)',
targetState: '2.0 min median (recovers the Nov-2025 baseline; below the 3-min context-switch threshold)',
gap: '6.2 min — dominated by waiting (serial mermaid regen, serial tsc, serial vitest)',
};
readonly rationale: Rationale = {
claim: 'The 8.2-min build violates the implicit takt of the developer workflow. ' +
'The 3-min threshold is where context-switch becomes automatic (Graziotin et al., 2015, replicated internally).',
kind: 'flow-impediment',
evidence: [
{ kind: 'metric',
name: 'build-median-duration',
value: '8.2',
unit: 'min',
source: 'build-log.ndjson, 40 builds, Apr 01–14 2026' },
{ kind: 'metric',
name: 'context-switch-rate',
value: '68',
unit: '%',
source: 'developer survey, Apr 12 2026, n=7 of 7' },
],
};
readonly source: RequirementSource = {
type: 'vsm',
streamName: 'build-pipeline',
mappedAt: '2026-04-14',
wasteCategory: 'waiting',
};
readonly verificationMethod: VerificationMethod = 'VSM';
readonly risk: RiskStatement = { level: 'HighImpactLowEffort' };
readonly fitCriteria = [
{ kind: 'metric-threshold',
id: 'build-median-under-2min',
metric: 'build-median-duration',
operator: 'lte',
threshold: 2.0,
unit: 'min',
description: 'Median build duration, over a rolling 20-build window, shall be at most 2.0 min.' },
{ kind: 'metric-threshold',
id: 'build-p95-under-3min',
metric: 'build-p95-duration',
operator: 'lte',
threshold: 3.0,
unit: 'min',
description: 'p95 build duration, over a rolling 20-build window, shall be at most 3.0 min.' },
] as const;
readonly history: HistoryEntry[] = [
{ at: '2026-04-14', author: 'Stéphane E.', change: 'created',
note: 'Filed after VSM walk of build-pipeline value stream.' },
];
}import {
Requirement,
Priority,
LeanStyle,
type LeanStyleType,
type Rationale,
type RequirementSource,
type RiskStatement,
type VerificationMethod,
type HistoryEntry,
} from '@frenchexdev/requirements';
export abstract class MyBuildWaitRequirement extends Requirement<LeanStyleType> {
readonly id = 'REQ-BUILD-WAIT';
readonly title = 'npm run build exceeds developer-flow window';
readonly priority = Priority.High;
readonly status = 'CurrentStateMapped' as const;
readonly kind = 'Waste-Elimination' as const;
readonly statement = {
pattern: 'problem-statement' as const,
problem: 'npm run build has crept from 2 min to 8.2 min; developers context-switch mid-build, losing flow.',
currentState: '8.2 min median over 40 builds (Apr 01–14, 2026, all contributors, warm cache)',
targetState: '2.0 min median (recovers the Nov-2025 baseline; below the 3-min context-switch threshold)',
gap: '6.2 min — dominated by waiting (serial mermaid regen, serial tsc, serial vitest)',
};
readonly rationale: Rationale = {
claim: 'The 8.2-min build violates the implicit takt of the developer workflow. ' +
'The 3-min threshold is where context-switch becomes automatic (Graziotin et al., 2015, replicated internally).',
kind: 'flow-impediment',
evidence: [
{ kind: 'metric',
name: 'build-median-duration',
value: '8.2',
unit: 'min',
source: 'build-log.ndjson, 40 builds, Apr 01–14 2026' },
{ kind: 'metric',
name: 'context-switch-rate',
value: '68',
unit: '%',
source: 'developer survey, Apr 12 2026, n=7 of 7' },
],
};
readonly source: RequirementSource = {
type: 'vsm',
streamName: 'build-pipeline',
mappedAt: '2026-04-14',
wasteCategory: 'waiting',
};
readonly verificationMethod: VerificationMethod = 'VSM';
readonly risk: RiskStatement = { level: 'HighImpactLowEffort' };
readonly fitCriteria = [
{ kind: 'metric-threshold',
id: 'build-median-under-2min',
metric: 'build-median-duration',
operator: 'lte',
threshold: 2.0,
unit: 'min',
description: 'Median build duration, over a rolling 20-build window, shall be at most 2.0 min.' },
{ kind: 'metric-threshold',
id: 'build-p95-under-3min',
metric: 'build-p95-duration',
operator: 'lte',
threshold: 3.0,
unit: 'min',
description: 'p95 build duration, over a rolling 20-build window, shall be at most 3.0 min.' },
] as const;
readonly history: HistoryEntry[] = [
{ at: '2026-04-14', author: 'Stéphane E.', change: 'created',
note: 'Filed after VSM walk of build-pipeline value stream.' },
];
}Walk through it against the four Style rules:
- Rule 3 — problem-statement requires a non-empty
gap. Thegapslot reads'6.2 min — dominated by waiting (…)'. Non-empty, measured, attributed. The validator accepts. - Rule 4 — Waste-Elimination requires
gemba-walkorvsmsource. Thesource.typeis'vsm'with the three required slots (streamName, mappedAt, wasteCategory). Validator accepts. - Rules 1 and 2 do not apply — this is not a
Kaizen-Experiment(no hypothesis yet) nor aStandardization(no standard yet).
The TIMWOODS classification is in the source.wasteCategory slot: 'waiting'. Not inventory, not motion, not defects — a judgement made by the author while mapping the stream. The validator does not verify the category is correct — that is not a type-level property — but it does enforce that a category be chosen from the eight-valued TIMWOODS enum. You cannot file this requirement with wasteCategory: 'grumpy developers'.
The two metric-threshold fit criteria embed the actual-measurement discipline at the fit-criterion layer. The requirement-level gap states the delta in prose; the fit-criteria state the numeric thresholds the team will use to decide whether a future countermeasure has closed the gap. The two layers answer different questions: what is the current→target story? (statement) vs how will we measure the landing? (fit criteria).
The next move, if this requirement graduates from CurrentStateMapped to TargetStateDefined, is to file a sibling Kaizen-Experiment requirement with a kaizen-hypothesis pattern — "if we parallelise mermaid regen with tsc, then build drops to 4.0 min, because ..." — and watch it cycle through Experimenting → Validated → Standardized. That second requirement @Refines(MyBuildWaitRequirement) the first, and the compliance scanner links them in the traceability graph.
The key observation for the Style argument: the same facts (build time, context-switch rate, serial-step bottleneck) that a Default register would compress into a single NonFunctional requirement with an ISO 25010: Performance Efficiency: Time Behaviour classification unfold in the Lean register into a waste observation plus a countermeasure hypothesis plus a standard-work definition, three linked requirements following the PDCA state machine. Same facts, different granularity of record, different audience, different verification obligations.
The eight wastes, in Lean vocabulary
TIMWOODS is not a mnemonic in the Lean register; it is a type. The acronym expands to:
- T — Transport. Moving material unnecessarily between steps.
- I — Inventory. Stock that sits waiting, tying up capital and space.
- M — Motion. Movement of people or equipment within a step (reaching, walking, searching).
- W — Waiting. The step is idle, blocked, or starved.
- O — Overproduction. Producing before the customer pulls.
- O — Over-processing. Doing more work than the customer values (extra polish, extra features, extra documents).
- D — Defects. Work that must be reworked or scrapped.
- S — Skills (unused talent). The Poppendieck extension. People's capabilities left on the table.
The Poppendiecks mapped these to software in 2003: partially-done work → Inventory, extra features → Overproduction, relearning → Motion, handoffs → Transport, task switching → Motion, delays → Waiting, defects → Defects. The mapping is sharp. In LeanStyle, the mapping becomes typed enumeration values on the vsm.wasteCategory slot.
The Style file's source declares the TIMWOODS hint explicitly:
{ kind: 'vsm', label: 'Value-stream map', slots: [
{ name: 'streamName', type: 'string', required: true },
{ name: 'mappedAt', type: 'iso-date', required: true },
{ name: 'wasteCategory', type: 'string', required: true,
hint: 'transport | inventory | motion | waiting | overproduction | over-processing | defects | unused-talent' },
]},{ kind: 'vsm', label: 'Value-stream map', slots: [
{ name: 'streamName', type: 'string', required: true },
{ name: 'mappedAt', type: 'iso-date', required: true },
{ name: 'wasteCategory', type: 'string', required: true,
hint: 'transport | inventory | motion | waiting | overproduction | over-processing | defects | unused-talent' },
]},At the wire level, this is a string slot with a union hint. At the TypeScript level, the project can narrow it into a discriminated-union variant if it wants stricter checking — a typical project adds a local type alias:
type WasteCategory =
| 'transport'
| 'inventory'
| 'motion'
| 'waiting'
| 'overproduction'
| 'over-processing'
| 'defects'
| 'unused-talent';
type VsmSource = {
type: 'vsm';
streamName: string;
mappedAt: string; // iso-date
wasteCategory: WasteCategory;
};type WasteCategory =
| 'transport'
| 'inventory'
| 'motion'
| 'waiting'
| 'overproduction'
| 'over-processing'
| 'defects'
| 'unused-talent';
type VsmSource = {
type: 'vsm';
streamName: string;
mappedAt: string; // iso-date
wasteCategory: WasteCategory;
};Now filing a Waste-Elimination requirement with wasteCategory: 'latency' is a TypeScript error at compile time, not a validation warning at commit time. The Style ships the flat string+hint; projects that want compile-time narrowing add the discriminated-union variant in their own src/requirements/types/waste-category.ts. Both layers exist because both audiences exist: some teams want the Style as a wire contract only, some teams want to carry the narrowing all the way down to the TypeScript compiler.
The validator's role remains the same either way: if a Waste-Elimination requirement skips the wasteCategory slot entirely, the validator rejects it. The source.wasteCategory is not optional on a VSM-sourced waste claim. If the author does not know which category, they do not have a waste claim — they have an unfiled observation that needs a second Gemba walk.
The eight categories are not equally frequent in software. In manufacturing, Transport and Inventory dominate. In knowledge work, Waiting (queue depth, review-cycle delay) and Over-processing (speculative features, extra abstraction layers) dominate. In software operations, Defects (production incidents) and Unused-Talent (junior engineers stuck in test-fixture plumbing) are the common picks. The Style does not care about frequency; it cares that every claim is categorised.
A practical consequence: the compliance report's --by-waste breakdown (a future chapter 24 subject) groups requirements by TIMWOODS category. A team looking at their backlog can, in one command, see "we have 14 open Waste-Elimination requirements, 9 are Waiting, 3 are Over-processing, 2 are Defects" — and that distribution is a type-enforced aggregation over a typed field, not a tag-guessing exercise over free-text labels. The type discipline pays off at the aggregate-reporting layer, not only the individual-requirement layer.
Flow metrics as first-class fields
Lean thinking has a standard set of flow metrics that appear over and over in the prose and rarely in the type systems that claim to model Lean work. LeanStyle's answer is to make them first-class — not via a dedicated FlowMetric type on the Style root, but via the fit-criterion layer, where the metric-threshold variant carries the unit as a typed field.
The canonical Lean flow metrics:
- Lead time. Customer-pull-to-delivery. The end-to-end duration from the moment the customer pulls to the moment the customer receives. In software: ticket-opened to ticket-delivered.
- Cycle time. Step duration. The time a single unit spends being actively worked on, from the moment work begins to the moment the unit leaves the step. In software: ticket-started to ticket-merged.
- Takt time. The pace the customer demands. Time-available-per-period divided by customer-units-demanded-per-period. In software, rarely meaningful per-ticket, but increasingly meaningful at the release-train cadence.
- Throughput. Units-per-period. Inverse of takt, roughly, when the system is balanced. In software: stories-per-sprint or deploys-per-week.
- Work-in-progress (WIP). Units currently inside the value stream, not yet delivered. The quantity Little's Law links to lead time:
LeadTime = WIP / Throughput.
A LeanStyle requirement whose fit-criterion is "lead time from REQ-draft to REQ-approved must not exceed 5 working days" looks like:
readonly fitCriteria = [
{ kind: 'metric-threshold',
id: 'req-lead-time-p80',
metric: 'req-approval-lead-time',
operator: 'lte',
threshold: 5,
unit: 'working-days',
description: 'p80 lead time from REQ-draft to REQ-approved shall be at most 5 working days.',
aggregation: { window: 'rolling', size: 20, percentile: 80 },
},
] as const;readonly fitCriteria = [
{ kind: 'metric-threshold',
id: 'req-lead-time-p80',
metric: 'req-approval-lead-time',
operator: 'lte',
threshold: 5,
unit: 'working-days',
description: 'p80 lead time from REQ-draft to REQ-approved shall be at most 5 working days.',
aggregation: { window: 'rolling', size: 20, percentile: 80 },
},
] as const;The unit: 'working-days' is a typed string. A sibling cycle-time criterion with unit: 'seconds' and a threshold of 180 for "CI step X must complete in under 3 minutes" is unit-incompatible — the compliance layer will refuse to aggregate them into the same summary row, because the units do not match. This is not a hypothetical protection; in practice teams routinely mix minutes and seconds in flow dashboards and end up comparing apples to apples-but-in-a-different-unit, with silently wrong conclusions.
The Style ships an adapter port — FitCriterionAdapter — so that projects can plug in Datadog, Grafana, or Prometheus as the live source of truth for these metrics. The metric-threshold fit criterion is a specification of what the threshold is and in what unit; the adapter is a plug-in that fetches the current reading from the live telemetry. A compliance run against the Datadog adapter reads req-approval-lead-time from Datadog, compares it to the threshold, and emits a pass/fail line.
Takt time is the most Lean-specific of the five, and worth a special note. In a software team, takt is rarely the customer-pull rate — it is more usefully the rhythm of the team's own process. A sprint length defines a takt of "1 sprint per 2 weeks". A CI pipeline defines a takt of "1 build per push". The Style does not prescribe a definition; the standard-work statement pattern has a taktTime slot whose content is free-text (see the worked example in lean.md's Line 3 changeover case), letting the author name the takt their team uses.
The practical protection the Style offers, via typed units and the adapter port, is not automatic Lean'ness. It is no-more-silent-unit-mismatches and no-more-dashboards-versus-requirements drift. Those two failure modes are where the bulk of Lean-tooling-that-is-not-quite-Lean crashes into reality. The type system picks them off at the requirement-spec layer.
The Kaizen loop vs the dog-food loop
Zoom out from the Style file for a moment and compare two loops at the structural level.
The Kaizen loop, as the Style encodes it:
- Observe the value stream (Gemba walk or VSM).
- Measure the current state (metric with unit).
- Name a target (metric with same unit, better value).
- Propose a countermeasure (Kaizen-hypothesis).
- Run the experiment (Experimenting state, time-boxed validation window).
- Measure again.
- If the gap closed — standardise (Validated → Standardized).
- If the gap did not close — revisit countermeasure or target (rework edges).
- Observe the value stream again (loop back to 1 — the standard you just set will eventually be superseded).
This is PDCA expanded into the language of Requirements. Each step is a typed operation on a Lean Requirement spec.
The dog-food loop, as the package enacts it on itself (subject of chapter 02 and chapter 18):
- Define the DSL (Requirement, Feature, AC, Test + decorators + styles).
- Declare a Requirement about how the package validates itself (
REQ-DOG-FOOD— "zero describe/it"). - Write Features that produce the package's functionality.
- Declare each Feature
@Satisfies(REQ-DOG-FOOD)among its other loyalties. - Write tests for those Features using
@FeatureTest/@Verifies(notdescribe/it). - Run the compliance scanner — which is itself a Feature built on the same decorators — to check that (5) actually happened.
- If coverage gaps show up, scaffold new tests (via
scaffoldCLI, itself built on the same decorators). - Loop back to 3 when the DSL evolves; loop back to 1 when the entire model needs a new stratum (which is why this series exists — the
typed-specspackage did not have Requirements, and adding them was a stratum-level change).
The two loops share a shape. Both are observation cycles that refine the artefact they are observing. Kaizen observes a value stream and refines the process; dog-food observes the package's own tests and refines the DSL. Both use the same two-phase rhythm — observe then act — and both tolerate backward edges (Kaizen can invalidate the target; dog-food can invalidate the decorator surface).
The critical structural difference: Kaizen's subject is an external value stream; dog-food's subject is the DSL itself. LeanStyle does not enact the dog-food loop. LeanStyle is what users of the package declare when their domain (manufacturing, healthcare operations, SaaS operations, service queues) is Lean-native. The dog-food loop is how we — the maintainers of @frenchexdev/requirements — develop the package. The two are parallel, not nested.
Put differently: Lean thinking informs the development of the package (we apply Kaizen to our own dev process — the build-wait requirement above is a concrete example). Lean Style informs what the package's users declare when their domain is Lean-native. One loop operates on the package's own codebase; the other loop operates on the user's value stream. They happen to share a pattern because both are Deming/Ohno's PDCA, applied to different subjects.
Drawing both in the same diagram makes the parallel visible.
Diagram 1 — a lean value stream
Read the map horizontally: cycle-time in the blue boxes, wait-time in the orange ones. Sum: 3 + 145 + 112 + 58 + 14 + 98 + 62 = 492 seconds = 8.2 minutes, matching the measurement in REQ-BUILD-WAIT. Of those 492 seconds, 126 are wait-time (the orange sum), and of those 126 seconds, 112 are a single Waiting block — the mermaid-regen-then-tsc serial barrier.
Lean reading: attack the 112-second wait first. That is the just-do-it quadrant of the Impact×Effort matrix. Convert the serial edge to parallel, and the diagram redraws with a par fork from mermaid-regen and tsc, wait-time collapsing to the longest of the two branches — roughly 145s on the mermaid side, tsc running in parallel inside that envelope. Build time drops from 492s to approximately 380s in one refactor. File the Kaizen-Experiment requirement that predicts this, run it for two weeks, measure the landing, standardise.
The map does not say how to parallelise — that is a Feature, a deliverable, a satisfier of a downstream Kaizen-Experiment requirement. The map says where the waste is, typed by TIMWOODS category, sized in the same unit as the requirement's fit-criteria. Those are the two things a VSM owes to the requirements layer above it.
Diagram 2 — lean flow / PDCA
Left diagram: the Plan-Do-Check-Act rhythm, with the two rework edges that Lean honesty demands (experiment can fail; target can be wrong). Right diagram: the package's meta-circle at the test-tooling layer, with its analogous rework edges (coverage gap loops back to Features; stratum-level gap loops all the way back to the DSL definition — which is how this very series came to exist, when the stratum-level gap named in Chapter 00 forced a new stratum to be added).
Both loops are observation-then-act. Both loops admit that learning can push you back further than you went forward. The difference is in the subject — Kaizen observes a value stream, dog-food observes a DSL — not in the shape.
Users of LeanStyle run the left loop on their domain. Maintainers of @frenchexdev/requirements run the right loop on the package. A user who happens to be a Lean-shop and a package maintainer runs both at once, on different artefacts, with no collision between them.
Where the Lean register earns its weight
Not every domain benefits from the LeanStyle overhead. The four-rule validator, the eight-state PDCA workflow, the TIMWOODS taxonomy, the mandatory genchi genbutsu on waste claims — these are shape constraints, and shape constraints are useful when they match the domain's existing discipline and costly when they do not.
LeanStyle earns its weight in three conditions:
1. The domain is continuous-improvement-native. Manufacturing lines, hospital operations, distribution centres, customer-service queues, SaaS ops rooms. The team already speaks the vocabulary; the Style removes the Excel-vs-Word-vs-Visio-vs-Miro fragmentation that currently scatters their A3s across four tools. Typing the artefacts is a win because the artefacts are already structured; the Style makes their structure machine-readable.
2. Measurement already exists at flow granularity. The team tracks cycle-time and wait-time per step. They have a dashboard — Datadog, Grafana, MES, call-centre-ACD — that emits the metrics LeanStyle's fit-criteria reference. In this case the Style's metric-threshold fit criterion plugs directly into their telemetry through the FitCriterionAdapter port, and the compliance run reads the live metrics without human intervention. If the team does not have this telemetry, the Style's metric-threshold criteria become aspirational strings, and the loop cannot close.
3. The team has internalised A3 discipline. Somebody on the team has actually written A3s. Somebody has facilitated a Kaizen. Somebody has done a Gemba walk. The Style's templates and wizard prompts ("source.type — gemba walk, customer feedback, process measurement, VSM, kaizen event, hoshin plan, kata coaching") assume the user recognises those terms. A team that does not already know what a Gemba walk is will experience the wizard as bureaucratic friction. A team that does will experience it as typed structure for their existing work.
Three conditions where LeanStyle does not earn its weight:
1. A one-off software project with no recurring operational rhythm. If the team ships and walks away, there is no value stream to observe repeatedly; there is a feature list. DefaultStyle (29148 + EARS) or AgileStyle (INVEST + BDD) is the right match. Filing an A3 for a one-shot ticket is ceremony without payoff.
2. A safety-critical domain where the regulatory register is the primary constraint. IEC 61508, 21 CFR Part 11, GAMP 5 demand their own lifecycle, their own verification obligations, their own bookkeeping. IndustrialStyle (chapter 09) exists precisely for this. Lean vocabulary can coexist — a nuclear plant does Kaizen too — but as a secondary register, not primary.
3. A product team that has not articulated its value stream. If the team cannot answer "what does the customer pull and how fast?", the Style's five principles (value, value stream, flow, pull, perfection) are upstream of the team's present state. They need to do the value-stream mapping first, then consider whether to encode the map in LeanStyle. The Style does not do the thinking for the team.
A pragmatic test: if the team already has a Kaizen log somewhere — even a messy Excel one — LeanStyle can absorb and improve it. If the team does not have one and would not start one, LeanStyle is asking them to adopt a discipline they are not ready for, at the cost of rejecting the typed register precisely when it would have been most useful later.
The pluralism axis of the Styles system (see chapter 08) handles this gracefully — a project can run DefaultStyle for most requirements and LeanStyle for the subset where the value-stream lens actually applies (typically: ops runbooks, build-pipeline performance, on-call workflow). The Styles compose at the project level; no project is locked into one register.
Running-example recap
The running example of this series — FEATURE-TRACE-EXPLORER-TUI — is a delivery, not a process. It does not have a cycle-time or a wait-time; it is a Feature that, when implemented, satisfies three Requirements. As a direct LeanStyle specimen it is a poor fit.
But we can still see it under a Lean gaze.
Imagine a REQ-TRACE-EXPLORATION-LATENCY, a LeanStyle requirement observing that "support engineers spend on average 14 minutes answering 'why does this test verify this requirement?' because the only way to traverse the graph is by opening four files in sequence". That is a Waste-Elimination requirement. Its source is a gemba-walk — five hours shadowing the support engineer on-call on a Wednesday. Its waste category is waiting (engineer waits on file-open and mental-stack-swap) plus motion (alt-tabbing between four editor tabs). Its current-state metric: 14 minutes median per graph-traversal question. Its target-state metric: 90 seconds (a developer's flow window). Its gap: 12.5 minutes, dominated by motion and waiting.
What delivery satisfies this Lean requirement? FEATURE-TRACE-EXPLORER-TUI — the interactive TUI that lets a user navigate the graph with arrow keys. One Feature, one satisfier.
Now the Feature is a deliverable under a measured gap. The TUI earns its place in the package not because "a TUI is a nice-to-have" but because a LeanStyle requirement observes that its absence costs 12.5 minutes of support-engineer time per question. The Feature is typed as a satisfier; the requirement is typed as a gap; the two are linked by @Satisfies(ReqTraceExplorationLatencyRequirement, ...).
This is what it means for the Lean register to compose with the Feature stratum. The register lives at the requirement layer; the Feature layer is register-agnostic. The TUI does not change whether it satisfies a Default-style requirement, a Lean-style requirement, or both at once — which is the scenario in practice, because it satisfies REQ-DISCOVERABLE-TRACEABILITY (Default) and a hypothetical REQ-TRACE-EXPLORATION-LATENCY (Lean). One deliverable, two registers above it, rendered differently, compliance-checked against different rule sets, both agreeing that the Feature's presence closes their respective gaps.
Related Reading
- Chapter 08 — Styles: A Plural Rhetoric — the Style registry and the five-register pluralism that LeanStyle is one instance of.
- Chapter 09 — Style Deep-Dive: Industrial / SIL — the opposite register to Lean, deep-dived with the same structure.
- Chapter 11 — Style Deep-Dive: EARS / Agile / Kanban — the three remaining registers, shown in shorter form to emphasise the Style system over any single register.
- a-style-is-a-tiny-compiler.md — the argument that a Style is a tiny compiler in its own right; LeanStyle is the most Lean-domain-specific instance.
- ops-dsl-ecosystem/ — the broader ecosystem of operations-DSLs where Lean vocabulary appears alongside on-call, incident-response, and runbook registers.
Previous: Chapter 09 — Style Deep-Dive: Industrial / SIL Next: Chapter 11 — Style Deep-Dive: EARS / Agile / Kanban