@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
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
|
|
6
|
+
const { validateContract } = require('./contract-schema');
|
|
7
|
+
const { checkContractIntegrity } = require('./contract-integrity');
|
|
8
|
+
const { evaluateStaticCriteria } = require('./static-criteria');
|
|
9
|
+
const { detectRuntimeFeature, gitChangedFiles } = require('./detect-runtime-feature');
|
|
10
|
+
const { runHarnessCheck } = require('../commands/harness-check');
|
|
11
|
+
|
|
12
|
+
function readJsonSafe(filePath) {
|
|
13
|
+
try {
|
|
14
|
+
if (!fs.existsSync(filePath)) return { exists: false, value: null, error: null };
|
|
15
|
+
return { exists: true, value: JSON.parse(fs.readFileSync(filePath, 'utf8')), error: null };
|
|
16
|
+
} catch (err) {
|
|
17
|
+
return { exists: true, value: null, error: err };
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function progressCompletedSteps(progress) {
|
|
22
|
+
if (!progress || typeof progress !== 'object') return [];
|
|
23
|
+
return [
|
|
24
|
+
progress.completed_steps,
|
|
25
|
+
progress.changed_files,
|
|
26
|
+
progress.touched_files
|
|
27
|
+
].flatMap((value) => Array.isArray(value) ? value : []);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function makeSilentLogger() {
|
|
31
|
+
return {
|
|
32
|
+
lines: [],
|
|
33
|
+
errors: [],
|
|
34
|
+
log(message = '') { this.lines.push(String(message)); },
|
|
35
|
+
error(message = '') { this.errors.push(String(message)); }
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function evaluateContractIntegrityGate(targetDir, slug, options = {}) {
|
|
40
|
+
const planDir = path.join(targetDir, '.aioson', 'plans', slug);
|
|
41
|
+
const contractPath = path.join(planDir, 'harness-contract.json');
|
|
42
|
+
const progressPath = path.join(planDir, 'progress.json');
|
|
43
|
+
const progressRead = readJsonSafe(progressPath);
|
|
44
|
+
const completedSteps = progressRead.value ? progressCompletedSteps(progressRead.value) : [];
|
|
45
|
+
const changedFiles = options.changedFiles || gitChangedFiles(targetDir);
|
|
46
|
+
const runtime = detectRuntimeFeature(targetDir, slug, { completedSteps, changedFiles });
|
|
47
|
+
|
|
48
|
+
const contractRead = readJsonSafe(contractPath);
|
|
49
|
+
if (!contractRead.exists) {
|
|
50
|
+
if (!runtime.isRuntimeFeature) {
|
|
51
|
+
return { ok: true, slug, has_contract: false, runtime, errors: [], warnings: [] };
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
ok: false,
|
|
55
|
+
slug,
|
|
56
|
+
has_contract: false,
|
|
57
|
+
runtime,
|
|
58
|
+
errors: [{
|
|
59
|
+
code: 'missing_runtime_contract',
|
|
60
|
+
message: `runtime feature detected (${runtime.signals.join(', ')}) but .aioson/plans/${slug}/harness-contract.json is missing — author it with the §2c RG-* runtime-gate criteria (run \`aioson harness:init . --slug=${slug}\`, or have @sheldon/@dev produce it), then re-run the stage.`
|
|
61
|
+
}],
|
|
62
|
+
warnings: []
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (contractRead.error) {
|
|
67
|
+
return {
|
|
68
|
+
ok: false,
|
|
69
|
+
slug,
|
|
70
|
+
has_contract: true,
|
|
71
|
+
runtime,
|
|
72
|
+
errors: [{
|
|
73
|
+
code: 'contract_invalid_json',
|
|
74
|
+
message: `invalid JSON in .aioson/plans/${slug}/harness-contract.json: ${contractRead.error.message}`
|
|
75
|
+
}],
|
|
76
|
+
warnings: []
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const schemaResult = validateContract(contractRead.value);
|
|
81
|
+
if (!schemaResult.ok) {
|
|
82
|
+
return {
|
|
83
|
+
ok: false,
|
|
84
|
+
slug,
|
|
85
|
+
has_contract: true,
|
|
86
|
+
runtime,
|
|
87
|
+
errors: schemaResult.errors.map((err) => ({
|
|
88
|
+
code: 'contract_schema_invalid',
|
|
89
|
+
message: `${err.field}: ${err.reason}`
|
|
90
|
+
})),
|
|
91
|
+
warnings: schemaResult.warnings || []
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const integrity = checkContractIntegrity(contractRead.value, {
|
|
96
|
+
isRuntimeFeature: runtime.isRuntimeFeature
|
|
97
|
+
});
|
|
98
|
+
const errors = [...integrity.errors];
|
|
99
|
+
const warnings = [...integrity.warnings];
|
|
100
|
+
let checkReport = null;
|
|
101
|
+
|
|
102
|
+
if (options.runChecks) {
|
|
103
|
+
// The full path runs the expensive runtime (RG-*) commands AND re-evaluates
|
|
104
|
+
// the cheap static (SG-*) criteria as part of its report — so it owns both.
|
|
105
|
+
checkReport = await runHarnessCheck({
|
|
106
|
+
args: [targetDir],
|
|
107
|
+
options: {
|
|
108
|
+
slug,
|
|
109
|
+
json: true,
|
|
110
|
+
strict: Boolean(options.strict || runtime.isRuntimeFeature)
|
|
111
|
+
},
|
|
112
|
+
logger: makeSilentLogger(),
|
|
113
|
+
t: () => undefined
|
|
114
|
+
});
|
|
115
|
+
if (!checkReport.ok) {
|
|
116
|
+
errors.push({
|
|
117
|
+
code: 'harness_check_failed',
|
|
118
|
+
message: `aioson harness:check failed for ${slug}; see .aioson/plans/${slug}/last-check-output.json`
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
// SG-* static criteria are build-independent (pure fs + RegExp + parse) — they
|
|
123
|
+
// gate at EVERY stage, even when the expensive runtime checks are deferred to
|
|
124
|
+
// the last gate (A5). Evaluate them directly here so a stubbed/placeholder
|
|
125
|
+
// implementation cannot pass @dev-done just because the build smoke runs later.
|
|
126
|
+
const staticResult = evaluateStaticCriteria({
|
|
127
|
+
criteria: Array.isArray(contractRead.value.criteria) ? contractRead.value.criteria : [],
|
|
128
|
+
cwd: targetDir
|
|
129
|
+
});
|
|
130
|
+
for (const check of staticResult.checks) {
|
|
131
|
+
if (!check.ok) {
|
|
132
|
+
errors.push({
|
|
133
|
+
code: 'static_criteria_failed',
|
|
134
|
+
message: `${check.id}: ${check.detail}`
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
ok: errors.length === 0,
|
|
142
|
+
slug,
|
|
143
|
+
has_contract: true,
|
|
144
|
+
runtime,
|
|
145
|
+
integrity,
|
|
146
|
+
checkReport,
|
|
147
|
+
errors,
|
|
148
|
+
warnings
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function formatContractIntegrityGateError(result, stageName = null) {
|
|
153
|
+
const header = stageName
|
|
154
|
+
? `[Harness Contract Gate BLOCKED] Cannot complete @${stageName} for "${result.slug}".`
|
|
155
|
+
: `[Harness Contract Gate BLOCKED] Feature "${result.slug}" cannot close.`;
|
|
156
|
+
const lines = [header];
|
|
157
|
+
for (const err of result.errors || []) {
|
|
158
|
+
lines.push(`- ${err.code}: ${err.message}`);
|
|
159
|
+
}
|
|
160
|
+
if (result.runtime && result.runtime.signals && result.runtime.signals.length) {
|
|
161
|
+
lines.push(`Runtime signals: ${result.runtime.signals.join(', ')}`);
|
|
162
|
+
}
|
|
163
|
+
lines.push(`Run: aioson harness:check . --slug=${result.slug} --json`);
|
|
164
|
+
return lines.join('\n');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
module.exports = {
|
|
168
|
+
evaluateContractIntegrityGate,
|
|
169
|
+
formatContractIntegrityGateError,
|
|
170
|
+
gitChangedFiles,
|
|
171
|
+
progressCompletedSteps
|
|
172
|
+
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Contract-integrity check — the deterministic core of @validator's Step 0
|
|
5
|
+
* (harness-contract.md §2c). Catches two contract-SHAPE failures a blind
|
|
6
|
+
* executor must never let through on a runtime feature:
|
|
7
|
+
*
|
|
8
|
+
* 1. missing_runtime_gate — a runtime feature whose contract carries NONE of
|
|
9
|
+
* the RG-* runtime-gate criteria (build / migrate / boot / smoke). The
|
|
10
|
+
* app's build, migrations, boot and Core happy-path are then unverified —
|
|
11
|
+
* the exact green-but-broken failure mode §2c exists to stop.
|
|
12
|
+
* 2. duplicate_verification — two binary criteria sharing an identical
|
|
13
|
+
* `verification` command (padding 11 criteria out of 6 real commands to
|
|
14
|
+
* fake an "11/11" score).
|
|
15
|
+
*
|
|
16
|
+
* This is contract-SHAPE verification, never a product judgment. Runtime-feature
|
|
17
|
+
* detection (see detect-runtime-feature.js) only fires on signals the framework
|
|
18
|
+
* can locate deterministically; the Play `manifest.json` `has_api` flag lives in
|
|
19
|
+
* the target app and stays with the LLM @validator. `isRuntimeFeature: false`
|
|
20
|
+
* therefore means "no reliable runtime signal", not "proven non-runtime" — so a
|
|
21
|
+
* duplicate on a non-runtime contract is reported as a warning, not a hard error.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
const RUNTIME_GATE_IDS = Object.freeze(['RG-build', 'RG-migrate', 'RG-boot', 'RG-smoke']);
|
|
25
|
+
|
|
26
|
+
function normId(id) {
|
|
27
|
+
return String(id || '').trim().toLowerCase();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const RUNTIME_GATE_ID_SET = new Set(RUNTIME_GATE_IDS.map(normId));
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* A criterion counts as a runtime-gate criterion when its id is one of the
|
|
34
|
+
* canonical RG-* ids (case-insensitive) or starts with `rg-`. We deliberately
|
|
35
|
+
* match on the id, not the verification text, so a contract author opts in
|
|
36
|
+
* explicitly (an RG-smoke that runs a unit test is a lie the author signs).
|
|
37
|
+
*/
|
|
38
|
+
function isRuntimeGateCriterion(criterion) {
|
|
39
|
+
const id = normId(criterion && criterion.id);
|
|
40
|
+
return RUNTIME_GATE_ID_SET.has(id) || id.startsWith('rg-');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function hasRuntimeGate(contract) {
|
|
44
|
+
const criteria = Array.isArray(contract && contract.criteria) ? contract.criteria : [];
|
|
45
|
+
return criteria.some(isRuntimeGateCriterion);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Groups of criterion ids that share an identical non-empty `verification`
|
|
50
|
+
* command among `binary: true` criteria. Each group has length >= 2.
|
|
51
|
+
*/
|
|
52
|
+
function findDuplicateVerifications(contract) {
|
|
53
|
+
const criteria = Array.isArray(contract && contract.criteria) ? contract.criteria : [];
|
|
54
|
+
const byCommand = new Map();
|
|
55
|
+
for (const criterion of criteria) {
|
|
56
|
+
if (!criterion || criterion.binary !== true) continue;
|
|
57
|
+
const command = typeof criterion.verification === 'string' ? criterion.verification.trim() : '';
|
|
58
|
+
if (!command) continue;
|
|
59
|
+
if (!byCommand.has(command)) byCommand.set(command, []);
|
|
60
|
+
byCommand.get(command).push(criterion.id);
|
|
61
|
+
}
|
|
62
|
+
const duplicates = [];
|
|
63
|
+
for (const [command, ids] of byCommand) {
|
|
64
|
+
if (ids.length > 1) duplicates.push({ command, ids });
|
|
65
|
+
}
|
|
66
|
+
return duplicates;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @param {object} contract parsed harness-contract.json
|
|
71
|
+
* @param {{ isRuntimeFeature?: boolean }} options
|
|
72
|
+
* @returns {{ ok: boolean, errors: Array<{code,message}>, warnings: Array<{code,message}>, isRuntimeFeature: boolean }}
|
|
73
|
+
* `ok === false` only when there is at least one blocking error. Warnings never
|
|
74
|
+
* set `ok = false` (advisory).
|
|
75
|
+
*/
|
|
76
|
+
function checkContractIntegrity(contract, options = {}) {
|
|
77
|
+
const isRuntimeFeature = Boolean(options.isRuntimeFeature);
|
|
78
|
+
const errors = [];
|
|
79
|
+
const warnings = [];
|
|
80
|
+
|
|
81
|
+
const duplicates = findDuplicateVerifications(contract);
|
|
82
|
+
for (const dup of duplicates) {
|
|
83
|
+
const entry = {
|
|
84
|
+
code: 'duplicate_verification',
|
|
85
|
+
message: `criteria ${dup.ids.join(', ')} share an identical verification command ("${dup.command}") — each binary criterion must map to a distinct check (harness-contract.md §2c).`
|
|
86
|
+
};
|
|
87
|
+
// Padding only fakes coverage on a runtime feature; on a non-runtime
|
|
88
|
+
// contract a shared command (e.g. two ACs both proven by `npm test`) can be
|
|
89
|
+
// legitimate, so it is advisory there.
|
|
90
|
+
if (isRuntimeFeature) errors.push(entry);
|
|
91
|
+
else warnings.push(entry);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (isRuntimeFeature && !hasRuntimeGate(contract)) {
|
|
95
|
+
errors.push({
|
|
96
|
+
code: 'missing_runtime_gate',
|
|
97
|
+
message: 'runtime feature but the contract has no RG-build / RG-migrate / RG-boot / RG-smoke criterion — the app\'s build, migrations, boot and Core happy-path are unverified. Add the §2c runtime-gate criteria, then re-run @dev.'
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return { ok: errors.length === 0, errors, warnings, isRuntimeFeature };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
module.exports = {
|
|
105
|
+
RUNTIME_GATE_IDS,
|
|
106
|
+
normId,
|
|
107
|
+
isRuntimeGateCriterion,
|
|
108
|
+
hasRuntimeGate,
|
|
109
|
+
findDuplicateVerifications,
|
|
110
|
+
checkContractIntegrity
|
|
111
|
+
};
|