@plures/praxis 2.0.0 → 2.0.3
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 +164 -1067
- package/dist/browser/{chunk-6MVRT7CK.js → chunk-IUEKGHQN.js} +13 -3
- package/dist/browser/index.js +1 -1
- package/dist/browser/unified/index.js +1 -1
- package/dist/node/{chunk-6MVRT7CK.js → chunk-IUEKGHQN.js} +13 -3
- package/dist/node/index.cjs +13 -3
- package/dist/node/index.js +1 -1
- package/dist/node/unified/index.cjs +13 -3
- package/dist/node/unified/index.js +1 -1
- package/docs/README.md +58 -102
- package/docs/archive/1.x/CONVERSATIONS_IMPLEMENTATION.md +207 -0
- package/docs/archive/1.x/DECISION_LEDGER_IMPLEMENTATION.md +109 -0
- package/docs/archive/1.x/DECISION_LEDGER_SUMMARY.md +424 -0
- package/docs/archive/1.x/ELEVATION_SUMMARY.md +249 -0
- package/docs/archive/1.x/FEATURE_SUMMARY.md +238 -0
- package/docs/archive/1.x/GOLDEN_PATH_IMPLEMENTATION.md +280 -0
- package/docs/archive/1.x/IMPLEMENTATION.md +166 -0
- package/docs/archive/1.x/IMPLEMENTATION_COMPLETE.md +389 -0
- package/docs/archive/1.x/IMPLEMENTATION_SUMMARY.md +59 -0
- package/docs/archive/1.x/INTEGRATION_ENHANCEMENT_SUMMARY.md +238 -0
- package/docs/archive/1.x/KNO_ENG_REFACTORING_SUMMARY.md +198 -0
- package/docs/archive/1.x/MONOREPO_SUMMARY.md +158 -0
- package/docs/archive/1.x/README.md +28 -0
- package/docs/archive/1.x/SVELTE_INTEGRATION_SUMMARY.md +415 -0
- package/docs/archive/1.x/TASK_1_COMPLETE.md +235 -0
- package/docs/archive/1.x/TASK_1_SUMMARY.md +281 -0
- package/docs/archive/1.x/VERSION_0.2.0_RELEASE_NOTES.md +288 -0
- package/docs/archive/1.x/ValidationChecklist.md +7 -0
- package/package.json +11 -5
- package/src/unified/__tests__/unified-qa.test.ts +761 -0
- package/src/unified/core.ts +19 -2
|
@@ -33,7 +33,8 @@ function createApp(config) {
|
|
|
33
33
|
}
|
|
34
34
|
const ruleStates = (config.rules ?? []).map((rule) => ({
|
|
35
35
|
rule,
|
|
36
|
-
lastResult: null
|
|
36
|
+
lastResult: null,
|
|
37
|
+
emittedTags: /* @__PURE__ */ new Set()
|
|
37
38
|
}));
|
|
38
39
|
const constraints = config.constraints ?? [];
|
|
39
40
|
const livenessConfig = config.liveness;
|
|
@@ -121,12 +122,22 @@ function createApp(config) {
|
|
|
121
122
|
switch (result.kind) {
|
|
122
123
|
case "emit":
|
|
123
124
|
newFacts.push(...result.facts);
|
|
125
|
+
for (const f of result.facts) {
|
|
126
|
+
rs.emittedTags.add(f.tag);
|
|
127
|
+
}
|
|
124
128
|
break;
|
|
125
129
|
case "retract":
|
|
126
130
|
retractions.push(...result.retractTags);
|
|
131
|
+
for (const tag of result.retractTags) {
|
|
132
|
+
rs.emittedTags.delete(tag);
|
|
133
|
+
}
|
|
127
134
|
break;
|
|
128
135
|
case "noop":
|
|
129
136
|
case "skip":
|
|
137
|
+
if (rs.emittedTags.size > 0) {
|
|
138
|
+
retractions.push(...rs.emittedTags);
|
|
139
|
+
rs.emittedTags.clear();
|
|
140
|
+
}
|
|
130
141
|
break;
|
|
131
142
|
}
|
|
132
143
|
} catch (err) {
|
|
@@ -281,9 +292,8 @@ function createApp(config) {
|
|
|
281
292
|
const state = paths.get(p);
|
|
282
293
|
const lastUpdated = state?.lastUpdated ?? 0;
|
|
283
294
|
const elapsed = lastUpdated > 0 ? now - lastUpdated : now - initTime;
|
|
284
|
-
const timeout = livenessConfig?.timeoutMs ?? 5e3;
|
|
285
295
|
result[p] = {
|
|
286
|
-
stale: state
|
|
296
|
+
stale: !state || state.updateCount === 0,
|
|
287
297
|
lastUpdated,
|
|
288
298
|
elapsed
|
|
289
299
|
};
|
package/dist/browser/index.js
CHANGED
|
@@ -33,7 +33,8 @@ function createApp(config) {
|
|
|
33
33
|
}
|
|
34
34
|
const ruleStates = (config.rules ?? []).map((rule) => ({
|
|
35
35
|
rule,
|
|
36
|
-
lastResult: null
|
|
36
|
+
lastResult: null,
|
|
37
|
+
emittedTags: /* @__PURE__ */ new Set()
|
|
37
38
|
}));
|
|
38
39
|
const constraints = config.constraints ?? [];
|
|
39
40
|
const livenessConfig = config.liveness;
|
|
@@ -121,12 +122,22 @@ function createApp(config) {
|
|
|
121
122
|
switch (result.kind) {
|
|
122
123
|
case "emit":
|
|
123
124
|
newFacts.push(...result.facts);
|
|
125
|
+
for (const f of result.facts) {
|
|
126
|
+
rs.emittedTags.add(f.tag);
|
|
127
|
+
}
|
|
124
128
|
break;
|
|
125
129
|
case "retract":
|
|
126
130
|
retractions.push(...result.retractTags);
|
|
131
|
+
for (const tag of result.retractTags) {
|
|
132
|
+
rs.emittedTags.delete(tag);
|
|
133
|
+
}
|
|
127
134
|
break;
|
|
128
135
|
case "noop":
|
|
129
136
|
case "skip":
|
|
137
|
+
if (rs.emittedTags.size > 0) {
|
|
138
|
+
retractions.push(...rs.emittedTags);
|
|
139
|
+
rs.emittedTags.clear();
|
|
140
|
+
}
|
|
130
141
|
break;
|
|
131
142
|
}
|
|
132
143
|
} catch (err) {
|
|
@@ -281,9 +292,8 @@ function createApp(config) {
|
|
|
281
292
|
const state = paths.get(p);
|
|
282
293
|
const lastUpdated = state?.lastUpdated ?? 0;
|
|
283
294
|
const elapsed = lastUpdated > 0 ? now - lastUpdated : now - initTime;
|
|
284
|
-
const timeout = livenessConfig?.timeoutMs ?? 5e3;
|
|
285
295
|
result[p] = {
|
|
286
|
-
stale: state
|
|
296
|
+
stale: !state || state.updateCount === 0,
|
|
287
297
|
lastUpdated,
|
|
288
298
|
elapsed
|
|
289
299
|
};
|
package/dist/node/index.cjs
CHANGED
|
@@ -7951,7 +7951,8 @@ function createApp(config) {
|
|
|
7951
7951
|
}
|
|
7952
7952
|
const ruleStates = (config.rules ?? []).map((rule) => ({
|
|
7953
7953
|
rule,
|
|
7954
|
-
lastResult: null
|
|
7954
|
+
lastResult: null,
|
|
7955
|
+
emittedTags: /* @__PURE__ */ new Set()
|
|
7955
7956
|
}));
|
|
7956
7957
|
const constraints = config.constraints ?? [];
|
|
7957
7958
|
const livenessConfig = config.liveness;
|
|
@@ -8039,12 +8040,22 @@ function createApp(config) {
|
|
|
8039
8040
|
switch (result.kind) {
|
|
8040
8041
|
case "emit":
|
|
8041
8042
|
newFacts.push(...result.facts);
|
|
8043
|
+
for (const f of result.facts) {
|
|
8044
|
+
rs.emittedTags.add(f.tag);
|
|
8045
|
+
}
|
|
8042
8046
|
break;
|
|
8043
8047
|
case "retract":
|
|
8044
8048
|
retractions.push(...result.retractTags);
|
|
8049
|
+
for (const tag of result.retractTags) {
|
|
8050
|
+
rs.emittedTags.delete(tag);
|
|
8051
|
+
}
|
|
8045
8052
|
break;
|
|
8046
8053
|
case "noop":
|
|
8047
8054
|
case "skip":
|
|
8055
|
+
if (rs.emittedTags.size > 0) {
|
|
8056
|
+
retractions.push(...rs.emittedTags);
|
|
8057
|
+
rs.emittedTags.clear();
|
|
8058
|
+
}
|
|
8048
8059
|
break;
|
|
8049
8060
|
}
|
|
8050
8061
|
} catch (err) {
|
|
@@ -8199,9 +8210,8 @@ function createApp(config) {
|
|
|
8199
8210
|
const state2 = paths.get(p);
|
|
8200
8211
|
const lastUpdated = state2?.lastUpdated ?? 0;
|
|
8201
8212
|
const elapsed = lastUpdated > 0 ? now - lastUpdated : now - initTime;
|
|
8202
|
-
const timeout = livenessConfig?.timeoutMs ?? 5e3;
|
|
8203
8213
|
result[p] = {
|
|
8204
|
-
stale: state2
|
|
8214
|
+
stale: !state2 || state2.updateCount === 0,
|
|
8205
8215
|
lastUpdated,
|
|
8206
8216
|
elapsed
|
|
8207
8217
|
};
|
package/dist/node/index.js
CHANGED
|
@@ -65,7 +65,8 @@ function createApp(config) {
|
|
|
65
65
|
}
|
|
66
66
|
const ruleStates = (config.rules ?? []).map((rule) => ({
|
|
67
67
|
rule,
|
|
68
|
-
lastResult: null
|
|
68
|
+
lastResult: null,
|
|
69
|
+
emittedTags: /* @__PURE__ */ new Set()
|
|
69
70
|
}));
|
|
70
71
|
const constraints = config.constraints ?? [];
|
|
71
72
|
const livenessConfig = config.liveness;
|
|
@@ -153,12 +154,22 @@ function createApp(config) {
|
|
|
153
154
|
switch (result.kind) {
|
|
154
155
|
case "emit":
|
|
155
156
|
newFacts.push(...result.facts);
|
|
157
|
+
for (const f of result.facts) {
|
|
158
|
+
rs.emittedTags.add(f.tag);
|
|
159
|
+
}
|
|
156
160
|
break;
|
|
157
161
|
case "retract":
|
|
158
162
|
retractions.push(...result.retractTags);
|
|
163
|
+
for (const tag of result.retractTags) {
|
|
164
|
+
rs.emittedTags.delete(tag);
|
|
165
|
+
}
|
|
159
166
|
break;
|
|
160
167
|
case "noop":
|
|
161
168
|
case "skip":
|
|
169
|
+
if (rs.emittedTags.size > 0) {
|
|
170
|
+
retractions.push(...rs.emittedTags);
|
|
171
|
+
rs.emittedTags.clear();
|
|
172
|
+
}
|
|
162
173
|
break;
|
|
163
174
|
}
|
|
164
175
|
} catch (err) {
|
|
@@ -313,9 +324,8 @@ function createApp(config) {
|
|
|
313
324
|
const state = paths.get(p);
|
|
314
325
|
const lastUpdated = state?.lastUpdated ?? 0;
|
|
315
326
|
const elapsed = lastUpdated > 0 ? now - lastUpdated : now - initTime;
|
|
316
|
-
const timeout = livenessConfig?.timeoutMs ?? 5e3;
|
|
317
327
|
result[p] = {
|
|
318
|
-
stale: state
|
|
328
|
+
stale: !state || state.updateCount === 0,
|
|
319
329
|
lastUpdated,
|
|
320
330
|
elapsed
|
|
321
331
|
};
|
package/docs/README.md
CHANGED
|
@@ -1,81 +1,77 @@
|
|
|
1
|
-
# Praxis Documentation
|
|
1
|
+
# Praxis 2.0 Documentation
|
|
2
2
|
|
|
3
|
-
Welcome to the official Praxis documentation
|
|
3
|
+
Welcome to the official Praxis documentation. Praxis is the full-stack declarative application framework for the Plures ecosystem — typed logic, reactive state, local-first data, and visual tooling for Svelte, Node, and the browser.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
**Start here for dogfooding:** [Dogfooding Index](./DOGFOODING_INDEX.md)
|
|
8
|
-
|
|
9
|
-
We actively dogfood all Plures tools during development. Key resources:
|
|
10
|
-
- [Quick Start Guide](./DOGFOODING_QUICK_START.md) - Get started in 5 minutes
|
|
11
|
-
- [Dogfooding Checklist](./DOGFOODING_CHECKLIST.md) - Daily/weekly/monthly workflows
|
|
12
|
-
- [Plures Tools Inventory](./PLURES_TOOLS_INVENTORY.md) - All available tools
|
|
13
|
-
- [Workflow Examples](./examples/DOGFOODING_WORKFLOW_EXAMPLE.md) - See it in action
|
|
5
|
+
> **New to Praxis?** Start with the [Getting Started guide](../GETTING_STARTED.md).
|
|
6
|
+
> **Upgrading from 1.x?** See the [Migration Guide](../MIGRATION_GUIDE.md).
|
|
14
7
|
|
|
15
8
|
## Quick Start
|
|
16
9
|
|
|
17
10
|
```bash
|
|
18
|
-
# Install Praxis
|
|
19
11
|
npm install @plures/praxis
|
|
20
|
-
|
|
21
|
-
# Create a new app
|
|
22
12
|
npx praxis create app my-app
|
|
23
|
-
cd my-app
|
|
24
|
-
npm install
|
|
25
|
-
|
|
26
|
-
# Start development
|
|
27
|
-
npm run dev
|
|
28
13
|
```
|
|
29
14
|
|
|
30
15
|
## Documentation Index
|
|
31
16
|
|
|
32
17
|
### Core Concepts
|
|
33
18
|
|
|
34
|
-
| Document
|
|
35
|
-
|
|
36
|
-
| [What is Praxis](./core/what-is-praxis.md)
|
|
37
|
-
| [Praxis-Core API](./core/praxis-core-api.md)
|
|
38
|
-
| [Extending Praxis-Core](./core/extending-praxis-core.md) | Extension guidelines
|
|
39
|
-
| [Schema Model](./core/schema-model.md)
|
|
40
|
-
| [Logic Engine](./core/logic-engine.md)
|
|
41
|
-
| [UI Generation](./core/ui-generation.md)
|
|
42
|
-
| [PluresDB Integration](./core/pluresdb-integration.md) | Local-first data with reactive storage
|
|
43
|
-
| [Code ↔ Canvas Sync](./core/code-canvas-sync.md)
|
|
44
|
-
| [CLI Usage](./core/cli-usage.md)
|
|
45
|
-
| [Building Extensions](./core/building-extensions.md)
|
|
19
|
+
| Document | Description |
|
|
20
|
+
|----------|-------------|
|
|
21
|
+
| [What is Praxis](./core/what-is-praxis.md) | Overview and philosophy |
|
|
22
|
+
| [Praxis-Core API](./core/praxis-core-api.md) | Stable API surface and guarantees |
|
|
23
|
+
| [Extending Praxis-Core](./core/extending-praxis-core.md) | Extension guidelines |
|
|
24
|
+
| [Schema Model](./core/schema-model.md) | Praxis Schema Format (PSF) |
|
|
25
|
+
| [Logic Engine](./core/logic-engine.md) | Facts, events, rules, and constraints |
|
|
26
|
+
| [UI Generation](./core/ui-generation.md) | Component generation from schemas |
|
|
27
|
+
| [PluresDB Integration](./core/pluresdb-integration.md) | Local-first data with reactive storage |
|
|
28
|
+
| [Code ↔ Canvas Sync](./core/code-canvas-sync.md) | Bidirectional synchronization |
|
|
29
|
+
| [CLI Usage](./core/cli-usage.md) | Command-line interface reference |
|
|
30
|
+
| [Building Extensions](./core/building-extensions.md) | Extending Praxis |
|
|
46
31
|
|
|
47
32
|
### Guides
|
|
48
33
|
|
|
49
|
-
| Guide
|
|
50
|
-
|
|
51
|
-
| [Getting Started](./guides/getting-started.md)
|
|
52
|
-
| [Svelte Integration](./guides/svelte-integration.md)
|
|
53
|
-
| [Canvas](./guides/canvas.md)
|
|
34
|
+
| Guide | Description |
|
|
35
|
+
|-------|-------------|
|
|
36
|
+
| [Getting Started](./guides/getting-started.md) | First steps with Praxis |
|
|
37
|
+
| [Svelte Integration](./guides/svelte-integration.md) | Using Praxis with Svelte 5 |
|
|
38
|
+
| [Canvas](./guides/canvas.md) | Visual development with CodeCanvas |
|
|
54
39
|
| [History & State Patterns](./guides/history-state-pattern.md) | Undo/redo and time-travel debugging |
|
|
55
|
-
| [Parallel State Patterns](./guides/parallel-state-pattern.md) | Managing parallel state machines
|
|
56
|
-
| [Orchestration](./guides/orchestration.md)
|
|
40
|
+
| [Parallel State Patterns](./guides/parallel-state-pattern.md) | Managing parallel state machines |
|
|
41
|
+
| [Orchestration](./guides/orchestration.md) | Distributed system coordination |
|
|
42
|
+
| [CI/CD Pipeline](./guides/cicd-pipeline.md) | Continuous integration setup |
|
|
57
43
|
|
|
58
44
|
### Tutorials
|
|
59
45
|
|
|
60
|
-
| Tutorial
|
|
61
|
-
|
|
62
|
-
| [Build Your First App](./tutorials/first-app.md)
|
|
63
|
-
| [Todo with PluresDB](./tutorials/todo-pluresdb.md) | Local-first todo application
|
|
64
|
-
| [Form Builder](./tutorials/form-builder.md)
|
|
65
|
-
| [E-commerce Cart](./tutorials/ecommerce-cart.md)
|
|
46
|
+
| Tutorial | Description |
|
|
47
|
+
|----------|-------------|
|
|
48
|
+
| [Build Your First App](./tutorials/first-app.md) | Step-by-step beginner tutorial |
|
|
49
|
+
| [Todo with PluresDB](./tutorials/todo-pluresdb.md) | Local-first todo application |
|
|
50
|
+
| [Form Builder](./tutorials/form-builder.md) | Dynamic form creation |
|
|
51
|
+
| [E-commerce Cart](./tutorials/ecommerce-cart.md) | Shopping cart with checkout flow |
|
|
52
|
+
|
|
53
|
+
### Decision Ledger
|
|
54
|
+
|
|
55
|
+
| Resource | Description |
|
|
56
|
+
|----------|-------------|
|
|
57
|
+
| [Dogfooding Guide](./decision-ledger/DOGFOODING.md) | Decision Ledger workflow |
|
|
58
|
+
| [Behavior Ledger](./decision-ledger/BEHAVIOR_LEDGER.md) | Rule/constraint change log |
|
|
59
|
+
| [Contract Index](./decision-ledger/contract-index.json) | Machine-readable contract inventory |
|
|
66
60
|
|
|
67
61
|
### Examples
|
|
68
62
|
|
|
69
|
-
| Example
|
|
70
|
-
|
|
71
|
-
| [
|
|
72
|
-
| [
|
|
73
|
-
| [
|
|
74
|
-
| [
|
|
75
|
-
| [
|
|
76
|
-
| [
|
|
63
|
+
| Example | Description |
|
|
64
|
+
|---------|-------------|
|
|
65
|
+
| [Unified App](../examples/unified-app/) | `createApp()` with rules and Mermaid docs |
|
|
66
|
+
| [Hero Shop](../examples/hero-shop/) | Full e-commerce application |
|
|
67
|
+
| [Todo](../examples/todo/) | Minimal todo application |
|
|
68
|
+
| [Form Builder](../examples/form-builder/) | Dynamic form builder |
|
|
69
|
+
| [Offline Chat](../examples/offline-chat/) | Local-first chat application |
|
|
70
|
+
| [Terminal Node](../examples/terminal-node/) | Command execution with YAML schemas |
|
|
71
|
+
| [Cloud Sync](../examples/cloud-sync/) | Multi-client synchronization |
|
|
72
|
+
| [Decision Ledger](../examples/decision-ledger/) | Contracts, validation, SARIF output |
|
|
77
73
|
|
|
78
|
-
## Architecture
|
|
74
|
+
## Architecture
|
|
79
75
|
|
|
80
76
|
```mermaid
|
|
81
77
|
flowchart TB
|
|
@@ -108,59 +104,19 @@ flowchart TB
|
|
|
108
104
|
Engine --> StateDocs
|
|
109
105
|
```
|
|
110
106
|
|
|
111
|
-
##
|
|
112
|
-
|
|
113
|
-
### 🎯 Schema-Driven Development
|
|
114
|
-
|
|
115
|
-
Define your entire application in PSF (Praxis Schema Format), then generate everything else.
|
|
116
|
-
|
|
117
|
-
### ⚡ Logic Engine
|
|
118
|
-
|
|
119
|
-
Pure, functional business logic with facts, events, rules, and constraints.
|
|
120
|
-
|
|
121
|
-
### 🧩 Component Generation
|
|
122
|
-
|
|
123
|
-
Automatically generate Svelte components from your schemas.
|
|
124
|
-
|
|
125
|
-
### 📱 Local-First
|
|
126
|
-
|
|
127
|
-
Built-in PluresDB integration for offline-capable, reactive data storage.
|
|
128
|
-
|
|
129
|
-
### 🎨 Visual Development
|
|
130
|
-
|
|
131
|
-
CodeCanvas provides visual schema and logic editing.
|
|
107
|
+
## Dogfooding
|
|
132
108
|
|
|
133
|
-
|
|
109
|
+
We actively dogfood all Plures tools during development:
|
|
134
110
|
|
|
135
|
-
|
|
111
|
+
- [Dogfooding Index](./DOGFOODING_INDEX.md) — overview
|
|
112
|
+
- [Quick Start](./DOGFOODING_QUICK_START.md) — get started in 5 minutes
|
|
113
|
+
- [Checklist](./DOGFOODING_CHECKLIST.md) — daily/weekly/monthly workflows
|
|
114
|
+
- [Tools Inventory](./PLURES_TOOLS_INVENTORY.md) — all available tools
|
|
115
|
+
- [Workflow Example](./examples/DOGFOODING_WORKFLOW_EXAMPLE.md) — see it in action
|
|
136
116
|
|
|
137
|
-
|
|
117
|
+
## 1.x Documentation Archive
|
|
138
118
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
### 🔄 Real-Time Sync
|
|
142
|
-
|
|
143
|
-
Praxis Cloud provides sync across devices and users.
|
|
144
|
-
|
|
145
|
-
## Installation Options
|
|
146
|
-
|
|
147
|
-
### npm
|
|
148
|
-
|
|
149
|
-
```bash
|
|
150
|
-
npm install @plures/praxis
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
### Deno
|
|
154
|
-
|
|
155
|
-
```typescript
|
|
156
|
-
import { createPraxisEngine } from 'jsr:@plures/praxis';
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
### C# (.NET)
|
|
160
|
-
|
|
161
|
-
```bash
|
|
162
|
-
dotnet add package Plures.Praxis
|
|
163
|
-
```
|
|
119
|
+
Historical documentation from Praxis 1.x development is preserved in [archive/1.x/](./archive/1.x/).
|
|
164
120
|
|
|
165
121
|
## Community
|
|
166
122
|
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# Praxis Conversations Subsystem Implementation
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This document summarizes the implementation of the **praxis-conversations** subsystem, a deterministic-first conversation ingestion pipeline integrated into the Praxis framework.
|
|
6
|
+
|
|
7
|
+
## Implementation Date
|
|
8
|
+
|
|
9
|
+
February 1, 2024
|
|
10
|
+
|
|
11
|
+
## Deliverables
|
|
12
|
+
|
|
13
|
+
### 1. JSON Schemas
|
|
14
|
+
|
|
15
|
+
Located in `src/conversations/`:
|
|
16
|
+
|
|
17
|
+
- **conversation.schema.json**: Defines the structure for conversation data including turns, metadata, and classification
|
|
18
|
+
- **candidate.schema.json**: Defines the structure for emission candidates (GitHub issues, documentation, etc.)
|
|
19
|
+
|
|
20
|
+
### 2. Core Pipeline Modules
|
|
21
|
+
|
|
22
|
+
The pipeline follows this deterministic flow:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
capture → redact → normalize → classify → candidates → gate → emit
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Modules** (all in `src/conversations/`):
|
|
29
|
+
|
|
30
|
+
- `capture.ts`: Capture conversations from various sources
|
|
31
|
+
- `redact.ts`: Deterministic PII redaction (email, phone, IP, SSN, credit cards)
|
|
32
|
+
- `normalize.ts`: Content normalization (whitespace, code blocks)
|
|
33
|
+
- `classify.ts`: Keyword-based classification (bug-report, feature-request, question, etc.)
|
|
34
|
+
- `candidates.ts`: Generate emission candidates from classified conversations
|
|
35
|
+
- `gate.ts`: Quality gates (minimum length, valid title, metadata, duplicates)
|
|
36
|
+
|
|
37
|
+
### 3. Emitters
|
|
38
|
+
|
|
39
|
+
Located in `src/conversations/emitters/`:
|
|
40
|
+
|
|
41
|
+
- **fs.ts**: Filesystem emitter with dry-run support
|
|
42
|
+
- **github.ts**: GitHub issue emitter with **HARD GATE** on `commit_intent=true`
|
|
43
|
+
|
|
44
|
+
### 4. CLI Commands
|
|
45
|
+
|
|
46
|
+
Command: `praxis conversations [subcommand]`
|
|
47
|
+
|
|
48
|
+
Subcommands:
|
|
49
|
+
- `capture`: Capture a conversation from input
|
|
50
|
+
- `push`: Process through redact + normalize pipeline
|
|
51
|
+
- `classify`: Classify conversation and generate candidate
|
|
52
|
+
- `emit`: Emit candidate to fs or github (with gates)
|
|
53
|
+
|
|
54
|
+
### 5. Tests & Fixtures
|
|
55
|
+
|
|
56
|
+
- **Tests**: `src/__tests__/conversations.test.ts` (18 comprehensive tests)
|
|
57
|
+
- **Fixtures**: `test/fixtures/conversations/` (3 test conversations)
|
|
58
|
+
- bug-report.json
|
|
59
|
+
- feature-request.json
|
|
60
|
+
- question.json
|
|
61
|
+
|
|
62
|
+
All tests passing (18/18 for conversations, 404/408 total)
|
|
63
|
+
|
|
64
|
+
### 6. Documentation
|
|
65
|
+
|
|
66
|
+
- **README**: `src/conversations/README.md` (comprehensive guide)
|
|
67
|
+
- Includes schema documentation, CLI usage, and programmatic API examples
|
|
68
|
+
|
|
69
|
+
## Key Features
|
|
70
|
+
|
|
71
|
+
1. **Deterministic-first**: No LLM required, all logic is rule-based
|
|
72
|
+
2. **Hard-gated GitHub emitter**: Requires explicit `--commit-intent` flag
|
|
73
|
+
3. **PII redaction**: Automatic removal of sensitive data
|
|
74
|
+
4. **Quality gates**: 4 gates ensure quality before emission
|
|
75
|
+
5. **Dry-run mode**: Test without side effects
|
|
76
|
+
6. **Extensible**: Easy to add new emitters, classifiers, or gates
|
|
77
|
+
|
|
78
|
+
## Usage Examples
|
|
79
|
+
|
|
80
|
+
### CLI Usage
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# Full pipeline
|
|
84
|
+
praxis conversations push -i input.json -o processed.json
|
|
85
|
+
praxis conversations classify -i processed.json -o candidate.json
|
|
86
|
+
praxis conversations emit -i candidate.json -e fs --output-dir ./output
|
|
87
|
+
|
|
88
|
+
# GitHub emission (requires --commit-intent)
|
|
89
|
+
praxis conversations emit -i candidate.json -e github \
|
|
90
|
+
--owner myorg --repo myrepo --commit-intent
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Programmatic Usage
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import {
|
|
97
|
+
captureConversation,
|
|
98
|
+
redactConversation,
|
|
99
|
+
normalizeConversation,
|
|
100
|
+
classifyConversation,
|
|
101
|
+
generateCandidate,
|
|
102
|
+
applyGates,
|
|
103
|
+
emitToFS,
|
|
104
|
+
} from '@plures/praxis/conversations';
|
|
105
|
+
|
|
106
|
+
// Process conversation
|
|
107
|
+
let conv = captureConversation({ turns: [...], metadata: {} });
|
|
108
|
+
conv = redactConversation(conv);
|
|
109
|
+
conv = normalizeConversation(conv);
|
|
110
|
+
conv = classifyConversation(conv);
|
|
111
|
+
|
|
112
|
+
// Generate and emit candidate
|
|
113
|
+
const candidate = generateCandidate(conv);
|
|
114
|
+
const gated = applyGates(candidate);
|
|
115
|
+
if (gated.gateStatus?.passed) {
|
|
116
|
+
await emitToFS(gated, { outputDir: './output' });
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Security
|
|
121
|
+
|
|
122
|
+
- **CodeQL Scan**: 0 vulnerabilities found
|
|
123
|
+
- **PII Redaction**: Implemented for emails, phones, IPs, SSNs, credit cards
|
|
124
|
+
- **GitHub Gate**: Hard-gated to prevent accidental issue creation
|
|
125
|
+
- **Input Validation**: All inputs validated before processing
|
|
126
|
+
|
|
127
|
+
## Testing
|
|
128
|
+
|
|
129
|
+
All tests passing:
|
|
130
|
+
- Conversations subsystem: 18/18 tests
|
|
131
|
+
- Full test suite: 404/408 tests (4 skipped)
|
|
132
|
+
|
|
133
|
+
Run tests:
|
|
134
|
+
```bash
|
|
135
|
+
npm test src/__tests__/conversations.test.ts
|
|
136
|
+
npm test # Full suite
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Code Review
|
|
140
|
+
|
|
141
|
+
Code review completed with all feedback addressed:
|
|
142
|
+
- Documented intentionally broad PII patterns (prioritize safety)
|
|
143
|
+
- Optimized label deduplication using Set (O(n) vs O(n²))
|
|
144
|
+
- Added clarifying comments for pattern limitations
|
|
145
|
+
|
|
146
|
+
## Files Modified/Created
|
|
147
|
+
|
|
148
|
+
### New Files (19 total)
|
|
149
|
+
|
|
150
|
+
**Core modules**:
|
|
151
|
+
- src/conversations/candidate.schema.json
|
|
152
|
+
- src/conversations/candidates.ts
|
|
153
|
+
- src/conversations/capture.ts
|
|
154
|
+
- src/conversations/classify.ts
|
|
155
|
+
- src/conversations/conversation.schema.json
|
|
156
|
+
- src/conversations/gate.ts
|
|
157
|
+
- src/conversations/index.ts
|
|
158
|
+
- src/conversations/normalize.ts
|
|
159
|
+
- src/conversations/redact.ts
|
|
160
|
+
- src/conversations/types.ts
|
|
161
|
+
- src/conversations/README.md
|
|
162
|
+
|
|
163
|
+
**Emitters**:
|
|
164
|
+
- src/conversations/emitters/fs.ts
|
|
165
|
+
- src/conversations/emitters/github.ts
|
|
166
|
+
|
|
167
|
+
**CLI**:
|
|
168
|
+
- src/cli/commands/conversations.ts
|
|
169
|
+
|
|
170
|
+
**Tests & Fixtures**:
|
|
171
|
+
- src/__tests__/conversations.test.ts
|
|
172
|
+
- test/fixtures/conversations/bug-report.json
|
|
173
|
+
- test/fixtures/conversations/feature-request.json
|
|
174
|
+
- test/fixtures/conversations/question.json
|
|
175
|
+
|
|
176
|
+
### Modified Files
|
|
177
|
+
|
|
178
|
+
- src/cli/index.ts (added conversations commands)
|
|
179
|
+
- .gitignore (added .demo/)
|
|
180
|
+
|
|
181
|
+
## Compliance with Praxis Decision Ledger
|
|
182
|
+
|
|
183
|
+
This implementation follows the Praxis Decision Ledger dogfooding guidelines:
|
|
184
|
+
- Deterministic implementation (no LLM dependencies)
|
|
185
|
+
- Comprehensive test coverage
|
|
186
|
+
- Clear contracts and schemas
|
|
187
|
+
- Documentation for all public APIs
|
|
188
|
+
|
|
189
|
+
## Future Enhancements
|
|
190
|
+
|
|
191
|
+
Potential improvements for future iterations:
|
|
192
|
+
- Additional emitters (Slack, Discord, email)
|
|
193
|
+
- More sophisticated classification rules
|
|
194
|
+
- Duplicate detection against real GitHub issues
|
|
195
|
+
- Custom PII patterns via configuration
|
|
196
|
+
- Batch processing support
|
|
197
|
+
|
|
198
|
+
## Conclusion
|
|
199
|
+
|
|
200
|
+
The praxis-conversations subsystem has been successfully implemented with:
|
|
201
|
+
- Complete deterministic pipeline
|
|
202
|
+
- Hard-gated GitHub emitter
|
|
203
|
+
- Comprehensive tests and documentation
|
|
204
|
+
- Zero security vulnerabilities
|
|
205
|
+
- All code review feedback addressed
|
|
206
|
+
|
|
207
|
+
The subsystem is ready for use and follows all Praxis framework conventions.
|