invar-tools 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. invar/__init__.py +68 -0
  2. invar/contracts.py +152 -0
  3. invar/core/__init__.py +8 -0
  4. invar/core/contracts.py +375 -0
  5. invar/core/extraction.py +172 -0
  6. invar/core/formatter.py +281 -0
  7. invar/core/hypothesis_strategies.py +454 -0
  8. invar/core/inspect.py +154 -0
  9. invar/core/lambda_helpers.py +190 -0
  10. invar/core/models.py +289 -0
  11. invar/core/must_use.py +172 -0
  12. invar/core/parser.py +276 -0
  13. invar/core/property_gen.py +383 -0
  14. invar/core/purity.py +369 -0
  15. invar/core/purity_heuristics.py +184 -0
  16. invar/core/references.py +180 -0
  17. invar/core/rule_meta.py +203 -0
  18. invar/core/rules.py +435 -0
  19. invar/core/strategies.py +267 -0
  20. invar/core/suggestions.py +324 -0
  21. invar/core/tautology.py +137 -0
  22. invar/core/timeout_inference.py +114 -0
  23. invar/core/utils.py +364 -0
  24. invar/decorators.py +94 -0
  25. invar/invariant.py +57 -0
  26. invar/mcp/__init__.py +10 -0
  27. invar/mcp/__main__.py +13 -0
  28. invar/mcp/server.py +251 -0
  29. invar/py.typed +0 -0
  30. invar/resource.py +99 -0
  31. invar/shell/__init__.py +8 -0
  32. invar/shell/cli.py +358 -0
  33. invar/shell/config.py +248 -0
  34. invar/shell/fs.py +112 -0
  35. invar/shell/git.py +85 -0
  36. invar/shell/guard_helpers.py +324 -0
  37. invar/shell/guard_output.py +235 -0
  38. invar/shell/init_cmd.py +289 -0
  39. invar/shell/mcp_config.py +171 -0
  40. invar/shell/perception.py +125 -0
  41. invar/shell/property_tests.py +227 -0
  42. invar/shell/prove.py +460 -0
  43. invar/shell/prove_cache.py +133 -0
  44. invar/shell/prove_fallback.py +183 -0
  45. invar/shell/templates.py +443 -0
  46. invar/shell/test_cmd.py +117 -0
  47. invar/shell/testing.py +297 -0
  48. invar/shell/update_cmd.py +191 -0
  49. invar/templates/CLAUDE.md.template +58 -0
  50. invar/templates/INVAR.md +134 -0
  51. invar/templates/__init__.py +1 -0
  52. invar/templates/aider.conf.yml.template +29 -0
  53. invar/templates/context.md.template +51 -0
  54. invar/templates/cursorrules.template +28 -0
  55. invar/templates/examples/README.md +21 -0
  56. invar/templates/examples/contracts.py +111 -0
  57. invar/templates/examples/core_shell.py +121 -0
  58. invar/templates/pre-commit-config.yaml.template +44 -0
  59. invar/templates/proposal.md.template +93 -0
  60. invar_tools-1.0.0.dist-info/METADATA +321 -0
  61. invar_tools-1.0.0.dist-info/RECORD +64 -0
  62. invar_tools-1.0.0.dist-info/WHEEL +4 -0
  63. invar_tools-1.0.0.dist-info/entry_points.txt +2 -0
  64. invar_tools-1.0.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,134 @@
1
+ <!--
2
+ ┌─────────────────────────────────────────────────────────────┐
3
+ │ INVAR-MANAGED FILE - DO NOT EDIT DIRECTLY │
4
+ │ │
5
+ │ This file is managed by Invar. Changes may be lost on │
6
+ │ `invar update`. Add project content to CLAUDE.md instead. │
7
+ └─────────────────────────────────────────────────────────────┘
8
+ -->
9
+ # The Invar Protocol v3.26
10
+
11
+ > **"Trade structure for safety."**
12
+
13
+ ## Six Laws
14
+
15
+ | Law | Principle |
16
+ |-----|-----------|
17
+ | 1. Separation | Core (pure logic) / Shell (I/O) physically separate |
18
+ | 2. Contract Complete | @pre/@post + doctests uniquely determine implementation |
19
+ | 3. Context Economy | map → sig → code (only read what's needed) |
20
+ | 4. Decompose First | Break into sub-functions before implementing |
21
+ | 5. Verify Reflectively | Fail → Reflect (why?) → Fix → Verify |
22
+ | 6. Integrate Fully | Local correct ≠ Global correct; verify all paths |
23
+
24
+ ## Core/Shell Architecture
25
+
26
+ | Zone | Location | Requirements |
27
+ |------|----------|--------------|
28
+ | Core | `**/core/**` | @pre/@post, pure (no I/O), doctests |
29
+ | Shell | `**/shell/**` | `Result[T, E]` return type |
30
+
31
+ **Forbidden in Core:** `os`, `sys`, `subprocess`, `pathlib`, `open`, `requests`, `datetime.now`
32
+
33
+ ## Core Example (Pure Logic)
34
+
35
+ ```python
36
+ from deal import pre, post
37
+
38
+ @pre(lambda price, discount: price > 0 and 0 <= discount <= 1)
39
+ @post(lambda result: result >= 0)
40
+ def discounted_price(price: float, discount: float) -> float:
41
+ """
42
+ >>> discounted_price(100, 0.2)
43
+ 80.0
44
+ >>> discounted_price(100, 0) # Edge: no discount
45
+ 100.0
46
+ """
47
+ return price * (1 - discount)
48
+ ```
49
+
50
+ **Self-test:** Can someone else write the exact same function from just @pre/@post + doctests?
51
+
52
+ ## Shell Example (I/O Operations)
53
+
54
+ ```python
55
+ from pathlib import Path
56
+ from returns.result import Result, Success, Failure
57
+
58
+ def read_config(path: Path) -> Result[dict, str]:
59
+ """Shell: handles I/O, returns Result for error handling."""
60
+ try:
61
+ import json
62
+ return Success(json.loads(path.read_text()))
63
+ except FileNotFoundError:
64
+ return Failure(f"File not found: {path}")
65
+ except json.JSONDecodeError as e:
66
+ return Failure(f"Invalid JSON: {e}")
67
+ ```
68
+
69
+ **Pattern:** Shell reads file → passes content to Core → returns Result.
70
+
71
+ More examples: `.invar/examples/`
72
+
73
+ ## Session Start (Required)
74
+
75
+ Before writing any code, execute:
76
+
77
+ 1. **invar_guard** (changed=true) — Check existing violations
78
+ 2. **invar_map** (top=10) — Understand code structure
79
+
80
+ Then read:
81
+ - `.invar/examples/` — Core/Shell patterns
82
+ - `.invar/context.md` — Project state, lessons learned
83
+
84
+ **Skipping these steps → Non-compliant code → Rework required.**
85
+
86
+ Use MCP tools if available (`invar_guard`, `invar_map`), otherwise use CLI commands.
87
+ For agent-specific entry format, see your configuration file (CLAUDE.md, .cursorrules, etc).
88
+
89
+ ## ICIDIV Workflow (Required Order)
90
+
91
+ ```
92
+ 1. Intent — What? Core or Shell? Edge cases?
93
+ 2. Contract — @pre/@post + doctests BEFORE code
94
+ 3. Inspect — invar sig <file>, invar map --top 10
95
+ 4. Design — Decompose: leaves first, then compose
96
+ 5. Implement — Write code to pass your doctests
97
+ 6. Verify — invar guard. If fail: reflect → fix → verify
98
+ ```
99
+
100
+ **Contract before Implement. Verify after every change. No exceptions.**
101
+
102
+ ## Task Completion
103
+
104
+ A task is complete only when ALL conditions are met:
105
+ - Session Start executed (invar_guard + invar_map, context read)
106
+ - Intent explicitly stated
107
+ - Contract written before implementation
108
+ - Final **invar_guard** passed
109
+ - User requirement satisfied
110
+
111
+ **Missing any = Task incomplete.**
112
+
113
+ ## Commands
114
+
115
+ ```bash
116
+ invar guard # Full: static + doctests + CrossHair + Hypothesis (default)
117
+ invar guard --static # Static only (quick debug, ~0.5s)
118
+ invar guard --changed # Modified files only
119
+ invar sig <file> # Show contracts + signatures
120
+ invar map --top 10 # Most-referenced symbols
121
+ ```
122
+
123
+ ## Configuration
124
+
125
+ ```toml
126
+ [tool.invar.guard]
127
+ core_paths = ["src/myapp/core"]
128
+ shell_paths = ["src/myapp/shell"]
129
+ exclude_doctest_lines = true # Don't count doctests in function size
130
+ ```
131
+
132
+ ---
133
+
134
+ *Protocol v3.26 | [Guide](docs/INVAR-GUIDE.md) | [Examples](.invar/examples/)*
@@ -0,0 +1 @@
1
+ """Template files for invar init command."""
@@ -0,0 +1,29 @@
1
+ # Invar Protocol Configuration for Aider
2
+ # Follow the Invar Protocol in INVAR.md
3
+
4
+ # Auto-read protocol files at session start
5
+ read:
6
+ - INVAR.md
7
+ - .invar/examples/core_example.py
8
+ - .invar/examples/shell_example.py
9
+ - .invar/context.md
10
+
11
+ # System prompt addition
12
+ system-prompt: |
13
+ Follow the Invar Protocol in INVAR.md.
14
+
15
+ Before writing code, execute:
16
+ 1. invar_guard (changed=true) - or: invar guard --changed
17
+ 2. invar_map (top=10) - or: invar map --top 10
18
+
19
+ Use MCP tools if available, otherwise use CLI commands.
20
+
21
+ Workflow (ICIDIV):
22
+ - Intent: What? Core or Shell?
23
+ - Contract: @pre/@post + doctests BEFORE code
24
+ - Inspect: invar_sig (or: invar sig <file>)
25
+ - Design: Decompose first
26
+ - Implement: Pass your doctests
27
+ - Verify: invar_guard (or: invar guard)
28
+
29
+ Task complete only when final invar_guard passes.
@@ -0,0 +1,51 @@
1
+ # Project Context
2
+
3
+ *Last updated: [DATE]*
4
+
5
+ ## Current State
6
+
7
+ - Phase: [current development phase]
8
+ - Working on: [current task or feature]
9
+ - Blockers: None
10
+
11
+ ## Recent Decisions
12
+
13
+ 1. [Decision summary] - [Brief rationale]
14
+
15
+ ## Lessons Learned
16
+
17
+ 1. [Pitfall or issue] → [Solution or workaround]
18
+
19
+ ## Documentation Structure
20
+
21
+ | File | Owner | Edit? |
22
+ |------|-------|-------|
23
+ | INVAR.md | Invar | No — use `invar update` |
24
+ | CLAUDE.md | User | Yes |
25
+ | .invar/context.md | User | Yes (this file) |
26
+ | .invar/examples/ | Invar | No |
27
+
28
+ **Decision rule:** Is this Invar protocol or project-specific?
29
+ - Protocol content → Already in INVAR.md, don't duplicate
30
+ - Project-specific → Add to CLAUDE.md or here
31
+
32
+ ## Technical Debt
33
+
34
+ *Run `invar guard` to check current status.*
35
+
36
+ | File | Warning | Priority |
37
+ |------|---------|----------|
38
+ | (none) | — | — |
39
+
40
+ ## Key Files
41
+
42
+ | File | Purpose |
43
+ |------|---------|
44
+ | INVAR.md | Protocol reference (Invar-managed) |
45
+ | CLAUDE.md | Project guide (customize freely) |
46
+ | src/core/ | Pure business logic |
47
+ | src/shell/ | I/O adapters |
48
+
49
+ ---
50
+
51
+ *Update this file when: completing major tasks, making design decisions, discovering pitfalls.*
@@ -0,0 +1,28 @@
1
+ # Invar Protocol
2
+
3
+ Follow the Invar Protocol in INVAR.md — includes Session Start, ICIDIV workflow, and Task Completion requirements.
4
+
5
+ ## Cursor-Specific: Entry Verification
6
+
7
+ Before writing any code, execute and show output from:
8
+
9
+ ```
10
+ invar_guard (changed=true) # Check existing violations
11
+ invar_map (top=10) # Understand code structure
12
+ ```
13
+
14
+ Use MCP tools if available, otherwise use CLI commands:
15
+ - `invar guard --changed`
16
+ - `invar map --top 10`
17
+
18
+ Then read .invar/examples/ and .invar/context.md.
19
+
20
+ Skipping these steps leads to non-compliant code.
21
+
22
+ ## Quick Reference
23
+
24
+ - Core (`**/core/**`): @pre/@post contracts, doctests, pure (no I/O)
25
+ - Shell (`**/shell/**`): Result[T, E] return type
26
+ - Workflow: Intent → Contract → Inspect → Design → Implement → Verify
27
+ - Contract before Implement. No exceptions.
28
+ - Task complete only when final invar_guard passes.
@@ -0,0 +1,21 @@
1
+ # Invar Examples
2
+
3
+ Reference examples for the Invar Protocol. These are managed by Invar.
4
+
5
+ ## Files
6
+
7
+ | File | Content |
8
+ |------|---------|
9
+ | [contracts.py](contracts.py) | @pre/@post patterns, doctest best practices |
10
+ | [core_shell.py](core_shell.py) | Core/Shell separation patterns |
11
+
12
+ ## Usage
13
+
14
+ Read these when you need:
15
+ - Contract pattern reference
16
+ - Core vs Shell decision guidance
17
+ - Doctest formatting examples
18
+
19
+ ---
20
+
21
+ *Managed by Invar. Do not edit — use `invar update` to sync.*
@@ -0,0 +1,111 @@
1
+ """
2
+ Invar Contract Examples
3
+
4
+ Reference patterns for @pre/@post contracts and doctests.
5
+ Managed by Invar - do not edit directly.
6
+ """
7
+
8
+ from deal import post, pre
9
+
10
+ # =============================================================================
11
+ # GOOD: Complete Contract
12
+ # =============================================================================
13
+
14
+
15
+ @pre(lambda price, discount: price > 0 and 0 <= discount <= 1)
16
+ @post(lambda result: result >= 0)
17
+ def discounted_price(price: float, discount: float) -> float:
18
+ """
19
+ Apply discount to price.
20
+
21
+ >>> discounted_price(100.0, 0.2)
22
+ 80.0
23
+ >>> discounted_price(100.0, 0) # Edge: no discount
24
+ 100.0
25
+ >>> discounted_price(100.0, 1) # Edge: full discount
26
+ 0.0
27
+ """
28
+ return price * (1 - discount)
29
+
30
+
31
+ # =============================================================================
32
+ # GOOD: List Processing with Length Constraint
33
+ # =============================================================================
34
+
35
+
36
+ @pre(lambda items: len(items) > 0)
37
+ @post(lambda result: result >= 0)
38
+ def average(items: list[float]) -> float:
39
+ """
40
+ Calculate average of non-empty list.
41
+
42
+ >>> average([1, 2, 3])
43
+ 2.0
44
+ >>> average([5]) # Edge: single element
45
+ 5.0
46
+ >>> average([0, 0, 0]) # Edge: all zeros
47
+ 0.0
48
+ """
49
+ return sum(items) / len(items)
50
+
51
+
52
+ # =============================================================================
53
+ # GOOD: Dict Comparison in Doctests
54
+ # =============================================================================
55
+
56
+
57
+ @pre(lambda data: isinstance(data, dict))
58
+ @post(lambda result: isinstance(result, dict))
59
+ def normalize_keys(data: dict[str, int]) -> dict[str, int]:
60
+ """
61
+ Lowercase all keys.
62
+
63
+ # GOOD: Use sorted() for deterministic output
64
+ >>> sorted(normalize_keys({'A': 1, 'B': 2}).items())
65
+ [('a', 1), ('b', 2)]
66
+
67
+ # GOOD: Or use equality comparison
68
+ >>> normalize_keys({'X': 10}) == {'x': 10}
69
+ True
70
+ """
71
+ return {k.lower(): v for k, v in data.items()}
72
+
73
+
74
+ # =============================================================================
75
+ # BAD: Incomplete Contract (anti-pattern)
76
+ # =============================================================================
77
+
78
+ # DON'T: Empty contract tells nothing
79
+ # @pre(lambda: True)
80
+ # @post(lambda result: True)
81
+ # def process(x): ... # noqa: ERA001
82
+
83
+ # DON'T: Missing edge cases in doctests
84
+ # def divide(a, b):
85
+ # """
86
+ # >>> divide(10, 2)
87
+ # 5.0
88
+ # # Missing: what about b=0?
89
+ # """
90
+
91
+
92
+ # =============================================================================
93
+ # GOOD: Multiple @pre for Clarity
94
+ # =============================================================================
95
+
96
+
97
+ @pre(lambda start, end: start >= 0)
98
+ @pre(lambda start, end: end >= start)
99
+ @post(lambda result: result >= 0)
100
+ def range_size(start: int, end: int) -> int:
101
+ """
102
+ Calculate size of range [start, end).
103
+
104
+ >>> range_size(0, 10)
105
+ 10
106
+ >>> range_size(5, 5) # Edge: empty range
107
+ 0
108
+ >>> range_size(0, 1) # Edge: single element
109
+ 1
110
+ """
111
+ return end - start
@@ -0,0 +1,121 @@
1
+ """
2
+ Invar Core/Shell Separation Examples
3
+
4
+ Reference patterns for Core vs Shell architecture.
5
+ Managed by Invar - do not edit directly.
6
+ """
7
+
8
+ from pathlib import Path
9
+
10
+ from deal import post, pre
11
+ from returns.result import Failure, Result, Success
12
+
13
+ # =============================================================================
14
+ # CORE: Pure Logic (no I/O)
15
+ # =============================================================================
16
+ # Location: src/*/core/
17
+ # Requirements: @pre/@post, doctests, no I/O imports
18
+ # =============================================================================
19
+
20
+
21
+ @pre(lambda content: isinstance(content, str))
22
+ @post(lambda result: isinstance(result, list))
23
+ def parse_lines(content: str) -> list[str]:
24
+ """
25
+ Parse content into non-empty lines.
26
+
27
+ >>> parse_lines("a\\nb\\nc")
28
+ ['a', 'b', 'c']
29
+ >>> parse_lines("")
30
+ []
31
+ >>> parse_lines(" \\n ") # Edge: whitespace only
32
+ []
33
+ """
34
+ return [line.strip() for line in content.split("\n") if line.strip()]
35
+
36
+
37
+ @pre(lambda items: isinstance(items, list))
38
+ @post(lambda result: isinstance(result, dict))
39
+ def count_items(items: list[str]) -> dict[str, int]:
40
+ """
41
+ Count occurrences of each item.
42
+
43
+ >>> sorted(count_items(['a', 'b', 'a']).items())
44
+ [('a', 2), ('b', 1)]
45
+ >>> count_items([])
46
+ {}
47
+ """
48
+ counts: dict[str, int] = {}
49
+ for item in items:
50
+ counts[item] = counts.get(item, 0) + 1
51
+ return counts
52
+
53
+
54
+ # =============================================================================
55
+ # SHELL: I/O Operations
56
+ # =============================================================================
57
+ # Location: src/*/shell/
58
+ # Requirements: Result[T, E] return type, calls Core for logic
59
+ # =============================================================================
60
+
61
+
62
+ def read_file(path: Path) -> Result[str, str]:
63
+ """
64
+ Read file content.
65
+
66
+ Shell handles I/O, returns Result for error handling.
67
+ """
68
+ try:
69
+ return Success(path.read_text())
70
+ except FileNotFoundError:
71
+ return Failure(f"File not found: {path}")
72
+ except PermissionError:
73
+ return Failure(f"Permission denied: {path}")
74
+
75
+
76
+ def count_lines_in_file(path: Path) -> Result[dict[str, int], str]:
77
+ """
78
+ Count lines in file - demonstrates Core/Shell integration.
79
+
80
+ Shell reads file → Core parses content → Shell returns result.
81
+ """
82
+ # Shell: I/O operation
83
+ content_result = read_file(path)
84
+
85
+ if isinstance(content_result, Failure):
86
+ return content_result
87
+
88
+ content = content_result.unwrap()
89
+
90
+ # Core: Pure logic (no I/O)
91
+ lines = parse_lines(content)
92
+ counts = count_items(lines)
93
+
94
+ # Shell: Return result
95
+ return Success(counts)
96
+
97
+
98
+ # =============================================================================
99
+ # ANTI-PATTERNS
100
+ # =============================================================================
101
+
102
+ # DON'T: I/O in Core
103
+ # def parse_file(path: Path): # BAD: Path in Core
104
+ # content = path.read_text() # BAD: I/O in Core # noqa: ERA001
105
+ # return parse_lines(content) # noqa: ERA001
106
+
107
+ # DO: Core receives content, not paths
108
+ # def parse_content(content: str): # GOOD: receives data
109
+ # return parse_lines(content) # noqa: ERA001
110
+
111
+
112
+ # DON'T: Missing Result in Shell
113
+ # def load_config(path: Path) -> dict: # BAD: no Result type
114
+ # return json.loads(path.read_text()) # Exceptions not handled # noqa: ERA001
115
+
116
+ # DO: Return Result[T, E]
117
+ # def load_config(path: Path) -> Result[dict, str]: # GOOD
118
+ # try: # noqa: ERA001
119
+ # return Success(json.loads(path.read_text())) # noqa: ERA001
120
+ # except Exception as e: # noqa: ERA001
121
+ # return Failure(str(e)) # noqa: ERA001
@@ -0,0 +1,44 @@
1
+ # Invar Pre-commit Hooks
2
+ # Install: pre-commit install
3
+ #
4
+ # Default runs full verification (static + doctests + CrossHair + Hypothesis).
5
+ # Incremental mode makes this fast: ~5s first commit, ~2s subsequent (cached).
6
+ #
7
+ # Smart Guard: Detects rule-affecting file changes and runs full guard when needed.
8
+ # Structure Protection: Warns if INVAR.md is modified directly.
9
+
10
+ repos:
11
+ - repo: local
12
+ hooks:
13
+ # Warn if INVAR.md is modified directly (use --no-verify if intentional)
14
+ - id: invar-md-protected
15
+ name: INVAR.md Protection
16
+ entry: bash -c 'if git diff --cached --name-only | grep -q "^INVAR.md$"; then echo "Warning - INVAR.md was modified directly. Use git commit --no-verify if intentional."; exit 1; fi'
17
+ language: system
18
+ pass_filenames: false
19
+ stages: [pre-commit]
20
+
21
+ # Invar Guard (full verification by default)
22
+ # Uses incremental mode: only verifies changed files, caches results
23
+ # Smart mode: runs full guard when rule files change, --changed otherwise
24
+ - id: invar-guard
25
+ name: Invar Guard
26
+ entry: bash -c '
27
+ RULE_FILES="rule_meta.py rules.py contracts.py purity.py pyproject.toml"
28
+ STAGED=$(git diff --cached --name-only)
29
+ FULL=false
30
+ for f in $RULE_FILES; do
31
+ if echo "$STAGED" | grep -q "$f"; then FULL=true; break; fi
32
+ done
33
+ if [ "$FULL" = true ]; then
34
+ echo "⚠️ Rule change detected - running FULL guard"
35
+ invar guard
36
+ else
37
+ invar guard --changed
38
+ fi
39
+ '
40
+ language: python
41
+ additional_dependencies: ['invar-tools']
42
+ pass_filenames: false
43
+ stages: [pre-commit]
44
+ types: [python]
@@ -0,0 +1,93 @@
1
+ # Protocol Change Proposal
2
+
3
+ > Copy this template to `YYYY-MM-DD-title.md` when proposing changes.
4
+
5
+ ---
6
+
7
+ ## Metadata
8
+
9
+ - **Date:** YYYY-MM-DD
10
+ - **Author:** [Agent/Human]
11
+ - **Status:** Draft | Pending Approval | Approved | Rejected
12
+ - **Layer:** L1 (Protocol) | L2 (Project)
13
+
14
+ ---
15
+
16
+ ## Trigger
17
+
18
+ What problem or friction caused this proposal?
19
+
20
+ ```
21
+ Describe the specific situation that revealed a gap in the protocol.
22
+ Include concrete examples if possible.
23
+ ```
24
+
25
+ ---
26
+
27
+ ## Proposed Change
28
+
29
+ What specific change is proposed?
30
+
31
+ ```
32
+ Be precise. Show before/after if applicable.
33
+ ```
34
+
35
+ ---
36
+
37
+ ## Evidence
38
+
39
+ What experience supports this change?
40
+
41
+ ```
42
+ - What happened that demonstrates the need?
43
+ - How many times did this issue occur?
44
+ - What was the impact (time lost, bugs introduced, etc.)?
45
+ ```
46
+
47
+ ---
48
+
49
+ ## Impact Analysis
50
+
51
+ What else needs to change if this is approved?
52
+
53
+ - [ ] INVAR.md sections affected
54
+ - [ ] CLAUDE.md updates needed
55
+ - [ ] Template files to update
56
+ - [ ] Code changes required
57
+ - [ ] Other documentation
58
+
59
+ ---
60
+
61
+ ## Alternatives Considered
62
+
63
+ What other approaches were considered and why were they rejected?
64
+
65
+ ```
66
+ 1. Alternative A: ...
67
+ Rejected because: ...
68
+
69
+ 2. Alternative B: ...
70
+ Rejected because: ...
71
+ ```
72
+
73
+ ---
74
+
75
+ ## Approval
76
+
77
+ **For Layer 1 changes only:**
78
+
79
+ - [ ] Human has reviewed this proposal
80
+ - [ ] Human explicitly approves: _____________ (signature/date)
81
+
82
+ ---
83
+
84
+ ## Implementation Checklist
85
+
86
+ After approval:
87
+
88
+ - [ ] Update INVAR.md
89
+ - [ ] Update version number
90
+ - [ ] Sync templates
91
+ - [ ] Update related documentation
92
+ - [ ] Add to version history
93
+ - [ ] Commit with clear message