invar-tools 1.7.1__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 (113) 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/template_helpers.py +32 -0
  16. invar/core/ts_parsers.py +286 -0
  17. invar/core/ts_sig_parser.py +307 -0
  18. invar/node_tools/MANIFEST +7 -0
  19. invar/node_tools/__init__.py +51 -0
  20. invar/node_tools/fc-runner/cli.js +77 -0
  21. invar/node_tools/quick-check/cli.js +28 -0
  22. invar/node_tools/ts-analyzer/cli.js +480 -0
  23. invar/shell/claude_hooks.py +35 -12
  24. invar/shell/commands/guard.py +36 -1
  25. invar/shell/commands/init.py +133 -7
  26. invar/shell/commands/perception.py +157 -33
  27. invar/shell/commands/skill.py +187 -0
  28. invar/shell/commands/template_sync.py +65 -13
  29. invar/shell/commands/uninstall.py +77 -12
  30. invar/shell/commands/update.py +6 -14
  31. invar/shell/contract_coverage.py +1 -0
  32. invar/shell/fs.py +66 -13
  33. invar/shell/pi_hooks.py +213 -0
  34. invar/shell/prove/guard_ts.py +899 -0
  35. invar/shell/skill_manager.py +353 -0
  36. invar/shell/template_engine.py +28 -4
  37. invar/shell/templates.py +4 -4
  38. invar/templates/claude-md/python/critical-rules.md +33 -0
  39. invar/templates/claude-md/python/quick-reference.md +24 -0
  40. invar/templates/claude-md/typescript/critical-rules.md +40 -0
  41. invar/templates/claude-md/typescript/quick-reference.md +24 -0
  42. invar/templates/claude-md/universal/check-in.md +25 -0
  43. invar/templates/claude-md/universal/skills.md +73 -0
  44. invar/templates/claude-md/universal/workflow.md +55 -0
  45. invar/templates/commands/{audit.md → audit.md.jinja} +18 -1
  46. invar/templates/config/AGENT.md.jinja +256 -0
  47. invar/templates/config/CLAUDE.md.jinja +16 -209
  48. invar/templates/config/context.md.jinja +19 -0
  49. invar/templates/examples/{README.md → python/README.md} +2 -0
  50. invar/templates/examples/{conftest.py → python/conftest.py} +1 -1
  51. invar/templates/examples/{contracts.py → python/contracts.py} +81 -4
  52. invar/templates/examples/python/core_shell.py +227 -0
  53. invar/templates/examples/python/functional.py +613 -0
  54. invar/templates/examples/typescript/README.md +31 -0
  55. invar/templates/examples/typescript/contracts.ts +163 -0
  56. invar/templates/examples/typescript/core_shell.ts +374 -0
  57. invar/templates/examples/typescript/functional.ts +601 -0
  58. invar/templates/examples/typescript/workflow.md +95 -0
  59. invar/templates/hooks/PostToolUse.sh.jinja +10 -1
  60. invar/templates/hooks/PreToolUse.sh.jinja +38 -0
  61. invar/templates/hooks/Stop.sh.jinja +1 -1
  62. invar/templates/hooks/UserPromptSubmit.sh.jinja +7 -0
  63. invar/templates/hooks/pi/invar.ts.jinja +82 -0
  64. invar/templates/manifest.toml +8 -6
  65. invar/templates/onboard/assessment.md.jinja +214 -0
  66. invar/templates/onboard/patterns/python.md +347 -0
  67. invar/templates/onboard/patterns/typescript.md +452 -0
  68. invar/templates/onboard/roadmap.md.jinja +168 -0
  69. invar/templates/protocol/INVAR.md.jinja +51 -0
  70. invar/templates/protocol/python/architecture-examples.md +41 -0
  71. invar/templates/protocol/python/contracts-syntax.md +56 -0
  72. invar/templates/protocol/python/markers.md +44 -0
  73. invar/templates/protocol/python/tools.md +24 -0
  74. invar/templates/protocol/python/troubleshooting.md +38 -0
  75. invar/templates/protocol/typescript/architecture-examples.md +52 -0
  76. invar/templates/protocol/typescript/contracts-syntax.md +73 -0
  77. invar/templates/protocol/typescript/markers.md +48 -0
  78. invar/templates/protocol/typescript/tools.md +65 -0
  79. invar/templates/protocol/typescript/troubleshooting.md +104 -0
  80. invar/templates/protocol/universal/architecture.md +36 -0
  81. invar/templates/protocol/universal/completion.md +14 -0
  82. invar/templates/protocol/universal/contracts-concept.md +37 -0
  83. invar/templates/protocol/universal/header.md +17 -0
  84. invar/templates/protocol/universal/session.md +17 -0
  85. invar/templates/protocol/universal/six-laws.md +10 -0
  86. invar/templates/protocol/universal/usbv.md +14 -0
  87. invar/templates/protocol/universal/visible-workflow.md +25 -0
  88. invar/templates/skills/develop/SKILL.md.jinja +98 -3
  89. invar/templates/skills/extensions/_registry.yaml +93 -0
  90. invar/templates/skills/extensions/acceptance/SKILL.md +383 -0
  91. invar/templates/skills/extensions/invar-onboard/SKILL.md +448 -0
  92. invar/templates/skills/extensions/invar-onboard/patterns/python.md +347 -0
  93. invar/templates/skills/extensions/invar-onboard/patterns/typescript.md +452 -0
  94. invar/templates/skills/extensions/invar-onboard/templates/assessment.md.jinja +214 -0
  95. invar/templates/skills/extensions/invar-onboard/templates/roadmap.md.jinja +168 -0
  96. invar/templates/skills/extensions/security/SKILL.md +382 -0
  97. invar/templates/skills/extensions/security/patterns/_common.yaml +126 -0
  98. invar/templates/skills/extensions/security/patterns/python.yaml +155 -0
  99. invar/templates/skills/extensions/security/patterns/typescript.yaml +194 -0
  100. invar/templates/skills/investigate/SKILL.md.jinja +15 -0
  101. invar/templates/skills/propose/SKILL.md.jinja +33 -0
  102. invar/templates/skills/review/SKILL.md.jinja +346 -71
  103. {invar_tools-1.7.1.dist-info → invar_tools-1.10.0.dist-info}/METADATA +326 -19
  104. invar_tools-1.10.0.dist-info/RECORD +173 -0
  105. invar/templates/examples/core_shell.py +0 -127
  106. invar/templates/protocol/INVAR.md +0 -310
  107. invar_tools-1.7.1.dist-info/RECORD +0 -112
  108. /invar/templates/examples/{workflow.md → python/workflow.md} +0 -0
  109. {invar_tools-1.7.1.dist-info → invar_tools-1.10.0.dist-info}/WHEEL +0 -0
  110. {invar_tools-1.7.1.dist-info → invar_tools-1.10.0.dist-info}/entry_points.txt +0 -0
  111. {invar_tools-1.7.1.dist-info → invar_tools-1.10.0.dist-info}/licenses/LICENSE +0 -0
  112. {invar_tools-1.7.1.dist-info → invar_tools-1.10.0.dist-info}/licenses/LICENSE-GPL +0 -0
  113. {invar_tools-1.7.1.dist-info → invar_tools-1.10.0.dist-info}/licenses/NOTICE +0 -0
@@ -0,0 +1,452 @@
1
+ # TypeScript Onboarding Patterns
2
+
3
+ > Patterns for migrating TypeScript projects to Invar framework.
4
+ > Library: `neverthrow`
5
+
6
+ ## 1. Overview
7
+
8
+ ```typescript
9
+ // Library: neverthrow
10
+ // Install: npm install neverthrow
11
+
12
+ import { Result, ResultAsync, ok, err, okAsync, errAsync } from 'neverthrow';
13
+ ```
14
+
15
+ ---
16
+
17
+ ## 2. Error Handling
18
+
19
+ ### 2.1 Sync vs Async Result
20
+
21
+ ```typescript
22
+ import { Result, ResultAsync, ok, err, okAsync, errAsync } from 'neverthrow';
23
+
24
+ // Sync (Core layer)
25
+ function validateEmail(email: string): Result<string, ValidationError> {
26
+ if (!email.includes('@')) {
27
+ return err(new ValidationError('invalid_email'));
28
+ }
29
+ return ok(email);
30
+ }
31
+
32
+ // Async (Shell layer)
33
+ function sendEmail(to: string): ResultAsync<void, EmailError> {
34
+ return ResultAsync.fromPromise(
35
+ emailClient.send({ to }),
36
+ (e) => new EmailError('send_failed', e)
37
+ );
38
+ }
39
+ ```
40
+
41
+ ### 2.2 Basic Transformation
42
+
43
+ ```typescript
44
+ // Before: throw
45
+ async function getUser(id: string): Promise<User> {
46
+ const user = await db.user.findUnique({ where: { id } });
47
+ if (!user) throw new NotFoundError(`User ${id} not found`);
48
+ return user;
49
+ }
50
+
51
+ // After: ResultAsync
52
+ function getUser(id: string): ResultAsync<User, GetUserError> {
53
+ return ResultAsync.fromPromise(
54
+ db.user.findUnique({ where: { id } }),
55
+ () => new DbError('query_failed')
56
+ ).andThen(user =>
57
+ user ? okAsync(user) : errAsync(new NotFoundError(`User ${id} not found`))
58
+ );
59
+ }
60
+ ```
61
+
62
+ ### 2.3 Chaining (andThen, map)
63
+
64
+ ```typescript
65
+ function processOrder(orderId: string): ResultAsync<Receipt, OrderError> {
66
+ return getOrder(orderId) // ResultAsync<Order, NotFoundError>
67
+ .andThen(validateOrder) // -> ResultAsync<Order, ValidationError>
68
+ .map(calculateTotal) // -> ResultAsync<number, ...>
69
+ .andThen(chargePayment) // -> ResultAsync<Payment, PaymentError>
70
+ .map(generateReceipt); // -> ResultAsync<Receipt, ...>
71
+ }
72
+ ```
73
+
74
+ ### 2.4 Error Type Hierarchy (Discriminated Union)
75
+
76
+ ```typescript
77
+ // Discriminated union for exhaustive checking
78
+ type OrderError =
79
+ | { type: 'NOT_FOUND'; orderId: string }
80
+ | { type: 'VALIDATION'; field: string; message: string }
81
+ | { type: 'PAYMENT'; code: string; retry: boolean };
82
+
83
+ function handleOrderError(error: OrderError): Response {
84
+ switch (error.type) {
85
+ case 'NOT_FOUND':
86
+ return notFound(`Order ${error.orderId} not found`);
87
+ case 'VALIDATION':
88
+ return badRequest(`${error.field}: ${error.message}`);
89
+ case 'PAYMENT':
90
+ return error.retry
91
+ ? serviceUnavailable('Payment failed, please retry')
92
+ : badRequest(`Payment error: ${error.code}`);
93
+ }
94
+ }
95
+ ```
96
+
97
+ ### 2.5 Safe Wrappers
98
+
99
+ ```typescript
100
+ // Catch exceptions -> Result
101
+ function safeJsonParse<T>(json: string): Result<T, ParseError> {
102
+ return Result.fromThrowable(
103
+ () => JSON.parse(json) as T,
104
+ (e) => new ParseError('invalid_json', e)
105
+ )();
106
+ }
107
+
108
+ // Wrap Promise -> ResultAsync
109
+ function safeFetch<T>(url: string): ResultAsync<T, FetchError> {
110
+ return ResultAsync.fromPromise(
111
+ fetch(url).then(r => r.json()),
112
+ (e) => new FetchError('fetch_failed', e)
113
+ );
114
+ }
115
+ ```
116
+
117
+ ### 2.6 Combining Multiple Results
118
+
119
+ ```typescript
120
+ import { Result, ResultAsync } from 'neverthrow';
121
+
122
+ // Combine array of Results
123
+ function validateOrderItems(items: OrderItem[]): Result<OrderItem[], ValidationError[]> {
124
+ const results = items.map(validateItem);
125
+ return Result.combineWithAllErrors(results); // Collect all errors
126
+ }
127
+
128
+ // Combine multiple independent Results
129
+ const combined = Result.combine([
130
+ validateName(name),
131
+ validateEmail(email),
132
+ validateAge(age),
133
+ ]);
134
+ // -> Result<[string, string, number], ValidationError>
135
+ ```
136
+
137
+ ---
138
+
139
+ ## 3. Contracts (Zod)
140
+
141
+ ### 3.1 Schema Definition
142
+
143
+ ```typescript
144
+ import { z } from 'zod';
145
+
146
+ // Basic schemas
147
+ const UserIdSchema = z.string()
148
+ .min(1, 'ID is required')
149
+ .max(36, 'ID too long')
150
+ .regex(/^[a-zA-Z0-9-]+$/, 'Invalid ID format');
151
+
152
+ const EmailSchema = z.string()
153
+ .email('Invalid email format')
154
+ .transform(s => s.toLowerCase());
155
+
156
+ // Composite schema
157
+ const CreateUserSchema = z.object({
158
+ email: EmailSchema,
159
+ name: z.string().min(1).max(100),
160
+ role: z.enum(['admin', 'user', 'guest']).default('user'),
161
+ });
162
+
163
+ // Schema with refinement
164
+ const OrderSchema = z.object({
165
+ items: z.array(z.object({
166
+ sku: z.string(),
167
+ qty: z.number().int().positive(),
168
+ price: z.number().positive(),
169
+ })).min(1, 'Order must have at least one item'),
170
+ }).refine(
171
+ (order) => order.items.reduce((sum, i) => sum + i.qty, 0) <= 100,
172
+ { message: 'Order cannot exceed 100 items total' }
173
+ );
174
+ ```
175
+
176
+ ### 3.2 Zod + Result Integration
177
+
178
+ ```typescript
179
+ import { z } from 'zod';
180
+ import { Result, ok, err } from 'neverthrow';
181
+
182
+ type ValidationError = {
183
+ type: 'VALIDATION';
184
+ issues: z.ZodIssue[];
185
+ };
186
+
187
+ function validate<T>(schema: z.ZodSchema<T>, data: unknown): Result<T, ValidationError> {
188
+ const result = schema.safeParse(data);
189
+ if (result.success) {
190
+ return ok(result.data);
191
+ }
192
+ return err({ type: 'VALIDATION', issues: result.error.issues });
193
+ }
194
+
195
+ // Usage
196
+ function createUser(input: unknown): ResultAsync<User, CreateUserError> {
197
+ return validate(CreateUserSchema, input)
198
+ .asyncAndThen(validated =>
199
+ checkEmailUnique(validated.email)
200
+ .map(() => validated)
201
+ )
202
+ .andThen(saveUser);
203
+ }
204
+ ```
205
+
206
+ ### 3.3 Branded Types
207
+
208
+ ```typescript
209
+ import { z } from 'zod';
210
+ import { ResultAsync } from 'neverthrow';
211
+
212
+ // Type-safe IDs that can't be mixed up
213
+ const UserId = z.string().uuid().brand<'UserId'>();
214
+ type UserId = z.infer<typeof UserId>;
215
+
216
+ const OrderId = z.string().uuid().brand<'OrderId'>();
217
+ type OrderId = z.infer<typeof OrderId>;
218
+
219
+ function getUser(id: UserId): ResultAsync<User, UserError> { ... }
220
+ function getOrder(id: OrderId): ResultAsync<Order, OrderError> { ... }
221
+
222
+ // Compile error: OrderId cannot be assigned to UserId
223
+ // getUser(orderId);
224
+ ```
225
+
226
+ ### 3.4 JSDoc Contracts
227
+
228
+ ```typescript
229
+ /**
230
+ * Calculate order total with tax.
231
+ *
232
+ * @pre items.length > 0
233
+ * @pre taxRate >= 0 && taxRate <= 1
234
+ * @post result >= 0
235
+ *
236
+ * @example
237
+ * ```ts
238
+ * const total = calculateTotal([{price: 100, qty: 2}], 0.1);
239
+ * assert(total === 220); // 200 + 20 tax
240
+ * ```
241
+ */
242
+ function calculateTotal(items: OrderItem[], taxRate: number): number {
243
+ const subtotal = items.reduce((sum, item) => sum + item.price * item.qty, 0);
244
+ return subtotal * (1 + taxRate);
245
+ }
246
+ ```
247
+
248
+ ---
249
+
250
+ ## 4. Core/Shell Separation
251
+
252
+ ### 4.1 Directory Structure
253
+
254
+ ```
255
+ lib/
256
+ ├── core/ # Pure functions, sync preferred
257
+ │ ├── order/
258
+ │ │ ├── validation.ts # Zod schemas + pure validation
259
+ │ │ ├── calculation.ts # Pure calculations
260
+ │ │ └── types.ts # Domain types
261
+ │ └── user/
262
+ │ └── ...
263
+ ├── services/ # Shell: I/O orchestration
264
+ │ ├── order.service.ts
265
+ │ └── user.service.ts
266
+ ├── repositories/ # Shell: Data access
267
+ │ ├── order.repository.ts
268
+ │ └── user.repository.ts
269
+ └── errors/ # Error type definitions
270
+ └── index.ts
271
+ ```
272
+
273
+ ### 4.2 Core Layer Example
274
+
275
+ ```typescript
276
+ // lib/core/order/validation.ts
277
+ import { z } from 'zod';
278
+ import { Result, ok, err } from 'neverthrow';
279
+
280
+ export const OrderItemSchema = z.object({
281
+ sku: z.string().min(1),
282
+ qty: z.number().int().positive(),
283
+ price: z.number().positive(),
284
+ });
285
+
286
+ export type OrderItem = z.infer<typeof OrderItemSchema>;
287
+
288
+ // Pure validation (sync Result)
289
+ export function validateOrder(order: unknown): Result<Order, ValidationError> {
290
+ const result = OrderSchema.safeParse(order);
291
+ if (!result.success) {
292
+ return err({ type: 'VALIDATION', issues: result.error.issues });
293
+ }
294
+ return ok(result.data);
295
+ }
296
+
297
+ // Pure calculation
298
+ export function calculateSubtotal(items: OrderItem[]): number {
299
+ return items.reduce((sum, item) => sum + item.qty * item.price, 0);
300
+ }
301
+
302
+ export function applyDiscount(amount: number, rate: number): number {
303
+ return amount * (1 - rate);
304
+ }
305
+ ```
306
+
307
+ ### 4.3 Shell Layer Example
308
+
309
+ ```typescript
310
+ // lib/services/order.service.ts
311
+ import { ResultAsync } from 'neverthrow';
312
+ import { validateOrder, calculateSubtotal } from '../core/order/validation';
313
+ import { OrderRepository } from '../repositories/order.repository';
314
+
315
+ export class OrderService {
316
+ constructor(private readonly repo: OrderRepository) {}
317
+
318
+ processOrder(orderId: string): ResultAsync<Receipt, OrderError> {
319
+ return this.repo.findById(orderId) // Shell: I/O
320
+ .andThen(validateOrder) // Core: pure (sync->async)
321
+ .map(order => ({ // Core: pure transform
322
+ order,
323
+ subtotal: calculateSubtotal(order.items),
324
+ }))
325
+ .andThen(({ order, subtotal }) =>
326
+ this.getDiscount(order.id)
327
+ .map(discount => applyDiscount(subtotal, discount))
328
+ )
329
+ .andThen(total => this.chargePayment(total)) // Shell: I/O
330
+ .map(this.generateReceipt); // Core: pure
331
+ }
332
+ }
333
+ ```
334
+
335
+ ---
336
+
337
+ ## 5. Next.js Integration
338
+
339
+ ### 5.1 Server Actions + Result
340
+
341
+ ```typescript
342
+ // app/actions/order.ts
343
+ 'use server';
344
+
345
+ import { ResultAsync } from 'neverthrow';
346
+ import { orderService } from '@/lib/services';
347
+
348
+ type ActionResult<T> =
349
+ | { success: true; data: T }
350
+ | { success: false; error: { type: string; message: string } };
351
+
352
+ export async function createOrder(formData: FormData): Promise<ActionResult<Order>> {
353
+ const input = Object.fromEntries(formData);
354
+ const result = await orderService.createOrder(input);
355
+
356
+ return result.match(
357
+ (order) => ({ success: true, data: order }),
358
+ (error) => ({
359
+ success: false,
360
+ error: { type: error.type, message: formatError(error) }
361
+ })
362
+ );
363
+ }
364
+ ```
365
+
366
+ ### 5.2 React Hook
367
+
368
+ ```typescript
369
+ // hooks/useAction.ts
370
+ import { useState, useCallback } from 'react';
371
+
372
+ export function useAction<TInput, TOutput>(
373
+ action: (input: TInput) => Promise<ActionResult<TOutput>>
374
+ ) {
375
+ const [isLoading, setIsLoading] = useState(false);
376
+ const [error, setError] = useState<string | null>(null);
377
+ const [data, setData] = useState<TOutput | null>(null);
378
+
379
+ const execute = useCallback(async (input: TInput) => {
380
+ setIsLoading(true);
381
+ setError(null);
382
+
383
+ const result = await action(input);
384
+
385
+ if (result.success) {
386
+ setData(result.data);
387
+ } else {
388
+ setError(result.error.message);
389
+ }
390
+
391
+ setIsLoading(false);
392
+ return result;
393
+ }, [action]);
394
+
395
+ return { execute, isLoading, error, data };
396
+ }
397
+ ```
398
+
399
+ ---
400
+
401
+ ## 6. Must Keep `throw` Scenarios
402
+
403
+ ```typescript
404
+ // 1. React Error Boundary (must throw)
405
+ async function OrderDetails({ id }: { id: string }) {
406
+ const result = await orderService.getOrder(id);
407
+ if (result.isErr()) {
408
+ throw new Error(result.error.message); // Let ErrorBoundary catch
409
+ }
410
+ return <OrderView order={result.value} />;
411
+ }
412
+
413
+ // 2. Next.js redirect/notFound (must throw)
414
+ import { redirect, notFound } from 'next/navigation';
415
+
416
+ export default async function OrderPage({ params }: { params: { id: string } }) {
417
+ const result = await orderService.getOrder(params.id);
418
+
419
+ if (result.isErr()) {
420
+ if (result.error.type === 'NOT_FOUND') {
421
+ notFound(); // throws internally
422
+ }
423
+ if (result.error.type === 'UNAUTHORIZED') {
424
+ redirect('/login'); // throws internally
425
+ }
426
+ throw new Error(result.error.message);
427
+ }
428
+
429
+ return <OrderDetails order={result.value} />;
430
+ }
431
+
432
+ // 3. Constructors (cannot return Result)
433
+ // 4. Top-level try-catch in entry points
434
+ ```
435
+
436
+ ---
437
+
438
+ ## 7. Migration Checklist
439
+
440
+ - [ ] Install `neverthrow` library: `npm install neverthrow`
441
+ - [ ] Install `zod` for validation: `npm install zod`
442
+ - [ ] Define error type hierarchy (discriminated unions)
443
+ - [ ] Transform entry points to return `ResultAsync<T, E>`
444
+ - [ ] Extract pure functions to `lib/core/` directory
445
+ - [ ] Add Zod schemas for Core validation
446
+ - [ ] Add JSDoc `@pre/@post` comments to Core functions
447
+ - [ ] Run TypeScript compiler in strict mode
448
+ - [ ] Update API handlers to use `result.match()`
449
+
450
+ ---
451
+
452
+ *Pattern Library v1.0 — LX-09*
@@ -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*