trackfw 2.5.0 → 2.5.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/package.json +1 -1
- package/src/commands/help.js +42 -0
- package/src/commands/validate.js +3 -3
- package/src/validator/index.js +41 -9
package/package.json
CHANGED
package/src/commands/help.js
CHANGED
|
@@ -162,6 +162,48 @@ const configDocs = {
|
|
|
162
162
|
description: 'Severidade: REQ bloqueada por ADR em rascunho.',
|
|
163
163
|
example: 'rules:\n blocked_by_draft_adr: warning',
|
|
164
164
|
impact: 'error bloqueia; warning apenas reporta; off desativa a regra.'
|
|
165
|
+
},
|
|
166
|
+
trace_id_field: {
|
|
167
|
+
type: 'string',
|
|
168
|
+
default: '""',
|
|
169
|
+
description: 'Campo de frontmatter usado como trace ID para verificação bidirecional REQ↔Roadmap. Vazio desativa a verificação.',
|
|
170
|
+
example: 'trace_id_field: req_id',
|
|
171
|
+
impact: 'Quando configurado, ativa as regras traceid_* que garantem que toda REQ tem Roadmap correspondente e vice-versa.'
|
|
172
|
+
},
|
|
173
|
+
'rules.traceid_orphan_roadmap': {
|
|
174
|
+
type: 'off|warning|error',
|
|
175
|
+
default: '"error"',
|
|
176
|
+
description: 'Severidade: Roadmap com trace ID sem REQ correspondente.',
|
|
177
|
+
example: 'rules:\n traceid_orphan_roadmap: warning',
|
|
178
|
+
impact: 'error bloqueia; warning apenas reporta; off desativa a regra.'
|
|
179
|
+
},
|
|
180
|
+
'rules.traceid_orphan_req': {
|
|
181
|
+
type: 'off|warning|error',
|
|
182
|
+
default: '"error"',
|
|
183
|
+
description: 'Severidade: REQ com trace ID sem Roadmap correspondente.',
|
|
184
|
+
example: 'rules:\n traceid_orphan_req: warning',
|
|
185
|
+
impact: 'error bloqueia; warning apenas reporta; off desativa a regra.'
|
|
186
|
+
},
|
|
187
|
+
'rules.traceid_state_mismatch': {
|
|
188
|
+
type: 'off|warning|error',
|
|
189
|
+
default: '"error"',
|
|
190
|
+
description: 'Severidade: REQ e Roadmap com mesmo trace ID em estados diferentes (ex: REQ em done, Roadmap em wip).',
|
|
191
|
+
example: 'rules:\n traceid_state_mismatch: warning',
|
|
192
|
+
impact: 'error bloqueia; warning apenas reporta; off desativa a regra.'
|
|
193
|
+
},
|
|
194
|
+
'rules.traceid_duplicate_req': {
|
|
195
|
+
type: 'off|warning|error',
|
|
196
|
+
default: '"error"',
|
|
197
|
+
description: 'Severidade: mesmo trace ID aparece em mais de uma REQ.',
|
|
198
|
+
example: 'rules:\n traceid_duplicate_req: warning',
|
|
199
|
+
impact: 'error bloqueia; warning apenas reporta; off desativa a regra.'
|
|
200
|
+
},
|
|
201
|
+
'rules.traceid_duplicate_roadmap': {
|
|
202
|
+
type: 'off|warning|error',
|
|
203
|
+
default: '"error"',
|
|
204
|
+
description: 'Severidade: mesmo trace ID aparece em mais de um Roadmap.',
|
|
205
|
+
example: 'rules:\n traceid_duplicate_roadmap: warning',
|
|
206
|
+
impact: 'error bloqueia; warning apenas reporta; off desativa a regra.'
|
|
165
207
|
}
|
|
166
208
|
}
|
|
167
209
|
|
package/src/commands/validate.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
const { Command } = require('commander')
|
|
3
|
-
const { validate, isLenient, lenientUntilDate } = require('../validator')
|
|
3
|
+
const { validate, isLenient, lenientUntilDate, getItemMeta } = require('../validator')
|
|
4
4
|
const { t } = require('../i18n')
|
|
5
5
|
|
|
6
6
|
const cmd = new Command('validate')
|
|
@@ -20,8 +20,8 @@ cmd.action(async (options) => {
|
|
|
20
20
|
mode,
|
|
21
21
|
exit_code: exitCode,
|
|
22
22
|
},
|
|
23
|
-
violations: violations.map(v => ({ message: v })
|
|
24
|
-
warnings: warnings.map(w => ({ message: w })
|
|
23
|
+
violations: violations.map(v => { const m = getItemMeta(v); return { message: v, rule: m.rule, file: m.file } }),
|
|
24
|
+
warnings: warnings.map(w => { const m = getItemMeta(w); return { message: w, rule: m.rule, file: m.file } }),
|
|
25
25
|
}
|
|
26
26
|
console.log(JSON.stringify(output, null, 2))
|
|
27
27
|
process.exit(exitCode)
|
package/src/validator/index.js
CHANGED
|
@@ -700,6 +700,27 @@ function validateFilenameUniqueness() {
|
|
|
700
700
|
return violations
|
|
701
701
|
}
|
|
702
702
|
|
|
703
|
+
// _itemMeta: mapa de message → { rule, file } para enriquecer saída JSON.
|
|
704
|
+
// Populado em applyRule e nos pushs diretos do validateUnfiltered.
|
|
705
|
+
// Permanece em memória apenas durante a execução de uma chamada validate*.
|
|
706
|
+
const _itemMeta = new Map()
|
|
707
|
+
|
|
708
|
+
// _setMeta registra metadados de rule/file para uma mensagem.
|
|
709
|
+
function _setMeta(msg, ruleName) {
|
|
710
|
+
const m = /"([^"]+)"/.exec(msg)
|
|
711
|
+
_itemMeta.set(msg, { rule: ruleName, file: m ? m[1] : '' })
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// getItemMeta retorna { rule, file } para uma mensagem, ou { rule: '', file: '' } se ausente.
|
|
715
|
+
function getItemMeta(msg) {
|
|
716
|
+
return _itemMeta.get(msg) || { rule: '', file: '' }
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
// resetMeta limpa o mapa entre execuções (usado internamente).
|
|
720
|
+
function resetMeta() {
|
|
721
|
+
_itemMeta.clear()
|
|
722
|
+
}
|
|
723
|
+
|
|
703
724
|
// ruleSeverity retorna a severidade configurada para uma regra ('error'|'warning'|'off').
|
|
704
725
|
function ruleSeverity(name) {
|
|
705
726
|
const cfg = config.load()
|
|
@@ -708,14 +729,15 @@ function ruleSeverity(name) {
|
|
|
708
729
|
|
|
709
730
|
// applyRule distribui msgs para violations ou warnings conforme a severidade configurada.
|
|
710
731
|
// Se severidade for 'off', descarta silenciosamente.
|
|
732
|
+
// Também popula _itemMeta com rule/file para cada mensagem aceita.
|
|
711
733
|
function applyRule(ruleName, msgs, violations, warnings) {
|
|
712
734
|
if (!msgs || msgs.length === 0) return
|
|
713
735
|
const severity = ruleSeverity(ruleName)
|
|
714
736
|
if (severity === 'off') return
|
|
715
737
|
if (severity === 'warning') {
|
|
716
|
-
warnings.push(
|
|
738
|
+
for (const msg of msgs) { _setMeta(msg, ruleName); warnings.push(msg) }
|
|
717
739
|
} else {
|
|
718
|
-
violations.push(
|
|
740
|
+
for (const msg of msgs) { _setMeta(msg, ruleName); violations.push(msg) }
|
|
719
741
|
}
|
|
720
742
|
}
|
|
721
743
|
|
|
@@ -745,11 +767,12 @@ function saveBaseline(violations, warnings) {
|
|
|
745
767
|
|
|
746
768
|
// validateUnfiltered executa todas as validações e retorna { violations, warnings } sem ratchet.
|
|
747
769
|
async function validateUnfiltered() {
|
|
770
|
+
resetMeta()
|
|
748
771
|
const wipLimitResult = validateWIPLimit()
|
|
749
772
|
const violations = []
|
|
750
773
|
const warnings = []
|
|
751
774
|
|
|
752
|
-
// Regras com severidade configurável via applyRule
|
|
775
|
+
// Regras com severidade configurável via applyRule (popula _itemMeta automaticamente)
|
|
753
776
|
applyRule('wip_has_req', validateWIPHasREQ(), violations, warnings)
|
|
754
777
|
applyRule('wip_acceptance', validateWIPHasAcceptanceCriteria(), violations, warnings)
|
|
755
778
|
applyRule('wip_limit', wipLimitResult.violations, violations, warnings)
|
|
@@ -761,18 +784,24 @@ async function validateUnfiltered() {
|
|
|
761
784
|
applyRule('blocked_by_draft_adr', validateREQsNotBlockedByDraftADRs(), violations, warnings)
|
|
762
785
|
|
|
763
786
|
// Regras diretas (sem configuração de severidade): violations sempre
|
|
764
|
-
|
|
765
|
-
violations.push(
|
|
766
|
-
violations.push(
|
|
767
|
-
violations.push(
|
|
787
|
+
// Popular _itemMeta manualmente para manter rastreabilidade no JSON
|
|
788
|
+
for (const msg of validateREQsHaveADR()) { _setMeta(msg, 'req_has_adr'); violations.push(msg) }
|
|
789
|
+
for (const msg of validateBlockedHasREQ()) { _setMeta(msg, 'blocked_has_req'); violations.push(msg) }
|
|
790
|
+
for (const msg of validateREQsHaveRoadmap()) { _setMeta(msg, 'req_has_roadmap'); violations.push(msg) }
|
|
791
|
+
for (const msg of validateFrontmatterPresence()) { _setMeta(msg, 'frontmatter_presence'); violations.push(msg) }
|
|
768
792
|
|
|
769
793
|
// warnings diretos do WIP limit (não configuráveis)
|
|
770
|
-
|
|
794
|
+
for (const msg of wipLimitResult.warnings) { _setMeta(msg, 'wip_limit'); warnings.push(msg) }
|
|
771
795
|
|
|
772
796
|
// Verificação bidirecional de trace ID (somente se traceIdField configurado)
|
|
773
797
|
const cfg = config.load()
|
|
774
798
|
if (cfg.traceIdField) {
|
|
775
|
-
|
|
799
|
+
for (const msg of checkTraceIds(cfg.reqDir, cfg.roadmapDir, cfg.traceIdField)) {
|
|
800
|
+
// O prefixo da mensagem traceid já carrega o nome da regra (ex: "traceid_orphan_roadmap: ...")
|
|
801
|
+
const ruleName = msg.split(':')[0].trim()
|
|
802
|
+
_setMeta(msg, ruleName)
|
|
803
|
+
violations.push(msg)
|
|
804
|
+
}
|
|
776
805
|
}
|
|
777
806
|
|
|
778
807
|
return { violations, warnings }
|
|
@@ -917,4 +946,7 @@ module.exports = {
|
|
|
917
946
|
contentHasMarker,
|
|
918
947
|
ruleSeverity,
|
|
919
948
|
applyRule,
|
|
949
|
+
// novas funções ML-1B (v2.5.1)
|
|
950
|
+
getItemMeta,
|
|
951
|
+
resetMeta,
|
|
920
952
|
}
|