@cakemail-org/cakemail-cli 1.5.0 → 2.0.0
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/.claude/settings.local.json +12 -0
- package/.env.example +40 -0
- package/.env.test.example +45 -0
- package/CHANGELOG.md +1031 -0
- package/README.md +319 -15
- package/audit-formats.js +128 -0
- package/cakemail.rb +20 -0
- package/dist/cli.js +27 -10
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +2 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +16 -6
- package/dist/client.js.map +1 -1
- package/dist/commands/account.js +1 -1
- package/dist/commands/account.js.map +1 -1
- package/dist/commands/attributes.js +1 -1
- package/dist/commands/attributes.js.map +1 -1
- package/dist/commands/campaigns.d.ts.map +1 -1
- package/dist/commands/campaigns.js +103 -8
- package/dist/commands/campaigns.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +63 -4
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/contacts.d.ts.map +1 -1
- package/dist/commands/contacts.js +91 -12
- package/dist/commands/contacts.js.map +1 -1
- package/dist/commands/emails.js +1 -1
- package/dist/commands/emails.js.map +1 -1
- package/dist/commands/interests.d.ts +5 -0
- package/dist/commands/interests.d.ts.map +1 -0
- package/dist/commands/interests.js +172 -0
- package/dist/commands/interests.js.map +1 -0
- package/dist/commands/lists.d.ts.map +1 -1
- package/dist/commands/lists.js +6 -8
- package/dist/commands/lists.js.map +1 -1
- package/dist/commands/logs.d.ts +5 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +237 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/reports.js +1 -1
- package/dist/commands/reports.js.map +1 -1
- package/dist/commands/segments.js +1 -1
- package/dist/commands/segments.js.map +1 -1
- package/dist/commands/senders.d.ts.map +1 -1
- package/dist/commands/senders.js +11 -8
- package/dist/commands/senders.js.map +1 -1
- package/dist/commands/suppressed.js +1 -1
- package/dist/commands/suppressed.js.map +1 -1
- package/dist/commands/tags.d.ts +5 -0
- package/dist/commands/tags.d.ts.map +1 -0
- package/dist/commands/tags.js +124 -0
- package/dist/commands/tags.js.map +1 -0
- package/dist/commands/templates.js +1 -1
- package/dist/commands/templates.js.map +1 -1
- package/dist/commands/transactional-templates.d.ts +5 -0
- package/dist/commands/transactional-templates.d.ts.map +1 -0
- package/dist/commands/transactional-templates.js +354 -0
- package/dist/commands/transactional-templates.js.map +1 -0
- package/dist/commands/webhooks.js +1 -1
- package/dist/commands/webhooks.js.map +1 -1
- package/dist/utils/auth.d.ts +8 -1
- package/dist/utils/auth.d.ts.map +1 -1
- package/dist/utils/auth.js +39 -11
- package/dist/utils/auth.js.map +1 -1
- package/dist/utils/config-file.d.ts +7 -0
- package/dist/utils/config-file.d.ts.map +1 -1
- package/dist/utils/config-file.js +15 -0
- package/dist/utils/config-file.js.map +1 -1
- package/dist/utils/config.d.ts +2 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +12 -4
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/errors.js +1 -1
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/list-defaults.d.ts +33 -0
- package/dist/utils/list-defaults.d.ts.map +1 -0
- package/dist/utils/list-defaults.js +52 -0
- package/dist/utils/list-defaults.js.map +1 -0
- package/dist/utils/output.d.ts.map +1 -1
- package/dist/utils/output.js +36 -13
- package/dist/utils/output.js.map +1 -1
- package/dist/utils/progress.d.ts.map +1 -1
- package/dist/utils/progress.js +32 -4
- package/dist/utils/progress.js.map +1 -1
- package/dist/utils/spinner.d.ts +17 -0
- package/dist/utils/spinner.d.ts.map +1 -0
- package/dist/utils/spinner.js +43 -0
- package/dist/utils/spinner.js.map +1 -0
- package/docs/DOCUMENTATION-STANDARD.md +1068 -0
- package/docs/README.md +161 -0
- package/docs/developer/ARCHITECTURE.md +516 -0
- package/docs/developer/AUTH.md +204 -0
- package/docs/developer/CONTRIBUTING.md +227 -0
- package/docs/developer/DOCUMENTATION_SUMMARY.md +346 -0
- package/docs/developer/PROJECT_INDEX.md +365 -0
- package/docs/planning/API_COVERAGE.md +1045 -0
- package/docs/planning/BACKLOG.md +1159 -0
- package/docs/planning/PROFILE_SYSTEM_TASKS.md +287 -0
- package/docs/planning/UX_IMPLEMENTATION_PLAN.md +691 -0
- package/docs/planning/archive/RELEASE_CHECKLIST_v1.3.0.md +332 -0
- package/docs/planning/archive/RELEASE_v1.3.0.md +428 -0
- package/docs/planning/archive/cakemail-cli-ux-improvements.md +438 -0
- package/docs/planning/cakemail-profile-system-plan.md +1121 -0
- package/docs/testing/AI_USER_SIMULATION_DESIGN.md +1342 -0
- package/docs/testing/KENOGAMI_BIDIRECTIONAL_FLOW.md +1517 -0
- package/docs/testing/KENOGAMI_TRUTH_RECONCILIATION_SYSTEM.md +1369 -0
- package/docs/user-manual/.obsidian/app.json +1 -0
- package/docs/user-manual/.obsidian/appearance.json +1 -0
- package/docs/user-manual/.obsidian/core-plugins.json +33 -0
- package/docs/user-manual/.obsidian/workspace.json +167 -0
- package/docs/user-manual/01-getting-started/01-installation.md +214 -0
- package/docs/user-manual/01-getting-started/02-quick-start.md +432 -0
- package/docs/user-manual/01-getting-started/03-authentication.md +448 -0
- package/docs/user-manual/01-getting-started/04-configuration.md +430 -0
- package/docs/user-manual/01-getting-started/05-output-formats.md +447 -0
- package/docs/user-manual/02-core-concepts/01-accounts.md +514 -0
- package/docs/user-manual/02-core-concepts/02-profile-system.md +771 -0
- package/docs/user-manual/02-core-concepts/03-smart-defaults.md +485 -0
- package/docs/user-manual/02-core-concepts/04-authentication-methods.md +435 -0
- package/docs/user-manual/02-core-concepts/05-pagination-filtering.md +600 -0
- package/docs/user-manual/02-core-concepts/06-error-handling.md +718 -0
- package/docs/user-manual/02-core-concepts/07-api-coverage.md +483 -0
- package/docs/user-manual/03-email-operations/01-senders.md +490 -0
- package/docs/user-manual/03-email-operations/02-templates.md +444 -0
- package/docs/user-manual/03-email-operations/03-transactional-emails.md +706 -0
- package/docs/user-manual/03-email-operations/04-email-tracking.md +407 -0
- package/docs/user-manual/04-campaign-management/01-campaigns-basics.md +394 -0
- package/docs/user-manual/04-campaign-management/02-campaign-scheduling.md +630 -0
- package/docs/user-manual/04-campaign-management/03-campaign-testing.md +997 -0
- package/docs/user-manual/04-campaign-management/04-campaign-lifecycle.md +709 -0
- package/docs/user-manual/04-campaign-management/05-campaign-links.md +934 -0
- package/docs/user-manual/05-contact-management/01-lists.md +836 -0
- package/docs/user-manual/05-contact-management/02-contacts.md +1035 -0
- package/docs/user-manual/05-contact-management/03-custom-attributes.md +788 -0
- package/docs/user-manual/05-contact-management/04-segments.md +1028 -0
- package/docs/user-manual/05-contact-management/05-contact-import-export.md +1031 -0
- package/docs/user-manual/06-analytics-reporting/01-campaign-analytics.md +867 -0
- package/docs/user-manual/06-analytics-reporting/02-account-reports.md +227 -0
- package/docs/user-manual/07-integrations/01-webhooks-integration.md +259 -0
- package/docs/user-manual/07-integrations/02-automation.md +326 -0
- package/docs/user-manual/08-advanced-usage/01-scripting-patterns.md +672 -0
- package/docs/user-manual/08-advanced-usage/02-bulk-operations.md +932 -0
- package/docs/user-manual/08-advanced-usage/03-ci-cd-integration.md +892 -0
- package/docs/user-manual/08-advanced-usage/04-performance-optimization.md +766 -0
- package/docs/user-manual/09-command-reference/01-config.md +776 -0
- package/docs/user-manual/09-command-reference/02-account.md +652 -0
- package/docs/user-manual/09-command-reference/03-lists.md +958 -0
- package/docs/user-manual/09-command-reference/04-contacts.md +1408 -0
- package/docs/user-manual/09-command-reference/05-attributes.md +617 -0
- package/docs/user-manual/09-command-reference/06-segments.md +894 -0
- package/docs/user-manual/09-command-reference/07-senders.md +803 -0
- package/docs/user-manual/09-command-reference/08-templates.md +818 -0
- package/docs/user-manual/09-command-reference/09-campaigns.md +1250 -0
- package/docs/user-manual/09-command-reference/10-emails.md +807 -0
- package/docs/user-manual/09-command-reference/11-reports.md +1135 -0
- package/docs/user-manual/09-command-reference/12-webhooks.md +773 -0
- package/docs/user-manual/09-command-reference/13-suppressed.md +797 -0
- package/docs/user-manual/09-command-reference/14-interests.md +630 -0
- package/docs/user-manual/09-command-reference/15-tags.md +584 -0
- package/docs/user-manual/09-command-reference/16-logs.md +656 -0
- package/docs/user-manual/09-command-reference/17-transactional-templates.md +850 -0
- package/docs/user-manual/10-troubleshooting/01-common-errors.md +457 -0
- package/docs/user-manual/10-troubleshooting/02-authentication-issues.md +558 -0
- package/docs/user-manual/10-troubleshooting/03-connection-problems.md +634 -0
- package/docs/user-manual/10-troubleshooting/04-debugging.md +725 -0
- package/docs/user-manual/11-appendix/04-faq.md +484 -0
- package/docs/user-manual/11-appendix/05-glossary.md +250 -0
- package/docs/user-manual/README.md +0 -0
- package/package.json +13 -47
- package/src/cli.ts +125 -0
- package/src/client.ts +16 -0
- package/src/commands/account.ts +267 -0
- package/src/commands/accounts.ts +78 -0
- package/src/commands/actions.ts +249 -0
- package/src/commands/attributes.ts +139 -0
- package/src/commands/campaign-blueprints.ts +106 -0
- package/src/commands/campaigns.ts +469 -0
- package/src/commands/config.ts +77 -0
- package/src/commands/contacts.ts +612 -0
- package/src/commands/custom-attributes.ts +127 -0
- package/src/commands/dkims.ts +117 -0
- package/src/commands/domains.ts +82 -0
- package/src/commands/email-apis.ts +569 -0
- package/src/commands/emails.ts +197 -0
- package/src/commands/forms.ts +283 -0
- package/src/commands/interests.ts +155 -0
- package/src/commands/links.ts +38 -0
- package/src/commands/lists.ts +406 -0
- package/src/commands/logos.ts +71 -0
- package/src/commands/logs.ts +386 -0
- package/src/commands/reports.ts +306 -0
- package/src/commands/segments.ts +158 -0
- package/src/commands/senders.ts +204 -0
- package/src/commands/sub-accounts.ts +271 -0
- package/src/commands/suppressed-emails.ts +234 -0
- package/src/commands/suppressed.ts +198 -0
- package/src/commands/system-emails.ts +85 -0
- package/src/commands/tags.ts +146 -0
- package/src/commands/tasks.ts +116 -0
- package/src/commands/templates.ts +189 -0
- package/src/commands/tokens.ts +83 -0
- package/src/commands/transactional-emails.ts +374 -0
- package/src/commands/transactional-templates.ts +385 -0
- package/src/commands/users.ts +506 -0
- package/src/commands/webhooks.ts +172 -0
- package/src/commands/workflow-blueprints.ts +123 -0
- package/src/commands/workflows.ts +265 -0
- package/src/types/profile.ts +93 -0
- package/src/utils/auth.ts +272 -0
- package/src/utils/config-file.ts +96 -0
- package/src/utils/config.ts +134 -0
- package/src/utils/confirm.ts +32 -0
- package/src/utils/defaults.ts +99 -0
- package/src/utils/errors.ts +116 -0
- package/src/utils/interactive.ts +91 -0
- package/src/utils/list-defaults.ts +74 -0
- package/src/utils/output.ts +190 -0
- package/src/utils/progress.ts +320 -0
- package/src/utils/spinner.ts +22 -0
- package/tests/IMPLEMENTATION_STATUS.md +258 -0
- package/tests/PTY_SETUP.md +118 -0
- package/tests/PTY_TESTING_GUIDE.md +507 -0
- package/tests/README.md +244 -0
- package/tests/fixtures/api-responses/campaigns.json +34 -0
- package/tests/fixtures/test-config.json +13 -0
- package/tests/helpers/cli-runner.ts +128 -0
- package/tests/helpers/mock-server.ts +301 -0
- package/tests/helpers/pty-runner.ts +181 -0
- package/tests/integration/campaigns-real-api.test.ts +196 -0
- package/tests/integration/setup-integration.ts +50 -0
- package/tests/pty/campaigns.test.ts +241 -0
- package/tests/setup.ts +34 -0
- package/tsconfig.json +15 -0
- package/vitest.config.ts +28 -0
|
@@ -0,0 +1,1369 @@
|
|
|
1
|
+
# Kenogami: Multi-Source Truth Reconciliation System
|
|
2
|
+
|
|
3
|
+
## Executive Summary
|
|
4
|
+
|
|
5
|
+
The fundamental challenge: **Truth exists in multiple places**, each with different authority and purpose. The knowledge graph is not the ultimate source of truth—it's a **reconciliation layer** that harmonizes truths from multiple authoritative sources, detects conflicts, identifies gaps, and maintains coherence across the entire system.
|
|
6
|
+
|
|
7
|
+
**Core Insight:** Don't force a single source of truth. Instead, recognize that truth is **distributed** and **context-dependent**, then build systems to **reconcile**, **validate**, and **synthesize** these distributed truths.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## The Reality: Distributed Sources of Truth
|
|
12
|
+
|
|
13
|
+
### Source 1: Product Code (Implementation Truth)
|
|
14
|
+
|
|
15
|
+
**What it represents:** What the system *actually does*
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
// cakemail-cli/src/commands/campaigns.ts
|
|
19
|
+
export function createCampaignsCommand() {
|
|
20
|
+
return new Command('campaigns')
|
|
21
|
+
.command('list')
|
|
22
|
+
.option('-s, --status <status>', 'Filter by status')
|
|
23
|
+
.option('-l, --limit <number>', 'Limit results')
|
|
24
|
+
.action(async (options) => {
|
|
25
|
+
// Implementation details
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Authority Level:** 🔴 **HIGHEST** - This is objective reality
|
|
31
|
+
**Characteristics:**
|
|
32
|
+
- Definitive for "what is implemented"
|
|
33
|
+
- Changes through code commits
|
|
34
|
+
- Version controlled
|
|
35
|
+
- Can be analyzed programmatically (AST parsing, type inference)
|
|
36
|
+
|
|
37
|
+
**Limitations:**
|
|
38
|
+
- Doesn't explain *why*
|
|
39
|
+
- Doesn't document *intent*
|
|
40
|
+
- Doesn't describe *workflows* or *best practices*
|
|
41
|
+
- Doesn't capture *user perspective*
|
|
42
|
+
|
|
43
|
+
### Source 2: API/OpenAPI Specification (Contract Truth)
|
|
44
|
+
|
|
45
|
+
**What it represents:** What the system *promises to do*
|
|
46
|
+
|
|
47
|
+
```yaml
|
|
48
|
+
# Cakemail API OpenAPI spec
|
|
49
|
+
/campaigns:
|
|
50
|
+
get:
|
|
51
|
+
parameters:
|
|
52
|
+
- name: status
|
|
53
|
+
in: query
|
|
54
|
+
schema:
|
|
55
|
+
type: string
|
|
56
|
+
enum: [draft, sent, scheduled]
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Authority Level:** 🟠 **HIGH** - This is the contract
|
|
60
|
+
**Characteristics:**
|
|
61
|
+
- Authoritative for API behavior
|
|
62
|
+
- Version controlled
|
|
63
|
+
- Machine-readable
|
|
64
|
+
- Can drift from implementation (bug or spec issue)
|
|
65
|
+
|
|
66
|
+
**Limitations:**
|
|
67
|
+
- May lag behind implementation
|
|
68
|
+
- Doesn't include CLI-specific features
|
|
69
|
+
- Doesn't describe user journeys
|
|
70
|
+
|
|
71
|
+
### Source 3: Original Documentation (Intent Truth)
|
|
72
|
+
|
|
73
|
+
**What it represents:** What the product team *intended* to communicate
|
|
74
|
+
|
|
75
|
+
```markdown
|
|
76
|
+
# Creating Campaigns
|
|
77
|
+
|
|
78
|
+
To create a campaign, use the `campaigns create` command.
|
|
79
|
+
You'll need a list ID and sender ID...
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Authority Level:** 🟡 **MEDIUM** - This is the official narrative
|
|
83
|
+
**Characteristics:**
|
|
84
|
+
- Captures product team's intent
|
|
85
|
+
- Includes context, rationale, workflows
|
|
86
|
+
- Human-written, human-optimized
|
|
87
|
+
- May drift from reality over time
|
|
88
|
+
|
|
89
|
+
**Limitations:**
|
|
90
|
+
- Can become outdated
|
|
91
|
+
- May have inconsistencies
|
|
92
|
+
- Subjective writing style
|
|
93
|
+
|
|
94
|
+
### Source 4: User Behavior Data (Usage Truth)
|
|
95
|
+
|
|
96
|
+
**What it represents:** How users *actually use* the product
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"command": "cakemail campaigns list --status sent",
|
|
101
|
+
"frequency": 1247,
|
|
102
|
+
"success_rate": 0.94,
|
|
103
|
+
"common_next_command": "cakemail campaigns get <id>"
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Authority Level:** 🟡 **MEDIUM** - This is behavioral reality
|
|
108
|
+
**Characteristics:**
|
|
109
|
+
- Shows actual usage patterns
|
|
110
|
+
- Reveals what users care about
|
|
111
|
+
- Indicates what works / doesn't work
|
|
112
|
+
- Data-driven insights
|
|
113
|
+
|
|
114
|
+
**Limitations:**
|
|
115
|
+
- Doesn't explain intent
|
|
116
|
+
- May show workarounds, not ideal usage
|
|
117
|
+
- Includes both correct and incorrect usage
|
|
118
|
+
|
|
119
|
+
### Source 5: Customer Support Tickets (Problem Truth)
|
|
120
|
+
|
|
121
|
+
**What it represents:** Where users *struggle*
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
Ticket #4521: "I tried 'campaigns list --status sending' but got an error.
|
|
125
|
+
The docs say 'sending' is a valid status, but it doesn't work."
|
|
126
|
+
|
|
127
|
+
Root Cause: Docs outdated. Status 'sending' was replaced with 'in_progress' in v1.5
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Authority Level:** 🟢 **LOW-MEDIUM** - This is the pain point signal
|
|
131
|
+
**Characteristics:**
|
|
132
|
+
- Identifies documentation gaps
|
|
133
|
+
- Shows common misconceptions
|
|
134
|
+
- Reveals UX problems
|
|
135
|
+
- Indicates priority areas
|
|
136
|
+
|
|
137
|
+
**Limitations:**
|
|
138
|
+
- Biased toward problems (not successes)
|
|
139
|
+
- May include user error
|
|
140
|
+
- Needs human interpretation
|
|
141
|
+
|
|
142
|
+
### Source 6: Chatbot Conversations (Learning Truth)
|
|
143
|
+
|
|
144
|
+
**What it represents:** What users *ask about* and how they *learn*
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
User: "How do I create a campaign?"
|
|
148
|
+
Bot: "Use 'cakemail campaigns create --name "My Campaign" --list-id 123'"
|
|
149
|
+
User: "What's a list ID?"
|
|
150
|
+
Bot: "A list ID is the unique identifier for your contact list..."
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Authority Level:** 🟢 **LOW** - This is the learning journey
|
|
154
|
+
**Characteristics:**
|
|
155
|
+
- Shows knowledge gaps
|
|
156
|
+
- Reveals terminology confusion
|
|
157
|
+
- Indicates documentation clarity issues
|
|
158
|
+
- Captures natural language queries
|
|
159
|
+
|
|
160
|
+
**Limitations:**
|
|
161
|
+
- Conversational, not canonical
|
|
162
|
+
- May include bot hallucinations
|
|
163
|
+
- Context-dependent
|
|
164
|
+
|
|
165
|
+
### Source 7: Test Results (Validation Truth)
|
|
166
|
+
|
|
167
|
+
**What it represents:** What has been *verified* to work
|
|
168
|
+
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"test": "campaigns list with status filter",
|
|
172
|
+
"status": "PASS",
|
|
173
|
+
"actual_output": {...},
|
|
174
|
+
"matches_documentation": true,
|
|
175
|
+
"matches_implementation": true
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Authority Level:** 🔵 **VALIDATION** - This is verification
|
|
180
|
+
**Characteristics:**
|
|
181
|
+
- Proves what works
|
|
182
|
+
- Detects regressions
|
|
183
|
+
- Validates consistency
|
|
184
|
+
- Objective measurement
|
|
185
|
+
|
|
186
|
+
**Limitations:**
|
|
187
|
+
- Only tests what we think to test
|
|
188
|
+
- Can have bugs in tests themselves
|
|
189
|
+
- Doesn't capture intent
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## The Problem: Truth Conflicts & Gaps
|
|
194
|
+
|
|
195
|
+
### Conflict Types
|
|
196
|
+
|
|
197
|
+
**Type 1: Code vs Documentation**
|
|
198
|
+
```
|
|
199
|
+
Code: Parameter 'status' accepts: ['draft', 'sent', 'scheduled', 'failed']
|
|
200
|
+
Docs: Parameter 'status' accepts: ['draft', 'sent', 'sending', 'scheduled']
|
|
201
|
+
Conflict: 'failed' missing from docs, 'sending' doesn't exist in code
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**Type 2: API Spec vs Implementation**
|
|
205
|
+
```
|
|
206
|
+
Spec: Max limit is 100
|
|
207
|
+
CLI Code: No max limit enforced (accepts any number)
|
|
208
|
+
API Code: Max limit is 50
|
|
209
|
+
Conflict: Three different truths!
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**Type 3: Documentation Inconsistency**
|
|
213
|
+
```
|
|
214
|
+
Tutorial: "Use --format json to get JSON output"
|
|
215
|
+
Reference: "JSON is the default format"
|
|
216
|
+
Quick Start: "Use -f table for readable output"
|
|
217
|
+
Conflict: What's actually the default?
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**Type 4: Usage vs Intent**
|
|
221
|
+
```
|
|
222
|
+
Intended: Users should use 'campaigns create' with all parameters
|
|
223
|
+
Actual: 80% of users use interactive mode (no parameters)
|
|
224
|
+
Conflict: Documentation focuses on non-interactive, users prefer interactive
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**Type 5: Support vs Documentation**
|
|
228
|
+
```
|
|
229
|
+
Docs: "Authentication is automatic"
|
|
230
|
+
Tickets: 50 tickets about "How do I authenticate?"
|
|
231
|
+
Conflict: Documentation assumption doesn't match user understanding
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Gap Types
|
|
235
|
+
|
|
236
|
+
**Type 1: Undocumented Features**
|
|
237
|
+
```
|
|
238
|
+
Code: Supports '--batch' flag for non-interactive mode
|
|
239
|
+
Docs: No mention of batch mode
|
|
240
|
+
Gap: Feature exists but not documented
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Type 2: Documented but Not Implemented**
|
|
244
|
+
```
|
|
245
|
+
Docs: "Use --template-id to create campaign from template"
|
|
246
|
+
Code: --template-id option doesn't exist yet
|
|
247
|
+
Gap: Documentation ahead of implementation (planned feature?)
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**Type 3: Missing Workflows**
|
|
251
|
+
```
|
|
252
|
+
Commands: campaigns create, campaigns schedule, campaigns send
|
|
253
|
+
Docs: Each command documented separately
|
|
254
|
+
Gap: Complete workflow not documented
|
|
255
|
+
Usage Data: Users struggle to understand the sequence
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**Type 4: Hidden Knowledge**
|
|
259
|
+
```
|
|
260
|
+
Support: "First confirm your sender before creating campaigns"
|
|
261
|
+
Docs: No mention of sender confirmation requirement
|
|
262
|
+
Code: Checks for confirmed sender, returns cryptic error if not
|
|
263
|
+
Gap: Domain knowledge only in support team's heads
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## The Solution: Multi-Layer Truth Reconciliation
|
|
269
|
+
|
|
270
|
+
### Architecture Overview
|
|
271
|
+
|
|
272
|
+
```
|
|
273
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
274
|
+
│ TRUTH SOURCES (Multiple) │
|
|
275
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
276
|
+
│ │ │ │ │ │ │
|
|
277
|
+
│Product │ API │Original │ Usage │Support │ Chatbot │
|
|
278
|
+
│ Code │ Spec │ Docs │ Data │Tickets │ Logs │
|
|
279
|
+
│ │ │ │ │ │ │
|
|
280
|
+
└────┬────┴────┬────┴────┬────┴────┬────┴────┬────┴────┬────┘
|
|
281
|
+
│ │ │ │ │ │
|
|
282
|
+
└─────────┴─────────┴─────────┴─────────┴─────────┘
|
|
283
|
+
│
|
|
284
|
+
▼
|
|
285
|
+
┌────────────────────────────────────────────────┐
|
|
286
|
+
│ EXTRACTION & INGESTION LAYER │
|
|
287
|
+
│ - Code AST Parser │
|
|
288
|
+
│ - OpenAPI Parser │
|
|
289
|
+
│ - Markdown Parser │
|
|
290
|
+
│ - Analytics Aggregator │
|
|
291
|
+
│ - Ticket Classifier │
|
|
292
|
+
│ - Conversation Analyzer │
|
|
293
|
+
└────────────────┬───────────────────────────────┘
|
|
294
|
+
│
|
|
295
|
+
▼
|
|
296
|
+
┌────────────────────────────────────────────────┐
|
|
297
|
+
│ RECONCILIATION ENGINE │
|
|
298
|
+
│ - Conflict Detection │
|
|
299
|
+
│ - Gap Analysis │
|
|
300
|
+
│ - Truth Scoring │
|
|
301
|
+
│ - Canonical Resolution │
|
|
302
|
+
└────────────────┬───────────────────────────────┘
|
|
303
|
+
│
|
|
304
|
+
▼
|
|
305
|
+
┌────────────────────────────────────────────────┐
|
|
306
|
+
│ KNOWLEDGE GRAPH (Reconciled) │
|
|
307
|
+
│ │
|
|
308
|
+
│ ┌──────────┐ ┌──────────┐ ┌─────────┐ │
|
|
309
|
+
│ │ Facts │ │Conflicts │ │ Gaps │ │
|
|
310
|
+
│ │ (Nodes) │ │ (Edges) │ │ (Nodes) │ │
|
|
311
|
+
│ └──────────┘ └──────────┘ └─────────┘ │
|
|
312
|
+
│ │
|
|
313
|
+
│ Each fact has provenance: │
|
|
314
|
+
│ - source: [code, spec, docs, usage, ...] │
|
|
315
|
+
│ - confidence: 0.0-1.0 │
|
|
316
|
+
│ - last_verified: timestamp │
|
|
317
|
+
│ - conflicts_with: [other facts] │
|
|
318
|
+
└────────────────┬───────────────────────────────┘
|
|
319
|
+
│
|
|
320
|
+
┌───────────┴──────────┐
|
|
321
|
+
│ │
|
|
322
|
+
▼ ▼
|
|
323
|
+
┌──────────────────┐ ┌──────────────────┐
|
|
324
|
+
│ OUTPUT LAYER │ │ FEEDBACK LAYER │
|
|
325
|
+
│ - Articles │ │ - CI/CD Alerts │
|
|
326
|
+
│ - Tests │ │ - Dashboards │
|
|
327
|
+
│ - API Docs │ │ - GitHub Issues │
|
|
328
|
+
│ - Chatbot KB │ │ - Slack Notifs │
|
|
329
|
+
└──────────────────┘ └──────────────────┘
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## Truth Reconciliation Strategies
|
|
335
|
+
|
|
336
|
+
### Strategy 1: Hierarchical Authority
|
|
337
|
+
|
|
338
|
+
Different sources have different authority for different questions:
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
interface TruthAuthority {
|
|
342
|
+
question: string;
|
|
343
|
+
primarySource: Source;
|
|
344
|
+
validationSources: Source[];
|
|
345
|
+
tieBreaker: Source;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const authorityRules: TruthAuthority[] = [
|
|
349
|
+
{
|
|
350
|
+
question: "What parameters does this command accept?",
|
|
351
|
+
primarySource: "product_code", // Code is ground truth
|
|
352
|
+
validationSources: ["api_spec", "test_results"],
|
|
353
|
+
tieBreaker: "test_results" // If code and spec conflict, tests prove reality
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
question: "What is the recommended workflow?",
|
|
357
|
+
primarySource: "documentation", // Product team's intent
|
|
358
|
+
validationSources: ["usage_data"],
|
|
359
|
+
tieBreaker: "usage_data" // But if users do something different, consider it
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
question: "What terminology should we use?",
|
|
363
|
+
primarySource: "documentation", // Canonical terms
|
|
364
|
+
validationSources: ["chatbot_logs"],
|
|
365
|
+
tieBreaker: "chatbot_logs" // Users' natural language reveals confusion
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
question: "Is this feature working correctly?",
|
|
369
|
+
primarySource: "test_results", // Tests prove it works
|
|
370
|
+
validationSources: ["support_tickets"],
|
|
371
|
+
tieBreaker: "support_tickets" // Tickets reveal edge cases tests missed
|
|
372
|
+
}
|
|
373
|
+
];
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### Strategy 2: Temporal Consensus
|
|
377
|
+
|
|
378
|
+
Truth can change over time. Track when each source was last updated:
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
interface TemporalFact {
|
|
382
|
+
fact: "campaigns list supports --format parameter";
|
|
383
|
+
sources: [
|
|
384
|
+
{
|
|
385
|
+
source: "code",
|
|
386
|
+
value: true,
|
|
387
|
+
timestamp: "2025-01-15T10:00:00Z",
|
|
388
|
+
version: "v1.5.0"
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
source: "documentation",
|
|
392
|
+
value: true,
|
|
393
|
+
timestamp: "2025-01-20T14:30:00Z", // Updated 5 days later
|
|
394
|
+
version: "docs-rev-234"
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
source: "test_results",
|
|
398
|
+
value: true,
|
|
399
|
+
timestamp: "2025-01-15T10:05:00Z", // Tested immediately
|
|
400
|
+
lastRun: "2025-10-26T08:00:00Z"
|
|
401
|
+
}
|
|
402
|
+
];
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Reconciliation logic
|
|
406
|
+
function reconcile(fact: TemporalFact): Resolution {
|
|
407
|
+
const newestSource = maxBy(fact.sources, s => s.timestamp);
|
|
408
|
+
const outdatedSources = fact.sources.filter(s =>
|
|
409
|
+
s.timestamp < newestSource.timestamp - STALENESS_THRESHOLD
|
|
410
|
+
);
|
|
411
|
+
|
|
412
|
+
if (outdatedSources.length > 0) {
|
|
413
|
+
return {
|
|
414
|
+
status: "NEEDS_UPDATE",
|
|
415
|
+
canonical: newestSource.value,
|
|
416
|
+
stale: outdatedSources,
|
|
417
|
+
action: `Update ${outdatedSources.map(s => s.source).join(', ')}`
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
return { status: "CONSISTENT" };
|
|
422
|
+
}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### Strategy 3: Confidence Scoring
|
|
426
|
+
|
|
427
|
+
Not all statements are equal. Score confidence based on multiple factors:
|
|
428
|
+
|
|
429
|
+
```typescript
|
|
430
|
+
interface ConfidenceScore {
|
|
431
|
+
fact: string;
|
|
432
|
+
confidence: number; // 0.0 - 1.0
|
|
433
|
+
factors: {
|
|
434
|
+
sourceAuthority: number; // How authoritative is the source?
|
|
435
|
+
sourceFreshness: number; // How recent is the information?
|
|
436
|
+
sourceConsensus: number; // How many sources agree?
|
|
437
|
+
validationStatus: number; // Has it been tested/verified?
|
|
438
|
+
userConfirmation: number; // Do users' actions confirm it?
|
|
439
|
+
supportEvidence: number; // Do tickets confirm or contradict?
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function calculateConfidence(fact: Fact): ConfidenceScore {
|
|
444
|
+
const scores = {
|
|
445
|
+
sourceAuthority: calculateAuthorityScore(fact.sources),
|
|
446
|
+
sourceFreshness: calculateFreshnessScore(fact.sources),
|
|
447
|
+
sourceConsensus: calculateConsensusScore(fact.sources),
|
|
448
|
+
validationStatus: fact.testResults?.passed ? 1.0 : 0.5,
|
|
449
|
+
userConfirmation: calculateUsageAlignment(fact, usageData),
|
|
450
|
+
supportEvidence: calculateTicketAlignment(fact, tickets)
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
// Weighted average
|
|
454
|
+
const weights = {
|
|
455
|
+
sourceAuthority: 0.3,
|
|
456
|
+
sourceFreshness: 0.2,
|
|
457
|
+
sourceConsensus: 0.2,
|
|
458
|
+
validationStatus: 0.15,
|
|
459
|
+
userConfirmation: 0.10,
|
|
460
|
+
supportEvidence: 0.05
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
const confidence = Object.entries(scores).reduce(
|
|
464
|
+
(sum, [key, score]) => sum + score * weights[key],
|
|
465
|
+
0
|
|
466
|
+
);
|
|
467
|
+
|
|
468
|
+
return { fact: fact.statement, confidence, factors: scores };
|
|
469
|
+
}
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Strategy 4: Gap Detection Patterns
|
|
473
|
+
|
|
474
|
+
Systematically identify gaps using cross-source analysis:
|
|
475
|
+
|
|
476
|
+
```typescript
|
|
477
|
+
class GapDetector {
|
|
478
|
+
async detectGaps(): Promise<Gap[]> {
|
|
479
|
+
const gaps: Gap[] = [];
|
|
480
|
+
|
|
481
|
+
// Gap Type 1: Code features not documented
|
|
482
|
+
const undocumentedFeatures = await this.findUndocumentedFeatures();
|
|
483
|
+
gaps.push(...undocumentedFeatures.map(f => ({
|
|
484
|
+
type: 'undocumented_feature',
|
|
485
|
+
severity: 'high',
|
|
486
|
+
description: `Feature '${f.name}' exists in code but not documented`,
|
|
487
|
+
sources: { has: ['code'], missing: ['documentation'] },
|
|
488
|
+
action: 'Document this feature'
|
|
489
|
+
})));
|
|
490
|
+
|
|
491
|
+
// Gap Type 2: Documentation references non-existent features
|
|
492
|
+
const ghostFeatures = await this.findGhostFeatures();
|
|
493
|
+
gaps.push(...ghostFeatures.map(f => ({
|
|
494
|
+
type: 'ghost_feature',
|
|
495
|
+
severity: 'critical',
|
|
496
|
+
description: `Documentation mentions '${f.name}' but it doesn't exist in code`,
|
|
497
|
+
sources: { has: ['documentation'], missing: ['code'] },
|
|
498
|
+
action: 'Remove from docs OR implement feature'
|
|
499
|
+
})));
|
|
500
|
+
|
|
501
|
+
// Gap Type 3: High usage features not well documented
|
|
502
|
+
const underdocumentedFeatures = await this.findUnderdocumented();
|
|
503
|
+
gaps.push(...underdocumentedFeatures.map(f => ({
|
|
504
|
+
type: 'underdocumented',
|
|
505
|
+
severity: 'medium',
|
|
506
|
+
description: `Feature '${f.name}' is heavily used (${f.usageCount} times) but docs are minimal`,
|
|
507
|
+
sources: { has: ['code', 'usage_data'], insufficient: ['documentation'] },
|
|
508
|
+
action: 'Expand documentation with examples and best practices'
|
|
509
|
+
})));
|
|
510
|
+
|
|
511
|
+
// Gap Type 4: Common support questions not in docs
|
|
512
|
+
const faqGaps = await this.findFAQGaps();
|
|
513
|
+
gaps.push(...faqGaps.map(q => ({
|
|
514
|
+
type: 'missing_faq',
|
|
515
|
+
severity: 'medium',
|
|
516
|
+
description: `Common question: "${q.question}" (${q.ticketCount} tickets)`,
|
|
517
|
+
sources: { has: ['support_tickets'], missing: ['documentation'] },
|
|
518
|
+
action: 'Add FAQ entry or improve relevant documentation'
|
|
519
|
+
})));
|
|
520
|
+
|
|
521
|
+
// Gap Type 5: Workflows implied but not documented
|
|
522
|
+
const workflowGaps = await this.findWorkflowGaps();
|
|
523
|
+
gaps.push(...workflowGaps.map(w => ({
|
|
524
|
+
type: 'missing_workflow',
|
|
525
|
+
severity: 'high',
|
|
526
|
+
description: `Common sequence: ${w.steps.join(' → ')} (${w.frequency} occurrences)`,
|
|
527
|
+
sources: { has: ['usage_data'], missing: ['documentation'] },
|
|
528
|
+
action: 'Document this workflow as a tutorial'
|
|
529
|
+
})));
|
|
530
|
+
|
|
531
|
+
return gaps;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
async findUndocumentedFeatures(): Promise<Feature[]> {
|
|
535
|
+
// Find features in code
|
|
536
|
+
const codeFeatures = await this.extractFeaturesFromCode();
|
|
537
|
+
|
|
538
|
+
// Find features in docs
|
|
539
|
+
const docFeatures = await this.extractFeaturesFromDocs();
|
|
540
|
+
|
|
541
|
+
// Features in code but not in docs
|
|
542
|
+
return codeFeatures.filter(cf =>
|
|
543
|
+
!docFeatures.some(df => df.name === cf.name)
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
async findWorkflowGaps(): Promise<Workflow[]> {
|
|
548
|
+
// Analyze command sequences from usage data
|
|
549
|
+
const sequences = await this.analyzeCommandSequences(usageData);
|
|
550
|
+
|
|
551
|
+
// Find common patterns (e.g., "create → schedule → send")
|
|
552
|
+
const commonWorkflows = sequences.filter(s =>
|
|
553
|
+
s.frequency > WORKFLOW_THRESHOLD
|
|
554
|
+
);
|
|
555
|
+
|
|
556
|
+
// Check if documented
|
|
557
|
+
const documentedWorkflows = await this.getDocumentedWorkflows();
|
|
558
|
+
|
|
559
|
+
return commonWorkflows.filter(cw =>
|
|
560
|
+
!documentedWorkflows.some(dw => dw.matches(cw))
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
### Strategy 5: Conflict Resolution Pipeline
|
|
567
|
+
|
|
568
|
+
When sources conflict, use a systematic resolution process:
|
|
569
|
+
|
|
570
|
+
```typescript
|
|
571
|
+
class ConflictResolver {
|
|
572
|
+
async resolve(conflict: Conflict): Promise<Resolution> {
|
|
573
|
+
// Step 1: Identify conflict type
|
|
574
|
+
const conflictType = this.classifyConflict(conflict);
|
|
575
|
+
|
|
576
|
+
// Step 2: Apply appropriate resolution strategy
|
|
577
|
+
switch (conflictType) {
|
|
578
|
+
case 'code_vs_docs':
|
|
579
|
+
return this.resolveCodeVsDocs(conflict);
|
|
580
|
+
|
|
581
|
+
case 'spec_vs_implementation':
|
|
582
|
+
return this.resolveSpecVsImpl(conflict);
|
|
583
|
+
|
|
584
|
+
case 'intent_vs_usage':
|
|
585
|
+
return this.resolveIntentVsUsage(conflict);
|
|
586
|
+
|
|
587
|
+
case 'multiple_doc_versions':
|
|
588
|
+
return this.resolveDocInconsistency(conflict);
|
|
589
|
+
|
|
590
|
+
default:
|
|
591
|
+
return this.escalateToHuman(conflict);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
async resolveCodeVsDocs(conflict: Conflict): Promise<Resolution> {
|
|
596
|
+
// Code is authoritative for "what is"
|
|
597
|
+
// But check if code might be the bug
|
|
598
|
+
|
|
599
|
+
// Run tests
|
|
600
|
+
const testResult = await this.runTests(conflict.codeVersion);
|
|
601
|
+
|
|
602
|
+
if (!testResult.passed) {
|
|
603
|
+
// Code is broken, docs might be right
|
|
604
|
+
return {
|
|
605
|
+
canonical: conflict.docsVersion,
|
|
606
|
+
action: 'FIX_CODE',
|
|
607
|
+
reason: 'Code fails tests, documentation describes correct behavior',
|
|
608
|
+
evidence: testResult
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// Code works, check if it matches API spec
|
|
613
|
+
const specCheck = await this.checkAgainstSpec(conflict.codeVersion);
|
|
614
|
+
|
|
615
|
+
if (!specCheck.matches) {
|
|
616
|
+
// Code works but doesn't match spec - need decision
|
|
617
|
+
return {
|
|
618
|
+
canonical: null,
|
|
619
|
+
action: 'DECISION_REQUIRED',
|
|
620
|
+
reason: 'Code works but deviates from API spec',
|
|
621
|
+
options: [
|
|
622
|
+
{ action: 'UPDATE_SPEC', rationale: 'Code is better' },
|
|
623
|
+
{ action: 'UPDATE_CODE', rationale: 'Spec is the contract' }
|
|
624
|
+
]
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// Code is correct, update docs
|
|
629
|
+
return {
|
|
630
|
+
canonical: conflict.codeVersion,
|
|
631
|
+
action: 'UPDATE_DOCS',
|
|
632
|
+
reason: 'Code is tested and matches spec'
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
async resolveIntentVsUsage(conflict: Conflict): Promise<Resolution> {
|
|
637
|
+
// Product intent says one thing, users do another
|
|
638
|
+
|
|
639
|
+
const usageStrength = conflict.usageData.frequency;
|
|
640
|
+
const intentClarity = conflict.documentation.clarity_score;
|
|
641
|
+
|
|
642
|
+
if (usageStrength > HIGH_USAGE_THRESHOLD && intentClarity < LOW_CLARITY_THRESHOLD) {
|
|
643
|
+
// Users found a better way despite poor docs
|
|
644
|
+
return {
|
|
645
|
+
canonical: 'HYBRID',
|
|
646
|
+
action: 'DOCUMENT_BOTH',
|
|
647
|
+
reason: 'Users prefer alternative approach, both should be documented',
|
|
648
|
+
recommendation: {
|
|
649
|
+
primary: conflict.usageData.approach,
|
|
650
|
+
alternative: conflict.documentation.approach
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
if (conflict.supportTickets.count > TICKET_THRESHOLD) {
|
|
656
|
+
// Intent is confusing users
|
|
657
|
+
return {
|
|
658
|
+
canonical: conflict.usageData.approach,
|
|
659
|
+
action: 'UPDATE_INTENT',
|
|
660
|
+
reason: 'User behavior reveals better UX',
|
|
661
|
+
evidence: conflict.supportTickets
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
// Intent is clear, users just need guidance
|
|
666
|
+
return {
|
|
667
|
+
canonical: conflict.documentation.approach,
|
|
668
|
+
action: 'IMPROVE_DOCS',
|
|
669
|
+
reason: 'Add examples showing intended usage pattern'
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
---
|
|
676
|
+
|
|
677
|
+
## Knowledge Graph Schema: Multi-Source Model
|
|
678
|
+
|
|
679
|
+
### Enhanced Node Schema
|
|
680
|
+
|
|
681
|
+
```typescript
|
|
682
|
+
interface FactNode {
|
|
683
|
+
id: string;
|
|
684
|
+
type: 'command' | 'parameter' | 'concept' | 'workflow' | 'error';
|
|
685
|
+
|
|
686
|
+
// The canonical fact (reconciled truth)
|
|
687
|
+
canonicalValue: any;
|
|
688
|
+
confidence: number; // 0.0 - 1.0
|
|
689
|
+
|
|
690
|
+
// Provenance: where did this fact come from?
|
|
691
|
+
sources: SourceEvidence[];
|
|
692
|
+
|
|
693
|
+
// Temporal tracking
|
|
694
|
+
firstSeen: Date;
|
|
695
|
+
lastUpdated: Date;
|
|
696
|
+
lastVerified: Date;
|
|
697
|
+
|
|
698
|
+
// Conflict tracking
|
|
699
|
+
hasConflicts: boolean;
|
|
700
|
+
conflicts?: Conflict[];
|
|
701
|
+
|
|
702
|
+
// Gap tracking
|
|
703
|
+
hasGaps: boolean;
|
|
704
|
+
gaps?: Gap[];
|
|
705
|
+
|
|
706
|
+
// Metadata
|
|
707
|
+
tags: string[];
|
|
708
|
+
version: string;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
interface SourceEvidence {
|
|
712
|
+
source: 'code' | 'spec' | 'docs' | 'usage' | 'support' | 'chatbot' | 'tests';
|
|
713
|
+
value: any;
|
|
714
|
+
confidence: number;
|
|
715
|
+
timestamp: Date;
|
|
716
|
+
version?: string;
|
|
717
|
+
|
|
718
|
+
// Provenance details
|
|
719
|
+
location?: string; // File path, URL, ticket ID, etc.
|
|
720
|
+
extractedBy?: string; // Parser, human, AI, etc.
|
|
721
|
+
validatedBy?: string[]; // What validated this?
|
|
722
|
+
|
|
723
|
+
// Metadata
|
|
724
|
+
metadata?: {
|
|
725
|
+
commit?: string;
|
|
726
|
+
author?: string;
|
|
727
|
+
reviewers?: string[];
|
|
728
|
+
[key: string]: any;
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
interface Conflict {
|
|
733
|
+
id: string;
|
|
734
|
+
type: 'value_mismatch' | 'presence_mismatch' | 'intent_mismatch';
|
|
735
|
+
severity: 'low' | 'medium' | 'high' | 'critical';
|
|
736
|
+
|
|
737
|
+
sources: [SourceEvidence, SourceEvidence]; // Conflicting sources
|
|
738
|
+
description: string;
|
|
739
|
+
|
|
740
|
+
// Resolution
|
|
741
|
+
status: 'detected' | 'analyzing' | 'resolved' | 'escalated';
|
|
742
|
+
resolution?: Resolution;
|
|
743
|
+
resolvedAt?: Date;
|
|
744
|
+
resolvedBy?: string; // 'ai' | 'human' | 'test'
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
interface Gap {
|
|
748
|
+
id: string;
|
|
749
|
+
type: 'undocumented' | 'unimplemented' | 'undertested' | 'underused' | 'faq_missing';
|
|
750
|
+
severity: 'low' | 'medium' | 'high' | 'critical';
|
|
751
|
+
|
|
752
|
+
description: string;
|
|
753
|
+
evidence: SourceEvidence[];
|
|
754
|
+
|
|
755
|
+
// Impact
|
|
756
|
+
affectedUsers?: number;
|
|
757
|
+
supportTicketCount?: number;
|
|
758
|
+
usageFrequency?: number;
|
|
759
|
+
|
|
760
|
+
// Resolution
|
|
761
|
+
status: 'detected' | 'planned' | 'in_progress' | 'resolved';
|
|
762
|
+
assignedTo?: string;
|
|
763
|
+
dueDate?: Date;
|
|
764
|
+
}
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
### Graph Relationships with Provenance
|
|
768
|
+
|
|
769
|
+
```cypher
|
|
770
|
+
// Command with multiple source evidence
|
|
771
|
+
CREATE (c:Command {
|
|
772
|
+
id: 'cmd-campaigns-list',
|
|
773
|
+
canonicalValue: {
|
|
774
|
+
name: 'campaigns list',
|
|
775
|
+
parameters: ['status', 'limit', 'page']
|
|
776
|
+
},
|
|
777
|
+
confidence: 0.95
|
|
778
|
+
})
|
|
779
|
+
|
|
780
|
+
// Source evidence from code
|
|
781
|
+
CREATE (e1:Evidence {
|
|
782
|
+
source: 'code',
|
|
783
|
+
location: 'src/commands/campaigns.ts:45',
|
|
784
|
+
extractedAt: datetime('2025-10-26T10:00:00Z'),
|
|
785
|
+
value: {
|
|
786
|
+
parameters: ['status', 'limit', 'page', 'sort'] // Note: has 'sort'!
|
|
787
|
+
}
|
|
788
|
+
})
|
|
789
|
+
|
|
790
|
+
// Source evidence from docs
|
|
791
|
+
CREATE (e2:Evidence {
|
|
792
|
+
source: 'documentation',
|
|
793
|
+
location: 'docs/commands/campaigns.md',
|
|
794
|
+
extractedAt: datetime('2025-10-20T14:00:00Z'),
|
|
795
|
+
value: {
|
|
796
|
+
parameters: ['status', 'limit', 'page'] // Note: missing 'sort'!
|
|
797
|
+
}
|
|
798
|
+
})
|
|
799
|
+
|
|
800
|
+
// Source evidence from tests
|
|
801
|
+
CREATE (e3:Evidence {
|
|
802
|
+
source: 'test_results',
|
|
803
|
+
location: 'tests/campaigns.test.ts',
|
|
804
|
+
lastRun: datetime('2025-10-26T08:00:00Z'),
|
|
805
|
+
value: {
|
|
806
|
+
parameters: ['status', 'limit', 'page', 'sort'], // Confirms 'sort' exists
|
|
807
|
+
allPassed: true
|
|
808
|
+
}
|
|
809
|
+
})
|
|
810
|
+
|
|
811
|
+
// Relationships
|
|
812
|
+
CREATE (c)-[:HAS_EVIDENCE {confidence: 0.9}]->(e1)
|
|
813
|
+
CREATE (c)-[:HAS_EVIDENCE {confidence: 0.7}]->(e2)
|
|
814
|
+
CREATE (c)-[:HAS_EVIDENCE {confidence: 1.0}]->(e3)
|
|
815
|
+
|
|
816
|
+
// Conflict detected
|
|
817
|
+
CREATE (conflict:Conflict {
|
|
818
|
+
type: 'value_mismatch',
|
|
819
|
+
description: 'Code and tests show sort parameter exists, docs missing it',
|
|
820
|
+
severity: 'medium'
|
|
821
|
+
})
|
|
822
|
+
CREATE (e1)-[:CONFLICTS_WITH]->(e2)
|
|
823
|
+
CREATE (c)-[:HAS_CONFLICT]->(conflict)
|
|
824
|
+
|
|
825
|
+
// Gap detected
|
|
826
|
+
CREATE (gap:Gap {
|
|
827
|
+
type: 'undocumented',
|
|
828
|
+
description: 'sort parameter not documented',
|
|
829
|
+
severity: 'medium'
|
|
830
|
+
})
|
|
831
|
+
CREATE (c)-[:HAS_GAP]->(gap)
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
---
|
|
835
|
+
|
|
836
|
+
## Operational Workflows
|
|
837
|
+
|
|
838
|
+
### Workflow 1: Continuous Reconciliation (Automated)
|
|
839
|
+
|
|
840
|
+
```typescript
|
|
841
|
+
// Runs continuously in CI/CD pipeline
|
|
842
|
+
class ContinuousReconciliation {
|
|
843
|
+
async reconcile() {
|
|
844
|
+
// 1. Extract truth from all sources
|
|
845
|
+
const codeExtract = await this.extractFromCode();
|
|
846
|
+
const specExtract = await this.extractFromSpec();
|
|
847
|
+
const docsExtract = await this.extractFromDocs();
|
|
848
|
+
const usageExtract = await this.extractFromUsage();
|
|
849
|
+
const supportExtract = await this.extractFromSupport();
|
|
850
|
+
const chatExtract = await this.extractFromChatbot();
|
|
851
|
+
const testExtract = await this.extractFromTests();
|
|
852
|
+
|
|
853
|
+
// 2. Ingest into graph
|
|
854
|
+
await this.ingestEvidence([
|
|
855
|
+
codeExtract,
|
|
856
|
+
specExtract,
|
|
857
|
+
docsExtract,
|
|
858
|
+
usageExtract,
|
|
859
|
+
supportExtract,
|
|
860
|
+
chatExtract,
|
|
861
|
+
testExtract
|
|
862
|
+
]);
|
|
863
|
+
|
|
864
|
+
// 3. Detect conflicts
|
|
865
|
+
const conflicts = await this.detectConflicts();
|
|
866
|
+
|
|
867
|
+
// 4. Detect gaps
|
|
868
|
+
const gaps = await this.detectGaps();
|
|
869
|
+
|
|
870
|
+
// 5. Auto-resolve what we can
|
|
871
|
+
const autoResolved = await this.autoResolve(conflicts);
|
|
872
|
+
|
|
873
|
+
// 6. Escalate what we can't
|
|
874
|
+
const escalated = conflicts.filter(c => !autoResolved.includes(c));
|
|
875
|
+
await this.createGitHubIssues(escalated);
|
|
876
|
+
|
|
877
|
+
// 7. Generate reports
|
|
878
|
+
await this.generateReport({
|
|
879
|
+
conflicts: { total: conflicts.length, resolved: autoResolved.length, escalated: escalated.length },
|
|
880
|
+
gaps: { total: gaps.length, byType: groupBy(gaps, 'type') },
|
|
881
|
+
confidence: this.calculateOverallConfidence()
|
|
882
|
+
});
|
|
883
|
+
|
|
884
|
+
// 8. Update outputs (docs, tests)
|
|
885
|
+
if (autoResolved.length > 0) {
|
|
886
|
+
await this.regenerateAffectedOutputs(autoResolved);
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
async extractFromCode(): Promise<SourceEvidence[]> {
|
|
891
|
+
// Use AST parsing to extract command structure
|
|
892
|
+
const ast = await parseTypeScript('src/commands/**/*.ts');
|
|
893
|
+
|
|
894
|
+
const commands = ast.findAll('Command')
|
|
895
|
+
.map(node => ({
|
|
896
|
+
source: 'code',
|
|
897
|
+
type: 'command',
|
|
898
|
+
value: {
|
|
899
|
+
name: node.name,
|
|
900
|
+
parameters: node.options.map(o => ({
|
|
901
|
+
name: o.name,
|
|
902
|
+
type: inferType(o.type),
|
|
903
|
+
required: o.required,
|
|
904
|
+
default: o.default
|
|
905
|
+
}))
|
|
906
|
+
},
|
|
907
|
+
location: `${node.file}:${node.line}`,
|
|
908
|
+
timestamp: node.lastModified,
|
|
909
|
+
metadata: {
|
|
910
|
+
commit: node.commit,
|
|
911
|
+
author: node.author
|
|
912
|
+
}
|
|
913
|
+
}));
|
|
914
|
+
|
|
915
|
+
return commands;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
async extractFromUsage(): Promise<SourceEvidence[]> {
|
|
919
|
+
// Query analytics database for command usage
|
|
920
|
+
const usageData = await analytics.query(`
|
|
921
|
+
SELECT
|
|
922
|
+
command,
|
|
923
|
+
COUNT(*) as frequency,
|
|
924
|
+
AVG(success::int) as success_rate,
|
|
925
|
+
MODE() WITHIN GROUP (ORDER BY next_command) as common_next_command
|
|
926
|
+
FROM command_logs
|
|
927
|
+
WHERE timestamp > NOW() - INTERVAL '30 days'
|
|
928
|
+
GROUP BY command
|
|
929
|
+
HAVING COUNT(*) > 10
|
|
930
|
+
`);
|
|
931
|
+
|
|
932
|
+
return usageData.map(row => ({
|
|
933
|
+
source: 'usage',
|
|
934
|
+
type: 'command_usage',
|
|
935
|
+
value: {
|
|
936
|
+
command: row.command,
|
|
937
|
+
frequency: row.frequency,
|
|
938
|
+
successRate: row.success_rate,
|
|
939
|
+
commonNextCommand: row.common_next_command
|
|
940
|
+
},
|
|
941
|
+
timestamp: new Date(),
|
|
942
|
+
confidence: row.frequency > 100 ? 0.9 : 0.7
|
|
943
|
+
}));
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
async extractFromSupport(): Promise<SourceEvidence[]> {
|
|
947
|
+
// Analyze support tickets with NLP
|
|
948
|
+
const tickets = await supportSystem.getRecentTickets(30);
|
|
949
|
+
|
|
950
|
+
const classified = await Promise.all(
|
|
951
|
+
tickets.map(async ticket => {
|
|
952
|
+
const analysis = await this.llm.analyze(`
|
|
953
|
+
Classify this support ticket:
|
|
954
|
+
|
|
955
|
+
Title: ${ticket.title}
|
|
956
|
+
Description: ${ticket.description}
|
|
957
|
+
Resolution: ${ticket.resolution}
|
|
958
|
+
|
|
959
|
+
Extract:
|
|
960
|
+
1. What feature/command is this about?
|
|
961
|
+
2. What was the user's confusion?
|
|
962
|
+
3. Is this a bug, doc issue, or UX issue?
|
|
963
|
+
4. What's the root cause?
|
|
964
|
+
`);
|
|
965
|
+
|
|
966
|
+
return {
|
|
967
|
+
source: 'support',
|
|
968
|
+
type: analysis.issueType,
|
|
969
|
+
value: {
|
|
970
|
+
feature: analysis.feature,
|
|
971
|
+
confusion: analysis.confusion,
|
|
972
|
+
rootCause: analysis.rootCause
|
|
973
|
+
},
|
|
974
|
+
location: ticket.id,
|
|
975
|
+
timestamp: ticket.created_at,
|
|
976
|
+
confidence: 0.6 // Human verification recommended
|
|
977
|
+
};
|
|
978
|
+
})
|
|
979
|
+
);
|
|
980
|
+
|
|
981
|
+
return classified;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
async detectConflicts(): Promise<Conflict[]> {
|
|
985
|
+
// Query graph for facts with multiple conflicting sources
|
|
986
|
+
const query = `
|
|
987
|
+
MATCH (f:Fact)-[:HAS_EVIDENCE]->(e1:Evidence)
|
|
988
|
+
MATCH (f)-[:HAS_EVIDENCE]->(e2:Evidence)
|
|
989
|
+
WHERE e1.value <> e2.value
|
|
990
|
+
AND e1.source <> e2.source
|
|
991
|
+
AND NOT exists((e1)-[:CONFLICTS_WITH]->(e2))
|
|
992
|
+
RETURN f, e1, e2
|
|
993
|
+
`;
|
|
994
|
+
|
|
995
|
+
const results = await this.graph.query(query);
|
|
996
|
+
|
|
997
|
+
return results.map(({ f, e1, e2 }) => ({
|
|
998
|
+
id: generateId(),
|
|
999
|
+
type: this.classifyConflictType(e1, e2),
|
|
1000
|
+
severity: this.assessSeverity(e1, e2, f),
|
|
1001
|
+
sources: [e1, e2],
|
|
1002
|
+
description: this.describeConflict(f, e1, e2),
|
|
1003
|
+
status: 'detected'
|
|
1004
|
+
}));
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
```
|
|
1008
|
+
|
|
1009
|
+
### Workflow 2: Human-Driven Resolution
|
|
1010
|
+
|
|
1011
|
+
```typescript
|
|
1012
|
+
// Interactive dashboard for resolving conflicts and gaps
|
|
1013
|
+
class ReconciliationDashboard {
|
|
1014
|
+
async showDashboard() {
|
|
1015
|
+
const conflicts = await this.graph.getUnresolvedConflicts();
|
|
1016
|
+
const gaps = await this.graph.getUnresolvedGaps();
|
|
1017
|
+
|
|
1018
|
+
console.log(`
|
|
1019
|
+
┌───────────────────────────────────────────────────────────┐
|
|
1020
|
+
│ Kenogami Reconciliation Dashboard │
|
|
1021
|
+
└───────────────────────────────────────────────────────────┘
|
|
1022
|
+
|
|
1023
|
+
📊 Status:
|
|
1024
|
+
├─ Overall Confidence: ${this.calculateConfidence()}%
|
|
1025
|
+
├─ Unresolved Conflicts: ${conflicts.length}
|
|
1026
|
+
├─ Unresolved Gaps: ${gaps.length}
|
|
1027
|
+
└─ Last Sync: ${this.lastSyncTime}
|
|
1028
|
+
|
|
1029
|
+
🚨 Critical Conflicts (${conflicts.filter(c => c.severity === 'critical').length}):
|
|
1030
|
+
${this.renderConflicts(conflicts.filter(c => c.severity === 'critical'))}
|
|
1031
|
+
|
|
1032
|
+
📝 High-Priority Gaps (${gaps.filter(g => g.severity === 'high').length}):
|
|
1033
|
+
${this.renderGaps(gaps.filter(g => g.severity === 'high'))}
|
|
1034
|
+
|
|
1035
|
+
🔍 Actions:
|
|
1036
|
+
1. Review conflicts
|
|
1037
|
+
2. Review gaps
|
|
1038
|
+
3. Run reconciliation
|
|
1039
|
+
4. Generate report
|
|
1040
|
+
5. Update sources
|
|
1041
|
+
|
|
1042
|
+
Choice:
|
|
1043
|
+
`);
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
async reviewConflict(conflict: Conflict) {
|
|
1047
|
+
console.log(`
|
|
1048
|
+
┌───────────────────────────────────────────────────────────┐
|
|
1049
|
+
│ Conflict: ${conflict.description} │
|
|
1050
|
+
│ Severity: ${conflict.severity} │
|
|
1051
|
+
└───────────────────────────────────────────────────────────┘
|
|
1052
|
+
|
|
1053
|
+
Source 1: ${conflict.sources[0].source}
|
|
1054
|
+
Location: ${conflict.sources[0].location}
|
|
1055
|
+
Value: ${JSON.stringify(conflict.sources[0].value, null, 2)}
|
|
1056
|
+
Confidence: ${conflict.sources[0].confidence}
|
|
1057
|
+
Last Updated: ${conflict.sources[0].timestamp}
|
|
1058
|
+
|
|
1059
|
+
Source 2: ${conflict.sources[1].source}
|
|
1060
|
+
Location: ${conflict.sources[1].location}
|
|
1061
|
+
Value: ${JSON.stringify(conflict.sources[1].value, null, 2)}
|
|
1062
|
+
Confidence: ${conflict.sources[1].confidence}
|
|
1063
|
+
Last Updated: ${conflict.sources[1].timestamp}
|
|
1064
|
+
|
|
1065
|
+
🤖 AI Recommendation: ${await this.getAIRecommendation(conflict)}
|
|
1066
|
+
|
|
1067
|
+
🔧 Resolution Options:
|
|
1068
|
+
1. Use Source 1 (${conflict.sources[0].source})
|
|
1069
|
+
2. Use Source 2 (${conflict.sources[1].source})
|
|
1070
|
+
3. Merge both
|
|
1071
|
+
4. Create new canonical value
|
|
1072
|
+
5. Escalate to product team
|
|
1073
|
+
6. Run tests to verify
|
|
1074
|
+
|
|
1075
|
+
Choice:
|
|
1076
|
+
`);
|
|
1077
|
+
|
|
1078
|
+
const choice = await this.prompt();
|
|
1079
|
+
return this.applyResolution(conflict, choice);
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
```
|
|
1083
|
+
|
|
1084
|
+
### Workflow 3: Feedback Loop from Outputs
|
|
1085
|
+
|
|
1086
|
+
```typescript
|
|
1087
|
+
// Outputs (docs, tests) feed back findings to the graph
|
|
1088
|
+
class OutputFeedbackLoop {
|
|
1089
|
+
async processTestResults(results: TestResult[]) {
|
|
1090
|
+
for (const result of results) {
|
|
1091
|
+
if (!result.passed) {
|
|
1092
|
+
// Test failed - reality doesn't match expectation
|
|
1093
|
+
await this.analyzeTestFailure(result);
|
|
1094
|
+
} else if (result.actualOutput !== result.expectedOutput) {
|
|
1095
|
+
// Test passed but output different - possible drift
|
|
1096
|
+
await this.flagPotentialDrift(result);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
async analyzeTestFailure(result: TestResult) {
|
|
1102
|
+
// Use AI to determine what's wrong
|
|
1103
|
+
const analysis = await this.llm.analyze(`
|
|
1104
|
+
Test failed:
|
|
1105
|
+
|
|
1106
|
+
Test: ${result.testName}
|
|
1107
|
+
Command: ${result.command}
|
|
1108
|
+
Expected: ${result.expectedOutput}
|
|
1109
|
+
Actual: ${result.actualOutput}
|
|
1110
|
+
Error: ${result.error}
|
|
1111
|
+
|
|
1112
|
+
Analyze:
|
|
1113
|
+
1. Is the test wrong (expected output incorrect)?
|
|
1114
|
+
2. Is the code wrong (bug in implementation)?
|
|
1115
|
+
3. Is the documentation wrong (describes non-existent behavior)?
|
|
1116
|
+
4. Is the API spec wrong?
|
|
1117
|
+
|
|
1118
|
+
Provide recommendation.
|
|
1119
|
+
`);
|
|
1120
|
+
|
|
1121
|
+
if (analysis.rootCause === 'documentation_wrong') {
|
|
1122
|
+
// Update graph with correct information from test
|
|
1123
|
+
await this.updateGraph({
|
|
1124
|
+
source: 'test_results',
|
|
1125
|
+
value: result.actualOutput,
|
|
1126
|
+
confidence: 0.9,
|
|
1127
|
+
evidence: result,
|
|
1128
|
+
suggestedAction: 'UPDATE_DOCS'
|
|
1129
|
+
});
|
|
1130
|
+
|
|
1131
|
+
// Create conflict between docs and reality
|
|
1132
|
+
await this.createConflict({
|
|
1133
|
+
type: 'docs_vs_reality',
|
|
1134
|
+
sources: ['documentation', 'test_results'],
|
|
1135
|
+
recommendation: 'Update documentation to match actual behavior'
|
|
1136
|
+
});
|
|
1137
|
+
} else if (analysis.rootCause === 'code_bug') {
|
|
1138
|
+
// Create GitHub issue for bug
|
|
1139
|
+
await this.createGitHubIssue({
|
|
1140
|
+
title: `Bug: ${result.testName} fails`,
|
|
1141
|
+
labels: ['bug', 'test-failure'],
|
|
1142
|
+
body: `Test expects: ${result.expectedOutput}\nActual: ${result.actualOutput}\n\n${analysis.explanation}`
|
|
1143
|
+
});
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
async processUserFeedback(feedback: UserFeedback) {
|
|
1148
|
+
// User reports: "The docs say X but when I tried it, Y happened"
|
|
1149
|
+
await this.createConflict({
|
|
1150
|
+
type: 'user_reported_mismatch',
|
|
1151
|
+
sources: ['documentation', 'user_feedback'],
|
|
1152
|
+
severity: 'medium',
|
|
1153
|
+
description: feedback.description,
|
|
1154
|
+
evidence: feedback
|
|
1155
|
+
});
|
|
1156
|
+
|
|
1157
|
+
// Track this for analysis
|
|
1158
|
+
await this.graph.createNode('UserReport', {
|
|
1159
|
+
source: 'user_feedback',
|
|
1160
|
+
type: feedback.type,
|
|
1161
|
+
description: feedback.description,
|
|
1162
|
+
timestamp: new Date(),
|
|
1163
|
+
user: feedback.userId
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
```
|
|
1168
|
+
|
|
1169
|
+
---
|
|
1170
|
+
|
|
1171
|
+
## Metrics & Monitoring
|
|
1172
|
+
|
|
1173
|
+
### Health Metrics
|
|
1174
|
+
|
|
1175
|
+
```typescript
|
|
1176
|
+
interface SystemHealth {
|
|
1177
|
+
// Confidence metrics
|
|
1178
|
+
overallConfidence: number; // 0-100%
|
|
1179
|
+
confidenceBySource: {
|
|
1180
|
+
code: number;
|
|
1181
|
+
spec: number;
|
|
1182
|
+
documentation: number;
|
|
1183
|
+
tests: number;
|
|
1184
|
+
usage: number;
|
|
1185
|
+
};
|
|
1186
|
+
|
|
1187
|
+
// Conflict metrics
|
|
1188
|
+
totalConflicts: number;
|
|
1189
|
+
conflictsBySeverity: {
|
|
1190
|
+
critical: number;
|
|
1191
|
+
high: number;
|
|
1192
|
+
medium: number;
|
|
1193
|
+
low: number;
|
|
1194
|
+
};
|
|
1195
|
+
conflictResolutionRate: number; // % resolved
|
|
1196
|
+
averageTimeToResolve: number; // hours
|
|
1197
|
+
|
|
1198
|
+
// Gap metrics
|
|
1199
|
+
totalGaps: number;
|
|
1200
|
+
gapsByType: {
|
|
1201
|
+
undocumented: number;
|
|
1202
|
+
unimplemented: number;
|
|
1203
|
+
undertested: number;
|
|
1204
|
+
faq_missing: number;
|
|
1205
|
+
};
|
|
1206
|
+
gapClosureRate: number; // % closed per week
|
|
1207
|
+
|
|
1208
|
+
// Freshness metrics
|
|
1209
|
+
averageSourceAge: {
|
|
1210
|
+
code: number; // days since last update
|
|
1211
|
+
documentation: number;
|
|
1212
|
+
tests: number;
|
|
1213
|
+
};
|
|
1214
|
+
staleSourcesCount: number; // sources older than threshold
|
|
1215
|
+
|
|
1216
|
+
// Coverage metrics
|
|
1217
|
+
documentationCoverage: number; // % of code features documented
|
|
1218
|
+
testCoverage: number; // % of documented features tested
|
|
1219
|
+
usageAlignment: number; // % of documented features actually used
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
// Alert thresholds
|
|
1223
|
+
const ALERTS = {
|
|
1224
|
+
overallConfidence: { critical: 60, warning: 75 },
|
|
1225
|
+
criticalConflicts: { critical: 5, warning: 2 },
|
|
1226
|
+
documentationCoverage: { critical: 70, warning: 85 },
|
|
1227
|
+
staleDocumentation: { critical: 90, warning: 60 } // days
|
|
1228
|
+
};
|
|
1229
|
+
```
|
|
1230
|
+
|
|
1231
|
+
### Dashboard Visualization
|
|
1232
|
+
|
|
1233
|
+
```
|
|
1234
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
1235
|
+
│ Kenogami System Health Dashboard │
|
|
1236
|
+
└─────────────────────────────────────────────────────────────┘
|
|
1237
|
+
|
|
1238
|
+
📊 Overall Health: 87% ████████░░ GOOD
|
|
1239
|
+
|
|
1240
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
1241
|
+
|
|
1242
|
+
🎯 Confidence Scores:
|
|
1243
|
+
|
|
1244
|
+
Code: 95% █████████░ Excellent
|
|
1245
|
+
Spec: 88% ████████░░ Good
|
|
1246
|
+
Documentation: 72% ███████░░░ Needs Attention ⚠️
|
|
1247
|
+
Tests: 91% █████████░ Good
|
|
1248
|
+
Usage Data: 85% ████████░░ Good
|
|
1249
|
+
|
|
1250
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
1251
|
+
|
|
1252
|
+
🚨 Conflicts:
|
|
1253
|
+
|
|
1254
|
+
Total: 23
|
|
1255
|
+
Critical: 2 🔴
|
|
1256
|
+
High: 5 🟠
|
|
1257
|
+
Medium: 12 🟡
|
|
1258
|
+
Low: 4 🟢
|
|
1259
|
+
|
|
1260
|
+
Resolution Rate: 78% (18/23 resolved this week)
|
|
1261
|
+
Avg Time to Resolve: 4.2 hours
|
|
1262
|
+
|
|
1263
|
+
Top Conflicts:
|
|
1264
|
+
1. API spec vs implementation (authentication flow)
|
|
1265
|
+
2. Documentation inconsistency (default output format)
|
|
1266
|
+
|
|
1267
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
1268
|
+
|
|
1269
|
+
📝 Gaps:
|
|
1270
|
+
|
|
1271
|
+
Total: 47
|
|
1272
|
+
Critical: 3 🔴 Fix immediately
|
|
1273
|
+
High: 12 🟠 Plan this sprint
|
|
1274
|
+
Medium: 21 🟡 Backlog
|
|
1275
|
+
Low: 11 🟢 Nice to have
|
|
1276
|
+
|
|
1277
|
+
Top Gaps:
|
|
1278
|
+
1. Workflow: Create → Schedule → Send (45 users, 0 docs)
|
|
1279
|
+
2. Parameter --batch not documented (12 support tickets)
|
|
1280
|
+
3. FAQ: "How do I authenticate?" (23 tickets)
|
|
1281
|
+
|
|
1282
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
1283
|
+
|
|
1284
|
+
📈 Coverage:
|
|
1285
|
+
|
|
1286
|
+
Documentation: 82% ████████░░ (112/136 commands)
|
|
1287
|
+
Testing: 94% █████████░ (128/136 commands)
|
|
1288
|
+
Usage: 76% ███████░░░ (104/136 commands used)
|
|
1289
|
+
|
|
1290
|
+
Undocumented but used: 8 features ⚠️
|
|
1291
|
+
Documented but unused: 24 features ℹ️
|
|
1292
|
+
|
|
1293
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
1294
|
+
|
|
1295
|
+
⏰ Freshness:
|
|
1296
|
+
|
|
1297
|
+
Code: 2 days ago ✅
|
|
1298
|
+
Documentation: 14 days ago ⚠️
|
|
1299
|
+
Tests: 1 day ago ✅
|
|
1300
|
+
|
|
1301
|
+
Stale sources: 3 (docs older than 30 days)
|
|
1302
|
+
|
|
1303
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
1304
|
+
|
|
1305
|
+
🎬 Actions:
|
|
1306
|
+
|
|
1307
|
+
⚡ Immediate:
|
|
1308
|
+
• Resolve 2 critical conflicts
|
|
1309
|
+
• Document 3 critical gaps
|
|
1310
|
+
|
|
1311
|
+
📅 This Week:
|
|
1312
|
+
• Update stale documentation (3 articles)
|
|
1313
|
+
• Close 5 high-priority gaps
|
|
1314
|
+
• Review 12 medium conflicts
|
|
1315
|
+
|
|
1316
|
+
🔮 Trends:
|
|
1317
|
+
• Confidence improving (+5% this week) ↗️
|
|
1318
|
+
• Conflicts decreasing (-3 resolved) ↘️
|
|
1319
|
+
• Gaps increasing (+7 detected) ⚠️
|
|
1320
|
+
```
|
|
1321
|
+
|
|
1322
|
+
---
|
|
1323
|
+
|
|
1324
|
+
## Summary: Philosophical Shift
|
|
1325
|
+
|
|
1326
|
+
### Old Mental Model: Single Source of Truth
|
|
1327
|
+
|
|
1328
|
+
```
|
|
1329
|
+
"The code is the truth" ❌
|
|
1330
|
+
"The docs are the truth" ❌
|
|
1331
|
+
"The spec is the truth" ❌
|
|
1332
|
+
```
|
|
1333
|
+
|
|
1334
|
+
**Problem:** No single source captures the full truth. Each source has partial truth.
|
|
1335
|
+
|
|
1336
|
+
### New Mental Model: Distributed Truth with Reconciliation
|
|
1337
|
+
|
|
1338
|
+
```
|
|
1339
|
+
"Truth is distributed across multiple authoritative sources,
|
|
1340
|
+
each with different authority for different questions.
|
|
1341
|
+
The knowledge graph reconciles these truths,
|
|
1342
|
+
detects conflicts and gaps,
|
|
1343
|
+
and synthesizes a coherent understanding
|
|
1344
|
+
that serves all stakeholders."
|
|
1345
|
+
```
|
|
1346
|
+
|
|
1347
|
+
**Reality:**
|
|
1348
|
+
- **Code** tells us what IS implemented
|
|
1349
|
+
- **Spec** tells us what SHOULD be implemented
|
|
1350
|
+
- **Documentation** tells us what we INTEND users to understand
|
|
1351
|
+
- **Usage** tells us what users ACTUALLY do
|
|
1352
|
+
- **Support** tells us where users STRUGGLE
|
|
1353
|
+
- **Tests** tell us what we've VERIFIED
|
|
1354
|
+
- **Chatbot** tells us how users LEARN
|
|
1355
|
+
|
|
1356
|
+
**Kenogami's Role:**
|
|
1357
|
+
Not to pick one truth, but to:
|
|
1358
|
+
1. **Capture** all truths with provenance
|
|
1359
|
+
2. **Detect** when truths conflict
|
|
1360
|
+
3. **Analyze** why conflicts exist
|
|
1361
|
+
4. **Resolve** conflicts using appropriate strategies
|
|
1362
|
+
5. **Identify** gaps where truth is missing
|
|
1363
|
+
6. **Synthesize** coherent output for each audience
|
|
1364
|
+
7. **Evolve** as all sources evolve
|
|
1365
|
+
|
|
1366
|
+
**Key Insight:**
|
|
1367
|
+
The knowledge graph is not the source of truth—it's the **reconciliation layer** that makes sense of distributed, evolving, sometimes-conflicting truths, maintaining coherence and surfacing problems for human decision-making.
|
|
1368
|
+
|
|
1369
|
+
This is fundamentally a **distributed systems problem** applied to knowledge management.
|