invar-tools 1.8.0__py3-none-any.whl → 1.10.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 (110) hide show
  1. invar/__init__.py +8 -0
  2. invar/core/language.py +88 -0
  3. invar/core/models.py +106 -0
  4. invar/core/patterns/detector.py +6 -1
  5. invar/core/patterns/p0_exhaustive.py +15 -3
  6. invar/core/patterns/p0_literal.py +15 -3
  7. invar/core/patterns/p0_newtype.py +15 -3
  8. invar/core/patterns/p0_nonempty.py +15 -3
  9. invar/core/patterns/p0_validation.py +15 -3
  10. invar/core/patterns/registry.py +5 -1
  11. invar/core/patterns/types.py +5 -1
  12. invar/core/property_gen.py +4 -0
  13. invar/core/rules.py +84 -18
  14. invar/core/sync_helpers.py +27 -1
  15. invar/core/ts_parsers.py +286 -0
  16. invar/core/ts_sig_parser.py +307 -0
  17. invar/node_tools/MANIFEST +7 -0
  18. invar/node_tools/__init__.py +51 -0
  19. invar/node_tools/fc-runner/cli.js +77 -0
  20. invar/node_tools/quick-check/cli.js +28 -0
  21. invar/node_tools/ts-analyzer/cli.js +480 -0
  22. invar/shell/claude_hooks.py +35 -12
  23. invar/shell/commands/guard.py +36 -1
  24. invar/shell/commands/init.py +82 -3
  25. invar/shell/commands/perception.py +157 -33
  26. invar/shell/commands/skill.py +187 -0
  27. invar/shell/commands/template_sync.py +65 -13
  28. invar/shell/commands/uninstall.py +60 -12
  29. invar/shell/commands/update.py +6 -14
  30. invar/shell/contract_coverage.py +1 -0
  31. invar/shell/fs.py +66 -13
  32. invar/shell/pi_hooks.py +6 -0
  33. invar/shell/prove/guard_ts.py +899 -0
  34. invar/shell/skill_manager.py +353 -0
  35. invar/shell/template_engine.py +28 -4
  36. invar/shell/templates.py +4 -4
  37. invar/templates/claude-md/python/critical-rules.md +33 -0
  38. invar/templates/claude-md/python/quick-reference.md +24 -0
  39. invar/templates/claude-md/typescript/critical-rules.md +40 -0
  40. invar/templates/claude-md/typescript/quick-reference.md +24 -0
  41. invar/templates/claude-md/universal/check-in.md +25 -0
  42. invar/templates/claude-md/universal/skills.md +73 -0
  43. invar/templates/claude-md/universal/workflow.md +55 -0
  44. invar/templates/commands/{audit.md → audit.md.jinja} +18 -1
  45. invar/templates/config/AGENT.md.jinja +58 -0
  46. invar/templates/config/CLAUDE.md.jinja +16 -209
  47. invar/templates/config/context.md.jinja +19 -0
  48. invar/templates/examples/{README.md → python/README.md} +2 -0
  49. invar/templates/examples/{conftest.py → python/conftest.py} +1 -1
  50. invar/templates/examples/{contracts.py → python/contracts.py} +81 -4
  51. invar/templates/examples/python/core_shell.py +227 -0
  52. invar/templates/examples/python/functional.py +613 -0
  53. invar/templates/examples/typescript/README.md +31 -0
  54. invar/templates/examples/typescript/contracts.ts +163 -0
  55. invar/templates/examples/typescript/core_shell.ts +374 -0
  56. invar/templates/examples/typescript/functional.ts +601 -0
  57. invar/templates/examples/typescript/workflow.md +95 -0
  58. invar/templates/hooks/PostToolUse.sh.jinja +10 -1
  59. invar/templates/hooks/PreToolUse.sh.jinja +38 -0
  60. invar/templates/hooks/Stop.sh.jinja +1 -1
  61. invar/templates/hooks/UserPromptSubmit.sh.jinja +7 -0
  62. invar/templates/hooks/pi/invar.ts.jinja +9 -0
  63. invar/templates/manifest.toml +7 -6
  64. invar/templates/onboard/assessment.md.jinja +214 -0
  65. invar/templates/onboard/patterns/python.md +347 -0
  66. invar/templates/onboard/patterns/typescript.md +452 -0
  67. invar/templates/onboard/roadmap.md.jinja +168 -0
  68. invar/templates/protocol/INVAR.md.jinja +51 -0
  69. invar/templates/protocol/python/architecture-examples.md +41 -0
  70. invar/templates/protocol/python/contracts-syntax.md +56 -0
  71. invar/templates/protocol/python/markers.md +44 -0
  72. invar/templates/protocol/python/tools.md +24 -0
  73. invar/templates/protocol/python/troubleshooting.md +38 -0
  74. invar/templates/protocol/typescript/architecture-examples.md +52 -0
  75. invar/templates/protocol/typescript/contracts-syntax.md +73 -0
  76. invar/templates/protocol/typescript/markers.md +48 -0
  77. invar/templates/protocol/typescript/tools.md +65 -0
  78. invar/templates/protocol/typescript/troubleshooting.md +104 -0
  79. invar/templates/protocol/universal/architecture.md +36 -0
  80. invar/templates/protocol/universal/completion.md +14 -0
  81. invar/templates/protocol/universal/contracts-concept.md +37 -0
  82. invar/templates/protocol/universal/header.md +17 -0
  83. invar/templates/protocol/universal/session.md +17 -0
  84. invar/templates/protocol/universal/six-laws.md +10 -0
  85. invar/templates/protocol/universal/usbv.md +14 -0
  86. invar/templates/protocol/universal/visible-workflow.md +25 -0
  87. invar/templates/skills/develop/SKILL.md.jinja +39 -3
  88. invar/templates/skills/extensions/_registry.yaml +93 -0
  89. invar/templates/skills/extensions/acceptance/SKILL.md +383 -0
  90. invar/templates/skills/extensions/invar-onboard/SKILL.md +448 -0
  91. invar/templates/skills/extensions/invar-onboard/patterns/python.md +347 -0
  92. invar/templates/skills/extensions/invar-onboard/patterns/typescript.md +452 -0
  93. invar/templates/skills/extensions/invar-onboard/templates/assessment.md.jinja +214 -0
  94. invar/templates/skills/extensions/invar-onboard/templates/roadmap.md.jinja +168 -0
  95. invar/templates/skills/extensions/security/SKILL.md +382 -0
  96. invar/templates/skills/extensions/security/patterns/_common.yaml +126 -0
  97. invar/templates/skills/extensions/security/patterns/python.yaml +155 -0
  98. invar/templates/skills/extensions/security/patterns/typescript.yaml +194 -0
  99. invar/templates/skills/review/SKILL.md.jinja +331 -71
  100. {invar_tools-1.8.0.dist-info → invar_tools-1.10.0.dist-info}/METADATA +304 -12
  101. invar_tools-1.10.0.dist-info/RECORD +173 -0
  102. invar/templates/examples/core_shell.py +0 -127
  103. invar/templates/protocol/INVAR.md +0 -310
  104. invar_tools-1.8.0.dist-info/RECORD +0 -116
  105. /invar/templates/examples/{workflow.md → python/workflow.md} +0 -0
  106. {invar_tools-1.8.0.dist-info → invar_tools-1.10.0.dist-info}/WHEEL +0 -0
  107. {invar_tools-1.8.0.dist-info → invar_tools-1.10.0.dist-info}/entry_points.txt +0 -0
  108. {invar_tools-1.8.0.dist-info → invar_tools-1.10.0.dist-info}/licenses/LICENSE +0 -0
  109. {invar_tools-1.8.0.dist-info → invar_tools-1.10.0.dist-info}/licenses/LICENSE-GPL +0 -0
  110. {invar_tools-1.8.0.dist-info → invar_tools-1.10.0.dist-info}/licenses/NOTICE +0 -0
@@ -48,11 +48,20 @@ is_git_repo() {
48
48
  detect_changes() {
49
49
  if is_git_repo; then
50
50
  # Primary: Git-based detection (includes staged + unstaged)
51
+ {% if language == "python" -%}
51
52
  { git diff --name-only -- '*.py' 2>/dev/null; git diff --cached --name-only -- '*.py' 2>/dev/null; } | sort -u
53
+ {% elif language == "typescript" -%}
54
+ { git diff --name-only -- '*.ts' '*.tsx' 2>/dev/null; git diff --cached --name-only -- '*.ts' '*.tsx' 2>/dev/null; } | sort -u
55
+ {% endif -%}
52
56
  elif [[ -f "$LAST_CHECK_MARKER" ]]; then
53
57
  # Fallback: Timestamp-based detection (approximate)
58
+ {% if language == "python" -%}
54
59
  find . -name "*.py" -newer "$LAST_CHECK_MARKER" -type f 2>/dev/null | \
55
60
  grep -v __pycache__ | grep -v '.venv' | head -20
61
+ {% elif language == "typescript" -%}
62
+ find . \( -name "*.ts" -o -name "*.tsx" \) -newer "$LAST_CHECK_MARKER" -type f 2>/dev/null | \
63
+ grep -v node_modules | grep -v dist | head -20
64
+ {% endif -%}
56
65
  fi
57
66
  # Update marker for next check
58
67
  touch "$LAST_CHECK_MARKER" 2>/dev/null
@@ -68,7 +77,7 @@ fi
68
77
  # ============================================
69
78
  # Smart trigger evaluation
70
79
  # ============================================
71
- CHANGE_COUNT=$(wc -l < "$CHANGES_FILE" 2>/dev/null | tr -d ' ' || echo 0)
80
+ CHANGE_COUNT=$([[ -f "$CHANGES_FILE" ]] && wc -l < "$CHANGES_FILE" | tr -d ' ' || echo 0)
72
81
  LAST_TIME=$(cat "$LAST_GUARD" 2>/dev/null || echo 0)
73
82
  NOW=$(date +%s)
74
83
  ELAPSED=$((NOW - LAST_TIME))
@@ -22,6 +22,7 @@ else
22
22
  fi
23
23
  [[ -z "$CMD" ]] && exit 0
24
24
 
25
+ {% if language == "python" -%}
25
26
  # ============================================
26
27
  # pytest blocking with smart escape
27
28
  # ============================================
@@ -70,5 +71,42 @@ if echo "$CMD" | grep -qE '\bcrosshair\b'; then
70
71
  echo " Manual escape: INVAR_ALLOW_CROSSHAIR=1 crosshair ..."
71
72
  exit 1
72
73
  fi
74
+ {% elif language == "typescript" -%}
75
+ # ============================================
76
+ # jest/vitest blocking with smart escape
77
+ # ============================================
78
+ if echo "$CMD" | grep -qE '\bjest\b|\bvitest\b|npx\s+(jest|vitest)\b|npm\s+(run\s+)?test\b'; then
79
+
80
+ # Auto-escape 1: Debugging mode
81
+ if echo "$CMD" | grep -qE '\-\-inspect|\-\-debug'; then
82
+ echo "⚠️ Test debugging allowed. Run {{ guard_cmd }} after."
83
+ exit 0
84
+ fi
85
+
86
+ # Auto-escape 2: External/vendor tests
87
+ if echo "$CMD" | grep -qE 'vendor/|third_party/|external/'; then
88
+ exit 0
89
+ fi
90
+
91
+ # Auto-escape 3: Explicit coverage collection
92
+ if echo "$CMD" | grep -qE '\-\-coverage'; then
93
+ echo "⚠️ Test coverage allowed. Run {{ guard_cmd }} for contract verification."
94
+ exit 0
95
+ fi
96
+
97
+ # Auto-escape 4: Environment variable override
98
+ if [[ "$INVAR_ALLOW_JEST" == "1" ]]; then
99
+ exit 0
100
+ fi
101
+
102
+ # Default: Block with helpful message
103
+ echo "❌ Use {{ guard_cmd }} instead of jest/vitest"
104
+ echo " {{ guard_cmd }} = tsc + eslint + vitest + fast-check"
105
+ echo ""
106
+ echo " Auto-allowed: --inspect (debug), --coverage"
107
+ echo " Manual escape: INVAR_ALLOW_JEST=1 jest ..."
108
+ exit 1
109
+ fi
110
+ {% endif -%}
73
111
 
74
112
  exit 0
@@ -13,7 +13,7 @@ if [[ -f "$CHANGES_FILE" ]]; then
13
13
  if [[ $CHANGE_COUNT -gt 0 ]]; then
14
14
  echo ""
15
15
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
16
- echo "⚠️ Invar: $CHANGE_COUNT Python files not verified"
16
+ echo "⚠️ Invar: $CHANGE_COUNT {{ language | capitalize }} files not verified"
17
17
  echo " Run before commit: {{ guard_cmd }} --changed"
18
18
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
19
19
  fi
@@ -41,10 +41,17 @@ echo "$COUNT" > "$COUNT_FILE"
41
41
  # Keyword triggers (independent of count)
42
42
  # ============================================
43
43
 
44
+ {% if language == "python" -%}
44
45
  # pytest intent → immediate correction
45
46
  if echo "$USER_MESSAGE" | grep -qiE "run.*pytest|pytest.*test|用.*pytest"; then
46
47
  echo "<system-reminder>Use {{ guard_cmd }}, not pytest.</system-reminder>"
47
48
  fi
49
+ {% elif language == "typescript" -%}
50
+ # jest/vitest intent → immediate correction
51
+ if echo "$USER_MESSAGE" | grep -qiE "run.*jest|run.*vitest|npm.*test|用.*jest|用.*vitest"; then
52
+ echo "<system-reminder>Use {{ guard_cmd }}, not jest/vitest directly.</system-reminder>"
53
+ fi
54
+ {% endif -%}
48
55
 
49
56
  # Implementation intent → workflow reminder (after warmup)
50
57
  if [[ $COUNT -gt 3 ]]; then
@@ -11,8 +11,13 @@
11
11
  import type { HookAPI } from "@mariozechner/pi-coding-agent/hooks";
12
12
 
13
13
  // Blocked commands (same as Claude Code)
14
+ {% if language == "python" -%}
14
15
  const BLOCKED_CMDS = [/^pytest\b/, /^python\s+-m\s+pytest/, /^crosshair\b/];
15
16
  const ALLOWED_FLAGS = [/--pdb/, /--cov/, /--debug/];
17
+ {% elif language == "typescript" -%}
18
+ const BLOCKED_CMDS = [/^jest\b/, /^vitest\b/, /^npx\s+(jest|vitest)\b/, /^npm\s+(run\s+)?test\b/];
19
+ const ALLOWED_FLAGS = [/--inspect/, /--coverage/, /--debug/];
20
+ {% endif -%}
16
21
 
17
22
  // Protocol content for injection (escaped for JS)
18
23
  const INVAR_PROTOCOL = `{{ invar_protocol_escaped }}`;
@@ -67,7 +72,11 @@ ${INVAR_PROTOCOL}
67
72
 
68
73
  return {
69
74
  block: true,
75
+ {% if language == "python" -%}
70
76
  reason: "Use `{{ guard_cmd }}` instead of pytest/crosshair.",
77
+ {% elif language == "typescript" -%}
78
+ reason: "Use `{{ guard_cmd }}` instead of jest/vitest.",
79
+ {% endif -%}
71
80
  };
72
81
  });
73
82
  }
@@ -49,8 +49,8 @@ extensions = { action = "preserve" }
49
49
  # =============================================================================
50
50
 
51
51
  [templates]
52
- # Protocol files (direct copy)
53
- "INVAR.md" = { src = "protocol/INVAR.md", type = "copy" }
52
+ # Protocol files (Jinja2 composition - LX-05)
53
+ "INVAR.md" = { src = "protocol/INVAR.md.jinja", type = "jinja" }
54
54
 
55
55
  # Config files (Jinja2 templates)
56
56
  "CLAUDE.md" = { src = "config/CLAUDE.md.jinja", type = "jinja" }
@@ -64,12 +64,12 @@ extensions = { action = "preserve" }
64
64
  ".claude/skills/propose/SKILL.md" = { src = "skills/propose/SKILL.md.jinja", type = "jinja" }
65
65
  ".claude/skills/review/SKILL.md" = { src = "skills/review/SKILL.md.jinja", type = "jinja" }
66
66
 
67
- # Commands (direct copy)
68
- ".claude/commands/audit.md" = { src = "commands/audit.md", type = "copy" }
67
+ # Commands (Jinja2 templates for language-specific content)
68
+ ".claude/commands/audit.md" = { src = "commands/audit.md.jinja", type = "jinja" }
69
69
  ".claude/commands/guard.md" = { src = "commands/guard.md", type = "copy" }
70
70
 
71
- # Examples (directory copy)
72
- ".invar/examples/" = { src = "examples/", type = "copy_dir" }
71
+ # Examples (language-aware directory copy - LX-05 hotfix)
72
+ ".invar/examples/" = { src = "examples/{language}/", type = "copy_dir_lang" }
73
73
 
74
74
  # =============================================================================
75
75
  # Variables
@@ -78,6 +78,7 @@ extensions = { action = "preserve" }
78
78
  [variables]
79
79
  # Available for Jinja2 templates
80
80
  syntax = "cli" # "cli" or "mcp"
81
+ language = "python" # "python" or "typescript" (LX-05)
81
82
  version = "5.0"
82
83
  project_name = "" # Set by init
83
84
 
@@ -0,0 +1,214 @@
1
+ {#
2
+ Expected variables:
3
+ - project_name: str
4
+ - timestamp: str
5
+ - invar_version: str
6
+ - language: str
7
+ - framework?: str (default "N/A")
8
+ - loc: int
9
+ - files: int
10
+ - test_type: str
11
+ - test_count: int
12
+ - compatibility: int (0-100)
13
+ - total_days: int
14
+ - risk_level: str ("Low" | "Medium" | "High")
15
+ - architecture_diagram: str
16
+ - dependency_map?: str
17
+ - current_error, gap_error: str
18
+ - current_validation, gap_validation: str
19
+ - current_separation, gap_separation: str
20
+ - current_test, gap_test: str
21
+ - error_patterns?: [{type: str, count: int, locations: [str]}]
22
+ - validation_patterns?: [{library: str, usage: str, files: [str]}]
23
+ - high_risk_areas?: [{name: str, reason: str, files: [str], impact: str}]
24
+ - blockers?: [{name: str, description: str, mitigation: str}]
25
+ - dependency_risks?: [{name: str, risk_level: str, reason: str}]
26
+ - phase1_days, phase2_days, phase3_days, phase4_days, phase5_days: int
27
+ - contract_type: str
28
+ - base_effort: float
29
+ - adjustments: [{factor: str, reason: str}]
30
+ - adjustment_formula: str
31
+ - recommendation: str
32
+ - result_library: str
33
+ - additional_prereqs?: [str]
34
+ - quick_wins?: [{name: str, description: str, effort: str, impact: str}]
35
+ - layers: [{name: str, files: int, loc: int, notes?: str}]
36
+ - priority_files: [{path: str, loc: int, current_state: str, target_state: str, dependencies?: [str]}]
37
+ #}
38
+ # Invar Onboarding Assessment
39
+
40
+ > Project: {{ project_name }}
41
+ > Assessed: {{ timestamp }}
42
+ > Invar Version: {{ invar_version }}
43
+
44
+ ## 1. Summary
45
+
46
+ | Metric | Value |
47
+ |--------|-------|
48
+ | Primary Language | {{ language }} |
49
+ | Framework | {{ framework | default("N/A") }} |
50
+ | Code Size | {{ loc }} lines / {{ files }} files |
51
+ | Test Coverage | {{ test_type }}: {{ test_count }} tests |
52
+ | **Invar Compatibility** | **{{ compatibility }}%** |
53
+ | **Estimated Effort** | **{{ total_days }} days** |
54
+ | **Risk Level** | **{{ risk_level }}** |
55
+
56
+ ## 2. Architecture Analysis
57
+
58
+ ### 2.1 Layer Structure
59
+
60
+ ```
61
+ {{ architecture_diagram }}
62
+ ```
63
+
64
+ ### 2.2 Dependency Map
65
+
66
+ {% if dependency_map %}
67
+ {{ dependency_map }}
68
+ {% else %}
69
+ *No complex dependencies detected.*
70
+ {% endif %}
71
+
72
+ ## 3. Pattern Analysis
73
+
74
+ | Dimension | Current | Invar Target | Gap |
75
+ |-----------|---------|--------------|-----|
76
+ | Error Handling | {{ current_error }} | Result[T, E] / Result<T, E> | {{ gap_error }} |
77
+ | Validation | {{ current_validation }} | @pre/@post / Zod | {{ gap_validation }} |
78
+ | Core/Shell | {{ current_separation }} | Explicit separation | {{ gap_separation }} |
79
+ | Testing | {{ current_test }} | Doctest + Property | {{ gap_test }} |
80
+
81
+ ### 3.1 Error Handling Details
82
+
83
+ {% if error_patterns %}
84
+ | Pattern | Count | Location |
85
+ |---------|-------|----------|
86
+ {% for pattern in error_patterns %}
87
+ | {{ pattern.type }} | {{ pattern.count }} | {{ pattern.locations | join(", ") }} |
88
+ {% endfor %}
89
+ {% else %}
90
+ *No error handling patterns detected.*
91
+ {% endif %}
92
+
93
+ ### 3.2 Validation Details
94
+
95
+ {% if validation_patterns %}
96
+ | Library | Usage | Files |
97
+ |---------|-------|-------|
98
+ {% for pattern in validation_patterns %}
99
+ | {{ pattern.library }} | {{ pattern.usage }} | {{ pattern.files | join(", ") }} |
100
+ {% endfor %}
101
+ {% else %}
102
+ *No validation libraries detected.*
103
+ {% endif %}
104
+
105
+ ## 4. Risk Assessment
106
+
107
+ ### 4.1 High Risk Areas
108
+
109
+ {% if high_risk_areas %}
110
+ {% for area in high_risk_areas %}
111
+ - **{{ area.name }}**: {{ area.reason }}
112
+ - Files: {{ area.files | join(", ") }}
113
+ - Impact: {{ area.impact }}
114
+ {% endfor %}
115
+ {% else %}
116
+ *No high risk areas identified.*
117
+ {% endif %}
118
+
119
+ ### 4.2 Blockers
120
+
121
+ {% if blockers %}
122
+ {% for blocker in blockers %}
123
+ - [ ] **{{ blocker.name }}**: {{ blocker.description }}
124
+ - Mitigation: {{ blocker.mitigation }}
125
+ {% endfor %}
126
+ {% else %}
127
+ *No blockers identified.*
128
+ {% endif %}
129
+
130
+ ### 4.3 Dependency Risks
131
+
132
+ {% if dependency_risks %}
133
+ | Dependency | Risk | Reason |
134
+ |------------|------|--------|
135
+ {% for dep in dependency_risks %}
136
+ | {{ dep.name }} | {{ dep.risk_level }} | {{ dep.reason }} |
137
+ {% endfor %}
138
+ {% else %}
139
+ *No dependency risks identified.*
140
+ {% endif %}
141
+
142
+ ## 5. Effort Breakdown
143
+
144
+ | Phase | Scope | Estimate |
145
+ |-------|-------|----------|
146
+ | Foundation | Error types, Result infrastructure | {{ phase1_days }} days |
147
+ | Core Extraction | Pure function isolation | {{ phase2_days }} days |
148
+ | Shell Refactor | I/O layer Result conversion | {{ phase3_days }} days |
149
+ | Contracts | {{ contract_type }} | {{ phase4_days }} days |
150
+ | Validation | Guard integration, test coverage | {{ phase5_days }} days |
151
+ | **Total** | | **{{ total_days }} days** |
152
+
153
+ ### 5.1 Estimation Factors
154
+
155
+ ```
156
+ Base effort: {{ base_effort }} days ({{ loc }} LOC / 100)
157
+
158
+ Adjustments:
159
+ {% for adj in adjustments %}
160
+ {{ adj.factor }} {{ adj.reason }}
161
+ {% endfor %}
162
+
163
+ Final: {{ base_effort }} {{ adjustment_formula }} = {{ total_days }} days
164
+ ```
165
+
166
+ ## 6. Recommendations
167
+
168
+ ### 6.1 Suggested Approach
169
+
170
+ {{ recommendation }}
171
+
172
+ ### 6.2 Prerequisites
173
+
174
+ - [ ] E2E test coverage > 80% for critical paths
175
+ - [ ] Result library installed ({{ result_library }})
176
+ - [ ] Error type hierarchy defined
177
+ {% for prereq in additional_prereqs %}
178
+ - [ ] {{ prereq }}
179
+ {% endfor %}
180
+
181
+ ### 6.3 Quick Wins
182
+
183
+ {% if quick_wins %}
184
+ {% for win in quick_wins %}
185
+ 1. **{{ win.name }}**: {{ win.description }}
186
+ - Effort: {{ win.effort }}
187
+ - Impact: {{ win.impact }}
188
+ {% endfor %}
189
+ {% else %}
190
+ *No quick wins identified.*
191
+ {% endif %}
192
+
193
+ ## 7. File Analysis
194
+
195
+ ### 7.1 Files by Layer (Proposed)
196
+
197
+ | Layer | Files | LOC | Notes |
198
+ |-------|-------|-----|-------|
199
+ {% for layer in layers %}
200
+ | {{ layer.name }} | {{ layer.files }} | {{ layer.loc }} | {{ layer.notes | default("") }} |
201
+ {% endfor %}
202
+
203
+ ### 7.2 Migration Priority
204
+
205
+ {% for file in priority_files %}
206
+ {{ loop.index }}. `{{ file.path }}` ({{ file.loc }} lines)
207
+ - Current: {{ file.current_state }}
208
+ - Target: {{ file.target_state }}
209
+ - Dependencies: {{ file.dependencies | join(", ") | default("None") }}
210
+ {% endfor %}
211
+
212
+ ---
213
+
214
+ *Generated by /invar-onboard*