@jaimevalasek/aioson 1.30.2 → 1.36.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/CHANGELOG.md +75 -0
- package/README.md +19 -6
- package/docs/en/1-understand/ecosystem-map.md +45 -29
- package/docs/en/1-understand/glossary.md +5 -5
- package/docs/en/1-understand/what-is-aioson.md +5 -5
- package/docs/en/2-start/existing-project.md +7 -7
- package/docs/en/2-start/first-project.md +32 -38
- package/docs/en/2-start/initial-decisions.md +18 -17
- package/docs/en/3-recipes/README.md +2 -2
- package/docs/en/3-recipes/continuity-between-sessions.md +2 -2
- package/docs/en/3-recipes/from-idea-to-prd-via-briefing.md +5 -2
- package/docs/en/3-recipes/full-feature-with-sheldon.md +327 -338
- package/docs/en/4-agents/README.md +28 -14
- package/docs/en/4-agents/discovery-design-doc.md +20 -8
- package/docs/en/4-agents/forge-run.md +3 -2
- package/docs/en/5-reference/cli-reference.md +51 -48
- package/docs/en/5-reference/executable-verification.md +10 -7
- package/docs/en/5-reference/parallel.md +2 -0
- package/docs/en/5-reference/qa-browser.md +2 -2
- package/docs/en/README.md +3 -3
- package/docs/pt/1-entender/glossario.md +4 -4
- package/docs/pt/1-entender/mapa-do-ecossistema.md +32 -21
- package/docs/pt/2-comecar/decisoes-iniciais.md +16 -16
- package/docs/pt/2-comecar/primeiro-projeto.md +1 -1
- package/docs/pt/3-receitas/README.md +1 -1
- package/docs/pt/3-receitas/app-saas-do-zero.md +35 -122
- package/docs/pt/3-receitas/feature-completa-com-sheldon.md +289 -338
- package/docs/pt/4-agentes/analyst.md +9 -5
- package/docs/pt/4-agentes/architect.md +9 -5
- package/docs/pt/4-agentes/dev.md +19 -7
- package/docs/pt/4-agentes/discovery-design-doc.md +25 -23
- package/docs/pt/4-agentes/orchestrator.md +164 -118
- package/docs/pt/4-agentes/pentester.md +5 -5
- package/docs/pt/4-agentes/pm.md +15 -7
- package/docs/pt/4-agentes/sheldon.md +166 -99
- package/docs/pt/4-agentes/ux-ui.md +7 -4
- package/docs/pt/5-referencia/agent-chain-continuity.md +14 -5
- package/docs/pt/5-referencia/comandos-cli.md +1 -1
- package/docs/pt/5-referencia/harness-retro.md +2 -1
- package/docs/pt/5-referencia/sdd-automation-scripts.md +6 -6
- package/docs/pt/5-referencia/sdd-framework.md +53 -16
- package/docs/pt/5-referencia/sdd-planos-e-estrutura.md +27 -15
- package/docs/pt/README.md +4 -4
- package/docs/pt/agentes.md +48 -50
- package/package.json +2 -2
- package/src/artifact-kinds.js +110 -0
- package/src/cli.js +82 -42
- package/src/commands/agent-epilogue.js +251 -186
- package/src/commands/agents.js +104 -48
- package/src/commands/audit-code.js +344 -0
- package/src/commands/classify.js +75 -13
- package/src/commands/feature-close.js +43 -18
- package/src/commands/harness-check.js +259 -175
- package/src/commands/harness-retro-promote.js +387 -0
- package/src/commands/live.js +24 -0
- package/src/commands/prototype-check.js +163 -0
- package/src/commands/review-feature.js +189 -0
- package/src/commands/runtime.js +81 -66
- package/src/commands/sync-agents-copy.js +115 -0
- package/src/commands/verification-plan.js +116 -0
- package/src/commands/verify-artifact.js +530 -0
- package/src/commands/verify-implementation.js +428 -0
- package/src/commands/workflow-execute.js +309 -309
- package/src/commands/workflow-next.js +361 -19
- package/src/commands/workflow-plan.js +5 -5
- package/src/constants.js +4 -0
- package/src/gateway-pointer-merge.js +7 -1
- package/src/handoff-contract.js +267 -172
- package/src/harness/contract-integrity-gate.js +172 -0
- package/src/harness/contract-integrity.js +111 -0
- package/src/harness/contract-schema.js +377 -332
- package/src/harness/detect-runtime-feature.js +90 -0
- package/src/harness/static-criteria.js +192 -0
- package/src/i18n/messages/en.js +8 -4
- package/src/i18n/messages/es.js +8 -4
- package/src/i18n/messages/fr.js +8 -4
- package/src/i18n/messages/pt-BR.js +8 -4
- package/src/install-wizard.js +8 -8
- package/src/installer.js +13 -6
- package/src/lib/retro/retro-render.js +10 -1
- package/src/lib/retro/retro-sources.js +45 -27
- package/src/lib/retro/verification-reports.js +230 -0
- package/src/parser.js +6 -0
- package/src/preflight-engine.js +12 -12
- package/src/runtime-store.js +13 -9
- package/src/verification/evidence-bundle.js +251 -0
- package/src/verification/ledger-store.js +221 -0
- package/src/verification/path-policy.js +74 -0
- package/src/verification/policy-engine.js +95 -0
- package/src/verification/prompt-package.js +314 -0
- package/src/verification/redaction.js +77 -0
- package/src/verification/report-parser.js +132 -0
- package/src/verification/report-store.js +97 -0
- package/src/verification/result.js +16 -0
- package/src/verification/runners/index.js +319 -0
- package/src/verification/runtime-telemetry.js +144 -0
- package/src/verification/schema.js +276 -0
- package/src/verification/source-discovery.js +153 -0
- package/src/verification-policy.js +398 -0
- package/src/version.js +52 -1
- package/template/.aioson/agents/analyst.md +9 -6
- package/template/.aioson/agents/architect.md +34 -5
- package/template/.aioson/agents/briefing-refiner.md +25 -0
- package/template/.aioson/agents/briefing.md +69 -12
- package/template/.aioson/agents/committer.md +2 -1
- package/template/.aioson/agents/copywriter.md +30 -21
- package/template/.aioson/agents/design-hybrid-forge.md +28 -15
- package/template/.aioson/agents/dev.md +28 -10
- package/template/.aioson/agents/deyvin.md +3 -2
- package/template/.aioson/agents/discover.md +12 -3
- package/template/.aioson/agents/discovery-design-doc.md +7 -2
- package/template/.aioson/agents/genome.md +19 -10
- package/template/.aioson/agents/neo.md +30 -30
- package/template/.aioson/agents/orache.md +20 -11
- package/template/.aioson/agents/orchestrator.md +84 -7
- package/template/.aioson/agents/pm.md +8 -8
- package/template/.aioson/agents/product.md +15 -11
- package/template/.aioson/agents/profiler-enricher.md +20 -11
- package/template/.aioson/agents/profiler-forge.md +20 -11
- package/template/.aioson/agents/profiler-researcher.md +20 -11
- package/template/.aioson/agents/qa.md +87 -17
- package/template/.aioson/agents/scope-check.md +19 -5
- package/template/.aioson/agents/setup.md +12 -1
- package/template/.aioson/agents/sheldon.md +92 -9
- package/template/.aioson/agents/site-forge.md +11 -2
- package/template/.aioson/agents/squad.md +20 -5
- package/template/.aioson/agents/ux-ui.md +4 -2
- package/template/.aioson/agents/validator.md +33 -1
- package/template/.aioson/config/verification.json +61 -0
- package/template/.aioson/config.md +13 -9
- package/template/.aioson/docs/LAYERS.md +2 -2
- package/template/.aioson/docs/autopilot-handoff.md +10 -10
- package/template/.aioson/docs/dev/execution-discipline.md +41 -0
- package/template/.aioson/docs/dev/phase-loop.md +47 -0
- package/template/.aioson/docs/feature-expansion-taxonomy.md +31 -3
- package/template/.aioson/docs/presets/workflow.config.full-merged.json +15 -0
- package/template/.aioson/docs/presets/workflow.config.lean.json +15 -0
- package/template/.aioson/docs/product/prd-contract.md +12 -12
- package/template/.aioson/docs/prototype-contract.md +98 -0
- package/template/.aioson/docs/reference-identity.md +94 -0
- package/template/.aioson/docs/sheldon/harness-contract.md +155 -28
- package/template/.aioson/docs/verification-config.md +82 -0
- package/template/.aioson/docs/verify-artifact-gates.md +91 -0
- package/template/.aioson/docs/workflow-lean-lane.md +129 -0
- package/template/.aioson/skills/design/interface-design/references/intent-and-domain.md +2 -0
- package/template/.aioson/skills/process/aioson-spec-driven/SKILL.md +16 -14
- package/template/.aioson/skills/process/aioson-spec-driven/references/approval-gates.md +2 -2
- package/template/.aioson/skills/process/aioson-spec-driven/references/classification-map.md +4 -4
- package/template/.aioson/skills/process/aioson-spec-driven/references/dev.md +15 -15
- package/template/.aioson/skills/process/briefing-expansion-scout/SKILL.md +25 -3
- package/template/.aioson/skills/process/design-hybrid-forge/SKILL.md +5 -3
- package/template/.aioson/skills/process/design-hybrid-forge/references/external-source-ingestion.md +89 -0
- package/template/.aioson/skills/process/product-scope-expansion/SKILL.md +29 -2
- package/template/.aioson/skills/process/prototype-forge/SKILL.md +98 -0
- package/template/.aioson/skills/process/reference-identity-extract/SKILL.md +164 -0
- package/template/.aioson/skills/process/sheldon-expansion-audit/SKILL.md +23 -2
- package/template/.aioson/skills/static/multi-agent-patterns.md +5 -5
- package/template/CLAUDE.md +15 -11
|
@@ -1,175 +1,259 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* aioson harness:check [path] --slug=<slug> [--criteria=C1,C2] [--timeout=<ms>]
|
|
5
|
-
* [--json] — runner standalone e determinístico de criteria[].verification.
|
|
6
|
-
*
|
|
7
|
-
* Executa os checks executáveis do contrato FORA do self:loop, para consumo
|
|
8
|
-
* pelo @validator (verificação binária antes de julgamento LLM), pelo @dev
|
|
9
|
-
* (feedback rápido pré-done) ou por CI. Reusa runCriteria/executeInSandbox —
|
|
10
|
-
* NÃO cria runner novo.
|
|
11
|
-
*
|
|
12
|
-
* Read-only sobre progress.json: quem muda estado do circuito continua sendo
|
|
13
|
-
* o ciclo harness:validate/apply-validation. Persiste o resultado em
|
|
14
|
-
* `last-check-output.json` no plan dir (espelha a convenção
|
|
15
|
-
* last-validator-output.json) e emite telemetria criteria_check_failed
|
|
16
|
-
* (best-effort, nunca quebra).
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
const fs = require('node:fs');
|
|
20
|
-
const path = require('node:path');
|
|
21
|
-
|
|
22
|
-
const { validateContract, resolveContract } = require('../harness/contract-schema');
|
|
23
|
-
const { runCriteria, DEFAULT_CHECK_TIMEOUT_MS } = require('../harness/criteria-runner');
|
|
24
|
-
const {
|
|
25
|
-
const {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* aioson harness:check [path] --slug=<slug> [--criteria=C1,C2] [--timeout=<ms>]
|
|
5
|
+
* [--json] — runner standalone e determinístico de criteria[].verification.
|
|
6
|
+
*
|
|
7
|
+
* Executa os checks executáveis do contrato FORA do self:loop, para consumo
|
|
8
|
+
* pelo @validator (verificação binária antes de julgamento LLM), pelo @dev
|
|
9
|
+
* (feedback rápido pré-done) ou por CI. Reusa runCriteria/executeInSandbox —
|
|
10
|
+
* NÃO cria runner novo.
|
|
11
|
+
*
|
|
12
|
+
* Read-only sobre progress.json: quem muda estado do circuito continua sendo
|
|
13
|
+
* o ciclo harness:validate/apply-validation. Persiste o resultado em
|
|
14
|
+
* `last-check-output.json` no plan dir (espelha a convenção
|
|
15
|
+
* last-validator-output.json) e emite telemetria criteria_check_failed
|
|
16
|
+
* (best-effort, nunca quebra).
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const fs = require('node:fs');
|
|
20
|
+
const path = require('node:path');
|
|
21
|
+
|
|
22
|
+
const { validateContract, resolveContract } = require('../harness/contract-schema');
|
|
23
|
+
const { runCriteria, DEFAULT_CHECK_TIMEOUT_MS } = require('../harness/criteria-runner');
|
|
24
|
+
const { evaluateStaticCriteria, isStaticCriterion } = require('../harness/static-criteria');
|
|
25
|
+
const { emitGuardEvent } = require('../harness/guard-events');
|
|
26
|
+
const { findActiveContract } = require('../harness/active-contract');
|
|
27
|
+
const { checkContractIntegrity } = require('../harness/contract-integrity');
|
|
28
|
+
const { detectRuntimeFeature, gitChangedFiles } = require('../harness/detect-runtime-feature');
|
|
29
|
+
|
|
30
|
+
function readProgressSignals(planDir) {
|
|
31
|
+
// Same progress fields the contract-integrity gate consults, so standalone
|
|
32
|
+
// `harness:check` detects the identical migration surface (completed_steps +
|
|
33
|
+
// changed_files + touched_files) the workflow finalize / feature:close gate does.
|
|
34
|
+
try {
|
|
35
|
+
const progressPath = path.join(planDir, 'progress.json');
|
|
36
|
+
if (!fs.existsSync(progressPath)) return [];
|
|
37
|
+
const progress = JSON.parse(fs.readFileSync(progressPath, 'utf8'));
|
|
38
|
+
return [progress.completed_steps, progress.changed_files, progress.touched_files]
|
|
39
|
+
.flatMap((value) => (Array.isArray(value) ? value : []));
|
|
40
|
+
} catch {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function resolveSlug(targetDir, options) {
|
|
46
|
+
const explicit = String(options.slug || '').trim();
|
|
47
|
+
if (explicit) return explicit;
|
|
48
|
+
try {
|
|
49
|
+
const active = findActiveContract(targetDir);
|
|
50
|
+
return active ? active.slug : '';
|
|
51
|
+
} catch {
|
|
52
|
+
return '';
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function runHarnessCheck({ args, options = {}, logger, t }) {
|
|
57
|
+
const targetDir = path.resolve(process.cwd(), args?.[0] || '.');
|
|
58
|
+
const slug = resolveSlug(targetDir, options);
|
|
59
|
+
|
|
60
|
+
if (!slug) {
|
|
61
|
+
logger.error(t('errors.missing_slug') || 'Error: --slug is required');
|
|
62
|
+
return { ok: false, error: 'missing_slug' };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const planDir = path.join(targetDir, '.aioson', 'plans', slug);
|
|
66
|
+
const contractPath = path.join(planDir, 'harness-contract.json');
|
|
67
|
+
|
|
68
|
+
if (!fs.existsSync(contractPath)) {
|
|
69
|
+
logger.error(t('harness.contract_not_found', { slug }) || `Contract not found for slug: ${slug}`);
|
|
70
|
+
return { ok: false, error: 'contract_not_found', slug };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
let contract;
|
|
74
|
+
try {
|
|
75
|
+
contract = JSON.parse(fs.readFileSync(contractPath, 'utf8'));
|
|
76
|
+
} catch (err) {
|
|
77
|
+
logger.error(`Invalid JSON in contract: ${err.message}`);
|
|
78
|
+
return { ok: false, error: 'invalid_json', slug, detail: err.message };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const schemaResult = validateContract(contract);
|
|
82
|
+
if (!schemaResult.ok) {
|
|
83
|
+
const first = schemaResult.errors[0];
|
|
84
|
+
logger.error(`Contract schema invalid: ${first.field} — ${first.reason}`);
|
|
85
|
+
await emitGuardEvent(targetDir, {
|
|
86
|
+
eventType: 'contract_invalid',
|
|
87
|
+
agent: 'harness-check',
|
|
88
|
+
message: `${first.field}: ${first.reason}`,
|
|
89
|
+
payload: { slug }
|
|
90
|
+
});
|
|
91
|
+
return { ok: false, error: 'contract_schema_invalid', slug, errors: schemaResult.errors };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const resolved = resolveContract(contract);
|
|
95
|
+
|
|
96
|
+
// ── Contract-integrity precheck (§2c, deterministic core of @validator Step 0) ──
|
|
97
|
+
// A runtime feature whose contract has no RG-* criterion, or that pads binary
|
|
98
|
+
// criteria with duplicate verification commands, cannot prove the app runs.
|
|
99
|
+
// Detection only fires on signals the framework locates reliably (prototype
|
|
100
|
+
// manifest, migration steps); the Play has_api trigger stays with @validator.
|
|
101
|
+
const runtime = detectRuntimeFeature(targetDir, slug, {
|
|
102
|
+
completedSteps: readProgressSignals(planDir),
|
|
103
|
+
changedFiles: gitChangedFiles(targetDir)
|
|
104
|
+
});
|
|
105
|
+
const integrity = checkContractIntegrity(contract, { isRuntimeFeature: runtime.isRuntimeFeature });
|
|
106
|
+
for (const err of integrity.errors) {
|
|
107
|
+
await emitGuardEvent(targetDir, {
|
|
108
|
+
eventType: 'contract_integrity_failed',
|
|
109
|
+
agent: 'harness-check',
|
|
110
|
+
message: `${err.code}: ${err.message}`,
|
|
111
|
+
payload: { slug, code: err.code, signals: runtime.signals }
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
let criteria = resolved.criteria;
|
|
116
|
+
if (options.criteria) {
|
|
117
|
+
const wanted = new Set(
|
|
118
|
+
String(options.criteria).split(',').map((id) => id.trim()).filter(Boolean)
|
|
119
|
+
);
|
|
120
|
+
criteria = criteria.filter((c) => c && wanted.has(c.id));
|
|
121
|
+
const found = new Set(criteria.map((c) => c.id));
|
|
122
|
+
const missing = [...wanted].filter((id) => !found.has(id));
|
|
123
|
+
if (missing.length) {
|
|
124
|
+
logger.error(t('harness.check_unknown_criteria', { ids: missing.join(', ') }) || `Unknown criteria ids: ${missing.join(', ')}`);
|
|
125
|
+
return { ok: false, error: 'unknown_criteria', slug, missing };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const timeoutMs = Number.isInteger(Number(options.timeout)) && Number(options.timeout) > 0
|
|
130
|
+
? Number(options.timeout)
|
|
131
|
+
: DEFAULT_CHECK_TIMEOUT_MS;
|
|
132
|
+
|
|
133
|
+
const executable = criteria.filter(
|
|
134
|
+
(c) => c && typeof c.verification === 'string' && c.verification.trim()
|
|
135
|
+
);
|
|
136
|
+
// Static (SG-*) criteria are deterministically checkable too — they are NOT
|
|
137
|
+
// "skipped / @validator-judged", so exclude them from that count and from the
|
|
138
|
+
// strict-mode verification-debt checks below.
|
|
139
|
+
const staticCriteria = criteria.filter((c) => isStaticCriterion(c));
|
|
140
|
+
const skipped = criteria.length - executable.length - staticCriteria.length;
|
|
141
|
+
const strict = Boolean(options.strict);
|
|
142
|
+
const binaryWithoutVerification = criteria.filter(
|
|
143
|
+
(c) => c && c.binary === true && !(typeof c.verification === 'string' && c.verification.trim()) && !isStaticCriterion(c)
|
|
144
|
+
);
|
|
145
|
+
const strictErrors = [];
|
|
146
|
+
if (strict && criteria.length > 0 && executable.length === 0 && staticCriteria.length === 0) {
|
|
147
|
+
strictErrors.push('strict mode requires at least one executable or static (SG-*) verification criterion');
|
|
148
|
+
}
|
|
149
|
+
if (strict && binaryWithoutVerification.length > 0) {
|
|
150
|
+
strictErrors.push(`strict mode requires verification for binary criteria: ${binaryWithoutVerification.map((c) => c.id).join(', ')}`);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const checks = await runCriteria({ criteria, cwd: targetDir, timeoutMs });
|
|
154
|
+
const failed = checks.filter((c) => !c.ok);
|
|
155
|
+
|
|
156
|
+
// SG-* static criteria — build-independent (fs + RegExp + parse), evaluated on
|
|
157
|
+
// every run (cheap). They gate the report just like executable criteria.
|
|
158
|
+
const staticResult = evaluateStaticCriteria({ criteria, cwd: targetDir });
|
|
159
|
+
const staticFailed = staticResult.checks.filter((c) => !c.ok);
|
|
160
|
+
|
|
161
|
+
for (const check of failed) {
|
|
162
|
+
await emitGuardEvent(targetDir, {
|
|
163
|
+
eventType: 'criteria_check_failed',
|
|
164
|
+
agent: 'harness-check',
|
|
165
|
+
message: `${check.id}: exit ${check.exitCode}${check.timedOut ? ' (timeout)' : ''}`,
|
|
166
|
+
payload: { slug, criterion_id: check.id, exit_code: check.exitCode, signature: check.signature }
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
for (const check of staticFailed) {
|
|
170
|
+
await emitGuardEvent(targetDir, {
|
|
171
|
+
eventType: 'criteria_check_failed',
|
|
172
|
+
agent: 'harness-check',
|
|
173
|
+
message: `${check.id}: ${check.detail}`,
|
|
174
|
+
payload: { slug, criterion_id: check.id, kind: 'static' }
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const report = {
|
|
179
|
+
ok: failed.length === 0 && staticFailed.length === 0 && strictErrors.length === 0 && integrity.ok,
|
|
180
|
+
slug,
|
|
181
|
+
checked_at: new Date().toISOString(),
|
|
182
|
+
strict,
|
|
183
|
+
criteria_total: criteria.length,
|
|
184
|
+
executable_total: executable.length,
|
|
185
|
+
passed: checks.length - failed.length,
|
|
186
|
+
failed: failed.length,
|
|
187
|
+
skipped_no_verification: skipped,
|
|
188
|
+
static_total: staticResult.total,
|
|
189
|
+
static_passed: staticResult.total - staticFailed.length,
|
|
190
|
+
static_failed: staticFailed.length,
|
|
191
|
+
strict_errors: strictErrors,
|
|
192
|
+
integrity: {
|
|
193
|
+
ok: integrity.ok,
|
|
194
|
+
is_runtime_feature: runtime.isRuntimeFeature,
|
|
195
|
+
runtime_signals: runtime.signals,
|
|
196
|
+
errors: integrity.errors,
|
|
197
|
+
warnings: integrity.warnings
|
|
198
|
+
},
|
|
199
|
+
checks,
|
|
200
|
+
static_checks: staticResult.checks
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
if (!fs.existsSync(planDir)) fs.mkdirSync(planDir, { recursive: true });
|
|
205
|
+
fs.writeFileSync(
|
|
206
|
+
path.join(planDir, 'last-check-output.json'),
|
|
207
|
+
JSON.stringify(report, null, 2),
|
|
208
|
+
'utf8'
|
|
209
|
+
);
|
|
210
|
+
} catch (err) {
|
|
211
|
+
// Persistência é conveniência, não gate — reporta sem falhar o run.
|
|
212
|
+
logger.error(`Could not persist last-check-output.json: ${err.message}`);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (options.json) {
|
|
216
|
+
logger.log(JSON.stringify(report, null, 2));
|
|
217
|
+
return report;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
logger.log(t('harness.check_header', { slug }) || `Harness check — ${slug}`);
|
|
221
|
+
for (const err of integrity.errors) {
|
|
222
|
+
logger.log(` ✗ contract-integrity (${err.code}): ${err.message}`);
|
|
223
|
+
}
|
|
224
|
+
for (const warn of integrity.warnings) {
|
|
225
|
+
logger.log(` ⚠ contract-integrity (${warn.code}): ${warn.message}`);
|
|
226
|
+
}
|
|
227
|
+
for (const error of strictErrors) {
|
|
228
|
+
logger.log(` ✗ ${error}`);
|
|
229
|
+
}
|
|
230
|
+
// SG-* static criteria render on every run — they are build-independent.
|
|
231
|
+
for (const check of staticResult.checks) {
|
|
232
|
+
const mark = check.ok ? '✓' : '✗';
|
|
233
|
+
const extra = check.ok ? ` [${check.files.join(', ')}]` : ` — ${check.detail}`;
|
|
234
|
+
logger.log(` ${mark} ${check.id} (static)${extra}`);
|
|
235
|
+
}
|
|
236
|
+
if (executable.length === 0) {
|
|
237
|
+
if (staticResult.total > 0) {
|
|
238
|
+
logger.log(` Static: ${report.static_passed}/${staticResult.total} SG-* passed${skipped > 0 ? ` (${skipped} without verification — judged by @validator)` : ''}.`);
|
|
239
|
+
} else {
|
|
240
|
+
logger.log(t('harness.check_no_executable', { total: criteria.length }) || ` No criteria with verification commands (${criteria.length} criteria total). @validator judges them all.`);
|
|
241
|
+
}
|
|
242
|
+
return report;
|
|
243
|
+
}
|
|
244
|
+
for (const check of checks) {
|
|
245
|
+
const mark = check.ok ? '✓' : '✗';
|
|
246
|
+
const extra = check.ok ? '' : ` (exit ${check.exitCode}${check.timedOut ? ', timeout' : ''})`;
|
|
247
|
+
logger.log(` ${mark} ${check.id} — ${check.command}${extra} [${check.durationMs}ms]`);
|
|
248
|
+
}
|
|
249
|
+
logger.log(
|
|
250
|
+
t('harness.check_summary', { passed: report.passed, executable: executable.length, skipped }) ||
|
|
251
|
+
` Checks: ${report.passed}/${executable.length} passed (${skipped} without verification — judged by @validator)`
|
|
252
|
+
);
|
|
253
|
+
if (staticResult.total > 0) {
|
|
254
|
+
logger.log(` Static: ${report.static_passed}/${staticResult.total} SG-* passed.`);
|
|
255
|
+
}
|
|
256
|
+
return report;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
module.exports = { runHarnessCheck };
|