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,168 @@
1
+ {#
2
+ Expected variables:
3
+ - project_name: str
4
+ - timestamp: str
5
+ - total_days: int
6
+ - session_count: int
7
+ - phases: list of {id: str, name: str, days: int, objective: str,
8
+ tasks: [{day: int, files: [str], scope: str}],
9
+ sessions: [{files: [str], estimate: str}],
10
+ gates: [str], verification_command?: str, rollback_action?: str}
11
+ - result_library: str
12
+ - install_command: str
13
+ - additional_deps?: [{name: str, purpose: str, install: str}]
14
+ - target_coverage?: int (default 80)
15
+ - dependency_graph?: str
16
+ - notes?: str
17
+ #}
18
+ # Invar Onboarding Roadmap
19
+
20
+ > Project: {{ project_name }}
21
+ > Generated: {{ timestamp }}
22
+ > Based on: docs/invar-onboard-assessment.md
23
+
24
+ ## Overview
25
+
26
+ | Metric | Value |
27
+ |--------|-------|
28
+ | Total Phases | {{ phases | length }} |
29
+ | Total Days | {{ total_days }} |
30
+ | Agent Sessions | {{ session_count }} |
31
+
32
+ ---
33
+
34
+ {% for phase in phases %}
35
+ ## Phase {{ loop.index }}: {{ phase.name }} ({{ phase.days }} days)
36
+
37
+ ### Objective
38
+
39
+ {{ phase.objective }}
40
+
41
+ ### Tasks
42
+
43
+ | Day | Files | Scope |
44
+ |-----|-------|-------|
45
+ {% for task in phase.tasks %}
46
+ | {{ task.day }} | {{ task.files | join(", ") }} | {{ task.scope }} |
47
+ {% endfor %}
48
+
49
+ ### Sessions
50
+
51
+ | Session | Files | Estimated |
52
+ |---------|-------|-----------|
53
+ {% for session in phase.sessions %}
54
+ | {{ phase.id }}.{{ loop.index }} | {{ session.files | join(", ") }} | {{ session.estimate }} |
55
+ {% endfor %}
56
+
57
+ ### Gate Checklist
58
+
59
+ {% for gate in phase.gates %}
60
+ - [ ] {{ gate }}
61
+ {% endfor %}
62
+
63
+ ### Verification
64
+
65
+ ```bash
66
+ {{ phase.verification_command | default("invar guard") }}
67
+ ```
68
+
69
+ ---
70
+
71
+ {% endfor %}
72
+
73
+ ## Rollback Strategy
74
+
75
+ | Phase | Rollback Point | Recovery Action |
76
+ |-------|----------------|-----------------|
77
+ {% for phase in phases %}
78
+ | {{ loop.index }} | Pre-{{ phase.name }} | {{ phase.rollback_action | default("Revert " + phase.name + " changes") }} |
79
+ {% endfor %}
80
+
81
+ ## Session Guidelines
82
+
83
+ ### Context Limits
84
+
85
+ Each agent session should:
86
+ - Focus on 2-3 files maximum
87
+ - Complete within 1 context window
88
+ - End with successful `invar guard`
89
+
90
+ ### Handoff Protocol
91
+
92
+ 1. **Before session end:**
93
+ - Commit all changes
94
+ - Update this roadmap (mark completed)
95
+ - Document any deviations
96
+
97
+ 2. **Session start:**
98
+ - Read assessment and this roadmap
99
+ - Review previous session's changes
100
+ - Verify Guard passes before proceeding
101
+
102
+ ### Emergency Procedures
103
+
104
+ | Situation | Action |
105
+ |-----------|--------|
106
+ | Guard fails after changes | Revert to last passing commit |
107
+ | Unexpected dependency | Add to blockers, pause phase |
108
+ | Scope creep detected | Stop, update assessment |
109
+
110
+ ## Progress Tracking
111
+
112
+ ### Phase Status
113
+
114
+ | Phase | Status | Started | Completed | Notes |
115
+ |-------|--------|---------|-----------|-------|
116
+ {% for phase in phases %}
117
+ | {{ loop.index }}. {{ phase.name }} | ⬜ Pending | - | - | |
118
+ {% endfor %}
119
+
120
+ ### Session Log
121
+
122
+ | Session | Date | Duration | Files Changed | Guard | Notes |
123
+ |---------|------|----------|---------------|-------|-------|
124
+ | - | - | - | - | - | - |
125
+
126
+ ## Dependencies
127
+
128
+ ### External Libraries
129
+
130
+ | Library | Purpose | Install Command |
131
+ |---------|---------|-----------------|
132
+ | {{ result_library }} | Result types | {{ install_command }} |
133
+ {% for dep in additional_deps %}
134
+ | {{ dep.name }} | {{ dep.purpose }} | {{ dep.install }} |
135
+ {% endfor %}
136
+
137
+ ### Internal Dependencies
138
+
139
+ ```
140
+ {{ dependency_graph | default("No complex internal dependencies.") }}
141
+ ```
142
+
143
+ ## Success Criteria
144
+
145
+ ### Phase Completion
146
+
147
+ Each phase is complete when:
148
+ 1. All tasks checked off
149
+ 2. Gate checklist passed
150
+ 3. `invar guard` passes
151
+ 4. E2E tests still pass (if applicable)
152
+
153
+ ### Project Completion
154
+
155
+ Project migration complete when:
156
+ - [ ] All phases completed
157
+ - [ ] Full `invar guard` passes
158
+ - [ ] Contract coverage > {{ target_coverage | default(80) }}%
159
+ - [ ] All Core functions have doctests
160
+ - [ ] Shell functions return Result types
161
+
162
+ ## Notes
163
+
164
+ {{ notes | default("No additional notes.") }}
165
+
166
+ ---
167
+
168
+ *Generated by /invar-onboard*
@@ -0,0 +1,51 @@
1
+ {# INVAR.md Composition Template
2
+ Composes universal protocol + language-specific fragments
3
+ Variables: language (python|typescript)
4
+ #}
5
+ {% include "protocol/universal/header.md" %}
6
+
7
+ {% include "protocol/universal/six-laws.md" %}
8
+
9
+ {% include "protocol/universal/architecture.md" %}
10
+
11
+ {% if language == "python" %}
12
+ {% include "protocol/python/architecture-examples.md" %}
13
+ {% elif language == "typescript" %}
14
+ {% include "protocol/typescript/architecture-examples.md" %}
15
+ {% endif %}
16
+
17
+ {% if language == "python" %}
18
+ {% include "protocol/python/contracts-syntax.md" %}
19
+ {% elif language == "typescript" %}
20
+ {% include "protocol/typescript/contracts-syntax.md" %}
21
+ {% endif %}
22
+
23
+ {% include "protocol/universal/session.md" %}
24
+
25
+ {% include "protocol/universal/usbv.md" %}
26
+
27
+ {% include "protocol/universal/visible-workflow.md" %}
28
+
29
+ {% include "protocol/universal/completion.md" %}
30
+
31
+ {% if language == "python" %}
32
+ {% include "protocol/python/markers.md" %}
33
+ {% elif language == "typescript" %}
34
+ {% include "protocol/typescript/markers.md" %}
35
+ {% endif %}
36
+
37
+ {% if language == "python" %}
38
+ {% include "protocol/python/tools.md" %}
39
+ {% elif language == "typescript" %}
40
+ {% include "protocol/typescript/tools.md" %}
41
+ {% endif %}
42
+
43
+ {% if language == "python" %}
44
+ {% include "protocol/python/troubleshooting.md" %}
45
+ {% elif language == "typescript" %}
46
+ {% include "protocol/typescript/troubleshooting.md" %}
47
+ {% endif %}
48
+
49
+ ---
50
+
51
+ *Protocol v5.0 — USBV workflow (DX-32) | [Examples](.invar/examples/)*
@@ -0,0 +1,41 @@
1
+ ## Core Example (Python)
2
+
3
+ ```python
4
+ from deal import pre, post
5
+
6
+ @pre(lambda price, discount: price > 0 and 0 <= discount <= 1)
7
+ @post(lambda result: result >= 0)
8
+ def discounted_price(price: float, discount: float) -> float:
9
+ """
10
+ >>> discounted_price(100, 0.2)
11
+ 80.0
12
+ >>> discounted_price(100, 0) # Edge: no discount
13
+ 100.0
14
+ """
15
+ return price * (1 - discount)
16
+ ```
17
+
18
+ **Self-test:** Can someone else write the exact same function from just @pre/@post + doctests?
19
+
20
+ **Forbidden in Core:** `os`, `sys`, `subprocess`, `pathlib`, `open`, `requests`, `datetime.now`
21
+
22
+ ## Shell Example (Python)
23
+
24
+ ```python
25
+ from pathlib import Path
26
+ from returns.result import Result, Success, Failure
27
+
28
+ def read_config(path: Path) -> Result[dict, str]:
29
+ """Shell: handles I/O, returns Result for error handling."""
30
+ try:
31
+ import json
32
+ return Success(json.loads(path.read_text()))
33
+ except FileNotFoundError:
34
+ return Failure(f"File not found: {path}")
35
+ except json.JSONDecodeError as e:
36
+ return Failure(f"Invalid JSON: {e}")
37
+ ```
38
+
39
+ **Pattern:** Shell reads file → passes content to Core → returns Result.
40
+
41
+ More examples: `.invar/examples/`