invar-tools 1.2.0__py3-none-any.whl → 1.3.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 (89) hide show
  1. invar/__init__.py +1 -0
  2. invar/core/contracts.py +10 -10
  3. invar/core/entry_points.py +105 -32
  4. invar/core/extraction.py +5 -6
  5. invar/core/format_specs.py +1 -2
  6. invar/core/formatter.py +6 -7
  7. invar/core/hypothesis_strategies.py +5 -7
  8. invar/core/inspect.py +1 -1
  9. invar/core/lambda_helpers.py +3 -3
  10. invar/core/models.py +7 -1
  11. invar/core/must_use.py +2 -1
  12. invar/core/parser.py +7 -4
  13. invar/core/postcondition_scope.py +128 -0
  14. invar/core/property_gen.py +8 -5
  15. invar/core/purity.py +3 -3
  16. invar/core/purity_heuristics.py +5 -9
  17. invar/core/references.py +8 -6
  18. invar/core/review_trigger.py +78 -6
  19. invar/core/rule_meta.py +8 -0
  20. invar/core/rules.py +18 -19
  21. invar/core/shell_analysis.py +5 -10
  22. invar/core/shell_architecture.py +2 -2
  23. invar/core/strategies.py +7 -14
  24. invar/core/suggestions.py +86 -0
  25. invar/core/sync_helpers.py +238 -0
  26. invar/core/tautology.py +102 -37
  27. invar/core/template_parser.py +467 -0
  28. invar/core/timeout_inference.py +4 -7
  29. invar/core/utils.py +13 -15
  30. invar/core/verification_routing.py +4 -7
  31. invar/mcp/server.py +100 -17
  32. invar/shell/commands/__init__.py +11 -0
  33. invar/shell/{cli.py → commands/guard.py} +94 -14
  34. invar/shell/{init_cmd.py → commands/init.py} +179 -27
  35. invar/shell/commands/merge.py +256 -0
  36. invar/shell/commands/sync_self.py +113 -0
  37. invar/shell/commands/template_sync.py +366 -0
  38. invar/shell/commands/update.py +48 -0
  39. invar/shell/config.py +12 -24
  40. invar/shell/coverage.py +351 -0
  41. invar/shell/guard_helpers.py +38 -17
  42. invar/shell/guard_output.py +7 -1
  43. invar/shell/property_tests.py +58 -22
  44. invar/shell/prove/__init__.py +9 -0
  45. invar/shell/{prove.py → prove/crosshair.py} +40 -33
  46. invar/shell/{prove_fallback.py → prove/hypothesis.py} +12 -4
  47. invar/shell/subprocess_env.py +393 -0
  48. invar/shell/template_engine.py +345 -0
  49. invar/shell/templates.py +19 -0
  50. invar/shell/testing.py +71 -20
  51. invar/templates/CLAUDE.md.template +38 -17
  52. invar/templates/aider.conf.yml.template +2 -2
  53. invar/templates/commands/{review.md → audit.md} +20 -82
  54. invar/templates/commands/guard.md +77 -0
  55. invar/templates/config/CLAUDE.md.jinja +206 -0
  56. invar/templates/config/context.md.jinja +92 -0
  57. invar/templates/config/pre-commit.yaml.jinja +44 -0
  58. invar/templates/context.md.template +33 -0
  59. invar/templates/cursorrules.template +7 -4
  60. invar/templates/examples/README.md +2 -0
  61. invar/templates/examples/conftest.py +3 -0
  62. invar/templates/examples/contracts.py +5 -5
  63. invar/templates/examples/core_shell.py +11 -7
  64. invar/templates/examples/workflow.md +81 -0
  65. invar/templates/manifest.toml +137 -0
  66. invar/templates/{INVAR.md → protocol/INVAR.md} +10 -7
  67. invar/templates/skills/develop/SKILL.md.jinja +318 -0
  68. invar/templates/skills/investigate/SKILL.md.jinja +106 -0
  69. invar/templates/skills/propose/SKILL.md.jinja +104 -0
  70. invar/templates/skills/review/SKILL.md.jinja +125 -0
  71. {invar_tools-1.2.0.dist-info → invar_tools-1.3.0.dist-info}/METADATA +108 -118
  72. invar_tools-1.3.0.dist-info/RECORD +95 -0
  73. invar_tools-1.3.0.dist-info/entry_points.txt +2 -0
  74. invar/contracts.py +0 -152
  75. invar/decorators.py +0 -94
  76. invar/invariant.py +0 -58
  77. invar/resource.py +0 -99
  78. invar/shell/update_cmd.py +0 -193
  79. invar_tools-1.2.0.dist-info/RECORD +0 -77
  80. invar_tools-1.2.0.dist-info/entry_points.txt +0 -2
  81. /invar/shell/{mutate_cmd.py → commands/mutate.py} +0 -0
  82. /invar/shell/{perception.py → commands/perception.py} +0 -0
  83. /invar/shell/{test_cmd.py → commands/test.py} +0 -0
  84. /invar/shell/{prove_accept.py → prove/accept.py} +0 -0
  85. /invar/shell/{prove_cache.py → prove/cache.py} +0 -0
  86. {invar_tools-1.2.0.dist-info → invar_tools-1.3.0.dist-info}/WHEEL +0 -0
  87. {invar_tools-1.2.0.dist-info → invar_tools-1.3.0.dist-info}/licenses/LICENSE +0 -0
  88. {invar_tools-1.2.0.dist-info → invar_tools-1.3.0.dist-info}/licenses/LICENSE-GPL +0 -0
  89. {invar_tools-1.2.0.dist-info → invar_tools-1.3.0.dist-info}/licenses/NOTICE +0 -0
@@ -1,73 +1,14 @@
1
- # Code Review (Reviewer Role)
1
+ # Audit
2
2
 
3
- ## Mode Detection (Required First Step)
4
-
5
- Before reviewing, determine the appropriate mode:
6
-
7
- ### Check for `review_suggested`
8
-
9
- Look at your conversation history for recent `invar guard` output, or run:
10
- ```bash
11
- invar guard --changed
12
- ```
13
-
14
- Check if `review_suggested` warning is present:
15
- ```
16
- WARNING: review_suggested - High escape hatch count: N @invar:allow markers
17
- WARNING: review_suggested - Security-sensitive path detected
18
- WARNING: review_suggested - Low contract coverage
19
- ```
20
-
21
- ### Select Mode
22
-
23
- | Condition | Mode | Why |
24
- |-----------|------|-----|
25
- | `review_suggested` present | **Isolated** | Eliminates confirmation bias |
26
- | No trigger | **Quick** | Faster, context preserved |
27
- | User requests `--isolated` | **Isolated** | Explicit override |
28
- | User requests `--quick` | **Quick** | Explicit override |
29
-
30
- ---
31
-
32
- ## Isolated Mode
33
-
34
- **Use when:** `review_suggested` triggered, or user explicitly requests isolation.
35
-
36
- Spawn an independent reviewer with fresh context using Task tool:
37
-
38
- ```
39
- I'll spawn an independent reviewer to eliminate confirmation bias...
40
-
41
- [Task tool call]
42
- prompt: |
43
- You are an adversarial code reviewer. Your job is to FIND PROBLEMS.
44
-
45
- Review these files: {files_to_review}
46
-
47
- Read .claude/commands/review.md for the full checklist, then:
48
- 1. Check contract semantic value (not just syntax)
49
- 2. Audit all escape hatches (@invar:allow)
50
- 3. Look for logic errors and edge cases
51
- 4. Check security if applicable
52
-
53
- Report issues as CRITICAL/MAJOR/MINOR with file:line locations.
54
-
55
- Your success is measured by problems found, not code approved.
56
-
57
- subagent_type: "general-purpose"
58
- ```
59
-
60
- After receiving the sub-agent's report, summarize findings for the user.
61
-
62
- **Key:** The sub-agent has NO conversation history. It only sees the code.
3
+ Read-only code review. Reports issues without fixing them.
63
4
 
64
5
  ---
65
6
 
66
- ## Quick Mode
67
-
68
- **Use when:** No `review_suggested` trigger, routine review needed.
7
+ ## Behavior
69
8
 
70
- Proceed with same-context review below.
9
+ 1. Analyze code for issues (style, bugs, security, architecture)
10
+ 2. Report findings with file:line references
11
+ 3. **Do NOT make any changes** - report only
71
12
 
72
13
  ---
73
14
 
@@ -149,7 +90,7 @@ You ARE here to:
149
90
 
150
91
  ---
151
92
 
152
- ## Excluded (Covered by Tools)
93
+ ## Excluded (Covered by Guard)
153
94
 
154
95
  These are checked by Guard or linters - don't duplicate:
155
96
  - Core/Shell separation → Guard (forbidden_import, impure_call)
@@ -157,7 +98,6 @@ These are checked by Guard or linters - don't duplicate:
157
98
  - Missing contracts → Guard (missing_contract)
158
99
  - File/function size limits → Guard (file_size, function_size)
159
100
  - Entry point thickness → Guard (entry_point_too_thick)
160
- - Magic numbers → Linters (ruff)
161
101
  - Escape hatch count → Guard (review_suggested)
162
102
 
163
103
  ---
@@ -166,11 +106,11 @@ These are checked by Guard or linters - don't duplicate:
166
106
 
167
107
  For each issue found, use severity levels:
168
108
 
169
- | Severity | Meaning | Enforcement |
170
- |----------|---------|-------------|
171
- | **CRITICAL** | Must fix before completion | Blocking |
172
- | **MAJOR** | Fix or provide written justification | Strong |
173
- | **MINOR** | Optional, can defer | Advisory |
109
+ | Severity | Meaning |
110
+ |----------|---------|
111
+ | **CRITICAL** | Must fix before completion |
112
+ | **MAJOR** | Fix or provide written justification |
113
+ | **MINOR** | Optional, can defer |
174
114
 
175
115
  ```markdown
176
116
  ### [CRITICAL/MAJOR/MINOR] Issue Title
@@ -178,22 +118,20 @@ For each issue found, use severity levels:
178
118
  **Location:** file.py:line_number
179
119
  **Category:** contract_quality | logic_error | security | escape_hatch | code_smell
180
120
  **Problem:** What's wrong
181
- **Suggestion:** How to fix (if applicable)
121
+ **Suggestion:** How to fix (but don't implement)
182
122
  ```
183
123
 
184
124
  ---
185
125
 
186
- ## Instructions Summary
126
+ ## Instructions
187
127
 
188
- 1. **Mode Detection:** Check for `review_suggested` in guard output
189
- 2. **If Isolated Mode:** Spawn Task sub-agent (fresh context)
190
- 3. **If Quick Mode:** Proceed with same-context adversarial review
191
- 4. Go through each checklist category
192
- 5. For each issue, determine severity (CRITICAL/MAJOR/MINOR)
193
- 6. Report with structured format above
194
- 7. Be thorough and adversarial
128
+ 1. Run `invar guard --changed` to see current state
129
+ 2. Go through each checklist category
130
+ 3. For each issue, determine severity (CRITICAL/MAJOR/MINOR)
131
+ 4. Report with structured format above
132
+ 5. Be thorough and adversarial
195
133
 
196
- **Remember:** You are READ-ONLY. Report issues, don't fix them directly.
134
+ **Remember:** You are READ-ONLY. Report issues, don't fix them.
197
135
 
198
136
  ---
199
137
 
@@ -0,0 +1,77 @@
1
+ # Guard
2
+
3
+ Run Invar verification on the project and report results.
4
+
5
+ ---
6
+
7
+ ## Behavior
8
+
9
+ Execute `invar_guard()` and report:
10
+ - Pass/fail status
11
+ - Error count with details
12
+ - Warning count with details
13
+
14
+ **Do NOT fix issues** - just report verification results.
15
+
16
+ ---
17
+
18
+ ## When to Use
19
+
20
+ - Quick verification check
21
+ - Before committing changes
22
+ - After pulling changes
23
+ - To see current project health
24
+
25
+ ---
26
+
27
+ ## Execution
28
+
29
+ Run verification:
30
+
31
+ ```
32
+ invar_guard(changed=true)
33
+ ```
34
+
35
+ Or for full project verification:
36
+
37
+ ```
38
+ invar_guard()
39
+ ```
40
+
41
+ ---
42
+
43
+ ## Report Format
44
+
45
+ ```
46
+ ## Guard Results
47
+
48
+ **Status:** PASS / FAIL
49
+ **Errors:** N
50
+ **Warnings:** N
51
+
52
+ ### Errors (if any)
53
+
54
+ | Rule | File | Line | Message |
55
+ |------|------|------|---------|
56
+ | missing_contract | src/foo.py | 42 | Function 'bar' has no @pre/@post |
57
+
58
+ ### Warnings (if any)
59
+
60
+ | Rule | File | Line | Message |
61
+ |------|------|------|---------|
62
+ | function_size | src/baz.py | 15 | Function exceeds 50 lines |
63
+ ```
64
+
65
+ ---
66
+
67
+ ## Next Steps
68
+
69
+ After reporting results:
70
+ - If PASS: No action needed
71
+ - If FAIL: User decides whether to fix issues
72
+
73
+ **Remember:** You are READ-ONLY. Report results, don't fix them.
74
+
75
+ ---
76
+
77
+ Now run verification on the current project.
@@ -0,0 +1,206 @@
1
+ <!--invar:managed version="{{ version }}"-->
2
+ # Project Development Guide
3
+
4
+ > **Protocol:** Follow [INVAR.md](./INVAR.md) — includes Check-In, USBV workflow, and Task Completion requirements.
5
+
6
+ ## Check-In (DX-54)
7
+
8
+ Your first message MUST display:
9
+
10
+ ```
11
+ ✓ Check-In: [project] | [branch] | [clean/dirty]
12
+ ```
13
+
14
+ Actions:
15
+ 1. Read `.invar/context.md` (Key Rules + Current State + Lessons Learned)
16
+ 2. Show one-line status
17
+
18
+ Example:
19
+ ```
20
+ ✓ Check-In: MyProject | main | clean
21
+ ```
22
+
23
+ **Do NOT execute guard or map at Check-In.**
24
+ Guard is for VALIDATE phase and Final only.
25
+
26
+ This is your sign-in. The user sees it immediately.
27
+ No visible check-in = Session not started.
28
+
29
+ ---
30
+
31
+ ## Final
32
+
33
+ Your last message for an implementation task MUST display:
34
+
35
+ ```
36
+ ✓ Final: guard PASS | 0 errors, 2 warnings
37
+ ```
38
+
39
+ {% if syntax == "mcp" -%}
40
+ Execute `invar_guard()` and show this one-line summary.
41
+ {% else -%}
42
+ Execute `invar guard` and show this one-line summary.
43
+ {% endif %}
44
+
45
+ This is your sign-out. Completes the Check-In/Final pair.
46
+
47
+ ---
48
+
49
+ ## Project Structure
50
+
51
+ ```
52
+ src/{project}/
53
+ ├── core/ # Pure logic (@pre/@post, doctests, no I/O)
54
+ └── shell/ # I/O operations (Result[T, E] return type)
55
+ ```
56
+
57
+ **Key insight:** Core receives data (strings), Shell handles I/O (paths, files).
58
+
59
+ ## Quick Reference
60
+
61
+ | Zone | Requirements |
62
+ |------|-------------|
63
+ | Core | `@pre`/`@post` + doctests, pure (no I/O) |
64
+ | Shell | Returns `Result[T, E]` from `returns` library |
65
+
66
+ ## Documentation Structure
67
+
68
+ | File | Owner | Edit? | Purpose |
69
+ |------|-------|-------|---------|
70
+ | INVAR.md | Invar | No | Protocol (`invar update` to sync) |
71
+ | CLAUDE.md | User | Yes | Project customization (this file) |
72
+ | .invar/context.md | User | Yes | Project state, lessons learned |
73
+ | .invar/examples/ | Invar | No | **Must read:** Core/Shell patterns, workflow |
74
+
75
+ ## Visible Workflow (DX-30)
76
+
77
+ For complex tasks (3+ functions), show 3 checkpoints in TodoList:
78
+
79
+ ```
80
+ □ [UNDERSTAND] Task description, codebase context, constraints
81
+ □ [SPECIFY] Contracts (@pre/@post) and design decomposition
82
+ □ [VALIDATE] Guard results, Review Gate status, integration status
83
+ ```
84
+
85
+ **BUILD is internal work** — not shown in TodoList.
86
+
87
+ **Show contracts before code.** See `.invar/examples/workflow.md` for full example.
88
+
89
+ ## Phase Visibility (DX-51)
90
+
91
+ Each USBV phase transition requires a visible header:
92
+
93
+ ```
94
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
95
+ 📍 /develop → SPECIFY (2/4)
96
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
97
+ ```
98
+
99
+ **Three-layer visibility:**
100
+ - **Skill** (`/develop`) — Routing announcement
101
+ - **Phase** (`SPECIFY 2/4`) — Phase header (this section)
102
+ - **Tasks** — TodoWrite items
103
+
104
+ Phase headers are SEPARATE from TodoWrite. Phase = where you are; TodoWrite = what to do.
105
+
106
+ ---
107
+
108
+ ## Context Management (DX-54)
109
+
110
+ Re-read `.invar/context.md` when:
111
+ 1. Entering any workflow (/develop, /review, etc.)
112
+ 2. Completing a TodoWrite task (before moving to next)
113
+ 3. Conversation exceeds ~15-20 exchanges
114
+ 4. Unsure about project rules or patterns
115
+
116
+ **Refresh is transparent** — do not announce "I'm refreshing context."
117
+ Only show routing announcements when entering workflows.
118
+
119
+ ---
120
+
121
+ ## Commands (User-Invokable)
122
+
123
+ | Command | Purpose |
124
+ |---------|---------|
125
+ | `/audit` | Read-only code review (reports issues, no fixes) |
126
+ | `/guard` | Run Invar verification (reports results) |
127
+
128
+ ## Skills (Agent-Invoked)
129
+
130
+ | Skill | Triggers | Purpose |
131
+ |-------|----------|---------|
132
+ | `/investigate` | "why", "explain", vague tasks | Research mode, no code changes |
133
+ | `/propose` | "should we", "compare" | Decision facilitation |
134
+ | `/develop` | "add", "fix", "implement" | USBV implementation workflow |
135
+ | `/review` | After /develop, `review_suggested` | Adversarial review with fix loop |
136
+
137
+ **Note:** Skills are invoked by agent based on context. Use `/audit` for user-initiated review.
138
+
139
+ Guard triggers `review_suggested` for: security-sensitive files, escape hatches >= 3, contract coverage < 50%.
140
+
141
+ ---
142
+
143
+ ## Workflow Routing (MANDATORY)
144
+
145
+ When user message contains these triggers, you MUST invoke the corresponding skill:
146
+
147
+ | Trigger Words | Skill | Notes |
148
+ |---------------|-------|-------|
149
+ | "review", "review and fix" | `/review` | Adversarial review with fix loop |
150
+ | "implement", "add", "fix", "update" | `/develop` | Unless in review context |
151
+ | "why", "explain", "investigate" | `/investigate` | Research mode, no code changes |
152
+ | "compare", "should we", "design" | `/propose` | Decision facilitation |
153
+
154
+ **Violation check (before writing ANY code):**
155
+ - "Am I in a workflow?"
156
+ - "Did I invoke the correct skill?"
157
+
158
+ ---
159
+
160
+ ## Routing Control (DX-42)
161
+
162
+ Agent announces routing decision before entering any workflow:
163
+
164
+ ```
165
+ 📍 Routing: /[skill] — [trigger or reason]
166
+ Task: [summary]
167
+ ```
168
+
169
+ **User can redirect with natural language:**
170
+ - "wait" / "stop" — pause and ask for direction
171
+ - "just do it" — proceed with /develop
172
+ - "let's discuss" — switch to /propose
173
+ - "explain first" — switch to /investigate
174
+
175
+ **Simple task optimization:** For simple tasks (single file, clear target, <50 lines), agent may offer:
176
+
177
+ ```
178
+ 📊 Simple task. Auto-orchestrate? [Y/N]
179
+ ```
180
+
181
+ - Y → Full cycle without intermediate confirmations
182
+ - N → Normal step-by-step workflow
183
+
184
+ **Auto-review (DX-41):** When Guard outputs `review_suggested`, agent automatically
185
+ enters /review. Say "skip" to bypass.
186
+ <!--/invar:managed-->
187
+
188
+ <!--invar:project-->
189
+ <!-- ========================================================================
190
+ PROJECT REGION - INVAR PROJECT ONLY
191
+ This section is populated by .invar/project-additions.md via sync-self.
192
+ For other projects, this region remains empty.
193
+ ======================================================================== -->
194
+ <!--/invar:project-->
195
+
196
+ <!--invar:user-->
197
+ <!-- ========================================================================
198
+ USER REGION - EDITABLE
199
+ Add your team conventions and project-specific rules below.
200
+ This section is preserved across invar update and sync-self.
201
+ ======================================================================== -->
202
+ <!--/invar:user-->
203
+
204
+ ---
205
+
206
+ *Generated by `invar init` v{{ version }}. Customize the user section freely.*
@@ -0,0 +1,92 @@
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
+ ## Key Rules (Quick Reference)
12
+
13
+ <!-- DX-54: Rules summary for long conversation resilience -->
14
+
15
+ ### Core/Shell Separation
16
+ - **Core** (`**/core/**`): @pre/@post + doctests, NO I/O imports
17
+ - **Shell** (`**/shell/**`): Result[T, E] return type
18
+
19
+ ### USBV Workflow
20
+ 1. Understand → 2. Specify (contracts first) → 3. Build → 4. Validate
21
+
22
+ ### Verification
23
+ {% if syntax == "mcp" -%}
24
+ - `invar_guard()` = static + doctests + CrossHair + Hypothesis
25
+ {% else -%}
26
+ - `invar guard` = static + doctests + CrossHair + Hypothesis
27
+ {% endif -%}
28
+ - Final must show: `✓ Final: guard PASS | ...`
29
+
30
+ ## Self-Reminder
31
+
32
+ <!-- DX-54: AI should re-read this file periodically -->
33
+
34
+ **When to re-read this file:**
35
+ - Starting a new task
36
+ - Completing a task (before moving to next)
37
+ - Conversation has been going on for a while (~15-20 exchanges)
38
+ - Unsure about project rules or patterns
39
+
40
+ **Quick rule check:**
41
+ - Am I in Core or Shell?
42
+ - Do I have @pre/@post contracts?
43
+ - Am I following USBV workflow?
44
+ - Did I run guard before claiming "done"?
45
+
46
+ ---
47
+
48
+ ## Recent Decisions
49
+
50
+ 1. [Decision summary] - [Brief rationale]
51
+
52
+ ## Lessons Learned
53
+
54
+ 1. [Pitfall or issue] → [Solution or workaround]
55
+
56
+ ## Documentation Structure
57
+
58
+ | File | Owner | Edit? |
59
+ |------|-------|-------|
60
+ | INVAR.md | Invar | No — use `invar update` |
61
+ | CLAUDE.md | User | Yes |
62
+ | .invar/context.md | User | Yes (this file) |
63
+ | .invar/examples/ | Invar | No |
64
+
65
+ **Decision rule:** Is this Invar protocol or project-specific?
66
+ - Protocol content → Already in INVAR.md, don't duplicate
67
+ - Project-specific → Add to CLAUDE.md or here
68
+
69
+ ## Technical Debt
70
+
71
+ {% if syntax == "mcp" -%}
72
+ *Run `invar_guard()` to check current status.*
73
+ {% else -%}
74
+ *Run `invar guard` to check current status.*
75
+ {% endif %}
76
+
77
+ | File | Warning | Priority |
78
+ |------|---------|----------|
79
+ | (none) | — | — |
80
+
81
+ ## Key Files
82
+
83
+ | File | Purpose |
84
+ |------|---------|
85
+ | INVAR.md | Protocol reference (Invar-managed) |
86
+ | CLAUDE.md | Project guide (customize freely) |
87
+ | src/core/ | Pure business logic |
88
+ | src/shell/ | I/O adapters |
89
+
90
+ ---
91
+
92
+ *Update this file when: completing major tasks, making design decisions, discovering pitfalls.*
@@ -0,0 +1,44 @@
1
+ # Invar Pre-commit Hooks v{{ version }}
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]
@@ -8,6 +8,39 @@
8
8
  - Working on: [current task or feature]
9
9
  - Blockers: None
10
10
 
11
+ ## Key Rules (Quick Reference)
12
+
13
+ <!-- DX-54: Rules summary for long conversation resilience -->
14
+
15
+ ### Core/Shell Separation
16
+ - **Core** (`**/core/**`): @pre/@post + doctests, NO I/O imports
17
+ - **Shell** (`**/shell/**`): Result[T, E] return type
18
+
19
+ ### USBV Workflow
20
+ 1. Understand → 2. Specify (contracts first) → 3. Build → 4. Validate
21
+
22
+ ### Verification
23
+ - `invar guard` = static + doctests + CrossHair + Hypothesis
24
+ - Final must show: `✓ Final: guard PASS | ...`
25
+
26
+ ## Self-Reminder
27
+
28
+ <!-- DX-54: AI should re-read this file periodically -->
29
+
30
+ **When to re-read this file:**
31
+ - Starting a new task
32
+ - Completing a task (before moving to next)
33
+ - Conversation has been going on for a while (~15-20 exchanges)
34
+ - Unsure about project rules or patterns
35
+
36
+ **Quick rule check:**
37
+ - Am I in Core or Shell?
38
+ - Do I have @pre/@post contracts?
39
+ - Am I following USBV workflow?
40
+ - Did I run guard before claiming "done"?
41
+
42
+ ---
43
+
11
44
  ## Recent Decisions
12
45
 
13
46
  1. [Decision summary] - [Brief rationale]
@@ -7,16 +7,19 @@ Follow the Invar Protocol in INVAR.md — includes Check-In, USBV workflow, and
7
7
  Your first message MUST display:
8
8
 
9
9
  ```
10
- ✓ Check-In: guard PASS | top: <entry1>, <entry2>
10
+ ✓ Check-In: [project] | [branch] | [clean/dirty]
11
11
  ```
12
12
 
13
- Execute `invar guard --changed` and `invar map --top 10`, then show this one-line summary.
13
+ Actions:
14
+ 1. Read `.invar/context.md` (Key Rules + Current State + Lessons Learned)
15
+ 2. Show one-line status
16
+
17
+ **Do NOT execute guard or map at Check-In.**
18
+ Guard is for VALIDATE phase and Final only.
14
19
 
15
20
  This is your sign-in. The user sees it immediately.
16
21
  No visible check-in = Session not started.
17
22
 
18
- Then read `.invar/context.md` for project state and lessons learned.
19
-
20
23
  ## Final
21
24
 
22
25
  Your last message for an implementation task MUST display:
@@ -8,6 +8,7 @@ Reference examples for the Invar Protocol. These are managed by Invar.
8
8
  |------|---------|
9
9
  | [contracts.py](contracts.py) | @pre/@post patterns, doctest best practices |
10
10
  | [core_shell.py](core_shell.py) | Core/Shell separation patterns |
11
+ | [workflow.md](workflow.md) | Visible USBV workflow example |
11
12
 
12
13
  ## Usage
13
14
 
@@ -15,6 +16,7 @@ Read these when you need:
15
16
  - Contract pattern reference
16
17
  - Core vs Shell decision guidance
17
18
  - Doctest formatting examples
19
+ - USBV workflow example
18
20
 
19
21
  ---
20
22
 
@@ -0,0 +1,3 @@
1
+ # Skip pytest collection for example files
2
+ # These are reference examples, not tests.
3
+ collect_ignore = ["contracts.py", "core_shell.py", "workflow.md"]
@@ -5,9 +5,9 @@ Reference patterns for @pre/@post contracts and doctests.
5
5
  Managed by Invar - do not edit directly.
6
6
  """
7
7
 
8
- # Use invar_runtime for lightweight runtime contracts
9
- # (or 'from deal import pre, post' works too - deal is the underlying library)
10
- from invar_runtime import post, pre
8
+ # For lambda-based contracts, use deal directly
9
+ # invar_runtime.pre/post are for Contract objects (NonEmpty, IsInstance, etc.)
10
+ from deal import post, pre
11
11
 
12
12
  # =============================================================================
13
13
  # GOOD: Complete Contract
@@ -56,8 +56,8 @@ def average(items: list[float]) -> float:
56
56
  # =============================================================================
57
57
 
58
58
 
59
- @pre(lambda data: isinstance(data, dict))
60
- @post(lambda result: isinstance(result, dict))
59
+ @pre(lambda data: len(data) > 0) # Non-empty input (type is in annotation)
60
+ @post(lambda result: len(result) > 0) # Preserves non-emptiness
61
61
  def normalize_keys(data: dict[str, int]) -> dict[str, int]:
62
62
  """
63
63
  Lowercase all keys.