Status: Contract (Stable)
Scope: Defines system capabilities, boundaries, and hard rules for problem generation
Philosophy: Anti-overengineering — extract patterns from working solutions
This document is a Contract: it defines rules that MUST be followed. Changes require review.
For the living registry of per-problem configurations, see config/problem-support.yaml.
- Hard Rules
- Core Principles
- Tier Classification
- Codec Mode Policy
- Canonical Semantics
- I/O Format Registry
- Representative Examples
- FAQ
These rules MUST NOT be violated.
IF solutions/{id}_{slug}.py EXISTS AND is_handwritten:
codegen MUST NOT overwrite without explicit --force flag
codegen MUST warn user before any modification
Rationale: Protect human effort. Auto-generation should never destroy manual work.
IF codec_mode == "inline":
inline_reason MUST be non-empty string
Rationale: Force documentation of why inline is needed. Prevents accidental inline.
IF tier == "1.5":
generators.random DEFAULT false
generators.complexity DEFAULT false
Rationale: Tier-1.5 problems have complex semantics; random generation is risky.
All codec implementations MUST follow canonical semantics. No exceptions.
Judge MUST NOT contain problem-specific logic.
| ✅ Judge Responsibilities | ❌ Judge MUST NOT |
|---|---|
| Exact string comparison | Know about ListNode/TreeNode |
| Float tolerance (configurable) | Have if problem_id == X branches |
| Order-independent comparison (flagged) | Implement problem-specific comparison |
The solve() function adapts between:
- Simple
.in/.out— Human-friendly, Example-derivable - LeetCode structures — ListNode, TreeNode, cycles, shared nodes
.in/.out (simple) ──→ solve() ──→ Solution.method()
↓
codec utilities
A solution file contains everything needed for practice generation:
| Component | Purpose | Practice Generation |
|---|---|---|
solve() |
I/O translation | ✅ Keep as-is |
JUDGE_FUNC |
Comparison semantics | ✅ Keep as-is |
ListNode etc. |
Data structures | ✅ Keep as-is |
Solution.method() |
Algorithm | ❌ Clear body → TODO |
Practice generation is mechanical: copy + clear method body.
Extract patterns from working solutions. Don't design universal systems upfront.
Evolution path:
- Write working
solve()for complex problems - Identify common patterns
- Extract into codec utilities
- Update tier classification
Tier = Overall support level (not just generation)
| Tier | Definition | Scaffold | Practice | Generator |
|---|---|---|---|---|
| "0" | Signature → I/O derivable | ✅ auto | ✅ | ✅ |
| "1" | Needs codec, value-based I/O | ✅ auto | ✅ | ✅ |
| "1.5" | I/O semantics need problem knowledge | ✅ scaffold | ✅ | |
| "2" | Complex structures (future) | ❌ | ❌ | ❌ |
- Tier "0"/"1"/"1.5": ALL can practice (scaffold always generated)
- Tier classification: About GENERATION capability, not practice capability
- Solution file is scaffold: Does not mean "already solved"
- Practice does not depend on existing solutions
Use string format for tier values:
tier: "1.5" # Correct
tier: 1.5 # Avoid (YAML float parsing issues)| Mode | Description | Use Case |
|---|---|---|
import |
Import from runner/utils/codec/ |
Standard codec, DRY |
inline |
Inline template into solution | Custom adapter, LeetCode-copyable |
defaults:
codec_mode: importcodec_mode: inline is REQUIRED when:
| # | Condition | Example |
|---|---|---|
| 1 | Custom adapter needed (semantic translation) | 0142: node_to_index |
| 2 | Custom JUDGE_FUNC needed | 0138: deep copy verification |
| 3 | LeetCode copy-paste required | User request |
"0142":
tier: "1.5"
codec_mode: inline # Explicit (not inherited)
inline_reason: "Output is node identity, needs node_to_index adapter"
codec_hints: [build_list_with_cycle, node_to_index]When codec_mode: import:
from runner.utils.codec import list_to_linkedlist, linkedlist_to_listThese semantics are non-negotiable. All implementations MUST follow.
| Item | Canonical Value |
|---|---|
node_to_index |
0-based |
pos (cycle position) |
0-based |
| Array indices | 0-based |
| Situation | Canonical Value | Type |
|---|---|---|
| No cycle found | -1 |
int |
| No intersection | -1 |
int |
| Null node | -1 or null (context-dependent) |
int or null |
| Value | Canonical Format |
|---|---|
| True | true (JSON lowercase) |
| False | false (JSON lowercase) |
Config uses io_format keys to reference these definitions.
| io_format | Input | Output |
|---|---|---|
list_to_list |
[values] |
[values] |
two_lists_to_list |
[list1] [list2] |
[values] |
list_of_lists_to_list |
[[l1],[l2],...] |
[values] |
list_int_to_list |
[values] int |
[values] |
list_with_pos_to_bool |
[values] pos |
true/false |
| io_format | Input | Output | Semantic |
|---|---|---|---|
list_with_pos_to_node_index |
[values] pos |
index or -1 |
Node identity |
two_lists_with_skips_to_node_value |
[listA] [listB] skipA skipB |
value or -1 |
Shared node |
random_pointer_list |
[[val,rand],...] |
[[val,rand],...] |
Deep copy |
These examples illustrate how the rules apply. For the complete registry, see config/problem-support.yaml.
| Aspect | Detail |
|---|---|
| Tier | "1.5" |
| codec_mode | inline |
| inline_reason | Output is node identity (cycle entry), needs node_to_index |
| io_format | list_with_pos_to_node_index |
.in/.out:
[3,2,0,-4]
1
# .out
1
| Aspect | Detail |
|---|---|
| Tier | "1.5" |
| codec_mode | inline |
| inline_reason | Multi-pointer structure + deep copy verification |
| io_format | random_pointer_list |
.in/.out:
[[7,null],[13,0],[11,4],[10,2],[1,0]]
# .out
[[7,null],[13,0],[11,4],[10,2],[1,0]]
A: Premature abstraction. We extract patterns from working solutions, not design upfront.
A: Yes. Tier defines what the system CAN auto-generate, not what you MUST use.
A: Ask: "Can the I/O format be derived from signature and values alone?"
- Yes → Tier-0 or Tier-1
- No (needs problem knowledge) → Tier-1.5
A: Config validation SHOULD warn. Tier-1.5 typically needs inline, and inline_reason is required.
| Document | Purpose |
|---|---|
config/problem-support.yaml |
Living registry of per-problem config |
| test-file-format.md | .in/.out format specification |
| solution-contract.md | solve() function requirements |
| Date | Change |
|---|---|
| 2026-01-03 | Initial version |
| 2026-01-03 | Refactored as Contract; added Hard Rules, Canonical Semantics |