Pattern Matching
How patterns from the pattern flywheel are matched and applied during codegen — what a pattern is, how candidates are scored, and how successful generations become reusable patterns.
Pattern Matching
The pattern flywheel is the mechanism by which Praetor's code generation improves over time. Every successful generation that produces something new becomes a pattern. Every subsequent generation that matches an existing pattern uses it as a seed — reducing the generation problem from "write this from scratch" to "adapt this known-good template for this specific context."
Over many projects, the pattern match rate rises and LLM call costs fall.
What a Pattern Is
A pattern is a structural template extracted from a verified generated output. It captures:
- The spec node type and metadata that triggered the generation (
artifact_type, relevant metadata fields) - The tech stack and conventions active during generation
- The structural signature of the generated code (exports, types, API surface — not the literal source text)
- The constraints under which it applies (field types, auth requirements, complexity indicators)
- A promotion state reflecting how much evidence has accumulated for this pattern
Patterns are stored as pattern_template nodes in the graph, linked to their source impl node via derived_from edges.
Pattern Promotion States
Patterns move through a lifecycle based on accumulated evidence:
| State | Meaning |
|---|---|
candidate | Newly extracted — used only in the project that created it |
validated | Used successfully in at least 3 projects without modification |
promoted | Actively recommended by the matching system across all tenants |
deprecated | Superseded by a higher-scoring pattern for the same node type |
Production generation runs use patterns at validated or higher. Development runs may use candidate patterns to gather evidence faster.
The Matching Pipeline
Before a Kit executes for a spec node, the pattern system runs a three-step matching pipeline:
Step 1: Database Filter
A SQL query filters the pattern table by:
node_type— must match the spec node'sartifact_typelayer— must match the spec node's graph layertenant_scope— either global or the current tenant's patternspromotion_state—validatedorpromotedfor production runs
This coarse filter produces a set of candidates from potentially thousands of stored patterns.
Step 2: Constraint Scoring
Each candidate pattern's constraints are evaluated against the node's metadata. Constraints are typed predicates:
| Constraint Type | Example |
|---|---|
exists | metadata.fields must exist |
equals | metadata.authRequired === true |
contains | metadata.features contains 'pagination' |
numeric_gte | metadata.fieldCount >= 5 |
numeric_lte | metadata.fieldCount <= 20 |
Each constraint produces a 0/1 score. The constraint satisfaction ratio is (passing constraints) / (total constraints).
Step 3: Composite Ranking
The final score for each candidate combines multiple signals:
compositeScore =
(constraintSatisfaction × 0.40)
+ (promotionStateWeight × 0.25)
+ (conventionMatchBonus × 0.20)
+ (historicalSuccessRate × 0.15)Promotion state weight assigns higher scores to more battle-tested patterns:
candidate: 0.25validated: 0.65promoted: 1.0
Convention match bonus boosts patterns that were generated under the same tech stack and naming conventions as the current project.
Historical success rate is the fraction of past uses of this pattern that passed CEGIS verification without requiring a retry. A pattern with a 95% first-attempt success rate scores higher than one that needed retries 40% of the time.
The top-scoring candidate above the confidence threshold (default: 0.70) becomes the patternSeed in KitInput.
How Kits Use Patterns
A Kit that receives a patternSeed uses it to constrain its generation:
- The pattern's structural signature guides the LLM toward a known-good code structure
- The pattern's constraint set tells the Kit which aspects of the spec are most important to preserve faithfully
- The pattern becomes the starting point for the PLAN phase, not a blank canvas
If the Kit significantly adapts the pattern — adding or removing exports, changing the structural shape — the adaptation is tracked. A large enough deviation triggers pattern extraction at the end of generation (see below).
If no pattern scores above the threshold, the Kit generates without a seed. These runs are more expensive (full LLM generation) but also the most likely to produce novel patterns.
Pattern Extraction
After a successful generation where:
- No
patternSeedwas used, or - The pattern was significantly adapted (structural delta above the extraction threshold)
...PatternExtractor analyzes the output and creates a new candidate pattern:
- Extract the structural signature from the generated code (exports, type shapes, API surface)
- Record the spec node type, metadata, and active constraints
- Record the tech stack and conventions
- Create a
pattern_templatenode linked to the source impl node viaderived_from - Set promotion state to
candidate
The pattern starts collecting evidence immediately. As other projects generate the same type of node and the pattern is surfaced as a candidate, each successful application increments its usage count. At 3 successful uses across 3 distinct projects, the pattern is auto-promoted to validated.
Pattern Analytics
The Flywheel Control Center (/api/flywheel) exposes metrics on pattern effectiveness:
- Match rate per run — what fraction of nodes had a pattern seed
- First-attempt success rate by pattern — patterns that consistently avoid retries
- Pattern promotion events — when patterns crossed promotion thresholds
- Coverage by node type — which node types have strong pattern coverage vs. which are still generating without seeds
These metrics answer the question: is the flywheel spinning? A healthy flywheel shows rising match rates and falling average CEGIS attempts over time.