@geraldmaron/construct 1.0.3 → 1.0.5

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 (157) hide show
  1. package/README.md +51 -42
  2. package/agents/prompts/cx-ai-engineer.md +6 -26
  3. package/agents/prompts/cx-architect.md +1 -0
  4. package/agents/prompts/cx-business-strategist.md +2 -0
  5. package/agents/prompts/cx-data-analyst.md +6 -26
  6. package/agents/prompts/cx-docs-keeper.md +1 -31
  7. package/agents/prompts/cx-explorer.md +1 -0
  8. package/agents/prompts/cx-orchestrator.md +40 -112
  9. package/agents/prompts/cx-platform-engineer.md +2 -22
  10. package/agents/prompts/cx-product-manager.md +2 -1
  11. package/agents/prompts/cx-qa.md +0 -20
  12. package/agents/prompts/cx-rd-lead.md +2 -0
  13. package/agents/prompts/cx-researcher.md +77 -31
  14. package/agents/prompts/cx-security.md +11 -49
  15. package/agents/prompts/cx-sre.md +9 -43
  16. package/agents/prompts/cx-ux-researcher.md +1 -0
  17. package/agents/role-manifests.json +4 -4
  18. package/bin/construct +279 -4
  19. package/commands/understand/research.md +5 -3
  20. package/db/schema/004_recommendations.sql +46 -0
  21. package/db/schema/005_strategy.sql +21 -0
  22. package/lib/auto-docs.mjs +3 -4
  23. package/lib/beads-automation.mjs +16 -7
  24. package/lib/cli-commands.mjs +52 -2
  25. package/lib/comment-lint.mjs +7 -1
  26. package/lib/config/schema.mjs +3 -0
  27. package/lib/embed/conflict-detection.mjs +26 -9
  28. package/lib/embed/customer-profiles.mjs +37 -17
  29. package/lib/embed/daemon.mjs +10 -8
  30. package/lib/embed/recommendation-store.mjs +213 -14
  31. package/lib/embed/workspaces.mjs +53 -18
  32. package/lib/flavors/loader.mjs +136 -0
  33. package/lib/gates-audit.mjs +3 -3
  34. package/lib/health-check.mjs +1 -1
  35. package/lib/hooks/agent-tracker.mjs +22 -3
  36. package/lib/hooks/pre-compact.mjs +3 -0
  37. package/lib/hooks/pre-push-gate.mjs +14 -1
  38. package/lib/hooks/read-tracker.mjs +10 -101
  39. package/lib/hooks/session-optimize.mjs +3 -2
  40. package/lib/hooks/session-reflect.mjs +68 -0
  41. package/lib/host-capabilities.mjs +90 -1
  42. package/lib/init-unified.mjs +25 -2
  43. package/lib/init-update.mjs +246 -131
  44. package/lib/intake/classify.mjs +61 -183
  45. package/lib/intake/prepare.mjs +7 -0
  46. package/lib/intake/tables/creative.mjs +94 -0
  47. package/lib/intake/tables/operations.mjs +85 -0
  48. package/lib/intake/tables/research.mjs +85 -0
  49. package/lib/intake/tables/rnd.mjs +175 -0
  50. package/lib/intent-classifier.mjs +1 -0
  51. package/lib/knowledge/layout.mjs +10 -0
  52. package/lib/knowledge/research-store.mjs +109 -0
  53. package/lib/mcp/tools/telemetry.mjs +30 -78
  54. package/lib/model-router.mjs +61 -1
  55. package/lib/observation-store.mjs +19 -0
  56. package/lib/ollama-manager.mjs +1 -1
  57. package/lib/opencode-telemetry.mjs +4 -5
  58. package/lib/orchestration-policy.mjs +9 -0
  59. package/lib/outcomes/aggregate.mjs +104 -0
  60. package/lib/outcomes/record.mjs +115 -0
  61. package/lib/parity.mjs +121 -21
  62. package/lib/profiles/lifecycle.mjs +388 -0
  63. package/lib/profiles/loader.mjs +123 -0
  64. package/lib/profiles/validate-custom.mjs +114 -0
  65. package/lib/prompt-composer.js +106 -29
  66. package/lib/read-tracker-store.mjs +149 -0
  67. package/lib/reflect/extractor.mjs +193 -0
  68. package/lib/reflect.mjs +89 -2
  69. package/lib/sandbox.mjs +102 -0
  70. package/lib/server/index.mjs +76 -0
  71. package/lib/server/telemetry-login.mjs +17 -25
  72. package/lib/service-manager.mjs +30 -22
  73. package/lib/services/local-postgres.mjs +15 -0
  74. package/lib/services/telemetry-backend.mjs +1 -2
  75. package/lib/setup.mjs +8 -43
  76. package/lib/status.mjs +51 -5
  77. package/lib/storage/backend.mjs +12 -2
  78. package/lib/strategy-store.mjs +371 -0
  79. package/lib/telemetry/backends/local.mjs +6 -4
  80. package/lib/telemetry/client.mjs +185 -0
  81. package/lib/telemetry/ingest.mjs +13 -5
  82. package/lib/telemetry/team-rollup.mjs +9 -2
  83. package/lib/worker/trace.mjs +17 -27
  84. package/package.json +10 -2
  85. package/personas/construct.md +20 -20
  86. package/platforms/claude/settings.template.json +13 -0
  87. package/rules/common/research.md +44 -12
  88. package/scripts/sync-agents.mjs +11 -0
  89. package/skills/docs/backlog-proposal-workflow.md +2 -2
  90. package/skills/docs/customer-profile-workflow.md +1 -1
  91. package/skills/docs/evidence-ingest-workflow.md +5 -5
  92. package/skills/docs/prfaq-workflow.md +1 -1
  93. package/skills/docs/product-intelligence-review.md +1 -1
  94. package/skills/docs/product-intelligence-workflow.md +3 -3
  95. package/skills/docs/product-signal-workflow.md +48 -18
  96. package/skills/docs/research-workflow.md +26 -14
  97. package/skills/docs/strategy-workflow.md +36 -0
  98. package/skills/roles/architect.ai-systems.md +4 -2
  99. package/skills/roles/architect.data.md +4 -2
  100. package/skills/roles/architect.enterprise.md +4 -2
  101. package/skills/roles/architect.integration.md +4 -2
  102. package/skills/roles/architect.md +7 -5
  103. package/skills/roles/architect.platform.md +4 -2
  104. package/skills/roles/data-analyst.experiment.md +4 -2
  105. package/skills/roles/data-analyst.md +9 -7
  106. package/skills/roles/data-analyst.product-intelligence.md +5 -3
  107. package/skills/roles/data-analyst.product.md +4 -2
  108. package/skills/roles/data-analyst.telemetry.md +4 -2
  109. package/skills/roles/data-engineer.pipeline.md +4 -2
  110. package/skills/roles/data-engineer.vector-retrieval.md +4 -2
  111. package/skills/roles/data-engineer.warehouse.md +4 -2
  112. package/skills/roles/debugger.md +7 -5
  113. package/skills/roles/designer.accessibility.md +4 -2
  114. package/skills/roles/designer.md +10 -8
  115. package/skills/roles/engineer.ai.md +4 -2
  116. package/skills/roles/engineer.data.md +5 -3
  117. package/skills/roles/engineer.md +14 -12
  118. package/skills/roles/engineer.platform.md +5 -3
  119. package/skills/roles/operator.docs.md +6 -4
  120. package/skills/roles/operator.md +6 -4
  121. package/skills/roles/operator.release.md +4 -2
  122. package/skills/roles/operator.sre.md +5 -3
  123. package/skills/roles/orchestrator.md +5 -3
  124. package/skills/roles/product-manager.ai-product.md +4 -2
  125. package/skills/roles/product-manager.business-strategy.md +4 -2
  126. package/skills/roles/product-manager.enterprise.md +4 -2
  127. package/skills/roles/product-manager.growth.md +4 -2
  128. package/skills/roles/product-manager.md +6 -4
  129. package/skills/roles/product-manager.platform.md +4 -2
  130. package/skills/roles/product-manager.product.md +4 -2
  131. package/skills/roles/qa.ai-eval.md +4 -2
  132. package/skills/roles/qa.api-contract.md +4 -2
  133. package/skills/roles/qa.data-pipeline.md +4 -2
  134. package/skills/roles/qa.md +7 -5
  135. package/skills/roles/qa.test-automation.md +5 -3
  136. package/skills/roles/qa.web-ui.md +4 -2
  137. package/skills/roles/researcher.explorer.md +4 -2
  138. package/skills/roles/researcher.md +35 -20
  139. package/skills/roles/researcher.ux.md +4 -2
  140. package/skills/roles/reviewer.devil-advocate.md +4 -2
  141. package/skills/roles/reviewer.evaluator.md +4 -2
  142. package/skills/roles/reviewer.md +14 -12
  143. package/skills/roles/reviewer.trace.md +4 -2
  144. package/skills/roles/security.ai.md +4 -2
  145. package/skills/roles/security.appsec.md +4 -2
  146. package/skills/roles/security.cloud.md +4 -2
  147. package/skills/roles/security.legal-compliance.md +4 -2
  148. package/skills/roles/security.md +7 -5
  149. package/skills/roles/security.privacy.md +4 -2
  150. package/skills/roles/security.supply-chain.md +4 -2
  151. package/skills/routing.md +8 -1
  152. package/templates/docs/persona-artifact.md +36 -0
  153. package/templates/docs/research-brief.md +63 -9
  154. package/templates/docs/research-finding.md +26 -0
  155. package/templates/docs/skill-artifact.md +27 -0
  156. package/templates/docs/strategy.md +36 -0
  157. package/templates/homebrew/construct.rb +6 -6
@@ -1,47 +1,26 @@
1
1
  /**
2
- * lib/intake/classify.mjs — R&D triage classification for intake packets.
2
+ * lib/intake/classify.mjs — Profile-aware triage classification for intake packets.
3
3
  *
4
- * Deterministic, keyword-driven classifier that maps a raw intake signal
5
- * onto the R&D loop: intakeType (what kind of work), rdStage (where in
6
- * the loop), primaryOwner persona, recommendedChain (handoff sequence),
7
- * recommendedAction, risk, requiresApproval, confidence, rationale.
4
+ * Deterministic, keyword-driven classifier that maps a raw intake signal onto
5
+ * the active org profile's loop. Returns a triage object with: intakeType,
6
+ * rdStage, primaryOwner, recommendedChain, recommendedAction, risk,
7
+ * requiresApproval, confidence, rationale.
8
8
  *
9
9
  * NO LLM call. The daemon path must remain synchronous and cheap; intent
10
10
  * verification belongs in offline measurement, not inline classification.
11
- * Persona names match agents/registry.json (unprefixed).
11
+ *
12
+ * Default profile is `rnd` so existing R&D users see no behavior change.
13
+ * The `tests/intake/golden-rnd.test.mjs` test locks that invariant.
12
14
  */
13
15
 
14
16
  import path from 'node:path';
15
17
 
16
- export const INTAKE_TYPES = [
17
- 'user-signal',
18
- 'bug',
19
- 'requirement',
20
- 'research',
21
- 'experiment',
22
- 'eval-finding',
23
- 'architecture',
24
- 'incident',
25
- 'launch-asset',
26
- 'ops',
27
- 'security',
28
- 'legal-compliance',
29
- 'unknown',
30
- ];
31
-
32
- export const RD_STAGES = [
33
- 'signal',
34
- 'framing',
35
- 'hypothesis',
36
- 'research',
37
- 'artifact',
38
- 'design',
39
- 'implementation',
40
- 'evaluation',
41
- 'release',
42
- 'operations',
43
- 'unknown',
44
- ];
18
+ // Backward-compatible exports. Default to RND values for any module that
19
+ // imports these constants directly (the symbol surface predates B2 and is
20
+ // referenced by intake-config, prepare, and tests).
21
+ import rndTable from './tables/rnd.mjs';
22
+ export const INTAKE_TYPES = rndTable.INTAKE_TYPES;
23
+ export const RD_STAGES = rndTable.STAGES;
45
24
 
46
25
  export const RECOMMENDED_ACTIONS = [
47
26
  'summarize',
@@ -60,146 +39,36 @@ export const RECOMMENDED_ACTIONS = [
60
39
  'archive',
61
40
  ];
62
41
 
63
- /**
64
- * Classification table intakeType triage spine.
65
- * Keyword set drives detection; the rest of the row is the canonical mapping
66
- * for that signal class. Order matters for tie-breaking: earlier rows win on
67
- * equal raw scores so that high-stakes classes (security, incident) take
68
- * precedence over generic ones (research) when keywords overlap.
69
- */
70
- const CLASSIFICATION_TABLE = [
71
- {
72
- intakeType: 'security',
73
- keywords: ['security', 'secret', 'cve', 'vulnerability', 'vuln', 'exploit', 'leak', 'auth bypass', 'privilege escalation', 'sqli', 'xss', 'csrf', 'rce'],
74
- rdStage: 'operations',
75
- primaryOwner: 'security',
76
- recommendedChain: ['security', 'engineer', 'reviewer'],
77
- recommendedAction: 'diagnose',
78
- risk: 'high',
79
- requiresApproval: true,
80
- },
81
- {
82
- intakeType: 'incident',
83
- keywords: ['incident', 'outage', 'slo breach', 'sla breach', 'latency spike', 'availability', 'down', 'p0 ', 'p1 ', 'pagerduty', '5xx', 'oncall'],
84
- rdStage: 'operations',
85
- primaryOwner: 'sre',
86
- recommendedChain: ['sre', 'debugger', 'platform-engineer'],
87
- recommendedAction: 'create-runbook',
88
- risk: 'high',
89
- requiresApproval: true,
90
- },
91
- {
92
- intakeType: 'legal-compliance',
93
- keywords: ['gdpr', 'ccpa', 'hipaa', 'sox', 'soc2', 'license', 'lawsuit', 'dpa', 'data retention', 'pii', 'subpoena', 'compliance audit'],
94
- rdStage: 'operations',
95
- primaryOwner: 'legal-compliance',
96
- recommendedChain: ['legal-compliance', 'security', 'product-manager'],
97
- recommendedAction: 'clarify',
98
- risk: 'high',
99
- requiresApproval: true,
100
- },
101
- {
102
- intakeType: 'architecture',
103
- keywords: ['architecture', 'adr', 'rfc', 'interface', 'tradeoff', 'boundary', 'system design', 'data model', 'api contract', 'migration plan'],
104
- rdStage: 'design',
105
- primaryOwner: 'architect',
106
- recommendedChain: ['architect', 'devil-advocate', 'engineer'],
107
- recommendedAction: 'draft-rfc',
108
- risk: 'medium',
109
- requiresApproval: false,
110
- },
111
- {
112
- intakeType: 'eval-finding',
113
- keywords: ['eval', 'evaluation', 'hallucination', 'judge', 'trace', 'score regression', 'recall@', 'precision@', 'mrr', 'ndcg', 'failure case', 'rubric'],
114
- rdStage: 'evaluation',
115
- primaryOwner: 'evaluator',
116
- recommendedChain: ['evaluator', 'ai-engineer', 'trace-reviewer'],
117
- recommendedAction: 'evaluate',
118
- risk: 'medium',
119
- requiresApproval: false,
120
- },
121
- {
122
- intakeType: 'bug',
123
- keywords: ['bug', 'broken', 'error', 'stack trace', 'regression', 'crash', 'exception', 'fails', 'failing', 'throws', 'not working', 'reproduce', 'repro:'],
124
- rdStage: 'implementation',
125
- primaryOwner: 'debugger',
126
- recommendedChain: ['debugger', 'engineer', 'qa', 'reviewer'],
127
- recommendedAction: 'diagnose',
128
- risk: 'medium',
129
- requiresApproval: false,
130
- },
131
- {
132
- intakeType: 'experiment',
133
- keywords: ['hypothesis', 'experiment', 'spike', 'prototype', 'falsifiable', 'research question', 'a/b test', 'pilot'],
134
- rdStage: 'hypothesis',
135
- primaryOwner: 'rd-lead',
136
- recommendedChain: ['rd-lead', 'researcher', 'evaluator'],
137
- recommendedAction: 'create-experiment',
138
- risk: 'low',
139
- requiresApproval: false,
140
- },
141
- {
142
- intakeType: 'launch-asset',
143
- keywords: ['release', 'changelog', 'version bump', 'ship', 'launch', 'rollout', 'cut a release', 'rc1', 'rc2', 'release candidate'],
144
- rdStage: 'release',
145
- primaryOwner: 'release-manager',
146
- recommendedChain: ['release-manager', 'qa', 'docs-keeper'],
147
- recommendedAction: 'release-review',
148
- risk: 'medium',
149
- requiresApproval: false,
150
- },
151
- {
152
- intakeType: 'research',
153
- keywords: ['competitor', 'market', 'pricing', 'positioning', 'industry', 'state of the art', 'literature', 'benchmark study', 'desk research'],
154
- rdStage: 'research',
155
- primaryOwner: 'business-strategist',
156
- recommendedChain: ['business-strategist', 'researcher', 'product-manager'],
157
- recommendedAction: 'research',
158
- risk: 'low',
159
- requiresApproval: false,
160
- },
161
- {
162
- intakeType: 'user-signal',
163
- keywords: ['customer', 'feedback', 'pain point', 'user says', 'user feedback', 'support ticket', 'churn', 'nps', 'usability', 'frustrated'],
164
- rdStage: 'signal',
165
- primaryOwner: 'product-manager',
166
- recommendedChain: ['product-manager', 'ux-researcher', 'researcher'],
167
- recommendedAction: 'clarify',
168
- risk: 'low',
169
- requiresApproval: false,
170
- },
171
- {
172
- intakeType: 'requirement',
173
- keywords: ['acceptance criteria', 'requirement', 'must have', 'should have', 'feature request', 'prd', 'use case', 'success metric'],
174
- rdStage: 'framing',
175
- primaryOwner: 'product-manager',
176
- recommendedChain: ['product-manager', 'architect', 'engineer'],
177
- recommendedAction: 'draft-prd',
178
- risk: 'low',
179
- requiresApproval: false,
180
- },
181
- {
182
- intakeType: 'ops',
183
- keywords: ['runbook', 'cron', 'scheduled job', 'maintenance', 'backup', 'restore', 'capacity plan', 'cost optimization', 'dependency upgrade'],
184
- rdStage: 'operations',
185
- primaryOwner: 'operations',
186
- recommendedChain: ['operations', 'sre', 'engineer'],
187
- recommendedAction: 'create-runbook',
188
- risk: 'low',
189
- requiresApproval: false,
190
- },
191
- ];
42
+ // Static profile → table map. New curated profiles register themselves here.
43
+ // Custom profiles (escape hatch) declare classificationTable as a repo-relative
44
+ // path; that path is loaded dynamically in classifyRdIntake when a profile arg
45
+ // supplies it.
46
+ import operationsTable from './tables/operations.mjs';
47
+ import creativeTable from './tables/creative.mjs';
48
+ import researchTable from './tables/research.mjs';
49
+ import { outcomeBoost } from '../outcomes/aggregate.mjs';
50
+
51
+ // Outcome boost is a soft re-rank applied when a cwd is supplied. Capped at
52
+ // ±0.05 in outcomeBoost itself, so the primary keyword signal (integer hits)
53
+ // always dominates. Returns 0 if no outcome data exists for the role.
54
+ function outcomeBoostFor(cwd, role) {
55
+ if (!cwd || !role) return 0;
56
+ try { return outcomeBoost(cwd, role); } catch { return 0; }
57
+ }
192
58
 
193
- const UNKNOWN_TRIAGE = {
194
- intakeType: 'unknown',
195
- rdStage: 'unknown',
196
- primaryOwner: 'orchestrator',
197
- recommendedChain: ['orchestrator'],
198
- recommendedAction: 'summarize',
199
- risk: 'low',
200
- requiresApproval: false,
59
+ const TABLES = {
60
+ rnd: rndTable,
61
+ operations: operationsTable,
62
+ creative: creativeTable,
63
+ research: researchTable,
201
64
  };
202
65
 
66
+ function resolveTable(profile) {
67
+ if (!profile) return rndTable;
68
+ const id = typeof profile === 'string' ? profile : profile.id;
69
+ return TABLES[id] || rndTable;
70
+ }
71
+
203
72
  function normalize(text) {
204
73
  return String(text || '').toLowerCase();
205
74
  }
@@ -225,27 +94,35 @@ function buildSignalText({ sourcePath, extractedText, related }) {
225
94
  }
226
95
 
227
96
  /**
228
- * Classify an R&D intake signal.
97
+ * Classify an intake signal against the active profile (defaults to RND).
98
+ *
99
+ * Backward-compatible: callers that did not pass a `profile` arg keep getting
100
+ * RND output, byte-identical to the pre-B2 behavior.
229
101
  *
230
- * Returns a triage object with: intakeType, rdStage, primaryOwner,
231
- * recommendedChain, recommendedAction, risk, requiresApproval, confidence,
232
- * rationale. The function is pure and deterministic; same input → same output.
102
+ * @param {object} input
103
+ * @param {string} [input.sourcePath]
104
+ * @param {string} [input.extractedText]
105
+ * @param {Array} [input.related]
106
+ * @param {string|object} [input.profile] - profile id (string) or full profile object
233
107
  */
234
- export function classifyRdIntake({ sourcePath = '', extractedText = '', related = [] } = {}) {
108
+ export function classifyRdIntake({ sourcePath = '', extractedText = '', related = [], profile = null, cwd = null } = {}) {
109
+ const table = resolveTable(profile);
235
110
  const signal = buildSignalText({ sourcePath, extractedText, related });
236
111
 
237
112
  let best = null;
238
- for (const entry of CLASSIFICATION_TABLE) {
113
+ for (const entry of table.CLASSIFICATION_TABLE) {
239
114
  const { hits, matched } = countMatches(signal, entry.keywords);
240
115
  if (hits === 0) continue;
241
- if (!best || hits > best.hits) {
242
- best = { entry, hits, matched };
116
+ const boost = cwd ? outcomeBoostFor(cwd, entry.primaryOwner) : 0;
117
+ const score = hits + boost;
118
+ if (!best || score > best.score) {
119
+ best = { entry, hits, matched, score };
243
120
  }
244
121
  }
245
122
 
246
123
  if (!best) {
247
124
  return {
248
- ...UNKNOWN_TRIAGE,
125
+ ...table.UNKNOWN_TRIAGE,
249
126
  confidence: 0.3,
250
127
  rationale: 'No classification keywords matched filename, content excerpt, or related-doc titles.',
251
128
  };
@@ -272,7 +149,8 @@ export function classifyRdIntake({ sourcePath = '', extractedText = '', related
272
149
  export function formatTriageLine(sourcePath, triage) {
273
150
  const basename = sourcePath ? path.basename(sourcePath) : '(unknown source)';
274
151
  if (!triage || triage.intakeType === 'unknown') {
275
- return `${basename} → unclassified · owner: orchestrator · next: summarize`;
152
+ return `${basename} → unclassified · owner: ${triage?.primaryOwner ?? 'orchestrator'} · next: ${triage?.recommendedAction ?? 'summarize'}`;
276
153
  }
277
- return `${basename} ${triage.intakeType} / ${triage.rdStage} · owner: ${triage.primaryOwner} · next: ${triage.recommendedAction}`;
154
+ const ownerLabel = triage.primaryOwner ?? 'unassigned';
155
+ return `${basename} → ${triage.intakeType} / ${triage.rdStage} · owner: ${ownerLabel} · next: ${triage.recommendedAction}`;
278
156
  }
@@ -29,6 +29,7 @@ import { suggestDocsLaneForFile } from '../docs-routing.mjs';
29
29
  import { createIntakeQueue } from './queue.mjs';
30
30
  import { classifyRdIntake } from './classify.mjs';
31
31
  import { detectCustomerMentions, linkSignalToCustomer, updateCustomerProfile } from '../embed/customer-profiles.mjs';
32
+ import { resolveActiveProfile } from '../profiles/loader.mjs';
32
33
 
33
34
  const DEFAULT_RELATED_LIMIT = 5;
34
35
  const EXCERPT_CHARS = 800;
@@ -67,10 +68,16 @@ export async function prepareIntakeForIngestedFile({
67
68
  }
68
69
 
69
70
  const lane = suggestDocsLaneForFile(ingestedFile.sourcePath, extracted) || null;
71
+ // Resolve the active profile so non-RND projects route to their own table.
72
+ // Falls back to rnd for any project without explicit configuration, which
73
+ // preserves prior behavior for every existing user.
74
+ const activeProfile = resolveActiveProfile(rootDir);
70
75
  const triage = classifyFn({
71
76
  sourcePath: ingestedFile.sourcePath,
72
77
  extractedText: extracted,
73
78
  related,
79
+ profile: activeProfile?.id,
80
+ cwd: rootDir,
74
81
  });
75
82
 
76
83
  // Detect customer mentions and update profiles
@@ -0,0 +1,94 @@
1
+ /**
2
+ * lib/intake/tables/creative.mjs — Creative production intake classification.
3
+ *
4
+ * Loop: brief → research → draft → review → publish → measure. Covers content
5
+ * creation, campaigns, design work. Roles are creative-org roles, not engineering.
6
+ */
7
+
8
+ export const INTAKE_TYPES = ['brief', 'content-request', 'asset', 'experiment', 'report', 'legal-compliance', 'ops', 'unknown'];
9
+ export const STAGES = ['brief', 'research', 'draft', 'review', 'publish', 'measure'];
10
+
11
+ export const UNKNOWN_TRIAGE = {
12
+ intakeType: 'unknown',
13
+ rdStage: 'unknown',
14
+ primaryOwner: 'operator',
15
+ recommendedChain: ['operator'],
16
+ recommendedAction: 'summarize',
17
+ risk: 'low',
18
+ requiresApproval: false,
19
+ };
20
+
21
+ export const CLASSIFICATION_TABLE = [
22
+ {
23
+ intakeType: 'legal-compliance',
24
+ keywords: ['gdpr', 'ccpa', 'privacy', 'consent', 'unsubscribe', 'can-spam', 'cookie banner', 'disclosure', 'trademark'],
25
+ rdStage: 'review',
26
+ primaryOwner: 'legal-compliance',
27
+ recommendedChain: ['legal-compliance', 'reviewer'],
28
+ recommendedAction: 'clarify',
29
+ risk: 'high',
30
+ requiresApproval: true,
31
+ },
32
+ {
33
+ intakeType: 'brief',
34
+ keywords: ['brief', 'campaign', 'launch plan', 'go-to-market', 'gtm', 'positioning', 'narrative', 'audience'],
35
+ rdStage: 'brief',
36
+ primaryOwner: 'product-lead',
37
+ recommendedChain: ['product-lead', 'researcher', 'content-writer'],
38
+ recommendedAction: 'draft-prd',
39
+ risk: 'medium',
40
+ requiresApproval: false,
41
+ },
42
+ {
43
+ intakeType: 'content-request',
44
+ keywords: ['blog', 'article', 'landing page', 'social post', 'newsletter', 'email copy', 'video script', 'headline', 'post', 'content'],
45
+ rdStage: 'draft',
46
+ primaryOwner: 'content-writer',
47
+ recommendedChain: ['content-writer', 'reviewer'],
48
+ recommendedAction: 'draft-rfc',
49
+ risk: 'low',
50
+ requiresApproval: false,
51
+ },
52
+ {
53
+ intakeType: 'asset',
54
+ keywords: ['asset', 'logo', 'image', 'banner', 'mockup', 'figma', 'brand guide', 'illustration'],
55
+ rdStage: 'draft',
56
+ primaryOwner: 'designer',
57
+ recommendedChain: ['designer', 'reviewer'],
58
+ recommendedAction: 'draft-rfc',
59
+ risk: 'low',
60
+ requiresApproval: false,
61
+ },
62
+ {
63
+ intakeType: 'experiment',
64
+ keywords: ['a/b test', 'experiment', 'hypothesis', 'multivariate', 'pilot', 'audience test'],
65
+ rdStage: 'measure',
66
+ primaryOwner: 'data-analyst',
67
+ recommendedChain: ['data-analyst', 'researcher'],
68
+ recommendedAction: 'create-experiment',
69
+ risk: 'low',
70
+ requiresApproval: false,
71
+ },
72
+ {
73
+ intakeType: 'report',
74
+ keywords: ['report', 'dashboard', 'attribution', 'ctr', 'cpa', 'roas', 'conversion', 'funnel', 'engagement'],
75
+ rdStage: 'measure',
76
+ primaryOwner: 'data-analyst',
77
+ recommendedChain: ['data-analyst', 'product-lead'],
78
+ recommendedAction: 'evaluate',
79
+ risk: 'low',
80
+ requiresApproval: false,
81
+ },
82
+ {
83
+ intakeType: 'ops',
84
+ keywords: ['process', 'workflow', 'template', 'sla', 'calendar', 'planning', 'editorial calendar'],
85
+ rdStage: 'review',
86
+ primaryOwner: 'operator',
87
+ recommendedChain: ['operator', 'product-lead'],
88
+ recommendedAction: 'create-runbook',
89
+ risk: 'low',
90
+ requiresApproval: false,
91
+ },
92
+ ];
93
+
94
+ export default { INTAKE_TYPES, STAGES, CLASSIFICATION_TABLE, UNKNOWN_TRIAGE };
@@ -0,0 +1,85 @@
1
+ /**
2
+ * lib/intake/tables/operations.mjs — Operations intake classification.
3
+ *
4
+ * Loop: request → triage → resolve → document → improve. Optimized for teams
5
+ * whose primary work is fulfilling requests and keeping things running, not
6
+ * building new product. Owners are operations roles (operator, sre, engineer).
7
+ */
8
+
9
+ export const INTAKE_TYPES = ['request', 'bug', 'incident', 'ops', 'security', 'docs', 'unknown'];
10
+ export const STAGES = ['request', 'triage', 'resolve', 'document', 'improve'];
11
+
12
+ export const UNKNOWN_TRIAGE = {
13
+ intakeType: 'unknown',
14
+ rdStage: 'unknown',
15
+ primaryOwner: 'operator',
16
+ recommendedChain: ['operator'],
17
+ recommendedAction: 'summarize',
18
+ risk: 'low',
19
+ requiresApproval: false,
20
+ };
21
+
22
+ export const CLASSIFICATION_TABLE = [
23
+ {
24
+ intakeType: 'security',
25
+ keywords: ['security', 'cve', 'vulnerability', 'leak', 'auth bypass', 'pii', 'secret'],
26
+ rdStage: 'resolve',
27
+ primaryOwner: 'security',
28
+ recommendedChain: ['security', 'engineer', 'reviewer'],
29
+ recommendedAction: 'diagnose',
30
+ risk: 'high',
31
+ requiresApproval: true,
32
+ },
33
+ {
34
+ intakeType: 'incident',
35
+ keywords: ['incident', 'outage', 'down', 'p0 ', 'p1 ', 'oncall', 'pager', '5xx', 'sla breach'],
36
+ rdStage: 'resolve',
37
+ primaryOwner: 'sre',
38
+ recommendedChain: ['sre', 'engineer'],
39
+ recommendedAction: 'create-runbook',
40
+ risk: 'high',
41
+ requiresApproval: true,
42
+ },
43
+ {
44
+ intakeType: 'bug',
45
+ keywords: ['bug', 'broken', 'error', 'fails', 'crash', 'exception', 'stack trace'],
46
+ rdStage: 'resolve',
47
+ primaryOwner: 'engineer',
48
+ recommendedChain: ['engineer', 'qa', 'reviewer'],
49
+ recommendedAction: 'diagnose',
50
+ risk: 'medium',
51
+ requiresApproval: false,
52
+ },
53
+ {
54
+ intakeType: 'docs',
55
+ keywords: ['docs', 'documentation', 'how to', 'guide', 'readme', 'wiki', 'runbook missing'],
56
+ rdStage: 'document',
57
+ primaryOwner: 'docs-keeper',
58
+ recommendedChain: ['docs-keeper', 'reviewer'],
59
+ recommendedAction: 'create-runbook',
60
+ risk: 'low',
61
+ requiresApproval: false,
62
+ },
63
+ {
64
+ intakeType: 'ops',
65
+ keywords: ['cron', 'scheduled job', 'maintenance', 'backup', 'restore', 'rotation', 'capacity', 'upgrade'],
66
+ rdStage: 'improve',
67
+ primaryOwner: 'sre',
68
+ recommendedChain: ['sre', 'engineer'],
69
+ recommendedAction: 'create-runbook',
70
+ risk: 'low',
71
+ requiresApproval: false,
72
+ },
73
+ {
74
+ intakeType: 'request',
75
+ keywords: ['request', 'access', 'feature request', 'integration', 'new tool', 'change request', 'how do i', 'can someone'],
76
+ rdStage: 'triage',
77
+ primaryOwner: 'operator',
78
+ recommendedChain: ['operator', 'engineer'],
79
+ recommendedAction: 'clarify',
80
+ risk: 'low',
81
+ requiresApproval: false,
82
+ },
83
+ ];
84
+
85
+ export default { INTAKE_TYPES, STAGES, CLASSIFICATION_TABLE, UNKNOWN_TRIAGE };
@@ -0,0 +1,85 @@
1
+ /**
2
+ * lib/intake/tables/research.mjs — Research intake classification.
3
+ *
4
+ * Loop: question → gather → analyze → synthesize → recommend. Covers analysis,
5
+ * market intelligence, evaluation, advisory work. Output is a written
6
+ * recommendation, not a shipped product.
7
+ */
8
+
9
+ export const INTAKE_TYPES = ['question', 'study', 'synthesis', 'report', 'experiment', 'ops', 'unknown'];
10
+ export const STAGES = ['question', 'gather', 'analyze', 'synthesize', 'recommend'];
11
+
12
+ export const UNKNOWN_TRIAGE = {
13
+ intakeType: 'unknown',
14
+ rdStage: 'unknown',
15
+ primaryOwner: 'researcher',
16
+ recommendedChain: ['researcher'],
17
+ recommendedAction: 'summarize',
18
+ risk: 'low',
19
+ requiresApproval: false,
20
+ };
21
+
22
+ export const CLASSIFICATION_TABLE = [
23
+ {
24
+ intakeType: 'study',
25
+ keywords: ['interview', 'user study', 'survey', 'focus group', 'usability test', 'diary study', 'ethnography'],
26
+ rdStage: 'gather',
27
+ primaryOwner: 'ux-researcher',
28
+ recommendedChain: ['ux-researcher', 'researcher'],
29
+ recommendedAction: 'create-experiment',
30
+ risk: 'low',
31
+ requiresApproval: false,
32
+ },
33
+ {
34
+ intakeType: 'experiment',
35
+ keywords: ['hypothesis', 'experiment', 'controlled trial', 'a/b test', 'pilot', 'falsifiable'],
36
+ rdStage: 'analyze',
37
+ primaryOwner: 'evaluator',
38
+ recommendedChain: ['evaluator', 'researcher', 'data-analyst'],
39
+ recommendedAction: 'evaluate',
40
+ risk: 'low',
41
+ requiresApproval: false,
42
+ },
43
+ {
44
+ intakeType: 'report',
45
+ keywords: ['report', 'finding', 'dashboard', 'metric', 'benchmark', 'baseline', 'comparison'],
46
+ rdStage: 'recommend',
47
+ primaryOwner: 'data-analyst',
48
+ recommendedChain: ['data-analyst', 'researcher', 'reviewer'],
49
+ recommendedAction: 'evaluate',
50
+ risk: 'low',
51
+ requiresApproval: false,
52
+ },
53
+ {
54
+ intakeType: 'synthesis',
55
+ keywords: ['synthesis', 'literature review', 'meta', 'state of the art', 'roundup', 'survey paper', 'taxonomy'],
56
+ rdStage: 'synthesize',
57
+ primaryOwner: 'researcher',
58
+ recommendedChain: ['researcher', 'reviewer'],
59
+ recommendedAction: 'research',
60
+ risk: 'low',
61
+ requiresApproval: false,
62
+ },
63
+ {
64
+ intakeType: 'question',
65
+ keywords: ['question', 'research question', 'what is', 'why does', 'how do', 'investigate', 'figure out', 'understand'],
66
+ rdStage: 'question',
67
+ primaryOwner: 'researcher',
68
+ recommendedChain: ['researcher'],
69
+ recommendedAction: 'clarify',
70
+ risk: 'low',
71
+ requiresApproval: false,
72
+ },
73
+ {
74
+ intakeType: 'ops',
75
+ keywords: ['process', 'methodology', 'template', 'protocol', 'consent form', 'data handling'],
76
+ rdStage: 'gather',
77
+ primaryOwner: 'operator',
78
+ recommendedChain: ['operator', 'researcher'],
79
+ recommendedAction: 'create-runbook',
80
+ risk: 'low',
81
+ requiresApproval: false,
82
+ },
83
+ ];
84
+
85
+ export default { INTAKE_TYPES, STAGES, CLASSIFICATION_TABLE, UNKNOWN_TRIAGE };