Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c85d03e70 | ||
|
|
3887547f1c |
@@ -24,6 +24,7 @@
|
|||||||
* MCP_GATEWAY_TOKEN Bearer token do gateway MCP
|
* MCP_GATEWAY_TOKEN Bearer token do gateway MCP
|
||||||
* MCP_GATEWAY_URL URL do MCP desk-crm (default https://gateway.descomplicar.pt/v1/desk-crm/mcp)
|
* MCP_GATEWAY_URL URL do MCP desk-crm (default https://gateway.descomplicar.pt/v1/desk-crm/mcp)
|
||||||
*/
|
*/
|
||||||
|
import { readFileSync, writeFileSync, existsSync } from 'node:fs'
|
||||||
import { openSessionsDb, type PatternRecord, type SessionsDb } from '../services/sessions/db.js'
|
import { openSessionsDb, type PatternRecord, type SessionsDb } from '../services/sessions/db.js'
|
||||||
import { DEFAULT_DB_PATH } from '../services/sessions/indexer.js'
|
import { DEFAULT_DB_PATH } from '../services/sessions/indexer.js'
|
||||||
import {
|
import {
|
||||||
@@ -34,6 +35,42 @@ import {
|
|||||||
type Pattern,
|
type Pattern,
|
||||||
} from '../services/sessions/patterns.js'
|
} from '../services/sessions/patterns.js'
|
||||||
|
|
||||||
|
const CARL_JSON_PATH = '/media/ealmeida/Dados/.carl/carl.json'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Propor padrão persistente como staging entry no carl.json.
|
||||||
|
* Idempotente: não duplica por pattern_key.
|
||||||
|
* Só dispara para severity action ou warning com ≥3 semanas consecutivas.
|
||||||
|
*/
|
||||||
|
function proposeCarlStagingEntry(p: PatternRecord): void {
|
||||||
|
if (!existsSync(CARL_JSON_PATH)) return
|
||||||
|
try {
|
||||||
|
const raw = readFileSync(CARL_JSON_PATH, 'utf-8')
|
||||||
|
const carl = JSON.parse(raw) as { staging?: unknown[] }
|
||||||
|
const staging = (carl.staging ??= [])
|
||||||
|
const stagingId = `pattern-${p.pattern_key}`
|
||||||
|
const exists = staging.some((e) => typeof e === 'object' && e !== null && (e as { id?: string }).id === stagingId)
|
||||||
|
if (exists) return
|
||||||
|
staging.push({
|
||||||
|
id: stagingId,
|
||||||
|
type: 'pattern-proposal',
|
||||||
|
source: 'observabilidade-patterns',
|
||||||
|
name: `Padrão recorrente: ${p.title}`,
|
||||||
|
description: p.description,
|
||||||
|
severity: p.severity,
|
||||||
|
consecutive_weeks: p.consecutive_weeks,
|
||||||
|
affected_count: p.affected_count,
|
||||||
|
sample_session_ids: p.sample_session_ids,
|
||||||
|
proposed_at: new Date().toISOString(),
|
||||||
|
status: 'pending-review',
|
||||||
|
})
|
||||||
|
writeFileSync(CARL_JSON_PATH, JSON.stringify(carl, null, 2), 'utf-8')
|
||||||
|
console.error(`[patterns] proposto em CARL staging: ${stagingId}`)
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`[patterns] falha ao propor em CARL staging: ${(err as Error).message}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface Args {
|
interface Args {
|
||||||
week?: string
|
week?: string
|
||||||
publish: boolean
|
publish: boolean
|
||||||
@@ -344,6 +381,8 @@ async function main(): Promise<void> {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(`[patterns] falha ao criar ticket para ${rec.pattern_key}:`, (e as Error).message)
|
console.error(`[patterns] falha ao criar ticket para ${rec.pattern_key}:`, (e as Error).message)
|
||||||
}
|
}
|
||||||
|
// Propor como staging no CARL — idempotente por pattern_key
|
||||||
|
proposeCarlStagingEntry(rec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -360,6 +399,7 @@ async function main(): Promise<void> {
|
|||||||
for (const rec of records) {
|
for (const rec of records) {
|
||||||
if (rec.consecutive_weeks >= 3 && (rec.severity === 'warning' || rec.severity === 'action')) {
|
if (rec.consecutive_weeks >= 3 && (rec.severity === 'warning' || rec.severity === 'action')) {
|
||||||
console.error(`[patterns] (dry-run) Ticket seria criado: ${rec.title} — ${rec.consecutive_weeks} sem.`)
|
console.error(`[patterns] (dry-run) Ticket seria criado: ${rec.title} — ${rec.consecutive_weeks} sem.`)
|
||||||
|
console.error(`[patterns] (dry-run) CARL staging seria proposto: pattern-${rec.pattern_key}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,11 @@ export function detectSkillsHighErrorRate(ctx: DetectCtx): Pattern[] {
|
|||||||
for (const sk of skills) {
|
for (const sk of skills) {
|
||||||
const entry = bySkill.get(sk) ?? { total: 0, fail: 0, ids: [] }
|
const entry = bySkill.get(sk) ?? { total: 0, fail: 0, ids: [] }
|
||||||
entry.total++
|
entry.total++
|
||||||
if (r.outcome === 'error' || r.outcome === 'interrupted') {
|
// Interrupções em sessões longas (≥10 eventos) são redirects naturais do utilizador,
|
||||||
|
// não falhas da skill. Só contar erros reais ou interrupções muito precoces.
|
||||||
|
const isRealFailure = r.outcome === 'error' ||
|
||||||
|
(r.outcome === 'interrupted' && (r.event_count ?? 0) < 10)
|
||||||
|
if (isRealFailure) {
|
||||||
entry.fail++
|
entry.fail++
|
||||||
if (entry.ids.length < 5) entry.ids.push(r.session_id)
|
if (entry.ids.length < 5) entry.ids.push(r.session_id)
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+3
-3
@@ -7967,9 +7967,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.5.6",
|
"version": "8.5.12",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.12.tgz",
|
||||||
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
|
"integrity": "sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user