@plures/praxis 1.2.0 → 1.2.10
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.
- package/README.md +10 -96
- package/dist/browser/{adapter-TM4IS5KT.js → adapter-CIMBGDC7.js} +5 -3
- package/dist/browser/{chunk-LE2ZJYFC.js → chunk-K377RW4V.js} +76 -0
- package/dist/{node/chunk-JQ64KMLN.js → browser/chunk-MBVHLOU2.js} +12 -1
- package/dist/browser/index.d.ts +32 -5
- package/dist/browser/index.js +15 -7
- package/dist/browser/integrations/svelte.d.ts +2 -2
- package/dist/browser/integrations/svelte.js +1 -1
- package/dist/browser/{reactive-engine.svelte-C9OpcTHf.d.ts → reactive-engine.svelte-9aS0kTa8.d.ts} +136 -1
- package/dist/node/{adapter-K6DOX6XS.js → adapter-75ISSMWD.js} +5 -3
- package/dist/node/chunk-5RH7UAQC.js +486 -0
- package/dist/{browser/chunk-JQ64KMLN.js → node/chunk-MBVHLOU2.js} +12 -1
- package/dist/node/{chunk-LE2ZJYFC.js → chunk-PRPQO6R5.js} +3 -72
- package/dist/node/chunk-R2PSBPKQ.js +150 -0
- package/dist/node/chunk-WZ6B3LZ6.js +638 -0
- package/dist/node/cli/index.cjs +2316 -832
- package/dist/node/cli/index.js +18 -0
- package/dist/node/components/index.d.cts +3 -2
- package/dist/node/components/index.d.ts +3 -2
- package/dist/node/index.cjs +620 -38
- package/dist/node/index.d.cts +259 -5
- package/dist/node/index.d.ts +259 -5
- package/dist/node/index.js +55 -65
- package/dist/node/integrations/svelte.cjs +76 -0
- package/dist/node/integrations/svelte.d.cts +2 -2
- package/dist/node/integrations/svelte.d.ts +2 -2
- package/dist/node/integrations/svelte.js +2 -1
- package/dist/node/{reactive-engine.svelte-1M4m_C_v.d.cts → reactive-engine.svelte-BFIZfawz.d.cts} +199 -1
- package/dist/node/{reactive-engine.svelte-ChNFn4Hj.d.ts → reactive-engine.svelte-CRNqHlbv.d.ts} +199 -1
- package/dist/node/reverse-W7THPV45.js +193 -0
- package/dist/node/{terminal-adapter-CWka-yL8.d.ts → terminal-adapter-B-UK_Vdz.d.ts} +28 -3
- package/dist/node/{terminal-adapter-CDzxoLKR.d.cts → terminal-adapter-BQSIF5bf.d.cts} +28 -3
- package/dist/node/validate-CNHUULQE.js +180 -0
- package/docs/core/pluresdb-integration.md +15 -15
- package/docs/decision-ledger/BEHAVIOR_LEDGER.md +225 -0
- package/docs/decision-ledger/DecisionLedger.tla +180 -0
- package/docs/decision-ledger/IMPLEMENTATION_SUMMARY.md +217 -0
- package/docs/decision-ledger/LATEST.md +166 -0
- package/docs/guides/cicd-pipeline.md +142 -0
- package/package.json +2 -2
- package/src/__tests__/cli-validate.test.ts +197 -0
- package/src/__tests__/decision-ledger.test.ts +485 -0
- package/src/__tests__/reverse-generator.test.ts +189 -0
- package/src/__tests__/scanner.test.ts +215 -0
- package/src/cli/commands/reverse.ts +289 -0
- package/src/cli/commands/validate.ts +264 -0
- package/src/cli/index.ts +47 -0
- package/src/core/pluresdb/adapter.ts +45 -2
- package/src/core/rules.ts +133 -0
- package/src/decision-ledger/README.md +400 -0
- package/src/decision-ledger/REVERSE_ENGINEERING.md +484 -0
- package/src/decision-ledger/facts-events.ts +121 -0
- package/src/decision-ledger/index.ts +70 -0
- package/src/decision-ledger/ledger.ts +246 -0
- package/src/decision-ledger/logic-ledger.ts +158 -0
- package/src/decision-ledger/reverse-generator.ts +426 -0
- package/src/decision-ledger/scanner.ts +506 -0
- package/src/decision-ledger/types.ts +247 -0
- package/src/decision-ledger/validation.ts +336 -0
- package/src/dsl/index.ts +13 -2
- package/src/index.browser.ts +2 -0
- package/src/index.ts +36 -0
- package/src/integrations/pluresdb.ts +14 -2
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
# Decision Ledger Integration
|
|
2
|
+
|
|
3
|
+
The Decision Ledger Integration extends Praxis with contract-based validation and documentation for rules and constraints, enabling teams to explicitly document, test, and enforce behavioral contracts.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Modern software systems—especially those incorporating AI-assisted logic, rules engines, and automated decision-making—lack a reliable, enforceable mechanism to explain, audit, and evolve decision logic over time. The Decision Ledger addresses this gap by providing:
|
|
8
|
+
|
|
9
|
+
1. **Contract Objects** for rules and constraints with canonical behavior, examples, invariants, assumptions, and references
|
|
10
|
+
2. **Compliance Pipeline** for build-time and runtime validation
|
|
11
|
+
3. **First-class Facts** for tracking missing artifacts
|
|
12
|
+
4. **Immutable Logic Ledger** with assumption invalidation and versioned snapshots
|
|
13
|
+
5. **Reverse Engineering** for migrating existing codebases to contracts
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
### For New Projects
|
|
18
|
+
|
|
19
|
+
Start with contracts from the beginning:
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { defineContract, defineRule } from '@plures/praxis';
|
|
23
|
+
|
|
24
|
+
// Define a contract
|
|
25
|
+
const loginContract = defineContract({
|
|
26
|
+
ruleId: 'auth.login',
|
|
27
|
+
behavior: 'Process login events and create user session facts',
|
|
28
|
+
examples: [
|
|
29
|
+
{
|
|
30
|
+
given: 'User provides valid credentials',
|
|
31
|
+
when: 'LOGIN event is received',
|
|
32
|
+
then: 'UserSessionCreated fact is emitted'
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
invariants: [
|
|
36
|
+
'Session must have unique ID',
|
|
37
|
+
'Session must have timestamp'
|
|
38
|
+
],
|
|
39
|
+
assumptions: [
|
|
40
|
+
{
|
|
41
|
+
id: 'assume-unique-username',
|
|
42
|
+
statement: 'Usernames are unique across the system',
|
|
43
|
+
confidence: 0.9,
|
|
44
|
+
justification: 'Standard practice in authentication systems',
|
|
45
|
+
impacts: ['spec', 'tests'],
|
|
46
|
+
status: 'active'
|
|
47
|
+
}
|
|
48
|
+
],
|
|
49
|
+
references: [
|
|
50
|
+
{ type: 'doc', url: 'https://docs.example.com/auth' }
|
|
51
|
+
]
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Attach contract to rule
|
|
55
|
+
const loginRule = defineRule({
|
|
56
|
+
id: 'auth.login',
|
|
57
|
+
description: 'Process login events',
|
|
58
|
+
impl: (state, events) => {
|
|
59
|
+
// Implementation
|
|
60
|
+
return [];
|
|
61
|
+
},
|
|
62
|
+
meta: { contract: loginContract }
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### For Existing Projects (Reverse Engineering)
|
|
67
|
+
|
|
68
|
+
Automatically generate contracts from existing code:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Scan your codebase and generate contracts
|
|
72
|
+
praxis reverse
|
|
73
|
+
|
|
74
|
+
# With interactive review
|
|
75
|
+
praxis reverse --interactive
|
|
76
|
+
|
|
77
|
+
# Using AI for better quality
|
|
78
|
+
export OPENAI_API_KEY="your-key"
|
|
79
|
+
praxis reverse --ai openai
|
|
80
|
+
|
|
81
|
+
# See REVERSE_ENGINEERING.md for complete guide
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Build-time Validation
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Validate contracts in your registry
|
|
88
|
+
praxis validate
|
|
89
|
+
|
|
90
|
+
# Output as JSON
|
|
91
|
+
praxis validate --output json
|
|
92
|
+
|
|
93
|
+
# Output as SARIF (for CI/CD integration)
|
|
94
|
+
praxis validate --output sarif
|
|
95
|
+
|
|
96
|
+
# Strict mode (exit with error if contracts missing)
|
|
97
|
+
praxis validate --strict
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Example output:
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
Contract Validation Report
|
|
104
|
+
==================================================
|
|
105
|
+
|
|
106
|
+
Total: 5
|
|
107
|
+
Complete: 3
|
|
108
|
+
Incomplete: 1
|
|
109
|
+
Missing: 1
|
|
110
|
+
|
|
111
|
+
✓ Complete Contracts:
|
|
112
|
+
✓ auth.login (v1.0.0)
|
|
113
|
+
✓ auth.logout (v1.0.0)
|
|
114
|
+
✓ cart.checkout (v1.0.0)
|
|
115
|
+
|
|
116
|
+
✗ Incomplete Contracts:
|
|
117
|
+
⚠ cart.addItem - Missing: tests
|
|
118
|
+
Contract is incomplete: missing tests
|
|
119
|
+
|
|
120
|
+
✗ No Contract:
|
|
121
|
+
✗ order.process
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Runtime Validation
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
import { validateContracts } from '@plures/praxis';
|
|
128
|
+
|
|
129
|
+
const registry = new PraxisRegistry();
|
|
130
|
+
// ... register rules with contracts
|
|
131
|
+
|
|
132
|
+
const report = validateContracts(registry, {
|
|
133
|
+
strict: true,
|
|
134
|
+
requiredFields: ['behavior', 'examples']
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
console.log(`Complete: ${report.complete.length}`);
|
|
138
|
+
console.log(`Incomplete: ${report.incomplete.length}`);
|
|
139
|
+
console.log(`Missing: ${report.missing.length}`);
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Contract Gap Acknowledgment
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
import { AcknowledgeContractGap } from '@plures/praxis';
|
|
146
|
+
|
|
147
|
+
// Acknowledge a known gap with justification
|
|
148
|
+
const event = AcknowledgeContractGap.create({
|
|
149
|
+
ruleId: 'legacy.process',
|
|
150
|
+
missing: ['spec', 'tests'],
|
|
151
|
+
justification: 'Legacy rule to be deprecated in v2.0',
|
|
152
|
+
expiresAt: '2025-12-31'
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Behavior Ledger
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
import { createBehaviorLedger, defineContract } from '@plures/praxis';
|
|
160
|
+
|
|
161
|
+
const ledger = createBehaviorLedger();
|
|
162
|
+
|
|
163
|
+
// Append a contract to the ledger
|
|
164
|
+
ledger.append({
|
|
165
|
+
id: 'entry-1',
|
|
166
|
+
timestamp: new Date().toISOString(),
|
|
167
|
+
status: 'active',
|
|
168
|
+
author: 'team',
|
|
169
|
+
contract: loginContract
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// Update contract (supersedes previous entry)
|
|
173
|
+
const updatedContract = defineContract({
|
|
174
|
+
ruleId: 'auth.login',
|
|
175
|
+
behavior: 'Updated behavior description',
|
|
176
|
+
examples: [...],
|
|
177
|
+
invariants: [...],
|
|
178
|
+
version: '2.0.0'
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
ledger.append({
|
|
182
|
+
id: 'entry-2',
|
|
183
|
+
timestamp: new Date().toISOString(),
|
|
184
|
+
status: 'active',
|
|
185
|
+
author: 'team',
|
|
186
|
+
contract: updatedContract,
|
|
187
|
+
supersedes: 'entry-1',
|
|
188
|
+
reason: 'behavior-updated'
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Query ledger
|
|
192
|
+
const latest = ledger.getLatestEntry('auth.login');
|
|
193
|
+
const history = ledger.getEntriesForRule('auth.login');
|
|
194
|
+
const activeAssumptions = ledger.getActiveAssumptions();
|
|
195
|
+
|
|
196
|
+
// Export/import
|
|
197
|
+
const json = ledger.toJSON();
|
|
198
|
+
const restored = BehaviorLedger.fromJSON(json);
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## API Reference
|
|
202
|
+
|
|
203
|
+
### Types
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
interface Contract {
|
|
207
|
+
ruleId: string;
|
|
208
|
+
behavior: string;
|
|
209
|
+
examples: Example[];
|
|
210
|
+
invariants: string[];
|
|
211
|
+
assumptions?: Assumption[];
|
|
212
|
+
references?: Reference[];
|
|
213
|
+
version?: string;
|
|
214
|
+
timestamp?: string;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
interface Example {
|
|
218
|
+
given: string;
|
|
219
|
+
when: string;
|
|
220
|
+
then: string;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
interface Assumption {
|
|
224
|
+
id: string;
|
|
225
|
+
statement: string;
|
|
226
|
+
confidence: number; // 0.0 to 1.0
|
|
227
|
+
justification: string;
|
|
228
|
+
derivedFrom?: string;
|
|
229
|
+
impacts: Array<'spec' | 'tests' | 'code'>;
|
|
230
|
+
status: 'active' | 'revised' | 'invalidated';
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
interface Reference {
|
|
234
|
+
type: string;
|
|
235
|
+
url?: string;
|
|
236
|
+
description?: string;
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Functions
|
|
241
|
+
|
|
242
|
+
#### `defineContract(options: DefineContractOptions): Contract`
|
|
243
|
+
|
|
244
|
+
Creates a contract for a rule or constraint.
|
|
245
|
+
|
|
246
|
+
#### `validateContracts(registry: PraxisRegistry, options?: ValidateOptions): ValidationReport`
|
|
247
|
+
|
|
248
|
+
Validates all rules and constraints in a registry.
|
|
249
|
+
|
|
250
|
+
#### `formatValidationReport(report: ValidationReport): string`
|
|
251
|
+
|
|
252
|
+
Formats a validation report as human-readable text.
|
|
253
|
+
|
|
254
|
+
#### `formatValidationReportJSON(report: ValidationReport): string`
|
|
255
|
+
|
|
256
|
+
Formats a validation report as JSON.
|
|
257
|
+
|
|
258
|
+
#### `formatValidationReportSARIF(report: ValidationReport): string`
|
|
259
|
+
|
|
260
|
+
Formats a validation report as SARIF (for CI/CD integration).
|
|
261
|
+
|
|
262
|
+
#### `scanRepository(options: ScanOptions): Promise<ScanResult>`
|
|
263
|
+
|
|
264
|
+
Scans a repository to discover existing rules and constraints.
|
|
265
|
+
|
|
266
|
+
#### `generateContractFromRule(descriptor: RuleDescriptor, options: ReverseGenerationOptions): Promise<GenerationResult>`
|
|
267
|
+
|
|
268
|
+
Generates a contract from an existing rule or constraint using AI or heuristics.
|
|
269
|
+
|
|
270
|
+
### Facts and Events
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
// Fact: Contract is missing
|
|
274
|
+
const fact = ContractMissing.create({
|
|
275
|
+
ruleId: 'test.rule',
|
|
276
|
+
missing: ['behavior', 'examples'],
|
|
277
|
+
severity: 'warning'
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
// Event: Acknowledge contract gap
|
|
281
|
+
const event = AcknowledgeContractGap.create({
|
|
282
|
+
ruleId: 'legacy.rule',
|
|
283
|
+
missing: ['tests'],
|
|
284
|
+
justification: 'To be deprecated',
|
|
285
|
+
expiresAt: '2025-12-31'
|
|
286
|
+
});
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## CLI Commands
|
|
290
|
+
|
|
291
|
+
### `praxis validate`
|
|
292
|
+
|
|
293
|
+
Validates contract coverage for rules and constraints.
|
|
294
|
+
|
|
295
|
+
**Options:**
|
|
296
|
+
- `--output <format>` - Output format: `console` (default), `json`, or `sarif`
|
|
297
|
+
- `--strict` - Exit with error if contracts are missing (default: false)
|
|
298
|
+
- `--registry <path>` - Path to registry module (optional)
|
|
299
|
+
|
|
300
|
+
**Examples:**
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
# Basic validation
|
|
304
|
+
praxis validate
|
|
305
|
+
|
|
306
|
+
# JSON output for programmatic processing
|
|
307
|
+
praxis validate --output json
|
|
308
|
+
|
|
309
|
+
# SARIF output for GitHub Actions/CI integration
|
|
310
|
+
praxis validate --output sarif > results.sarif
|
|
311
|
+
|
|
312
|
+
# Strict mode for CI/CD pipelines
|
|
313
|
+
praxis validate --strict
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### `praxis reverse`
|
|
317
|
+
|
|
318
|
+
Reverse engineer contracts from existing codebase.
|
|
319
|
+
|
|
320
|
+
**Options:**
|
|
321
|
+
- `-d, --dir <path>` - Root directory to scan (default: current directory)
|
|
322
|
+
- `--ai <provider>` - AI provider: `none` (default), `github-copilot`, `openai`, `auto`
|
|
323
|
+
- `-o, --output <dir>` - Output directory for contracts (default: `./contracts`)
|
|
324
|
+
- `--ledger` - Write to logic ledger (default: false)
|
|
325
|
+
- `--dry-run` - Preview without writing files (default: false)
|
|
326
|
+
- `-i, --interactive` - Interactive mode, prompt for each (default: false)
|
|
327
|
+
- `--confidence <threshold>` - Confidence threshold 0.0-1.0 (default: 0.7)
|
|
328
|
+
- `--limit <n>` - Max number of rules to process
|
|
329
|
+
- `--author <name>` - Author name for ledger entries (default: 'reverse-engineer')
|
|
330
|
+
- `--format <format>` - Output format: `json` (default), `yaml`
|
|
331
|
+
|
|
332
|
+
**Examples:**
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
# Basic reverse engineering
|
|
336
|
+
praxis reverse
|
|
337
|
+
|
|
338
|
+
# Interactive mode with AI
|
|
339
|
+
praxis reverse --interactive --ai auto
|
|
340
|
+
|
|
341
|
+
# Generate and write to ledger
|
|
342
|
+
praxis reverse --ledger --author "migration-2024"
|
|
343
|
+
|
|
344
|
+
# Preview what would be generated
|
|
345
|
+
praxis reverse --dry-run
|
|
346
|
+
|
|
347
|
+
# Process first 10 rules only
|
|
348
|
+
praxis reverse --limit 10
|
|
349
|
+
|
|
350
|
+
# See REVERSE_ENGINEERING.md for complete guide
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
## Integration with CI/CD
|
|
354
|
+
|
|
355
|
+
### GitHub Actions Example
|
|
356
|
+
|
|
357
|
+
```yaml
|
|
358
|
+
name: Validate Contracts
|
|
359
|
+
|
|
360
|
+
on: [push, pull_request]
|
|
361
|
+
|
|
362
|
+
jobs:
|
|
363
|
+
validate:
|
|
364
|
+
runs-on: ubuntu-latest
|
|
365
|
+
steps:
|
|
366
|
+
- uses: actions/checkout@v3
|
|
367
|
+
- uses: actions/setup-node@v3
|
|
368
|
+
with:
|
|
369
|
+
node-version: '18'
|
|
370
|
+
- run: npm install
|
|
371
|
+
- run: npm run build
|
|
372
|
+
- name: Validate contracts
|
|
373
|
+
run: npx praxis validate --output sarif > results.sarif
|
|
374
|
+
- name: Upload SARIF
|
|
375
|
+
uses: github/codeql-action/upload-sarif@v2
|
|
376
|
+
with:
|
|
377
|
+
sarif_file: results.sarif
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
## Documentation
|
|
381
|
+
|
|
382
|
+
- **Behavior Ledger**: See [docs/decision-ledger/BEHAVIOR_LEDGER.md](../../docs/decision-ledger/BEHAVIOR_LEDGER.md) for the canonical behavior specification
|
|
383
|
+
- **LATEST Snapshot**: See [docs/decision-ledger/LATEST.md](../../docs/decision-ledger/LATEST.md) for the current behavior summary
|
|
384
|
+
- **TLA+ Spec**: See [docs/decision-ledger/DecisionLedger.tla](../../docs/decision-ledger/DecisionLedger.tla) for formal specification
|
|
385
|
+
|
|
386
|
+
## Design Principles
|
|
387
|
+
|
|
388
|
+
1. **Contracts are Optional by Default**: Backward compatibility with existing Praxis code
|
|
389
|
+
2. **Immutable Ledger**: Append-only history; entries can be superseded but never deleted
|
|
390
|
+
3. **Explicit Assumptions**: All inferred requirements must be documented with confidence levels
|
|
391
|
+
4. **JSON Serializable**: All types are JSON-friendly for cross-language compatibility
|
|
392
|
+
5. **Validation is Deterministic**: Same inputs always produce same validation results
|
|
393
|
+
|
|
394
|
+
## Examples
|
|
395
|
+
|
|
396
|
+
See [src/__tests__/decision-ledger.test.ts](../__tests__/decision-ledger.test.ts) for comprehensive usage examples.
|
|
397
|
+
|
|
398
|
+
## License
|
|
399
|
+
|
|
400
|
+
MIT
|