mergen-server 1.4.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/LICENSE +57 -0
- package/README.md +96 -0
- package/dist/__stubs__/calibration.js +471 -0
- package/dist/__stubs__/causal.js +601 -0
- package/dist/__stubs__/closed-source.js +150 -0
- package/dist/__stubs__/license.js +35 -0
- package/dist/__stubs__/plans.js +197 -0
- package/dist/app.js +467 -0
- package/dist/cli.js +250 -0
- package/dist/commands/agent-identity.js +79 -0
- package/dist/commands/gate.js +107 -0
- package/dist/commands/github.js +632 -0
- package/dist/commands/incident.js +644 -0
- package/dist/commands/policy.js +710 -0
- package/dist/commands/scan.js +243 -0
- package/dist/commands/setup.js +1218 -0
- package/dist/commands/shared.js +109 -0
- package/dist/commands/team.js +809 -0
- package/dist/datadog/blame-attribution.js +228 -0
- package/dist/datadog/client.js +159 -0
- package/dist/datadog/compactor.js +169 -0
- package/dist/datadog/fingerprinter.js +34 -0
- package/dist/datadog/incident-state.js +21 -0
- package/dist/datadog/line-matcher.js +56 -0
- package/dist/datadog/memory-store.js +399 -0
- package/dist/datadog/otel-trace.js +67 -0
- package/dist/index.js +505 -0
- package/dist/intelligence/action-risk.js +132 -0
- package/dist/intelligence/activity-feed.js +40 -0
- package/dist/intelligence/agent-identity.js +115 -0
- package/dist/intelligence/agent-pipeline.js +329 -0
- package/dist/intelligence/agent-profiles.js +81 -0
- package/dist/intelligence/ai-commit.js +16 -0
- package/dist/intelligence/approval-analytics.js +42 -0
- package/dist/intelligence/approval-events.js +5 -0
- package/dist/intelligence/arch-boundaries.js +94 -0
- package/dist/intelligence/arch-graph.js +117 -0
- package/dist/intelligence/autonomy.js +397 -0
- package/dist/intelligence/azure-broker.js +57 -0
- package/dist/intelligence/azure-proxy-sessions.js +49 -0
- package/dist/intelligence/baseline.js +1 -0
- package/dist/intelligence/behavior-baseline.js +134 -0
- package/dist/intelligence/billing.js +1 -0
- package/dist/intelligence/blast-radius.js +224 -0
- package/dist/intelligence/bypass.js +157 -0
- package/dist/intelligence/calibration-classifier.js +77 -0
- package/dist/intelligence/calibration-git-sync.js +74 -0
- package/dist/intelligence/calibration.js +1 -0
- package/dist/intelligence/cascade-detector.js +58 -0
- package/dist/intelligence/case-study-generator.js +126 -0
- package/dist/intelligence/causal-graph.js +126 -0
- package/dist/intelligence/causal.js +1 -0
- package/dist/intelligence/change-risk.js +102 -0
- package/dist/intelligence/compliance-report.js +134 -0
- package/dist/intelligence/confidence-report.js +85 -0
- package/dist/intelligence/corpus-to-policy.js +140 -0
- package/dist/intelligence/credential-broker.js +112 -0
- package/dist/intelligence/credential-misuse.js +39 -0
- package/dist/intelligence/debug-sessions.js +108 -0
- package/dist/intelligence/decision-escalation.js +36 -0
- package/dist/intelligence/decision-memory.js +47 -0
- package/dist/intelligence/decision-similarity.js +85 -0
- package/dist/intelligence/default-safety-tests.js +53 -0
- package/dist/intelligence/degradation-watcher.js +108 -0
- package/dist/intelligence/detector-plugins.js +70 -0
- package/dist/intelligence/detectors.js +1 -0
- package/dist/intelligence/device-auth.js +138 -0
- package/dist/intelligence/diff-size.js +42 -0
- package/dist/intelligence/ebpf-verify.js +45 -0
- package/dist/intelligence/enterprise-policy-engine.js +1122 -0
- package/dist/intelligence/error-fingerprint.js +1 -0
- package/dist/intelligence/execution-gate.js +100 -0
- package/dist/intelligence/execution-mode.js +22 -0
- package/dist/intelligence/gate-analytics.js +256 -0
- package/dist/intelligence/gate-decision.js +64 -0
- package/dist/intelligence/gcp-broker.js +50 -0
- package/dist/intelligence/git-adr-sync.js +207 -0
- package/dist/intelligence/hitl-hold.js +460 -0
- package/dist/intelligence/hypothesis-history.js +93 -0
- package/dist/intelligence/idp-identity.js +83 -0
- package/dist/intelligence/impl-critic.js +216 -0
- package/dist/intelligence/incident-autopilot.js +622 -0
- package/dist/intelligence/incident-replay.js +162 -0
- package/dist/intelligence/incident-result-cache.js +33 -0
- package/dist/intelligence/incident-similarity.js +58 -0
- package/dist/intelligence/infra-detectors.js +312 -0
- package/dist/intelligence/license.js +185 -0
- package/dist/intelligence/llm-spokesperson.js +62 -0
- package/dist/intelligence/mcp-prompts.js +320 -0
- package/dist/intelligence/mcp-resources.js +171 -0
- package/dist/intelligence/normalize.js +108 -0
- package/dist/intelligence/notifications.js +83 -0
- package/dist/intelligence/oidc-issuer.js +87 -0
- package/dist/intelligence/override-corpus.js +597 -0
- package/dist/intelligence/planning-gate.js +84 -0
- package/dist/intelligence/plans.js +223 -0
- package/dist/intelligence/platt-scaling.js +164 -0
- package/dist/intelligence/policy-proposals.js +84 -0
- package/dist/intelligence/policy-suggester.js +161 -0
- package/dist/intelligence/policy-sync.js +103 -0
- package/dist/intelligence/policy-test-runner.js +35 -0
- package/dist/intelligence/postmortem-parser.js +181 -0
- package/dist/intelligence/postmortem-retrieval.js +224 -0
- package/dist/intelligence/postmortem-store.js +596 -0
- package/dist/intelligence/pr-commenter.js +81 -0
- package/dist/intelligence/pr-policy-gate.js +38 -0
- package/dist/intelligence/pr-shadow-analyzer.js +229 -0
- package/dist/intelligence/process-tree.js +108 -0
- package/dist/intelligence/prompts.js +1 -0
- package/dist/intelligence/replay.js +38 -0
- package/dist/intelligence/repro-steps.js +1 -0
- package/dist/intelligence/resource-extractors.js +0 -0
- package/dist/intelligence/resource-file-context.js +138 -0
- package/dist/intelligence/risk-score.js +22 -0
- package/dist/intelligence/rollback.js +137 -0
- package/dist/intelligence/runbook-updater.js +143 -0
- package/dist/intelligence/sandbox.js +194 -0
- package/dist/intelligence/script-trust.js +104 -0
- package/dist/intelligence/session-metrics.js +67 -0
- package/dist/intelligence/session-threat-tracker.js +231 -0
- package/dist/intelligence/shadow-digest-cron.js +81 -0
- package/dist/intelligence/shadow-log.js +284 -0
- package/dist/intelligence/shell-ast.js +145 -0
- package/dist/intelligence/siem-forward.js +104 -0
- package/dist/intelligence/slack-digest.js +151 -0
- package/dist/intelligence/slack-override-loop.js +217 -0
- package/dist/intelligence/slack-routing.js +67 -0
- package/dist/intelligence/slack.js +900 -0
- package/dist/intelligence/sql-ast.js +31 -0
- package/dist/intelligence/team.js +1 -0
- package/dist/intelligence/telemetry.js +76 -0
- package/dist/intelligence/threshold-optimizer.js +75 -0
- package/dist/intelligence/token-budget.js +66 -0
- package/dist/intelligence/tool-guard.js +708 -0
- package/dist/intelligence/tool-manifest 2.js +74 -0
- package/dist/intelligence/tool-manifest.js +125 -0
- package/dist/intelligence/tools-analysis.js +857 -0
- package/dist/intelligence/tools-arch.js +152 -0
- package/dist/intelligence/tools-autonomy.js +495 -0
- package/dist/intelligence/tools-blast-radius.js +140 -0
- package/dist/intelligence/tools-browser.js +431 -0
- package/dist/intelligence/tools-change-timeline.js +154 -0
- package/dist/intelligence/tools-credentials.js +117 -0
- package/dist/intelligence/tools-datadog.js +233 -0
- package/dist/intelligence/tools-debug-sessions.js +209 -0
- package/dist/intelligence/tools-discovery.js +284 -0
- package/dist/intelligence/tools-infra.js +612 -0
- package/dist/intelligence/tools-intent.js +128 -0
- package/dist/intelligence/tools-memory.js +514 -0
- package/dist/intelligence/tools-runbook.js +951 -0
- package/dist/intelligence/tools-sessions.js +107 -0
- package/dist/intelligence/tools-state.js +232 -0
- package/dist/intelligence/tools-utility.js +430 -0
- package/dist/intelligence/tools-validate.js +215 -0
- package/dist/intelligence/tools.js +1 -0
- package/dist/intelligence/trace-context.js +11 -0
- package/dist/intelligence/unclassified-clusters.js +87 -0
- package/dist/intelligence/usage.js +195 -0
- package/dist/routes/active-authors.js +63 -0
- package/dist/routes/activity-feed.js +21 -0
- package/dist/routes/adr.js +117 -0
- package/dist/routes/agent-activity.js +184 -0
- package/dist/routes/agent-blunders.js +163 -0
- package/dist/routes/agents.js +175 -0
- package/dist/routes/api-keys.js +65 -0
- package/dist/routes/arch.js +75 -0
- package/dist/routes/audit-export.js +93 -0
- package/dist/routes/billing-dashboard.js +158 -0
- package/dist/routes/billing-outcome.js +77 -0
- package/dist/routes/calibration.js +305 -0
- package/dist/routes/ci-gate-history.js +20 -0
- package/dist/routes/ci-gate.js +232 -0
- package/dist/routes/ci.js +293 -0
- package/dist/routes/compliance-report.js +24 -0
- package/dist/routes/confidence.js +30 -0
- package/dist/routes/credentials.js +119 -0
- package/dist/routes/dashboard.js +1407 -0
- package/dist/routes/decision-memory.js +42 -0
- package/dist/routes/demo.js +844 -0
- package/dist/routes/device-auth-stub.js +173 -0
- package/dist/routes/explain-why.js +39 -0
- package/dist/routes/gate-analytics.js +213 -0
- package/dist/routes/gate.js +28 -0
- package/dist/routes/github-webhook.js +364 -0
- package/dist/routes/habituation.js +30 -0
- package/dist/routes/health-integrations.js +243 -0
- package/dist/routes/heartbeats.js +45 -0
- package/dist/routes/hitl.js +364 -0
- package/dist/routes/impact-report.js +645 -0
- package/dist/routes/incident-webhook.js +63 -0
- package/dist/routes/incidents.js +366 -0
- package/dist/routes/layers.js +62 -0
- package/dist/routes/license.js +187 -0
- package/dist/routes/oidc-issuer.js +30 -0
- package/dist/routes/onboarding.js +170 -0
- package/dist/routes/otel.js +67 -0
- package/dist/routes/otlp-receiver.js +179 -0
- package/dist/routes/overrides.js +241 -0
- package/dist/routes/pagerduty.js +258 -0
- package/dist/routes/policies.js +809 -0
- package/dist/routes/policy-nl.js +169 -0
- package/dist/routes/postmortem.js +102 -0
- package/dist/routes/pr-shadow.js +47 -0
- package/dist/routes/rbac.js +61 -0
- package/dist/routes/replay.js +17 -0
- package/dist/routes/risk-report.js +164 -0
- package/dist/routes/runbooks.js +125 -0
- package/dist/routes/safety-test.js +174 -0
- package/dist/routes/sdk.js +222 -0
- package/dist/routes/sensor.js +819 -0
- package/dist/routes/sentry.js +140 -0
- package/dist/routes/sessions.js +43 -0
- package/dist/routes/setup-ui.js +594 -0
- package/dist/routes/shadow-report.js +107 -0
- package/dist/routes/slack-routing.js +171 -0
- package/dist/routes/team-usage.js +71 -0
- package/dist/routes/telemetry.js +28 -0
- package/dist/routes/tenants.js +199 -0
- package/dist/routes/tickets.js +167 -0
- package/dist/routes/validate.js +13 -0
- package/dist/routes/war-room.js +113 -0
- package/dist/scripts/check-arch.js +22 -0
- package/dist/seeds/community-corpus.js +176 -0
- package/dist/seeds/corpus.js +1224 -0
- package/dist/sensor/action-ledger.js +327 -0
- package/dist/sensor/adr-store.js +140 -0
- package/dist/sensor/agent-blunder-store.js +370 -0
- package/dist/sensor/agent-context-store.js +225 -0
- package/dist/sensor/agent-memory-store.js +231 -0
- package/dist/sensor/audit-fetch.js +23 -0
- package/dist/sensor/audit-log.js +273 -0
- package/dist/sensor/buffer-schemas.js +225 -0
- package/dist/sensor/buffer.js +599 -0
- package/dist/sensor/bypass-tracker.js +93 -0
- package/dist/sensor/ci-gate-history.js +70 -0
- package/dist/sensor/cloud-auth.js +183 -0
- package/dist/sensor/commit-context-store.js +235 -0
- package/dist/sensor/docker-log-stream.js +164 -0
- package/dist/sensor/docker-monitor.js +122 -0
- package/dist/sensor/extended-buffer.js +46 -0
- package/dist/sensor/feedback-token.js +41 -0
- package/dist/sensor/file-lock.js +6 -0
- package/dist/sensor/fs-watcher.js +106 -0
- package/dist/sensor/gate-heartbeat.js +122 -0
- package/dist/sensor/git-suspect.js +136 -0
- package/dist/sensor/habituation-store.js +77 -0
- package/dist/sensor/heartbeat-monitor.js +133 -0
- package/dist/sensor/incident-store.js +340 -0
- package/dist/sensor/infra-normalizer.js +513 -0
- package/dist/sensor/ingest.js +339 -0
- package/dist/sensor/jest-reporter.js +52 -0
- package/dist/sensor/k8s-events.js +132 -0
- package/dist/sensor/layer2-store.js +111 -0
- package/dist/sensor/layer3-store.js +230 -0
- package/dist/sensor/layer4-store.js +147 -0
- package/dist/sensor/logger.js +13 -0
- package/dist/sensor/otel-exporter.js +161 -0
- package/dist/sensor/paths.js +71 -0
- package/dist/sensor/policy-history.js +147 -0
- package/dist/sensor/pr-shadow-store.js +83 -0
- package/dist/sensor/process-watcher.js +162 -0
- package/dist/sensor/rbac.js +92 -0
- package/dist/sensor/redact.js +114 -0
- package/dist/sensor/redis-store.js +191 -0
- package/dist/sensor/route-reachability.js +64 -0
- package/dist/sensor/security-utils.js +18 -0
- package/dist/sensor/service-graph.js +170 -0
- package/dist/sensor/service-topology.js +227 -0
- package/dist/sensor/session-history.js +74 -0
- package/dist/sensor/session-persist.js +38 -0
- package/dist/sensor/shadow-promote.js +122 -0
- package/dist/sensor/sourcemap.js +281 -0
- package/dist/sensor/sqlite-store.js +205 -0
- package/dist/sensor/sso.js +164 -0
- package/dist/sensor/vitest-reporter.js +65 -0
- package/dist/sensor/watcher.js +48 -0
- package/dist/storage/interfaces.js +0 -0
- package/dist/storage/pg/pg-action-ledger.js +138 -0
- package/dist/storage/pg/pg-approval-store.js +107 -0
- package/dist/storage/pg/pg-blunder-store.js +193 -0
- package/dist/storage/pg/pg-ci-gate-history.js +83 -0
- package/dist/storage/pg/pg-client.js +24 -0
- package/dist/storage/pg/pg-event-store.js +63 -0
- package/dist/storage/pg/pg-incident-store.js +190 -0
- package/dist/storage/pg/pg-migrations.js +26 -0
- package/dist/storage/pg/pg-override-corpus.js +447 -0
- package/dist/storage/pg/pg-shadow-log.js +129 -0
- package/dist/storage/sqlite/sqlite-action-ledger.js +18 -0
- package/dist/storage/sqlite/sqlite-approval-store.js +37 -0
- package/dist/storage/sqlite/sqlite-blunder-store.js +27 -0
- package/dist/storage/sqlite/sqlite-ci-gate-history.js +19 -0
- package/dist/storage/sqlite/sqlite-event-store.js +29 -0
- package/dist/storage/sqlite/sqlite-incident-store.js +34 -0
- package/dist/storage/sqlite/sqlite-override-corpus.js +75 -0
- package/dist/storage/sqlite/sqlite-shadow-log.js +36 -0
- package/dist/storage/store-factory.js +55 -0
- package/dist/storage/store-registry.js +31 -0
- package/dist/update-checker.js +107 -0
- package/dist/workers/autopilot-worker.js +28 -0
- package/dist/workers/notification-worker.js +28 -0
- package/dist/workers/queues.js +58 -0
- package/dist/workers/validation-worker.js +24 -0
- package/dist/workers/worker-registry.js +18 -0
- package/package.json +123 -0
- package/sdk/mergen-inject.js +260 -0
- package/sdk/node.js +313 -0
- package/sdk/vite-plugin.ts +57 -0
- package/sdk/webpack-plugin.js +106 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
Mergen — Open-Core License
|
|
2
|
+
|
|
3
|
+
This repository uses a dual-license model:
|
|
4
|
+
|
|
5
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
6
|
+
MIT License (open-source layer)
|
|
7
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
8
|
+
|
|
9
|
+
The following components are MIT-licensed:
|
|
10
|
+
|
|
11
|
+
extension/ Chrome and Edge browser extension
|
|
12
|
+
extension-firefox/ Firefox browser extension
|
|
13
|
+
vscode-extension/ VS Code sidebar extension
|
|
14
|
+
packages/ mergen-node and mergen-python SDKs
|
|
15
|
+
sdk/ Integration helpers and plugins
|
|
16
|
+
server/src/sensor/ Ingest, ring buffer, event schemas
|
|
17
|
+
server/src/routes/ HTTP API routes
|
|
18
|
+
server/src/app.ts Express application factory
|
|
19
|
+
server/src/index.ts Boot entrypoint
|
|
20
|
+
scripts/ Setup and tooling scripts
|
|
21
|
+
|
|
22
|
+
Copyright (c) 2026 Mergen contributors
|
|
23
|
+
|
|
24
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
25
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
26
|
+
in the Software without restriction, including without limitation the rights
|
|
27
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
28
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
29
|
+
furnished to do so, subject to the following conditions:
|
|
30
|
+
|
|
31
|
+
The above copyright notice and this permission notice shall be included in all
|
|
32
|
+
copies or substantial portions of the Software.
|
|
33
|
+
|
|
34
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
35
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
36
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
37
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
38
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
39
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
40
|
+
SOFTWARE.
|
|
41
|
+
|
|
42
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
43
|
+
Proprietary License (Hypothesis Engine)
|
|
44
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
45
|
+
|
|
46
|
+
The following components are proprietary and all rights are reserved:
|
|
47
|
+
|
|
48
|
+
server/src/intelligence/ Causal chain reconstruction, hypothesis
|
|
49
|
+
detectors, calibration feedback loop,
|
|
50
|
+
anomaly baseline, billing, and licensing
|
|
51
|
+
|
|
52
|
+
These components are distributed in compiled form only as part of the
|
|
53
|
+
mergen-server npm package. They may not be copied, modified, redistributed,
|
|
54
|
+
or used to build a competing service. See server/src/intelligence/LICENSE
|
|
55
|
+
for the full proprietary license terms.
|
|
56
|
+
|
|
57
|
+
Commercial licenses and pricing: https://mergen.dev/pricing
|
package/README.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# mergen-server
|
|
2
|
+
|
|
3
|
+
Claude Code doesn't know what happened in production. Mergen does.
|
|
4
|
+
|
|
5
|
+
MCP server for your AI IDE. Once connected, ask *"what caused the 3am incident"* and get a causal chain from live telemetry — not a log dump, a structured hypothesis with evidence and a fix command. At ≥85% confidence it executes the fix, validates the result, and posts the audit trail to your Slack thread.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/mergen-server)
|
|
8
|
+
[](https://github.com/omertt27/Mergen/blob/main/LICENSE)
|
|
9
|
+
[](https://modelcontextprotocol.io)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Quick start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g mergen-server
|
|
17
|
+
mergen-server setup
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Then add to Claude Code:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
claude mcp add mergen --transport stdio -- mergen-server start
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Ask: *"Triage the api-service."*
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## What it does
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
PagerDuty fires
|
|
34
|
+
→ Mergen pulls correlated telemetry
|
|
35
|
+
→ Causal analysis (root cause + evidence)
|
|
36
|
+
→ If confidence ≥ 85% → executes fix
|
|
37
|
+
→ Validates result
|
|
38
|
+
→ Posts audit trail to Slack thread
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
All data stays on your infrastructure. No cloud. No copy-paste.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## MCP tools
|
|
46
|
+
|
|
47
|
+
| Tool | What it does |
|
|
48
|
+
|------|-------------|
|
|
49
|
+
| `triage_incident` | Full autonomous loop — diagnosis + optional fix |
|
|
50
|
+
| `execute_fix` | Execute a specific fix (requires `confirm: true`) |
|
|
51
|
+
| `analyze_runtime` | Causal analysis — root cause + fix hint, no execution |
|
|
52
|
+
| `get_recent_logs` | Console events from the ring buffer |
|
|
53
|
+
| `get_network_activity` | HTTP/fetch events with status, duration, body |
|
|
54
|
+
| `validate_fix` | Compare error counts before/after a fix |
|
|
55
|
+
| `generate_runbook` | Self-updating runbook from your incident corpus |
|
|
56
|
+
| `search_postmortems` | Semantic search over past incidents |
|
|
57
|
+
| `draft_postmortem` | Blameless post-mortem draft in seconds |
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Environment variables
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
MERGEN_AUTOPILOT=true # enable autonomous fix execution
|
|
65
|
+
MERGEN_SLACK_BOT_TOKEN=xoxb-... # Slack Web API (threads + replies)
|
|
66
|
+
MERGEN_SLACK_CHANNEL=#incidents # default incident channel
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Point your OTLP exporter at `http://127.0.0.1:3000` and PagerDuty webhooks at `/webhooks/pagerduty`.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Node.js SDK (one line)
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
import 'mergen-server/sdk/node.js';
|
|
77
|
+
// Captures uncaught exceptions, unhandledRejections, and process exits automatically
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Post-mortem from Slack thread
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
curl -X POST http://127.0.0.1:3000/postmortem/from-slack \
|
|
86
|
+
-H 'Content-Type: application/json' \
|
|
87
|
+
-d '{"thread_url":"https://yourworkspace.slack.com/archives/C1234567/p1700000000000000","service":"api"}'
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Fetches the thread via `conversations.replies`, correlates with telemetry, and returns a blameless post-mortem draft in seconds.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Full documentation
|
|
95
|
+
|
|
96
|
+
[github.com/omertt27/Mergen](https://github.com/omertt27/Mergen)
|
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { randomUUID } from "crypto";
|
|
4
|
+
import { calibrationClassifier } from "../intelligence/calibration-classifier.js";
|
|
5
|
+
import { invalidateThresholdCache } from "../intelligence/threshold-optimizer.js";
|
|
6
|
+
import { CALIBRATION_FILE, zeroRetentionMode } from "../sensor/paths.js";
|
|
7
|
+
import { gitSyncCalibration } from "../intelligence/calibration-git-sync.js";
|
|
8
|
+
import logger from "../sensor/logger.js";
|
|
9
|
+
const MIN_SAMPLES = 5;
|
|
10
|
+
const DEMOTE_THRESHOLD = 0.5;
|
|
11
|
+
const SUPPRESS_THRESHOLD = 0.2;
|
|
12
|
+
const PENDING_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
13
|
+
const LABELED_TTL_MS = 90 * 24 * 60 * 60 * 1e3;
|
|
14
|
+
const SEED_TTL_MS = 365 * 24 * 60 * 60 * 1e3;
|
|
15
|
+
let _records = [];
|
|
16
|
+
let _loaded = false;
|
|
17
|
+
let _corpusIsSeeded = false;
|
|
18
|
+
let _persistTimer = null;
|
|
19
|
+
function schedulePersist() {
|
|
20
|
+
if (zeroRetentionMode()) return;
|
|
21
|
+
if (_persistTimer) clearTimeout(_persistTimer);
|
|
22
|
+
_persistTimer = setTimeout(() => {
|
|
23
|
+
_persistTimer = null;
|
|
24
|
+
_persist();
|
|
25
|
+
}, 1e3);
|
|
26
|
+
}
|
|
27
|
+
function _persist() {
|
|
28
|
+
try {
|
|
29
|
+
fs.mkdirSync(path.dirname(CALIBRATION_FILE), { recursive: true });
|
|
30
|
+
const payload = {
|
|
31
|
+
version: 1,
|
|
32
|
+
records: _records.map((r) => ({
|
|
33
|
+
...r,
|
|
34
|
+
predictedAt: r.predictedAt.toISOString(),
|
|
35
|
+
verdictAt: r.verdictAt?.toISOString() ?? null,
|
|
36
|
+
isBuiltinSeed: r.isBuiltinSeed,
|
|
37
|
+
remediationVerdict: r.remediationVerdict,
|
|
38
|
+
remediationVerdictAt: r.remediationVerdictAt?.toISOString() ?? null
|
|
39
|
+
}))
|
|
40
|
+
};
|
|
41
|
+
const tmp = `${CALIBRATION_FILE}.tmp.${process.pid}`;
|
|
42
|
+
fs.writeFileSync(tmp, JSON.stringify(payload), "utf8");
|
|
43
|
+
fs.renameSync(tmp, CALIBRATION_FILE);
|
|
44
|
+
} catch (err) {
|
|
45
|
+
logger.warn({ err }, "calibration: persist failed");
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function _trainClassifierFromCorpus() {
|
|
49
|
+
const tagMap = /* @__PURE__ */ new Map();
|
|
50
|
+
for (const r of _records) {
|
|
51
|
+
if (!r.verdict) continue;
|
|
52
|
+
if (r.isBuiltinSeed) continue;
|
|
53
|
+
const list = tagMap.get(r.tag) ?? [];
|
|
54
|
+
list.push(r);
|
|
55
|
+
tagMap.set(r.tag, list);
|
|
56
|
+
}
|
|
57
|
+
const samples = [];
|
|
58
|
+
for (const recs of tagMap.values()) {
|
|
59
|
+
const verdicts = recs.length;
|
|
60
|
+
let correct = 0;
|
|
61
|
+
for (const r of recs) {
|
|
62
|
+
if (r.verdict === "correct") correct += 1;
|
|
63
|
+
else if (r.verdict === "partial") correct += 0.5;
|
|
64
|
+
}
|
|
65
|
+
const accuracy = correct / verdicts;
|
|
66
|
+
const trusted = verdicts >= MIN_SAMPLES;
|
|
67
|
+
for (const r of recs) {
|
|
68
|
+
samples.push({
|
|
69
|
+
confidence: r.confidenceScore,
|
|
70
|
+
tagAccuracy: accuracy,
|
|
71
|
+
sampleCount: verdicts,
|
|
72
|
+
trusted,
|
|
73
|
+
isCorrect: r.verdict === "correct" || r.verdict === "partial"
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (samples.length >= 10) {
|
|
78
|
+
calibrationClassifier.trainBulk(samples);
|
|
79
|
+
}
|
|
80
|
+
logger.debug(
|
|
81
|
+
{ samples: samples.length, totalRecords: _records.length },
|
|
82
|
+
"calibration: classifier warm-started from real corpus (seeds excluded)"
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
function load() {
|
|
86
|
+
if (_loaded) return;
|
|
87
|
+
_loaded = true;
|
|
88
|
+
if (zeroRetentionMode()) {
|
|
89
|
+
_seedBuiltInPriors();
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (!fs.existsSync(CALIBRATION_FILE)) {
|
|
93
|
+
_seedBuiltInPriors();
|
|
94
|
+
schedulePersist();
|
|
95
|
+
_trainClassifierFromCorpus();
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
const raw = JSON.parse(fs.readFileSync(CALIBRATION_FILE, "utf8"));
|
|
100
|
+
if (raw?.version === 1 && Array.isArray(raw.records)) {
|
|
101
|
+
const now = Date.now();
|
|
102
|
+
_records = raw.records.filter((r) => r.expiresAt > now).map((r) => ({
|
|
103
|
+
pid: r.pid,
|
|
104
|
+
tag: r.tag,
|
|
105
|
+
confidence: r.confidence,
|
|
106
|
+
confidenceScore: r.confidenceScore,
|
|
107
|
+
predictedAt: new Date(r.predictedAt),
|
|
108
|
+
verdict: r.verdict,
|
|
109
|
+
verdictAt: r.verdictAt ? new Date(r.verdictAt) : null,
|
|
110
|
+
note: r.note,
|
|
111
|
+
verdictDimension: r.verdictDimension,
|
|
112
|
+
expiresAt: r.expiresAt,
|
|
113
|
+
isBuiltinSeed: r.isBuiltinSeed ?? false,
|
|
114
|
+
remediationVerdict: r.remediationVerdict ?? null,
|
|
115
|
+
remediationVerdictAt: r.remediationVerdictAt ? new Date(r.remediationVerdictAt) : null
|
|
116
|
+
}));
|
|
117
|
+
if (_records.length > 0) {
|
|
118
|
+
_corpusIsSeeded = _records.every((r) => r.isBuiltinSeed);
|
|
119
|
+
}
|
|
120
|
+
if (_records.length === 0) {
|
|
121
|
+
_seedBuiltInPriors();
|
|
122
|
+
schedulePersist();
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
_seedBuiltInPriors();
|
|
126
|
+
schedulePersist();
|
|
127
|
+
}
|
|
128
|
+
} catch (err) {
|
|
129
|
+
logger.warn({ err }, "calibration: failed to load \u2014 seeding built-in priors");
|
|
130
|
+
_seedBuiltInPriors();
|
|
131
|
+
schedulePersist();
|
|
132
|
+
}
|
|
133
|
+
_trainClassifierFromCorpus();
|
|
134
|
+
}
|
|
135
|
+
function _resetForTesting() {
|
|
136
|
+
_records = [];
|
|
137
|
+
_loaded = true;
|
|
138
|
+
}
|
|
139
|
+
function recordPrediction(hypotheses) {
|
|
140
|
+
load();
|
|
141
|
+
return hypotheses.map((h) => {
|
|
142
|
+
const existing = h.pid ? _records.find((r) => r.pid === h.pid) : null;
|
|
143
|
+
if (existing) return h;
|
|
144
|
+
const pid = randomUUID();
|
|
145
|
+
_records.push({
|
|
146
|
+
pid,
|
|
147
|
+
tag: h.tag,
|
|
148
|
+
confidence: h.confidence,
|
|
149
|
+
confidenceScore: h.confidenceScore,
|
|
150
|
+
predictedAt: /* @__PURE__ */ new Date(),
|
|
151
|
+
verdict: null,
|
|
152
|
+
verdictAt: null,
|
|
153
|
+
note: null,
|
|
154
|
+
verdictDimension: null,
|
|
155
|
+
// Pending predictions expire after PENDING_TTL_MS (30 days). If a verdict
|
|
156
|
+
// is recorded before expiry, recordVerdict() extends expiresAt to
|
|
157
|
+
// LABELED_TTL_MS (90 days) so the labeled record survives for classifier
|
|
158
|
+
// training. The two TTLs serve different purposes and must not be merged.
|
|
159
|
+
expiresAt: Date.now() + PENDING_TTL_MS,
|
|
160
|
+
isBuiltinSeed: false,
|
|
161
|
+
remediationVerdict: null,
|
|
162
|
+
remediationVerdictAt: null
|
|
163
|
+
});
|
|
164
|
+
schedulePersist();
|
|
165
|
+
return { ...h, pid };
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
function recordVerdict(pid, verdict, note, dimension) {
|
|
169
|
+
load();
|
|
170
|
+
const rec = _records.find((r) => r.pid === pid);
|
|
171
|
+
if (!rec) return { found: false, persisted: false };
|
|
172
|
+
rec.isBuiltinSeed = false;
|
|
173
|
+
_corpusIsSeeded = false;
|
|
174
|
+
if (dimension === "remediation") {
|
|
175
|
+
rec.remediationVerdict = verdict;
|
|
176
|
+
rec.remediationVerdictAt = /* @__PURE__ */ new Date();
|
|
177
|
+
} else {
|
|
178
|
+
rec.verdict = verdict;
|
|
179
|
+
rec.verdictAt = /* @__PURE__ */ new Date();
|
|
180
|
+
rec.note = note ?? null;
|
|
181
|
+
rec.verdictDimension = dimension ?? null;
|
|
182
|
+
}
|
|
183
|
+
rec.expiresAt = Date.now() + LABELED_TTL_MS;
|
|
184
|
+
if (dimension !== "remediation") {
|
|
185
|
+
const stats = getStatsForTag(rec.tag);
|
|
186
|
+
calibrationClassifier.update(
|
|
187
|
+
rec.confidenceScore,
|
|
188
|
+
stats?.accuracy ?? 0.5,
|
|
189
|
+
stats?.verdicts ?? 0,
|
|
190
|
+
stats?.trusted ?? false,
|
|
191
|
+
verdict === "correct" || verdict === "partial"
|
|
192
|
+
);
|
|
193
|
+
invalidateThresholdCache();
|
|
194
|
+
}
|
|
195
|
+
schedulePersist();
|
|
196
|
+
gitSyncCalibration(rec.tag, verdict, pid);
|
|
197
|
+
return { found: true, persisted: true };
|
|
198
|
+
}
|
|
199
|
+
function getRecords() {
|
|
200
|
+
load();
|
|
201
|
+
return [..._records];
|
|
202
|
+
}
|
|
203
|
+
function normalizeNote(s) {
|
|
204
|
+
return s.toLowerCase().replace(/[^a-z0-9\s]/g, "").trim().replace(/\s+/g, " ");
|
|
205
|
+
}
|
|
206
|
+
function _computeTagStats(tag, recs) {
|
|
207
|
+
const predictions = recs.length;
|
|
208
|
+
const withVerdict = recs.filter((r) => r.verdict !== null);
|
|
209
|
+
const verdicts = withVerdict.length;
|
|
210
|
+
let correct = 0;
|
|
211
|
+
for (const r of withVerdict) {
|
|
212
|
+
if (r.verdict === "correct") correct += 1;
|
|
213
|
+
else if (r.verdict === "partial") correct += 0.5;
|
|
214
|
+
}
|
|
215
|
+
const accuracy = verdicts > 0 ? correct / verdicts : 0;
|
|
216
|
+
const trusted = verdicts >= MIN_SAMPLES;
|
|
217
|
+
const cutoff7d = Date.now() - 7 * 24 * 60 * 60 * 1e3;
|
|
218
|
+
const recent = withVerdict.filter((r) => r.verdictAt && r.verdictAt.getTime() >= cutoff7d);
|
|
219
|
+
let recentCorrect = 0;
|
|
220
|
+
for (const r of recent) {
|
|
221
|
+
if (r.verdict === "correct") recentCorrect += 1;
|
|
222
|
+
else if (r.verdict === "partial") recentCorrect += 0.5;
|
|
223
|
+
}
|
|
224
|
+
const accuracy7d = recent.length >= 3 ? recentCorrect / recent.length : null;
|
|
225
|
+
const trendDelta = accuracy7d !== null ? accuracy7d - accuracy : null;
|
|
226
|
+
const noteGroups = /* @__PURE__ */ new Map();
|
|
227
|
+
for (const r of withVerdict) {
|
|
228
|
+
if (r.note && r.verdict === "wrong") {
|
|
229
|
+
const key = normalizeNote(r.note);
|
|
230
|
+
const ex = noteGroups.get(key);
|
|
231
|
+
if (ex) ex.count++;
|
|
232
|
+
else noteGroups.set(key, { canonical: r.note, count: 1 });
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
const commonFailureModes = [...noteGroups.values()].sort((a, b) => b.count - a.count).map(({ canonical, count }) => ({ note: canonical, count }));
|
|
236
|
+
const remediationRecs = recs.filter((r) => r.remediationVerdict !== null);
|
|
237
|
+
let remediationCorrect = 0;
|
|
238
|
+
for (const r of remediationRecs) {
|
|
239
|
+
if (r.remediationVerdict === "correct") remediationCorrect += 1;
|
|
240
|
+
else if (r.remediationVerdict === "partial") remediationCorrect += 0.5;
|
|
241
|
+
}
|
|
242
|
+
const remediationAccuracy = remediationRecs.length > 0 ? remediationCorrect / remediationRecs.length : null;
|
|
243
|
+
return {
|
|
244
|
+
tag,
|
|
245
|
+
predictions,
|
|
246
|
+
verdicts,
|
|
247
|
+
accuracy,
|
|
248
|
+
trusted,
|
|
249
|
+
isEmpirical: trusted,
|
|
250
|
+
shouldInterrupt: trusted && accuracy < SUPPRESS_THRESHOLD,
|
|
251
|
+
diagnosisAccuracy: accuracy,
|
|
252
|
+
remediationAccuracy,
|
|
253
|
+
trendDelta,
|
|
254
|
+
accuracy7d,
|
|
255
|
+
commonFailureModes
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
function getStats() {
|
|
259
|
+
load();
|
|
260
|
+
const tagMap = /* @__PURE__ */ new Map();
|
|
261
|
+
for (const r of _records) {
|
|
262
|
+
const list = tagMap.get(r.tag) ?? [];
|
|
263
|
+
list.push(r);
|
|
264
|
+
tagMap.set(r.tag, list);
|
|
265
|
+
}
|
|
266
|
+
return [...tagMap.entries()].map(([tag, recs]) => _computeTagStats(tag, recs));
|
|
267
|
+
}
|
|
268
|
+
function getGlobalStats() {
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
function classifyVerdict(beforeCount, afterCount) {
|
|
272
|
+
if (afterCount === 0) return beforeCount > 0 ? "correct" : "partial";
|
|
273
|
+
if (afterCount < beforeCount) return "partial";
|
|
274
|
+
return "wrong";
|
|
275
|
+
}
|
|
276
|
+
function recordRemediationVerdict(pid, verdict) {
|
|
277
|
+
return recordVerdict(pid, verdict, void 0, "remediation");
|
|
278
|
+
}
|
|
279
|
+
function isCorpusSeeded() {
|
|
280
|
+
load();
|
|
281
|
+
return _corpusIsSeeded;
|
|
282
|
+
}
|
|
283
|
+
function getStatsForTag(tag) {
|
|
284
|
+
load();
|
|
285
|
+
const recs = _records.filter((r) => r.tag === tag);
|
|
286
|
+
if (recs.length === 0) return void 0;
|
|
287
|
+
return _computeTagStats(tag, recs);
|
|
288
|
+
}
|
|
289
|
+
function applyCalibration(hypotheses) {
|
|
290
|
+
load();
|
|
291
|
+
const active = [];
|
|
292
|
+
const suppressed = [];
|
|
293
|
+
for (const h of hypotheses) {
|
|
294
|
+
const stats = getStatsForTag(h.tag);
|
|
295
|
+
if (!stats || !stats.trusted) {
|
|
296
|
+
active.push({ ...h, calibrationAction: "passed" });
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
if (stats.accuracy >= DEMOTE_THRESHOLD) {
|
|
300
|
+
active.push({ ...h, calibrationAction: "passed" });
|
|
301
|
+
} else if (stats.accuracy >= SUPPRESS_THRESHOLD) {
|
|
302
|
+
const demoted = {
|
|
303
|
+
...h,
|
|
304
|
+
confidence: h.confidence === "HIGH" ? "MEDIUM" : h.confidence === "MEDIUM" ? "LOW" : "LOW",
|
|
305
|
+
confidenceScore: h.confidenceScore * 0.5,
|
|
306
|
+
calibrationAction: "demoted"
|
|
307
|
+
};
|
|
308
|
+
active.push(demoted);
|
|
309
|
+
} else {
|
|
310
|
+
suppressed.push({ ...h, calibrationAction: "suppressed" });
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return { active, suppressed };
|
|
314
|
+
}
|
|
315
|
+
function updateCalibrationNote(pid, note) {
|
|
316
|
+
load();
|
|
317
|
+
const rec = _records.find((r) => r.pid === pid);
|
|
318
|
+
if (!rec) return false;
|
|
319
|
+
rec.note = note.slice(0, 500);
|
|
320
|
+
schedulePersist();
|
|
321
|
+
return true;
|
|
322
|
+
}
|
|
323
|
+
function getRealVerdictCount() {
|
|
324
|
+
load();
|
|
325
|
+
return _records.filter((r) => !r.isBuiltinSeed && r.verdict !== null).length;
|
|
326
|
+
}
|
|
327
|
+
function getPendingFeedback() {
|
|
328
|
+
load();
|
|
329
|
+
const now = Date.now();
|
|
330
|
+
return _records.filter((r) => r.verdict === null && r.expiresAt > now).map((r) => ({ pid: r.pid, tag: r.tag, expiresAt: r.expiresAt }));
|
|
331
|
+
}
|
|
332
|
+
function seedCalibration(tag, counts) {
|
|
333
|
+
load();
|
|
334
|
+
const { correct = 0, wrong = 0, partial = 0 } = counts;
|
|
335
|
+
const addRecords = (count, verdict) => {
|
|
336
|
+
for (let i = 0; i < count; i++) {
|
|
337
|
+
_records.push({
|
|
338
|
+
pid: randomUUID(),
|
|
339
|
+
tag,
|
|
340
|
+
confidence: "HIGH",
|
|
341
|
+
confidenceScore: 0.9,
|
|
342
|
+
predictedAt: new Date(Date.now() - 6e4),
|
|
343
|
+
verdict,
|
|
344
|
+
verdictAt: /* @__PURE__ */ new Date(),
|
|
345
|
+
note: null,
|
|
346
|
+
verdictDimension: null,
|
|
347
|
+
expiresAt: Date.now() + LABELED_TTL_MS,
|
|
348
|
+
// already labeled — use retention TTL
|
|
349
|
+
isBuiltinSeed: false,
|
|
350
|
+
remediationVerdict: null,
|
|
351
|
+
remediationVerdictAt: null
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
addRecords(correct, "correct");
|
|
356
|
+
addRecords(wrong, "wrong");
|
|
357
|
+
addRecords(partial, "partial");
|
|
358
|
+
schedulePersist();
|
|
359
|
+
}
|
|
360
|
+
import { createHash } from "crypto";
|
|
361
|
+
function csvQuote(s) {
|
|
362
|
+
if (s === null || s === void 0) return "";
|
|
363
|
+
if (!/[",\n\r]/.test(s)) return s;
|
|
364
|
+
return '"' + s.replace(/"/g, '""') + '"';
|
|
365
|
+
}
|
|
366
|
+
function exportCsv() {
|
|
367
|
+
load();
|
|
368
|
+
const header = "pid,tag,confidence,predictedAt,verdict,verdictAt,note,verdictDimension";
|
|
369
|
+
const rows = _records.map((r) => [
|
|
370
|
+
r.pid,
|
|
371
|
+
r.tag,
|
|
372
|
+
r.confidence,
|
|
373
|
+
r.predictedAt.toISOString(),
|
|
374
|
+
r.verdict ?? "",
|
|
375
|
+
r.verdictAt ? r.verdictAt.toISOString() : "",
|
|
376
|
+
csvQuote(r.note),
|
|
377
|
+
r.verdictDimension ?? ""
|
|
378
|
+
].join(","));
|
|
379
|
+
const dataBlock = rows.length > 0 ? rows.join("\n") : "";
|
|
380
|
+
const sha256 = createHash("sha256").update(dataBlock).digest("hex");
|
|
381
|
+
const comment = `# rows: ${rows.length}, sha256: ${sha256}`;
|
|
382
|
+
if (rows.length === 0) return `${comment}
|
|
383
|
+
${header}`;
|
|
384
|
+
return `${comment}
|
|
385
|
+
${header}
|
|
386
|
+
${dataBlock}
|
|
387
|
+
`;
|
|
388
|
+
}
|
|
389
|
+
const CALIBRATION_CONFIG = {};
|
|
390
|
+
function _seedBuiltInPriors() {
|
|
391
|
+
if (_records.length > 0) return;
|
|
392
|
+
_corpusIsSeeded = true;
|
|
393
|
+
const DAY = 24 * 60 * 60 * 1e3;
|
|
394
|
+
const seeds = [
|
|
395
|
+
["auth_token_not_persisted", 17, 3],
|
|
396
|
+
["disk_full", 19, 1],
|
|
397
|
+
["memory_leak_oom", 23, 2],
|
|
398
|
+
["deployment_induced_regression", 22, 3],
|
|
399
|
+
["missing_env_var", 20, 2],
|
|
400
|
+
["unhandled_promise_rejection", 22, 2],
|
|
401
|
+
["connection_refused", 19, 3],
|
|
402
|
+
["rate_limit_silent", 18, 4],
|
|
403
|
+
["cors_preflight_failure", 20, 4],
|
|
404
|
+
["jwt_expiry", 21, 3],
|
|
405
|
+
["n_plus_one_query", 15, 6],
|
|
406
|
+
["health_check_degraded", 18, 5],
|
|
407
|
+
["stale_cache", 14, 6],
|
|
408
|
+
["cascading_timeout", 17, 6],
|
|
409
|
+
["connection_pool_exhausted", 19, 5],
|
|
410
|
+
["session_fixation", 15, 7],
|
|
411
|
+
["db_migration_lock", 16, 6],
|
|
412
|
+
["failed_migration", 20, 3],
|
|
413
|
+
["slow_api_silent", 16, 7],
|
|
414
|
+
["empty_response_silent", 14, 8]
|
|
415
|
+
];
|
|
416
|
+
for (const [tag, correct, wrong] of seeds) {
|
|
417
|
+
for (let i = 0; i < correct; i++) {
|
|
418
|
+
_records.push({
|
|
419
|
+
pid: randomUUID(),
|
|
420
|
+
tag,
|
|
421
|
+
confidence: "HIGH",
|
|
422
|
+
confidenceScore: 0.88,
|
|
423
|
+
predictedAt: new Date(Date.now() - Math.floor(Math.random() * 60) * DAY),
|
|
424
|
+
verdict: "correct",
|
|
425
|
+
verdictAt: new Date(Date.now() - Math.floor(Math.random() * 59) * DAY),
|
|
426
|
+
note: null,
|
|
427
|
+
verdictDimension: null,
|
|
428
|
+
expiresAt: Date.now() + SEED_TTL_MS,
|
|
429
|
+
isBuiltinSeed: true,
|
|
430
|
+
remediationVerdict: null,
|
|
431
|
+
remediationVerdictAt: null
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
for (let i = 0; i < wrong; i++) {
|
|
435
|
+
_records.push({
|
|
436
|
+
pid: randomUUID(),
|
|
437
|
+
tag,
|
|
438
|
+
confidence: "HIGH",
|
|
439
|
+
confidenceScore: 0.88,
|
|
440
|
+
predictedAt: new Date(Date.now() - Math.floor(Math.random() * 60) * DAY),
|
|
441
|
+
verdict: "wrong",
|
|
442
|
+
verdictAt: new Date(Date.now() - Math.floor(Math.random() * 59) * DAY),
|
|
443
|
+
note: null,
|
|
444
|
+
verdictDimension: null,
|
|
445
|
+
expiresAt: Date.now() + SEED_TTL_MS,
|
|
446
|
+
isBuiltinSeed: true,
|
|
447
|
+
remediationVerdict: null,
|
|
448
|
+
remediationVerdictAt: null
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
export {
|
|
454
|
+
CALIBRATION_CONFIG,
|
|
455
|
+
_resetForTesting,
|
|
456
|
+
applyCalibration,
|
|
457
|
+
classifyVerdict,
|
|
458
|
+
exportCsv,
|
|
459
|
+
getGlobalStats,
|
|
460
|
+
getPendingFeedback,
|
|
461
|
+
getRealVerdictCount,
|
|
462
|
+
getRecords,
|
|
463
|
+
getStats,
|
|
464
|
+
getStatsForTag,
|
|
465
|
+
isCorpusSeeded,
|
|
466
|
+
recordPrediction,
|
|
467
|
+
recordRemediationVerdict,
|
|
468
|
+
recordVerdict,
|
|
469
|
+
seedCalibration,
|
|
470
|
+
updateCalibrationNote
|
|
471
|
+
};
|