musubi-sdd 5.0.0 → 5.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +106 -48
- package/README.md +110 -32
- package/bin/musubi-analyze.js +74 -67
- package/bin/musubi-browser.js +27 -26
- package/bin/musubi-change.js +48 -47
- package/bin/musubi-checkpoint.js +10 -7
- package/bin/musubi-convert.js +25 -25
- package/bin/musubi-costs.js +27 -10
- package/bin/musubi-gui.js +52 -46
- package/bin/musubi-init.js +1952 -10
- package/bin/musubi-orchestrate.js +327 -239
- package/bin/musubi-remember.js +69 -56
- package/bin/musubi-resolve.js +53 -45
- package/bin/musubi-trace.js +51 -22
- package/bin/musubi-validate.js +39 -30
- package/bin/musubi-workflow.js +33 -34
- package/bin/musubi.js +39 -2
- package/package.json +1 -1
- package/src/agents/agent-loop.js +94 -95
- package/src/agents/agentic/code-generator.js +119 -109
- package/src/agents/agentic/code-reviewer.js +105 -108
- package/src/agents/agentic/index.js +4 -4
- package/src/agents/browser/action-executor.js +13 -13
- package/src/agents/browser/ai-comparator.js +11 -10
- package/src/agents/browser/context-manager.js +6 -6
- package/src/agents/browser/index.js +5 -5
- package/src/agents/browser/nl-parser.js +31 -46
- package/src/agents/browser/screenshot.js +2 -2
- package/src/agents/browser/test-generator.js +6 -4
- package/src/agents/function-tool.js +71 -65
- package/src/agents/index.js +7 -7
- package/src/agents/schema-generator.js +98 -94
- package/src/analyzers/ast-extractor.js +164 -145
- package/src/analyzers/codegraph-auto-update.js +858 -0
- package/src/analyzers/complexity-analyzer.js +536 -0
- package/src/analyzers/context-optimizer.js +247 -125
- package/src/analyzers/impact-analyzer.js +1 -1
- package/src/analyzers/large-project-analyzer.js +766 -0
- package/src/analyzers/repository-map.js +83 -80
- package/src/analyzers/security-analyzer.js +19 -11
- package/src/analyzers/stuck-detector.js +19 -17
- package/src/converters/index.js +78 -57
- package/src/converters/ir/types.js +12 -12
- package/src/converters/parsers/musubi-parser.js +134 -126
- package/src/converters/parsers/openapi-parser.js +70 -53
- package/src/converters/parsers/speckit-parser.js +239 -175
- package/src/converters/writers/musubi-writer.js +123 -118
- package/src/converters/writers/speckit-writer.js +124 -113
- package/src/generators/rust-migration-generator.js +512 -0
- package/src/gui/public/index.html +1365 -1211
- package/src/gui/server.js +41 -40
- package/src/gui/services/file-watcher.js +23 -8
- package/src/gui/services/project-scanner.js +26 -20
- package/src/gui/services/replanning-service.js +27 -23
- package/src/gui/services/traceability-service.js +8 -8
- package/src/gui/services/workflow-service.js +14 -7
- package/src/index.js +151 -0
- package/src/integrations/cicd.js +90 -104
- package/src/integrations/codegraph-mcp.js +643 -0
- package/src/integrations/documentation.js +142 -103
- package/src/integrations/examples.js +95 -80
- package/src/integrations/github-client.js +17 -17
- package/src/integrations/index.js +5 -5
- package/src/integrations/mcp/index.js +21 -21
- package/src/integrations/mcp/mcp-context-provider.js +76 -78
- package/src/integrations/mcp/mcp-discovery.js +74 -72
- package/src/integrations/mcp/mcp-tool-registry.js +99 -94
- package/src/integrations/mcp-connector.js +70 -66
- package/src/integrations/platforms.js +50 -49
- package/src/integrations/tool-discovery.js +37 -31
- package/src/llm-providers/anthropic-provider.js +11 -11
- package/src/llm-providers/base-provider.js +16 -18
- package/src/llm-providers/copilot-provider.js +22 -19
- package/src/llm-providers/index.js +26 -25
- package/src/llm-providers/ollama-provider.js +11 -11
- package/src/llm-providers/openai-provider.js +12 -12
- package/src/managers/agent-memory.js +36 -24
- package/src/managers/checkpoint-manager.js +4 -8
- package/src/managers/delta-spec.js +19 -19
- package/src/managers/index.js +13 -4
- package/src/managers/memory-condenser.js +35 -45
- package/src/managers/repo-skill-manager.js +57 -31
- package/src/managers/skill-loader.js +25 -22
- package/src/managers/skill-tools.js +36 -72
- package/src/managers/workflow.js +30 -22
- package/src/monitoring/cost-tracker.js +53 -44
- package/src/monitoring/incident-manager.js +123 -103
- package/src/monitoring/index.js +144 -134
- package/src/monitoring/observability.js +82 -59
- package/src/monitoring/quality-dashboard.js +51 -39
- package/src/monitoring/release-manager.js +70 -50
- package/src/orchestration/agent-skill-binding.js +39 -47
- package/src/orchestration/error-handler.js +65 -107
- package/src/orchestration/guardrails/base-guardrail.js +26 -24
- package/src/orchestration/guardrails/guardrail-rules.js +50 -64
- package/src/orchestration/guardrails/index.js +5 -5
- package/src/orchestration/guardrails/input-guardrail.js +58 -45
- package/src/orchestration/guardrails/output-guardrail.js +104 -81
- package/src/orchestration/guardrails/safety-check.js +79 -79
- package/src/orchestration/index.js +38 -55
- package/src/orchestration/mcp-tool-adapters.js +96 -99
- package/src/orchestration/orchestration-engine.js +21 -21
- package/src/orchestration/pattern-registry.js +60 -45
- package/src/orchestration/patterns/auto.js +34 -47
- package/src/orchestration/patterns/group-chat.js +59 -65
- package/src/orchestration/patterns/handoff.js +67 -65
- package/src/orchestration/patterns/human-in-loop.js +51 -72
- package/src/orchestration/patterns/nested.js +25 -40
- package/src/orchestration/patterns/sequential.js +35 -34
- package/src/orchestration/patterns/swarm.js +63 -56
- package/src/orchestration/patterns/triage.js +150 -109
- package/src/orchestration/reasoning/index.js +9 -9
- package/src/orchestration/reasoning/planning-engine.js +143 -140
- package/src/orchestration/reasoning/reasoning-engine.js +206 -144
- package/src/orchestration/reasoning/self-correction.js +121 -128
- package/src/orchestration/replanning/adaptive-goal-modifier.js +107 -112
- package/src/orchestration/replanning/alternative-generator.js +37 -42
- package/src/orchestration/replanning/config.js +63 -59
- package/src/orchestration/replanning/goal-progress-tracker.js +98 -100
- package/src/orchestration/replanning/index.js +24 -20
- package/src/orchestration/replanning/plan-evaluator.js +49 -50
- package/src/orchestration/replanning/plan-monitor.js +32 -28
- package/src/orchestration/replanning/proactive-path-optimizer.js +175 -178
- package/src/orchestration/replanning/replan-history.js +33 -26
- package/src/orchestration/replanning/replanning-engine.js +106 -108
- package/src/orchestration/skill-executor.js +107 -109
- package/src/orchestration/skill-registry.js +85 -89
- package/src/orchestration/workflow-examples.js +228 -231
- package/src/orchestration/workflow-executor.js +65 -68
- package/src/orchestration/workflow-orchestrator.js +72 -73
- package/src/phase4-integration.js +47 -40
- package/src/phase5-integration.js +89 -30
- package/src/reporters/coverage-report.js +82 -30
- package/src/reporters/hierarchical-reporter.js +498 -0
- package/src/reporters/traceability-matrix-report.js +29 -20
- package/src/resolvers/issue-resolver.js +43 -31
- package/src/steering/advanced-validation.js +133 -124
- package/src/steering/auto-updater.js +60 -73
- package/src/steering/index.js +6 -6
- package/src/steering/quality-metrics.js +41 -35
- package/src/steering/steering-auto-update.js +83 -86
- package/src/steering/steering-validator.js +98 -106
- package/src/steering/template-constraints.js +53 -54
- package/src/templates/agents/claude-code/CLAUDE.md +32 -32
- package/src/templates/agents/claude-code/skills/agent-assistant/SKILL.md +13 -5
- package/src/templates/agents/claude-code/skills/ai-ml-engineer/mlops-guide.md +23 -23
- package/src/templates/agents/claude-code/skills/ai-ml-engineer/model-card-template.md +60 -41
- package/src/templates/agents/claude-code/skills/api-designer/api-patterns.md +27 -19
- package/src/templates/agents/claude-code/skills/api-designer/openapi-template.md +11 -7
- package/src/templates/agents/claude-code/skills/bug-hunter/SKILL.md +4 -3
- package/src/templates/agents/claude-code/skills/bug-hunter/root-cause-analysis.md +37 -15
- package/src/templates/agents/claude-code/skills/change-impact-analyzer/dependency-graph-patterns.md +36 -42
- package/src/templates/agents/claude-code/skills/change-impact-analyzer/impact-analysis-template.md +69 -60
- package/src/templates/agents/claude-code/skills/cloud-architect/aws-patterns.md +31 -38
- package/src/templates/agents/claude-code/skills/cloud-architect/azure-patterns.md +28 -23
- package/src/templates/agents/claude-code/skills/code-reviewer/SKILL.md +61 -0
- package/src/templates/agents/claude-code/skills/code-reviewer/best-practices.md +27 -0
- package/src/templates/agents/claude-code/skills/code-reviewer/review-checklist.md +29 -10
- package/src/templates/agents/claude-code/skills/code-reviewer/review-standards.md +29 -24
- package/src/templates/agents/claude-code/skills/constitution-enforcer/SKILL.md +8 -6
- package/src/templates/agents/claude-code/skills/constitution-enforcer/constitutional-articles.md +62 -26
- package/src/templates/agents/claude-code/skills/constitution-enforcer/phase-minus-one-gates.md +35 -16
- package/src/templates/agents/claude-code/skills/database-administrator/backup-recovery.md +27 -17
- package/src/templates/agents/claude-code/skills/database-administrator/tuning-guide.md +25 -20
- package/src/templates/agents/claude-code/skills/database-schema-designer/schema-patterns.md +39 -22
- package/src/templates/agents/claude-code/skills/devops-engineer/ci-cd-templates.md +25 -22
- package/src/templates/agents/claude-code/skills/issue-resolver/SKILL.md +24 -21
- package/src/templates/agents/claude-code/skills/orchestrator/SKILL.md +148 -63
- package/src/templates/agents/claude-code/skills/orchestrator/patterns.md +35 -16
- package/src/templates/agents/claude-code/skills/orchestrator/selection-matrix.md +69 -64
- package/src/templates/agents/claude-code/skills/performance-engineer/optimization-playbook.md +47 -47
- package/src/templates/agents/claude-code/skills/performance-optimizer/SKILL.md +69 -0
- package/src/templates/agents/claude-code/skills/performance-optimizer/benchmark-template.md +63 -45
- package/src/templates/agents/claude-code/skills/performance-optimizer/optimization-patterns.md +33 -35
- package/src/templates/agents/claude-code/skills/project-manager/SKILL.md +7 -6
- package/src/templates/agents/claude-code/skills/project-manager/agile-ceremonies.md +47 -28
- package/src/templates/agents/claude-code/skills/project-manager/project-templates.md +94 -78
- package/src/templates/agents/claude-code/skills/quality-assurance/SKILL.md +20 -17
- package/src/templates/agents/claude-code/skills/quality-assurance/qa-plan-template.md +63 -49
- package/src/templates/agents/claude-code/skills/release-coordinator/SKILL.md +5 -5
- package/src/templates/agents/claude-code/skills/release-coordinator/feature-flag-guide.md +30 -26
- package/src/templates/agents/claude-code/skills/release-coordinator/release-plan-template.md +67 -35
- package/src/templates/agents/claude-code/skills/requirements-analyst/ears-format.md +54 -42
- package/src/templates/agents/claude-code/skills/requirements-analyst/validation-rules.md +36 -33
- package/src/templates/agents/claude-code/skills/security-auditor/SKILL.md +77 -19
- package/src/templates/agents/claude-code/skills/security-auditor/audit-checklists.md +24 -24
- package/src/templates/agents/claude-code/skills/security-auditor/owasp-top-10.md +61 -20
- package/src/templates/agents/claude-code/skills/security-auditor/vulnerability-patterns.md +43 -11
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/SKILL.md +1 -0
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/incident-response-template.md +55 -25
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/observability-patterns.md +78 -68
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/slo-sli-guide.md +73 -53
- package/src/templates/agents/claude-code/skills/software-developer/solid-principles.md +83 -37
- package/src/templates/agents/claude-code/skills/software-developer/test-first-workflow.md +38 -31
- package/src/templates/agents/claude-code/skills/steering/SKILL.md +1 -0
- package/src/templates/agents/claude-code/skills/steering/auto-update-rules.md +31 -0
- package/src/templates/agents/claude-code/skills/system-architect/adr-template.md +25 -7
- package/src/templates/agents/claude-code/skills/system-architect/c4-model-guide.md +74 -61
- package/src/templates/agents/claude-code/skills/technical-writer/doc-templates/documentation-templates.md +70 -52
- package/src/templates/agents/claude-code/skills/test-engineer/SKILL.md +2 -0
- package/src/templates/agents/claude-code/skills/test-engineer/ears-test-mapping.md +75 -71
- package/src/templates/agents/claude-code/skills/test-engineer/test-types.md +85 -63
- package/src/templates/agents/claude-code/skills/traceability-auditor/coverage-matrix-template.md +39 -36
- package/src/templates/agents/claude-code/skills/traceability-auditor/gap-detection-rules.md +22 -17
- package/src/templates/agents/claude-code/skills/ui-ux-designer/SKILL.md +1 -0
- package/src/templates/agents/claude-code/skills/ui-ux-designer/accessibility-guidelines.md +49 -75
- package/src/templates/agents/claude-code/skills/ui-ux-designer/design-system-components.md +71 -59
- package/src/templates/agents/codex/AGENTS.md +74 -42
- package/src/templates/agents/cursor/AGENTS.md +74 -42
- package/src/templates/agents/gemini-cli/GEMINI.md +74 -42
- package/src/templates/agents/github-copilot/AGENTS.md +83 -51
- package/src/templates/agents/qwen-code/QWEN.md +74 -42
- package/src/templates/agents/windsurf/AGENTS.md +74 -42
- package/src/templates/architectures/README.md +41 -0
- package/src/templates/architectures/clean-architecture/README.md +113 -0
- package/src/templates/architectures/event-driven/README.md +162 -0
- package/src/templates/architectures/hexagonal/README.md +130 -0
- package/src/templates/index.js +6 -1
- package/src/templates/locale-manager.js +16 -16
- package/src/templates/shared/delta-spec-template.md +20 -13
- package/src/templates/shared/github-actions/musubi-issue-resolver.yml +5 -5
- package/src/templates/shared/github-actions/musubi-security-check.yml +3 -3
- package/src/templates/shared/github-actions/musubi-validate.yml +4 -4
- package/src/templates/shared/steering/structure.md +95 -0
- package/src/templates/skills/browser-agent.md +21 -16
- package/src/templates/skills/web-gui.md +8 -0
- package/src/templates/template-constraints.js +50 -53
- package/src/validators/advanced-validation.js +30 -36
- package/src/validators/constitutional-validator.js +77 -73
- package/src/validators/critic-system.js +49 -59
- package/src/validators/delta-format.js +59 -55
- package/src/validators/traceability-validator.js +7 -11
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Observability Module - Logs, Metrics, and Traces
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Provides unified observability capabilities:
|
|
5
5
|
* - Structured logging
|
|
6
6
|
* - Metrics collection
|
|
7
7
|
* - Distributed tracing
|
|
8
8
|
* - Correlation IDs
|
|
9
|
+
*
|
|
10
|
+
* Part of MUSUBI v5.0.0 - Production Readiness
|
|
11
|
+
*
|
|
12
|
+
* @module monitoring/observability
|
|
13
|
+
* @version 1.0.0
|
|
14
|
+
*
|
|
15
|
+
* @traceability
|
|
16
|
+
* - Requirement: REQ-P5-004 (Observability Integration)
|
|
17
|
+
* - Design: docs/design/tdd-musubi-v5.0.0.md#3.4
|
|
18
|
+
* - Test: tests/monitoring/observability.test.js
|
|
9
19
|
*/
|
|
10
20
|
|
|
11
21
|
const { EventEmitter } = require('events');
|
|
@@ -19,7 +29,7 @@ const LogLevel = {
|
|
|
19
29
|
INFO: 'info',
|
|
20
30
|
WARN: 'warn',
|
|
21
31
|
ERROR: 'error',
|
|
22
|
-
FATAL: 'fatal'
|
|
32
|
+
FATAL: 'fatal',
|
|
23
33
|
};
|
|
24
34
|
|
|
25
35
|
/**
|
|
@@ -31,7 +41,7 @@ const LOG_PRIORITY = {
|
|
|
31
41
|
[LogLevel.INFO]: 2,
|
|
32
42
|
[LogLevel.WARN]: 3,
|
|
33
43
|
[LogLevel.ERROR]: 4,
|
|
34
|
-
[LogLevel.FATAL]: 5
|
|
44
|
+
[LogLevel.FATAL]: 5,
|
|
35
45
|
};
|
|
36
46
|
|
|
37
47
|
/**
|
|
@@ -40,7 +50,7 @@ const LOG_PRIORITY = {
|
|
|
40
50
|
const TraceStatus = {
|
|
41
51
|
OK: 'ok',
|
|
42
52
|
ERROR: 'error',
|
|
43
|
-
UNSET: 'unset'
|
|
53
|
+
UNSET: 'unset',
|
|
44
54
|
};
|
|
45
55
|
|
|
46
56
|
/**
|
|
@@ -51,7 +61,7 @@ const SpanKind = {
|
|
|
51
61
|
SERVER: 'server',
|
|
52
62
|
CLIENT: 'client',
|
|
53
63
|
PRODUCER: 'producer',
|
|
54
|
-
CONSUMER: 'consumer'
|
|
64
|
+
CONSUMER: 'consumer',
|
|
55
65
|
};
|
|
56
66
|
|
|
57
67
|
/**
|
|
@@ -88,7 +98,7 @@ class Logger extends EventEmitter {
|
|
|
88
98
|
level: this.level,
|
|
89
99
|
context: { ...this.context, ...context },
|
|
90
100
|
outputs: this.outputs,
|
|
91
|
-
parent: this
|
|
101
|
+
parent: this,
|
|
92
102
|
});
|
|
93
103
|
}
|
|
94
104
|
|
|
@@ -111,7 +121,7 @@ class Logger extends EventEmitter {
|
|
|
111
121
|
logger: this.name,
|
|
112
122
|
message,
|
|
113
123
|
...this.context,
|
|
114
|
-
...meta
|
|
124
|
+
...meta,
|
|
115
125
|
};
|
|
116
126
|
|
|
117
127
|
for (const output of this.outputs) {
|
|
@@ -121,12 +131,24 @@ class Logger extends EventEmitter {
|
|
|
121
131
|
this.emit('log', entry);
|
|
122
132
|
}
|
|
123
133
|
|
|
124
|
-
trace(message, meta) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
134
|
+
trace(message, meta) {
|
|
135
|
+
this.log(LogLevel.TRACE, message, meta);
|
|
136
|
+
}
|
|
137
|
+
debug(message, meta) {
|
|
138
|
+
this.log(LogLevel.DEBUG, message, meta);
|
|
139
|
+
}
|
|
140
|
+
info(message, meta) {
|
|
141
|
+
this.log(LogLevel.INFO, message, meta);
|
|
142
|
+
}
|
|
143
|
+
warn(message, meta) {
|
|
144
|
+
this.log(LogLevel.WARN, message, meta);
|
|
145
|
+
}
|
|
146
|
+
error(message, meta) {
|
|
147
|
+
this.log(LogLevel.ERROR, message, meta);
|
|
148
|
+
}
|
|
149
|
+
fatal(message, meta) {
|
|
150
|
+
this.log(LogLevel.FATAL, message, meta);
|
|
151
|
+
}
|
|
130
152
|
|
|
131
153
|
/**
|
|
132
154
|
* Add an output
|
|
@@ -156,10 +178,8 @@ class ConsoleOutput {
|
|
|
156
178
|
|
|
157
179
|
write(entry) {
|
|
158
180
|
if (this.format === 'json') {
|
|
159
|
-
const output = this.pretty
|
|
160
|
-
|
|
161
|
-
: JSON.stringify(entry);
|
|
162
|
-
|
|
181
|
+
const output = this.pretty ? JSON.stringify(entry, null, 2) : JSON.stringify(entry);
|
|
182
|
+
|
|
163
183
|
if (entry.level === LogLevel.ERROR || entry.level === LogLevel.FATAL) {
|
|
164
184
|
console.error(output);
|
|
165
185
|
} else if (entry.level === LogLevel.WARN) {
|
|
@@ -187,7 +207,7 @@ class FileOutput {
|
|
|
187
207
|
|
|
188
208
|
write(entry) {
|
|
189
209
|
this.buffer.push(JSON.stringify(entry) + '\n');
|
|
190
|
-
|
|
210
|
+
|
|
191
211
|
if (this.buffer.length >= this.bufferSize) {
|
|
192
212
|
this.flush();
|
|
193
213
|
}
|
|
@@ -232,7 +252,7 @@ class MetricsCollector extends EventEmitter {
|
|
|
232
252
|
type: 'counter',
|
|
233
253
|
name: fullName,
|
|
234
254
|
help,
|
|
235
|
-
values: new Map()
|
|
255
|
+
values: new Map(),
|
|
236
256
|
});
|
|
237
257
|
}
|
|
238
258
|
return new CounterMetric(this.metrics.get(fullName), this.labels);
|
|
@@ -248,7 +268,7 @@ class MetricsCollector extends EventEmitter {
|
|
|
248
268
|
type: 'gauge',
|
|
249
269
|
name: fullName,
|
|
250
270
|
help,
|
|
251
|
-
values: new Map()
|
|
271
|
+
values: new Map(),
|
|
252
272
|
});
|
|
253
273
|
}
|
|
254
274
|
return new GaugeMetric(this.metrics.get(fullName), this.labels);
|
|
@@ -265,7 +285,7 @@ class MetricsCollector extends EventEmitter {
|
|
|
265
285
|
name: fullName,
|
|
266
286
|
help,
|
|
267
287
|
buckets,
|
|
268
|
-
values: new Map()
|
|
288
|
+
values: new Map(),
|
|
269
289
|
});
|
|
270
290
|
}
|
|
271
291
|
return new HistogramMetric(this.metrics.get(fullName), this.labels);
|
|
@@ -313,13 +333,13 @@ class MetricsCollector extends EventEmitter {
|
|
|
313
333
|
name: metric.name,
|
|
314
334
|
type: metric.type,
|
|
315
335
|
help: metric.help,
|
|
316
|
-
values: []
|
|
336
|
+
values: [],
|
|
317
337
|
};
|
|
318
338
|
|
|
319
339
|
for (const [labelsKey, value] of metric.values) {
|
|
320
340
|
metricData.values.push({
|
|
321
341
|
labels: labelsKey,
|
|
322
|
-
value: metric.type === 'histogram' ? { ...value } : value
|
|
342
|
+
value: metric.type === 'histogram' ? { ...value } : value,
|
|
323
343
|
});
|
|
324
344
|
}
|
|
325
345
|
|
|
@@ -420,12 +440,12 @@ class HistogramMetric {
|
|
|
420
440
|
observe(value, labels = {}) {
|
|
421
441
|
const key = this._labelKey(labels);
|
|
422
442
|
let data = this.metric.values.get(key);
|
|
423
|
-
|
|
443
|
+
|
|
424
444
|
if (!data) {
|
|
425
445
|
data = {
|
|
426
446
|
buckets: this.metric.buckets.map(() => 0),
|
|
427
447
|
sum: 0,
|
|
428
|
-
count: 0
|
|
448
|
+
count: 0,
|
|
429
449
|
};
|
|
430
450
|
this.metric.values.set(key, data);
|
|
431
451
|
}
|
|
@@ -490,7 +510,7 @@ class Span {
|
|
|
490
510
|
this.events.push({
|
|
491
511
|
name,
|
|
492
512
|
timestamp: Date.now(),
|
|
493
|
-
attributes
|
|
513
|
+
attributes,
|
|
494
514
|
});
|
|
495
515
|
return this;
|
|
496
516
|
}
|
|
@@ -526,7 +546,7 @@ class Span {
|
|
|
526
546
|
getContext() {
|
|
527
547
|
return {
|
|
528
548
|
traceId: this.traceId,
|
|
529
|
-
spanId: this.spanId
|
|
549
|
+
spanId: this.spanId,
|
|
530
550
|
};
|
|
531
551
|
}
|
|
532
552
|
|
|
@@ -544,7 +564,7 @@ class Span {
|
|
|
544
564
|
statusMessage: this.statusMessage,
|
|
545
565
|
attributes: this.attributes,
|
|
546
566
|
events: this.events,
|
|
547
|
-
links: this.links
|
|
567
|
+
links: this.links,
|
|
548
568
|
};
|
|
549
569
|
}
|
|
550
570
|
}
|
|
@@ -573,9 +593,9 @@ class Tracer extends EventEmitter {
|
|
|
573
593
|
attributes: {
|
|
574
594
|
'service.name': this.serviceName,
|
|
575
595
|
'service.version': this.version,
|
|
576
|
-
...options.attributes
|
|
596
|
+
...options.attributes,
|
|
577
597
|
},
|
|
578
|
-
links: options.links
|
|
598
|
+
links: options.links,
|
|
579
599
|
});
|
|
580
600
|
|
|
581
601
|
this.spans.push(span);
|
|
@@ -590,7 +610,7 @@ class Tracer extends EventEmitter {
|
|
|
590
610
|
return this.startSpan(name, {
|
|
591
611
|
traceId: parent.traceId,
|
|
592
612
|
parentSpanId: parent.spanId,
|
|
593
|
-
...options
|
|
613
|
+
...options,
|
|
594
614
|
});
|
|
595
615
|
}
|
|
596
616
|
|
|
@@ -600,11 +620,11 @@ class Tracer extends EventEmitter {
|
|
|
600
620
|
endSpan(span) {
|
|
601
621
|
span.end();
|
|
602
622
|
this.emit('spanEnded', span);
|
|
603
|
-
|
|
623
|
+
|
|
604
624
|
for (const exporter of this.exporters) {
|
|
605
625
|
exporter.export(span);
|
|
606
626
|
}
|
|
607
|
-
|
|
627
|
+
|
|
608
628
|
return span;
|
|
609
629
|
}
|
|
610
630
|
|
|
@@ -712,7 +732,7 @@ class CorrelationContext {
|
|
|
712
732
|
*/
|
|
713
733
|
toHeaders() {
|
|
714
734
|
const headers = {};
|
|
715
|
-
|
|
735
|
+
|
|
716
736
|
if (this.has('traceId')) {
|
|
717
737
|
headers['x-trace-id'] = this.get('traceId');
|
|
718
738
|
}
|
|
@@ -722,7 +742,7 @@ class CorrelationContext {
|
|
|
722
742
|
if (this.has('correlationId')) {
|
|
723
743
|
headers['x-correlation-id'] = this.get('correlationId');
|
|
724
744
|
}
|
|
725
|
-
|
|
745
|
+
|
|
726
746
|
return headers;
|
|
727
747
|
}
|
|
728
748
|
|
|
@@ -731,7 +751,7 @@ class CorrelationContext {
|
|
|
731
751
|
*/
|
|
732
752
|
static fromHeaders(headers) {
|
|
733
753
|
const ctx = new CorrelationContext();
|
|
734
|
-
|
|
754
|
+
|
|
735
755
|
if (headers['x-trace-id']) {
|
|
736
756
|
ctx.set('traceId', headers['x-trace-id']);
|
|
737
757
|
}
|
|
@@ -741,7 +761,7 @@ class CorrelationContext {
|
|
|
741
761
|
if (headers['x-correlation-id']) {
|
|
742
762
|
ctx.set('correlationId', headers['x-correlation-id']);
|
|
743
763
|
}
|
|
744
|
-
|
|
764
|
+
|
|
745
765
|
return ctx;
|
|
746
766
|
}
|
|
747
767
|
}
|
|
@@ -754,22 +774,22 @@ class ObservabilityProvider extends EventEmitter {
|
|
|
754
774
|
super();
|
|
755
775
|
this.serviceName = options.serviceName || 'musubi-service';
|
|
756
776
|
this.version = options.version || '1.0.0';
|
|
757
|
-
|
|
777
|
+
|
|
758
778
|
this.logger = new Logger({
|
|
759
779
|
name: this.serviceName,
|
|
760
|
-
level: options.logLevel || LogLevel.INFO
|
|
780
|
+
level: options.logLevel || LogLevel.INFO,
|
|
761
781
|
});
|
|
762
|
-
|
|
782
|
+
|
|
763
783
|
this.metrics = new MetricsCollector({
|
|
764
784
|
name: this.serviceName,
|
|
765
|
-
prefix: options.metricsPrefix || ''
|
|
785
|
+
prefix: options.metricsPrefix || '',
|
|
766
786
|
});
|
|
767
|
-
|
|
787
|
+
|
|
768
788
|
this.tracer = new Tracer({
|
|
769
789
|
serviceName: this.serviceName,
|
|
770
|
-
version: this.version
|
|
790
|
+
version: this.version,
|
|
771
791
|
});
|
|
772
|
-
|
|
792
|
+
|
|
773
793
|
// Standard metrics
|
|
774
794
|
this._setupStandardMetrics();
|
|
775
795
|
}
|
|
@@ -780,9 +800,12 @@ class ObservabilityProvider extends EventEmitter {
|
|
|
780
800
|
_setupStandardMetrics() {
|
|
781
801
|
// Request metrics
|
|
782
802
|
this.requestCounter = this.metrics.counter('http_requests_total', 'Total HTTP requests');
|
|
783
|
-
this.requestDuration = this.metrics.histogram(
|
|
803
|
+
this.requestDuration = this.metrics.histogram(
|
|
804
|
+
'http_request_duration_seconds',
|
|
805
|
+
'HTTP request duration'
|
|
806
|
+
);
|
|
784
807
|
this.requestErrors = this.metrics.counter('http_request_errors_total', 'Total HTTP errors');
|
|
785
|
-
|
|
808
|
+
|
|
786
809
|
// Resource metrics
|
|
787
810
|
this.activeConnections = this.metrics.gauge('active_connections', 'Active connections');
|
|
788
811
|
}
|
|
@@ -813,10 +836,10 @@ class ObservabilityProvider extends EventEmitter {
|
|
|
813
836
|
*/
|
|
814
837
|
trace(name, fn, options = {}) {
|
|
815
838
|
const span = this.tracer.startSpan(name, options);
|
|
816
|
-
|
|
839
|
+
|
|
817
840
|
try {
|
|
818
841
|
const result = fn(span);
|
|
819
|
-
|
|
842
|
+
|
|
820
843
|
if (result && typeof result.then === 'function') {
|
|
821
844
|
return result
|
|
822
845
|
.then(r => {
|
|
@@ -828,13 +851,13 @@ class ObservabilityProvider extends EventEmitter {
|
|
|
828
851
|
span.setStatus(TraceStatus.ERROR, err.message);
|
|
829
852
|
span.addEvent('exception', {
|
|
830
853
|
'exception.type': err.name,
|
|
831
|
-
'exception.message': err.message
|
|
854
|
+
'exception.message': err.message,
|
|
832
855
|
});
|
|
833
856
|
this.tracer.endSpan(span);
|
|
834
857
|
throw err;
|
|
835
858
|
});
|
|
836
859
|
}
|
|
837
|
-
|
|
860
|
+
|
|
838
861
|
span.setStatus(TraceStatus.OK);
|
|
839
862
|
this.tracer.endSpan(span);
|
|
840
863
|
return result;
|
|
@@ -842,7 +865,7 @@ class ObservabilityProvider extends EventEmitter {
|
|
|
842
865
|
span.setStatus(TraceStatus.ERROR, err.message);
|
|
843
866
|
span.addEvent('exception', {
|
|
844
867
|
'exception.type': err.name,
|
|
845
|
-
'exception.message': err.message
|
|
868
|
+
'exception.message': err.message,
|
|
846
869
|
});
|
|
847
870
|
this.tracer.endSpan(span);
|
|
848
871
|
throw err;
|
|
@@ -854,10 +877,10 @@ class ObservabilityProvider extends EventEmitter {
|
|
|
854
877
|
*/
|
|
855
878
|
recordRequest(method, path, statusCode, duration) {
|
|
856
879
|
const labels = { method, path, status_code: statusCode.toString() };
|
|
857
|
-
|
|
880
|
+
|
|
858
881
|
this.requestCounter.inc(labels);
|
|
859
882
|
this.requestDuration.observe(duration / 1000, { method, path }); // Convert to seconds
|
|
860
|
-
|
|
883
|
+
|
|
861
884
|
if (statusCode >= 400) {
|
|
862
885
|
this.requestErrors.inc(labels);
|
|
863
886
|
}
|
|
@@ -870,10 +893,10 @@ class ObservabilityProvider extends EventEmitter {
|
|
|
870
893
|
return {
|
|
871
894
|
service: {
|
|
872
895
|
name: this.serviceName,
|
|
873
|
-
version: this.version
|
|
896
|
+
version: this.version,
|
|
874
897
|
},
|
|
875
898
|
metrics: this.metrics.toJSON(),
|
|
876
|
-
traces: this.tracer.getAllSpans()
|
|
899
|
+
traces: this.tracer.getAllSpans(),
|
|
877
900
|
};
|
|
878
901
|
}
|
|
879
902
|
}
|
|
@@ -921,18 +944,18 @@ module.exports = {
|
|
|
921
944
|
MemoryExporter,
|
|
922
945
|
CorrelationContext,
|
|
923
946
|
ObservabilityProvider,
|
|
924
|
-
|
|
947
|
+
|
|
925
948
|
// Constants
|
|
926
949
|
LogLevel,
|
|
927
950
|
TraceStatus,
|
|
928
951
|
SpanKind,
|
|
929
|
-
|
|
952
|
+
|
|
930
953
|
// Factories
|
|
931
954
|
createLogger,
|
|
932
955
|
createMetricsCollector,
|
|
933
956
|
createTracer,
|
|
934
957
|
createObservability,
|
|
935
|
-
|
|
958
|
+
|
|
936
959
|
// Utilities
|
|
937
|
-
generateId
|
|
960
|
+
generateId,
|
|
938
961
|
};
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Quality Metrics Dashboard
|
|
3
3
|
* カバレッジメトリクス、Constitutional準拠メトリクス、プロジェクトヘルス指標
|
|
4
|
-
*
|
|
4
|
+
*
|
|
5
|
+
* Part of MUSUBI v5.0.0 - Production Readiness
|
|
6
|
+
*
|
|
5
7
|
* @module monitoring/quality-dashboard
|
|
8
|
+
* @version 1.0.0
|
|
9
|
+
*
|
|
10
|
+
* @traceability
|
|
11
|
+
* - Requirement: REQ-P5-001 (Quality Dashboard)
|
|
12
|
+
* - Design: docs/design/tdd-musubi-v5.0.0.md#3.1
|
|
13
|
+
* - Test: tests/monitoring/quality-dashboard.test.js
|
|
6
14
|
*/
|
|
7
15
|
|
|
8
16
|
const EventEmitter = require('events');
|
|
@@ -16,17 +24,17 @@ const METRIC_CATEGORY = {
|
|
|
16
24
|
QUALITY: 'quality',
|
|
17
25
|
HEALTH: 'health',
|
|
18
26
|
PERFORMANCE: 'performance',
|
|
19
|
-
CUSTOM: 'custom'
|
|
27
|
+
CUSTOM: 'custom',
|
|
20
28
|
};
|
|
21
29
|
|
|
22
30
|
/**
|
|
23
31
|
* Health status levels
|
|
24
32
|
*/
|
|
25
33
|
const HEALTH_STATUS = {
|
|
26
|
-
HEALTHY: 'healthy',
|
|
27
|
-
WARNING: 'warning',
|
|
28
|
-
CRITICAL: 'critical',
|
|
29
|
-
FAILING: 'failing'
|
|
34
|
+
HEALTHY: 'healthy', // 80-100%
|
|
35
|
+
WARNING: 'warning', // 50-79%
|
|
36
|
+
CRITICAL: 'critical', // 20-49%
|
|
37
|
+
FAILING: 'failing', // <20%
|
|
30
38
|
};
|
|
31
39
|
|
|
32
40
|
/**
|
|
@@ -41,7 +49,7 @@ const CONSTITUTIONAL_ARTICLES = {
|
|
|
41
49
|
INCREMENTAL_ADOPTION: 'article-6',
|
|
42
50
|
SEPARATION_OF_CONCERNS: 'article-7',
|
|
43
51
|
FEEDBACK_LOOPS: 'article-8',
|
|
44
|
-
GOVERNANCE: 'article-9'
|
|
52
|
+
GOVERNANCE: 'article-9',
|
|
45
53
|
};
|
|
46
54
|
|
|
47
55
|
/**
|
|
@@ -56,17 +64,17 @@ class QualityDashboard extends EventEmitter {
|
|
|
56
64
|
*/
|
|
57
65
|
constructor(options = {}) {
|
|
58
66
|
super();
|
|
59
|
-
|
|
67
|
+
|
|
60
68
|
this.thresholds = {
|
|
61
69
|
coverage: { healthy: 80, warning: 50, critical: 20 },
|
|
62
70
|
constitutional: { healthy: 90, warning: 70, critical: 50 },
|
|
63
71
|
quality: { healthy: 80, warning: 60, critical: 40 },
|
|
64
|
-
...options.thresholds
|
|
72
|
+
...options.thresholds,
|
|
65
73
|
};
|
|
66
74
|
|
|
67
75
|
this.autoCollect = options.autoCollect ?? false;
|
|
68
76
|
this.collectInterval = options.collectInterval ?? 60000;
|
|
69
|
-
|
|
77
|
+
|
|
70
78
|
this.metrics = new Map();
|
|
71
79
|
this.history = [];
|
|
72
80
|
this.collectors = new Map();
|
|
@@ -85,25 +93,27 @@ class QualityDashboard extends EventEmitter {
|
|
|
85
93
|
*/
|
|
86
94
|
initializeDefaultCollectors() {
|
|
87
95
|
// Coverage metrics collector
|
|
88
|
-
this.registerCollector('coverage', async
|
|
96
|
+
this.registerCollector('coverage', async context => ({
|
|
89
97
|
lines: context?.coverage?.lines ?? 0,
|
|
90
98
|
branches: context?.coverage?.branches ?? 0,
|
|
91
99
|
functions: context?.coverage?.functions ?? 0,
|
|
92
100
|
statements: context?.coverage?.statements ?? 0,
|
|
93
|
-
overall:
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
101
|
+
overall:
|
|
102
|
+
context?.coverage?.overall ??
|
|
103
|
+
((context?.coverage?.lines ?? 0) +
|
|
104
|
+
(context?.coverage?.branches ?? 0) +
|
|
105
|
+
(context?.coverage?.functions ?? 0) +
|
|
106
|
+
(context?.coverage?.statements ?? 0)) /
|
|
107
|
+
4,
|
|
98
108
|
}));
|
|
99
109
|
|
|
100
110
|
// Constitutional compliance collector
|
|
101
|
-
this.registerCollector('constitutional', async
|
|
111
|
+
this.registerCollector('constitutional', async context => {
|
|
102
112
|
const articles = context?.constitutional ?? {};
|
|
103
113
|
const scores = Object.values(CONSTITUTIONAL_ARTICLES).map(id => ({
|
|
104
114
|
id,
|
|
105
115
|
score: articles[id]?.score ?? 0,
|
|
106
|
-
compliant: articles[id]?.compliant ?? false
|
|
116
|
+
compliant: articles[id]?.compliant ?? false,
|
|
107
117
|
}));
|
|
108
118
|
|
|
109
119
|
const totalScore = scores.reduce((sum, s) => sum + s.score, 0) / scores.length;
|
|
@@ -114,25 +124,27 @@ class QualityDashboard extends EventEmitter {
|
|
|
114
124
|
totalScore,
|
|
115
125
|
compliantCount,
|
|
116
126
|
totalArticles: scores.length,
|
|
117
|
-
complianceRate: (compliantCount / scores.length) * 100
|
|
127
|
+
complianceRate: (compliantCount / scores.length) * 100,
|
|
118
128
|
};
|
|
119
129
|
});
|
|
120
130
|
|
|
121
131
|
// Quality metrics collector
|
|
122
|
-
this.registerCollector('quality', async
|
|
132
|
+
this.registerCollector('quality', async context => ({
|
|
123
133
|
codeComplexity: context?.quality?.complexity ?? 0,
|
|
124
134
|
maintainability: context?.quality?.maintainability ?? 0,
|
|
125
135
|
documentation: context?.quality?.documentation ?? 0,
|
|
126
136
|
testQuality: context?.quality?.testQuality ?? 0,
|
|
127
|
-
overall:
|
|
137
|
+
overall:
|
|
138
|
+
context?.quality?.overall ??
|
|
128
139
|
((context?.quality?.complexity ?? 0) +
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
140
|
+
(context?.quality?.maintainability ?? 0) +
|
|
141
|
+
(context?.quality?.documentation ?? 0) +
|
|
142
|
+
(context?.quality?.testQuality ?? 0)) /
|
|
143
|
+
4,
|
|
132
144
|
}));
|
|
133
145
|
|
|
134
146
|
// Health metrics collector
|
|
135
|
-
this.registerCollector('health', async
|
|
147
|
+
this.registerCollector('health', async _context => {
|
|
136
148
|
const coverage = await this.getMetric('coverage');
|
|
137
149
|
const constitutional = await this.getMetric('constitutional');
|
|
138
150
|
const quality = await this.getMetric('quality');
|
|
@@ -149,7 +161,7 @@ class QualityDashboard extends EventEmitter {
|
|
|
149
161
|
qualityScore,
|
|
150
162
|
overall,
|
|
151
163
|
status: this.calculateStatus(overall, 'quality'),
|
|
152
|
-
timestamp: new Date().toISOString()
|
|
164
|
+
timestamp: new Date().toISOString(),
|
|
153
165
|
};
|
|
154
166
|
});
|
|
155
167
|
}
|
|
@@ -189,20 +201,20 @@ class QualityDashboard extends EventEmitter {
|
|
|
189
201
|
const data = await collector(context);
|
|
190
202
|
results[name] = {
|
|
191
203
|
...data,
|
|
192
|
-
collectedAt: timestamp
|
|
204
|
+
collectedAt: timestamp,
|
|
193
205
|
};
|
|
194
206
|
this.metrics.set(name, results[name]);
|
|
195
207
|
} catch (error) {
|
|
196
208
|
results[name] = {
|
|
197
209
|
error: error.message,
|
|
198
|
-
collectedAt: timestamp
|
|
210
|
+
collectedAt: timestamp,
|
|
199
211
|
};
|
|
200
212
|
}
|
|
201
213
|
}
|
|
202
214
|
|
|
203
215
|
const snapshot = {
|
|
204
216
|
timestamp,
|
|
205
|
-
metrics: { ...results }
|
|
217
|
+
metrics: { ...results },
|
|
206
218
|
};
|
|
207
219
|
|
|
208
220
|
this.history.push(snapshot);
|
|
@@ -263,20 +275,20 @@ class QualityDashboard extends EventEmitter {
|
|
|
263
275
|
breakdown: {
|
|
264
276
|
coverage: {
|
|
265
277
|
score: coverage?.overall ?? 0,
|
|
266
|
-
status: this.calculateStatus(coverage?.overall ?? 0, 'coverage')
|
|
278
|
+
status: this.calculateStatus(coverage?.overall ?? 0, 'coverage'),
|
|
267
279
|
},
|
|
268
280
|
constitutional: {
|
|
269
281
|
score: constitutional?.totalScore ?? 0,
|
|
270
282
|
status: this.calculateStatus(constitutional?.totalScore ?? 0, 'constitutional'),
|
|
271
283
|
compliantArticles: constitutional?.compliantCount ?? 0,
|
|
272
|
-
totalArticles: constitutional?.totalArticles ?? 9
|
|
284
|
+
totalArticles: constitutional?.totalArticles ?? 9,
|
|
273
285
|
},
|
|
274
286
|
quality: {
|
|
275
287
|
score: quality?.overall ?? 0,
|
|
276
|
-
status: this.calculateStatus(quality?.overall ?? 0, 'quality')
|
|
277
|
-
}
|
|
288
|
+
status: this.calculateStatus(quality?.overall ?? 0, 'quality'),
|
|
289
|
+
},
|
|
278
290
|
},
|
|
279
|
-
lastUpdated: health?.timestamp ?? null
|
|
291
|
+
lastUpdated: health?.timestamp ?? null,
|
|
280
292
|
};
|
|
281
293
|
}
|
|
282
294
|
|
|
@@ -292,7 +304,7 @@ class QualityDashboard extends EventEmitter {
|
|
|
292
304
|
.slice(-limit)
|
|
293
305
|
.map(h => ({
|
|
294
306
|
timestamp: h.timestamp,
|
|
295
|
-
value: h.metrics[metricName]
|
|
307
|
+
value: h.metrics[metricName],
|
|
296
308
|
}));
|
|
297
309
|
|
|
298
310
|
if (data.length < 2) {
|
|
@@ -406,7 +418,7 @@ class QualityDashboard extends EventEmitter {
|
|
|
406
418
|
[HEALTH_STATUS.HEALTHY]: '🟢',
|
|
407
419
|
[HEALTH_STATUS.WARNING]: '🟡',
|
|
408
420
|
[HEALTH_STATUS.CRITICAL]: '🟠',
|
|
409
|
-
[HEALTH_STATUS.FAILING]: '🔴'
|
|
421
|
+
[HEALTH_STATUS.FAILING]: '🔴',
|
|
410
422
|
};
|
|
411
423
|
return emojis[status] || '⚪';
|
|
412
424
|
}
|
|
@@ -448,7 +460,7 @@ class QualityDashboard extends EventEmitter {
|
|
|
448
460
|
setThresholds(category, thresholds) {
|
|
449
461
|
this.thresholds[category] = {
|
|
450
462
|
...this.thresholds[category],
|
|
451
|
-
...thresholds
|
|
463
|
+
...thresholds,
|
|
452
464
|
};
|
|
453
465
|
}
|
|
454
466
|
|
|
@@ -462,7 +474,7 @@ class QualityDashboard extends EventEmitter {
|
|
|
462
474
|
collectorsCount: this.collectors.size,
|
|
463
475
|
historyCount: this.history.length,
|
|
464
476
|
autoCollecting: this.intervalId !== null,
|
|
465
|
-
thresholds: { ...this.thresholds }
|
|
477
|
+
thresholds: { ...this.thresholds },
|
|
466
478
|
};
|
|
467
479
|
}
|
|
468
480
|
}
|
|
@@ -479,5 +491,5 @@ module.exports = {
|
|
|
479
491
|
createQualityDashboard,
|
|
480
492
|
METRIC_CATEGORY,
|
|
481
493
|
HEALTH_STATUS,
|
|
482
|
-
CONSTITUTIONAL_ARTICLES
|
|
494
|
+
CONSTITUTIONAL_ARTICLES,
|
|
483
495
|
};
|