@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.
Files changed (31) hide show
  1. package/README.md +164 -1067
  2. package/dist/browser/{chunk-6MVRT7CK.js → chunk-IUEKGHQN.js} +13 -3
  3. package/dist/browser/index.js +1 -1
  4. package/dist/browser/unified/index.js +1 -1
  5. package/dist/node/{chunk-6MVRT7CK.js → chunk-IUEKGHQN.js} +13 -3
  6. package/dist/node/index.cjs +13 -3
  7. package/dist/node/index.js +1 -1
  8. package/dist/node/unified/index.cjs +13 -3
  9. package/dist/node/unified/index.js +1 -1
  10. package/docs/README.md +58 -102
  11. package/docs/archive/1.x/CONVERSATIONS_IMPLEMENTATION.md +207 -0
  12. package/docs/archive/1.x/DECISION_LEDGER_IMPLEMENTATION.md +109 -0
  13. package/docs/archive/1.x/DECISION_LEDGER_SUMMARY.md +424 -0
  14. package/docs/archive/1.x/ELEVATION_SUMMARY.md +249 -0
  15. package/docs/archive/1.x/FEATURE_SUMMARY.md +238 -0
  16. package/docs/archive/1.x/GOLDEN_PATH_IMPLEMENTATION.md +280 -0
  17. package/docs/archive/1.x/IMPLEMENTATION.md +166 -0
  18. package/docs/archive/1.x/IMPLEMENTATION_COMPLETE.md +389 -0
  19. package/docs/archive/1.x/IMPLEMENTATION_SUMMARY.md +59 -0
  20. package/docs/archive/1.x/INTEGRATION_ENHANCEMENT_SUMMARY.md +238 -0
  21. package/docs/archive/1.x/KNO_ENG_REFACTORING_SUMMARY.md +198 -0
  22. package/docs/archive/1.x/MONOREPO_SUMMARY.md +158 -0
  23. package/docs/archive/1.x/README.md +28 -0
  24. package/docs/archive/1.x/SVELTE_INTEGRATION_SUMMARY.md +415 -0
  25. package/docs/archive/1.x/TASK_1_COMPLETE.md +235 -0
  26. package/docs/archive/1.x/TASK_1_SUMMARY.md +281 -0
  27. package/docs/archive/1.x/VERSION_0.2.0_RELEASE_NOTES.md +288 -0
  28. package/docs/archive/1.x/ValidationChecklist.md +7 -0
  29. package/package.json +11 -5
  30. package/src/unified/__tests__/unified-qa.test.ts +761 -0
  31. 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?.updateCount === 0 || elapsed > timeout,
296
+ stale: !state || state.updateCount === 0,
287
297
  lastUpdated,
288
298
  elapsed
289
299
  };
@@ -32,7 +32,7 @@ import {
32
32
  defineModule,
33
33
  definePath,
34
34
  defineRule
35
- } from "./chunk-6MVRT7CK.js";
35
+ } from "./chunk-IUEKGHQN.js";
36
36
  import {
37
37
  LogicEngine,
38
38
  PRAXIS_PROTOCOL_VERSION,
@@ -4,7 +4,7 @@ import {
4
4
  defineModule,
5
5
  definePath,
6
6
  defineRule
7
- } from "../chunk-6MVRT7CK.js";
7
+ } from "../chunk-IUEKGHQN.js";
8
8
  import {
9
9
  RuleResult,
10
10
  fact
@@ -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?.updateCount === 0 || elapsed > timeout,
296
+ stale: !state || state.updateCount === 0,
287
297
  lastUpdated,
288
298
  elapsed
289
299
  };
@@ -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?.updateCount === 0 || elapsed > timeout,
8214
+ stale: !state2 || state2.updateCount === 0,
8205
8215
  lastUpdated,
8206
8216
  elapsed
8207
8217
  };
@@ -109,7 +109,7 @@ import {
109
109
  defineModule as defineModule2,
110
110
  definePath,
111
111
  defineRule as defineRule2
112
- } from "./chunk-6MVRT7CK.js";
112
+ } from "./chunk-IUEKGHQN.js";
113
113
  import {
114
114
  RuleResult,
115
115
  fact
@@ -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?.updateCount === 0 || elapsed > timeout,
328
+ stale: !state || state.updateCount === 0,
319
329
  lastUpdated,
320
330
  elapsed
321
331
  };
@@ -4,7 +4,7 @@ import {
4
4
  defineModule,
5
5
  definePath,
6
6
  defineRule
7
- } from "../chunk-6MVRT7CK.js";
7
+ } from "../chunk-IUEKGHQN.js";
8
8
  import {
9
9
  RuleResult,
10
10
  fact
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! Praxis is the full-stack application framework for the Plures ecosystem, providing a complete solution for building modern, local-first, distributed applications.
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
- ## 🐕 Dogfooding Plures Tools
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 | Description |
35
- | ------------------------------------------------------ | -------------------------------------------- |
36
- | [What is Praxis](./core/what-is-praxis.md) | Overview of Praxis and its core philosophy |
37
- | [Praxis-Core API](./core/praxis-core-api.md) | Stable API surface and guarantees |
38
- | [Extending Praxis-Core](./core/extending-praxis-core.md) | Extension guidelines without breaking changes |
39
- | [Schema Model](./core/schema-model.md) | Understanding the Praxis Schema Format (PSF) |
40
- | [Logic Engine](./core/logic-engine.md) | Facts, events, rules, and constraints |
41
- | [UI Generation](./core/ui-generation.md) | Automatic component generation from schemas |
42
- | [PluresDB Integration](./core/pluresdb-integration.md) | Local-first data with reactive storage |
43
- | [Code ↔ Canvas Sync](./core/code-canvas-sync.md) | Bidirectional synchronization |
44
- | [CLI Usage](./core/cli-usage.md) | Command-line interface reference |
45
- | [Building Extensions](./core/building-extensions.md) | Extending Praxis functionality |
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 | Description |
50
- | ------------------------------------------------------------- | ----------------------------------- |
51
- | [Getting Started](./guides/getting-started.md) | First steps with Praxis |
52
- | [Svelte Integration](./guides/svelte-integration.md) | Using Praxis with Svelte 5 |
53
- | [Canvas](./guides/canvas.md) | Visual development with CodeCanvas |
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) | Distributed system coordination |
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 | Description |
61
- | -------------------------------------------------- | -------------------------------- |
62
- | [Build Your First App](./tutorials/first-app.md) | Step-by-step beginner tutorial |
63
- | [Todo with PluresDB](./tutorials/todo-pluresdb.md) | Local-first todo application |
64
- | [Form Builder](./tutorials/form-builder.md) | Dynamic form creation |
65
- | [E-commerce Cart](./tutorials/ecommerce-cart.md) | Shopping cart with checkout flow |
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 | Description |
70
- | ------------------------------------------- | ---------------------------- |
71
- | [Hero Shop](../examples/hero-shop/) | Full e-commerce application |
72
- | [Todo](../examples/todo/) | Minimal todo application |
73
- | [Form Builder](../examples/form-builder/) | Dynamic form builder |
74
- | [Offline Chat](../examples/offline-chat/) | Local-first chat application |
75
- | [Terminal Node](../examples/terminal-node/) | Self-orchestrating node |
76
- | [Cloud Sync](../examples/cloud-sync/) | Multi-client synchronization |
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 Overview
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
- ## Key Features
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
- ### 📚 Auto-Documentation
109
+ We actively dogfood all Plures tools during development:
134
110
 
135
- State-Docs generates documentation automatically from schemas.
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
- ### 🌐 Cross-Platform
117
+ ## 1.x Documentation Archive
138
118
 
139
- Deploy to web, desktop (Tauri), and mobile from a single codebase.
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.