@manhd_d/ai-harness 0.10.0 → 0.12.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 +29 -0
- package/README.md +2 -0
- package/capabilities/architecture/capability.json +1 -1
- package/capabilities/architecture/checks/verification.json +11 -0
- package/capabilities/architecture/evals/cases.json +10 -0
- package/capabilities/architecture/skills/harness-architecture-change-impact/SKILL.md +5 -0
- package/capabilities/architecture/templates/project-map.md +5 -0
- package/capabilities/architecture/workflows/change-review.md +2 -0
- package/capabilities/delivery/capability.json +1 -1
- package/capabilities/delivery/checks/verification.json +11 -0
- package/capabilities/delivery/evals/cases.json +10 -0
- package/capabilities/delivery/skills/harness-delivery-scope-change/SKILL.md +6 -0
- package/capabilities/delivery/workflows/execution-change.md +2 -0
- package/capabilities/product/capability.json +7 -4
- package/capabilities/product/checks/verification.json +23 -0
- package/capabilities/product/evals/cases.json +21 -0
- package/capabilities/product/skills/harness-product-backlog-prioritization/SKILL.md +7 -0
- package/capabilities/product/skills/harness-product-business-analysis/SKILL.md +5 -0
- package/capabilities/product/skills/harness-product-techspec/SKILL.md +35 -0
- package/capabilities/product/skills/harness-product-traceability/SKILL.md +7 -1
- package/capabilities/product/templates/backlog.md +7 -0
- package/capabilities/product/templates/techspec.md +17 -0
- package/capabilities/product/templates/traceability.md +7 -0
- package/capabilities/product/workflows/change-impact-analysis.md +6 -2
- package/capabilities/product/workflows/document-driven.md +2 -0
- package/capabilities/product/workflows/idea-driven.md +2 -0
- package/capabilities/product/workflows/techspec-maintenance.md +7 -0
- package/cli/harness.js +6 -3
- package/cli/main.js +19 -7
- package/cli/verification-report.js +177 -0
- package/cli/verification.js +78 -0
- package/core/agents/test-engineer.md +2 -0
- package/core/checks/verification.json +25 -0
- package/core/evals/cases.json +81 -0
- package/core/evals/composition.json +15 -0
- package/core/rules/context.md +4 -0
- package/core/skills/harness-debugging/SKILL.md +6 -0
- package/core/skills/harness-review/SKILL.md +6 -0
- package/core/skills/harness-spec/SKILL.md +6 -0
- package/core/skills/harness-verification/SKILL.md +24 -0
- package/core/workflows/adaptive-verification.md +8 -0
- package/core/workflows/artifact-contract.md +5 -0
- package/core/workflows/continuous-development.md +98 -0
- package/core/workflows/spec-to-code.md +5 -0
- package/docs/README.md +4 -0
- package/docs/adaptive-verification.md +59 -0
- package/docs/agent-handoffs.md +4 -0
- package/docs/architecture.md +6 -0
- package/docs/cli.md +3 -1
- package/docs/continuous-development.md +88 -0
- package/docs/documentation-workflows.md +4 -0
- package/docs/end-to-end-workflow.md +4 -0
- package/docs/examples/continuous-development.md +40 -0
- package/docs/getting-started.md +2 -0
- package/docs/i18n/README.vi.md +4 -0
- package/docs/skill-matrix.md +12 -4
- package/docs/versioning.md +8 -0
- package/evals/README.md +4 -0
- package/harness.yaml +1 -1
- package/package.json +1 -1
- package/templates/AGENTS.md +3 -0
- package/templates/openspec/design.md +10 -0
- package/templates/openspec/tasks.md +8 -1
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
3
|
+
import { safe, stat, digest, isObject, HarnessError } from './files.js';
|
|
4
|
+
import { readConfig } from './project-config.js';
|
|
5
|
+
|
|
6
|
+
const text = v => typeof v === 'string' && v.trim().length > 0 && !/[\0\r\n]/.test(v);
|
|
7
|
+
const list = a => Array.isArray(a) && a.length > 0 && a.every(text) && new Set(a).size === a.length;
|
|
8
|
+
const assert = (ok, msg) => { if (!ok) throw new HarnessError(msg); };
|
|
9
|
+
const statuses = ['PASSED', 'FAILED', 'BLOCKED', 'NOT_RUN'];
|
|
10
|
+
const errorKinds = ['timeout', 'network', 'http', 'application', 'assertion', 'environment'];
|
|
11
|
+
const finite = n => typeof n === 'number' && Number.isFinite(n) && n >= 0;
|
|
12
|
+
const iso = s => text(s) && /^\d{4}-\d{2}-\d{2}T.*(?:Z|[+-]\d{2}:\d{2})$/.test(s) && Number.isFinite(Date.parse(s));
|
|
13
|
+
const secretKey = /^(password|passwd|secret|api[_-]?key|access[_-]?token|refresh[_-]?token|authorization|cookie|credentials?)$/i;
|
|
14
|
+
function redacted(value) {
|
|
15
|
+
if (typeof value === 'string') {
|
|
16
|
+
assert(!/Bearer\s+[A-Za-z0-9._~-]{8,}/i.test(value), 'Redact bearer credentials before verification');
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (Array.isArray(value)) { value.forEach(redacted); return; }
|
|
20
|
+
if (!isObject(value)) return;
|
|
21
|
+
for (const [k, v] of Object.entries(value)) {
|
|
22
|
+
if (secretKey.test(k)) assert(v === '[REDACTED]' || v === '<REDACTED>', 'Redact credential fields before verification');
|
|
23
|
+
redacted(v);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function evidence(root, refs) {
|
|
27
|
+
assert(Array.isArray(refs), 'Invalid evidence list');
|
|
28
|
+
return refs.map(ref => {
|
|
29
|
+
assert(isObject(ref) && text(ref.path) && typeof ref.sha256 === 'string' && /^[a-f0-9]{64}$/.test(ref.sha256), 'Invalid evidence reference');
|
|
30
|
+
const p = safe(root, ref.path), info = stat(p);
|
|
31
|
+
assert(info?.isFile() && info.size <= 1024 * 1024, 'Evidence missing or exceeds 1 MiB');
|
|
32
|
+
const bytes = fs.readFileSync(p);
|
|
33
|
+
assert(digest(bytes) === ref.sha256, 'Evidence digest mismatch');
|
|
34
|
+
const body = bytes.toString('utf8');
|
|
35
|
+
try { redacted(JSON.parse(body)); } catch (e) {
|
|
36
|
+
if (e instanceof HarnessError) throw e;
|
|
37
|
+
assert(!/Bearer\s+[A-Za-z0-9._~-]{8,}|(?:password|api[_-]?key|access_token)\s*[:=]\s*(?!\[REDACTED\]|<REDACTED>)\S+/i.test(body), 'Redact credentials in evidence');
|
|
38
|
+
}
|
|
39
|
+
return ref;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function observedValue(root, refs, actual) {
|
|
43
|
+
assert(isObject(actual) && text(actual.evidence) && refs.some(r => r.path === actual.evidence) &&
|
|
44
|
+
typeof actual.pointer === 'string' && (actual.pointer === '' || actual.pointer.startsWith('/')), 'Assertion needs a JSON evidence pointer');
|
|
45
|
+
let value;
|
|
46
|
+
try { value = JSON.parse(fs.readFileSync(safe(root, actual.evidence), 'utf8')); }
|
|
47
|
+
catch { throw new HarnessError('Assertion evidence must be JSON'); }
|
|
48
|
+
if (actual.pointer !== '') for (const part of actual.pointer.slice(1).split('/')) {
|
|
49
|
+
assert(!/~(?![01])/.test(part), 'Invalid JSON pointer escape');
|
|
50
|
+
const key = part.replaceAll('~1', '/').replaceAll('~0', '~');
|
|
51
|
+
assert(value !== null && typeof value === 'object' && Object.hasOwn(value, key), 'Assertion JSON pointer is missing');
|
|
52
|
+
value = value[key];
|
|
53
|
+
}
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
function assertion(row, root, refs) {
|
|
57
|
+
assert(isObject(row) && text(row.id) && text(row.basis) && Object.hasOwn(row, 'expected'), 'Assertions need independent expected/observed values and requirement basis');
|
|
58
|
+
const { expected, operator } = row;
|
|
59
|
+
assert(['transport', 'schema', 'business', 'state', 'authorization', 'result'].includes(row.layer), 'Assertion needs a semantic layer');
|
|
60
|
+
const observed = observedValue(root, refs, row.actual);
|
|
61
|
+
if (Object.hasOwn(row, 'observed')) assert(isDeepStrictEqual(row.observed, observed), 'Typed observation does not match raw evidence');
|
|
62
|
+
let passed;
|
|
63
|
+
if (operator === 'equal') passed = isDeepStrictEqual(observed, expected);
|
|
64
|
+
else if (operator === 'not-equal') passed = !isDeepStrictEqual(observed, expected);
|
|
65
|
+
else if (operator === 'contains') {
|
|
66
|
+
assert(typeof observed === 'string' || Array.isArray(observed), 'Contains assertion needs string or array');
|
|
67
|
+
passed = typeof observed === 'string' ? typeof expected === 'string' && observed.includes(expected) : observed.some(v => isDeepStrictEqual(v, expected));
|
|
68
|
+
} else if (operator === 'type') {
|
|
69
|
+
assert(['object', 'array', 'string', 'number', 'boolean', 'null'].includes(expected), 'Invalid expected JSON type');
|
|
70
|
+
const actual = observed === null ? 'null' : Array.isArray(observed) ? 'array' : typeof observed;
|
|
71
|
+
passed = actual === expected;
|
|
72
|
+
} else throw new HarnessError('Unsupported assertion operator');
|
|
73
|
+
return { id: row.id, basis: row.basis, layer: row.layer, actual: row.actual, operator, expected, observed, passed };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function reviewVerification(root, reportPath) {
|
|
77
|
+
const report = readConfig(root, reportPath);
|
|
78
|
+
assert(isObject(report) && report.schema_version === 1 && isObject(report.metadata), 'Invalid verification report schema');
|
|
79
|
+
redacted(report);
|
|
80
|
+
const meta = report.metadata;
|
|
81
|
+
for (const field of ['run_id', 'feature', 'source_revision', 'environment', 'producer']) assert(text(meta[field]), 'Missing report metadata: ' + field);
|
|
82
|
+
assert(iso(meta.timestamp), 'Report needs an ISO timestamp with timezone');
|
|
83
|
+
if (meta.usage !== undefined) {
|
|
84
|
+
assert(isObject(meta.usage) && text(meta.usage.source), 'Runtime usage needs an actual measurement source');
|
|
85
|
+
for (const key of ['tokens', 'cost']) if (meta.usage[key] !== undefined) assert(finite(meta.usage[key]), 'Invalid measured usage');
|
|
86
|
+
if (meta.usage.cost !== undefined) assert(text(meta.usage.currency), 'Measured cost requires currency');
|
|
87
|
+
}
|
|
88
|
+
assert(Array.isArray(report.requirements) && report.requirements.length > 0, 'Declare requirement/AC coverage');
|
|
89
|
+
const reqs = new Map();
|
|
90
|
+
for (const req of report.requirements) {
|
|
91
|
+
assert(isObject(req) && text(req.id) && !reqs.has(req.id) && text(req.description) && text(req.source), 'Invalid/duplicate requirement');
|
|
92
|
+
reqs.set(req.id, req);
|
|
93
|
+
}
|
|
94
|
+
assert(Array.isArray(report.scenarios) && report.scenarios.length > 0, 'Declare scenarios, including NOT_RUN/BLOCKED gaps');
|
|
95
|
+
const ids = new Set();
|
|
96
|
+
const scenarios = report.scenarios.map(row => {
|
|
97
|
+
assert(isObject(row) && text(row.id) && !ids.has(row.id) && statuses.includes(row.status) && typeof row.executed === 'boolean', 'Invalid/duplicate scenario status');
|
|
98
|
+
ids.add(row.id);
|
|
99
|
+
assert(list(row.references) && row.references.every(r => reqs.has(r)), 'Unknown/missing requirement references');
|
|
100
|
+
assert(text(row.method) && list(row.preconditions) && text(row.fixture) && list(row.steps) && text(row.expected) && text(row.observed), 'Scenario needs preconditions, fixture, steps and expected/observed results');
|
|
101
|
+
assert(iso(row.timestamp), 'Scenario needs an ISO timestamp');
|
|
102
|
+
assert(typeof row.mutates === 'boolean' && isObject(row.cleanup) && text(row.cleanup.strategy) && statuses.includes(row.cleanup.status), 'Scenario needs mutation/cleanup classification');
|
|
103
|
+
if (row.error !== undefined) assert(isObject(row.error) && errorKinds.includes(row.error.kind) && text(row.error.message), 'Invalid error classification');
|
|
104
|
+
assert(row.expected_error === undefined || ['http', 'application'].includes(row.expected_error), 'Expected errors must name HTTP/application semantics, never arbitrary exceptions');
|
|
105
|
+
const refs = evidence(root, row.evidence);
|
|
106
|
+
const assertionIds = new Set();
|
|
107
|
+
assert(Array.isArray(row.assertions), 'Invalid assertions');
|
|
108
|
+
const assertions = row.assertions.map(a => {
|
|
109
|
+
const result = assertion(a, root, refs);
|
|
110
|
+
assert(!assertionIds.has(result.id) && row.references.includes(result.basis), 'Assertion ID/basis must match this scenario coverage');
|
|
111
|
+
assertionIds.add(result.id); return result;
|
|
112
|
+
});
|
|
113
|
+
if (!row.executed) {
|
|
114
|
+
assert(row.execution === undefined, 'Unexecuted scenarios cannot contain execution receipts');
|
|
115
|
+
assert(['BLOCKED', 'NOT_RUN'].includes(row.status) && text(row.reason) && assertions.length === 0, 'Unexecuted scenarios cannot contain runtime assertions or claim PASS/FAIL');
|
|
116
|
+
} else {
|
|
117
|
+
assert(['PASSED', 'FAILED'].includes(row.status) && isObject(row.execution), 'Executed scenario needs execution receipt');
|
|
118
|
+
const ex = row.execution;
|
|
119
|
+
assert(text(ex.tool) && list(ex.command) && Number.isInteger(ex.exit_code) &&
|
|
120
|
+
Number.isInteger(ex.timeout_ms) && ex.timeout_ms > 0 &&
|
|
121
|
+
Number.isInteger(ex.attempts) && ex.attempts > 0 &&
|
|
122
|
+
Number.isInteger(ex.max_attempts) && ex.max_attempts >= ex.attempts, 'Execution needs tool, command, exit code and bounded timeout/attempts');
|
|
123
|
+
assert(refs.length > 0, 'Executed scenarios need digest-checked evidence');
|
|
124
|
+
if (ex.duration_ms !== undefined) assert(finite(ex.duration_ms), 'Invalid observed duration');
|
|
125
|
+
const permittedError = !row.error || (row.expected_error === row.error.kind && ['http', 'application'].includes(row.error.kind));
|
|
126
|
+
const semantic = !['api', 'backend-e2e', 'business-workflow', 'authorization', 'security'].includes(row.method) || assertions.some(a => a.layer !== 'transport');
|
|
127
|
+
const pass = semantic && ex.exit_code === 0 && assertions.length > 0 && assertions.every(a => a.passed) && permittedError &&
|
|
128
|
+
(!row.mutates || row.cleanup.status === 'PASSED');
|
|
129
|
+
// Trust no typed PASS: recompute assertion/execution/cleanup consistency.
|
|
130
|
+
assert(row.status === (pass ? 'PASSED' : 'FAILED'), 'Claimed status contradicts assertions, execution, error or cleanup');
|
|
131
|
+
}
|
|
132
|
+
return { ...row, assertions, evidence: refs };
|
|
133
|
+
});
|
|
134
|
+
const requirements = [...reqs.values()].map(req => {
|
|
135
|
+
const linked = scenarios.filter(s => s.references.includes(req.id));
|
|
136
|
+
return { ...req, verification: linked.length > 0 && linked.every(s => s.status === 'PASSED' && s.assertions.some(a => a.basis === req.id && a.passed)) ? 'VERIFIED' : 'UNVERIFIED',
|
|
137
|
+
scenarios: linked.map(s => s.id) };
|
|
138
|
+
});
|
|
139
|
+
const counts = Object.fromEntries(statuses.map(s => [s, scenarios.filter(row => row.status === s).length]));
|
|
140
|
+
const verdict = counts.FAILED ? 'FAILED' : counts.BLOCKED ? 'BLOCKED'
|
|
141
|
+
: counts.NOT_RUN || requirements.some(r => r.verification === 'UNVERIFIED') ? 'NOT_RUN' : 'PASSED';
|
|
142
|
+
return { status: { PASSED: 'ok', FAILED: 'fail', BLOCKED: 'blocked', NOT_RUN: 'planned' }[verdict],
|
|
143
|
+
verdict, schema_version: 1, metadata: meta, counts, requirements, scenarios, executed: false,
|
|
144
|
+
note: 'Evidence/report consistency only. Execution receipts are producer-declared; inspect raw logs and source revision independently. No application commands or model calls are run by aih.' };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const cell = s => String(s).replace(/[\r\n]/g, ' ').replace(/\|/g, '\\|').replace(/</g, '<');
|
|
148
|
+
export function techspecEvidence(summary) {
|
|
149
|
+
return [
|
|
150
|
+
'# TechSpec: ' + cell(summary.metadata.feature),
|
|
151
|
+
'',
|
|
152
|
+
'Status: draft / pending-review. Source revision: ' + cell(summary.metadata.source_revision),
|
|
153
|
+
'Runtime report: ' + summary.verdict + '. Static-analysis statements remain UNVERIFIED until independently checked.',
|
|
154
|
+
'',
|
|
155
|
+
'## Feature overview and source contracts',
|
|
156
|
+
'UNVERIFIED: link approved requirements, relevant source/code revision and existing contracts; inspect only affected sections.',
|
|
157
|
+
'',
|
|
158
|
+
'## Architecture, business rules and interfaces',
|
|
159
|
+
'UNVERIFIED: document applicable components, business/error flows, API/data/auth/integrations. Omit sections not relevant to this project.',
|
|
160
|
+
'',
|
|
161
|
+
'## Requirements and verification',
|
|
162
|
+
'| Requirement | Source | Verification | Scenarios |',
|
|
163
|
+
'| --- | --- | --- | --- |',
|
|
164
|
+
...summary.requirements.map(r => '| ' + cell(r.id) + ' — ' + cell(r.description) + ' | ' + cell(r.source) + ' | ' + r.verification + ' | ' + cell(r.scenarios.join(', ')) + ' |'),
|
|
165
|
+
'',
|
|
166
|
+
'## Scenario results',
|
|
167
|
+
'| Scenario | Method | Status | Expected | Observed | Evidence |',
|
|
168
|
+
'| --- | --- | --- | --- | --- | --- |',
|
|
169
|
+
...summary.scenarios.map(s => '| ' + cell(s.id) + ' | ' + cell(s.method) + ' | ' + s.status + ' | ' + cell(s.expected) + ' | ' + cell(s.observed) + ' | ' + cell(s.evidence.map(e => e.path + ' sha256:' + e.sha256).join(', ')) + ' |'),
|
|
170
|
+
'',
|
|
171
|
+
'## Limitations and change maintenance',
|
|
172
|
+
'Report validation checks consistency, not independent execution authenticity or business approval.',
|
|
173
|
+
'Preserve existing user edits; propose only affected section changes with before/after revision, contract compatibility and artifact-impact evidence.',
|
|
174
|
+
'Source/output write policy and actual host permission apply. No automatic source overwrite, merge or deployment.',
|
|
175
|
+
'',
|
|
176
|
+
].join('\n');
|
|
177
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { safe, stat, HarnessError } from './files.js';
|
|
3
|
+
import { detect } from './adapters.js';
|
|
4
|
+
import { loadArtifactContract } from './artifacts.js';
|
|
5
|
+
import { loadEnvironment } from './environment.js';
|
|
6
|
+
|
|
7
|
+
function read(root, name) {
|
|
8
|
+
const p = safe(root, name), info = stat(p);
|
|
9
|
+
if (!info) return null;
|
|
10
|
+
if (info.size > 1024 * 1024) throw new HarnessError('Discovery file exceeds 1 MiB');
|
|
11
|
+
return fs.readFileSync(p, 'utf8');
|
|
12
|
+
}
|
|
13
|
+
export function adaptiveVerification(root, source) {
|
|
14
|
+
const detected = detect(root, source), signals = [], frameworks = new Set(), languages = new Set(), methods = new Map();
|
|
15
|
+
const add = (method, reason, evidence) => {
|
|
16
|
+
if (!methods.has(method)) methods.set(method, { method, reasons: [], evidence: [], executed: false });
|
|
17
|
+
const row = methods.get(method); row.reasons.push(reason); row.evidence.push(evidence);
|
|
18
|
+
};
|
|
19
|
+
const pkgBody = read(root, 'package.json');
|
|
20
|
+
let pkg = {};
|
|
21
|
+
if (pkgBody !== null) {
|
|
22
|
+
try { pkg = JSON.parse(pkgBody); } catch { throw new HarnessError('Invalid project package.json'); }
|
|
23
|
+
if (!pkg || typeof pkg !== 'object' || Array.isArray(pkg)) throw new HarnessError('Invalid project package.json');
|
|
24
|
+
if (pkg.scripts !== undefined && (!pkg.scripts || typeof pkg.scripts !== 'object' || Array.isArray(pkg.scripts))) throw new HarnessError('Invalid package scripts during discovery');
|
|
25
|
+
languages.add('javascript/typescript');
|
|
26
|
+
const deps = new Set(Object.keys({ ...pkg.dependencies, ...pkg.devDependencies }));
|
|
27
|
+
for (const [dep, method] of [['vitest','unit'],['jest','unit'],['@playwright/test','browser-e2e'],['cypress','browser-e2e'],['detox','mobile-e2e']]) {
|
|
28
|
+
if (deps.has(dep)) { frameworks.add(dep); add(method, 'Reuse declared project framework', 'package.json#' + dep); }
|
|
29
|
+
}
|
|
30
|
+
for (const [name, command] of Object.entries(pkg.scripts ?? {})) {
|
|
31
|
+
if (typeof command !== 'string') throw new HarnessError('Invalid package script during discovery');
|
|
32
|
+
signals.push({ source: 'package.json#scripts.' + name, fact: 'Declared script; review before execution' });
|
|
33
|
+
if (/^(test|test:unit)$/.test(name)) add('unit', 'Existing test entry point', 'package.json#scripts.' + name);
|
|
34
|
+
if (/^(build|typecheck|lint|check)$/.test(name)) add(name, 'Existing project check', 'package.json#scripts.' + name);
|
|
35
|
+
if (/maestro/i.test(command)) { frameworks.add('maestro'); add('mobile-e2e', 'Existing mobile test script', 'package.json#scripts.' + name); }
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
for (const name of ['pom.xml','build.gradle','build.gradle.kts','pyproject.toml','requirements.txt','go.mod','Cargo.toml']) {
|
|
39
|
+
const body = read(root, name); if (body === null) continue;
|
|
40
|
+
signals.push({ source: name, fact: 'Build/dependency metadata exists; source inspection still needed' });
|
|
41
|
+
if (/pom|gradle/.test(name)) {
|
|
42
|
+
languages.add('java/jvm');
|
|
43
|
+
for (const dep of ['junit','testcontainers','rest-assured','spring-boot-starter-test']) if (body.toLowerCase().includes(dep)) frameworks.add(dep);
|
|
44
|
+
if (/test|junit/i.test(body)) add('unit', 'Test dependency declared', name);
|
|
45
|
+
if (/testcontainers/i.test(body)) add('integration', 'Container fixture dependency declared; verify runtime access', name);
|
|
46
|
+
if (/rest-assured/i.test(body)) add('api', 'Existing API testing dependency', name);
|
|
47
|
+
} else if (/pyproject|requirements/.test(name)) {
|
|
48
|
+
languages.add('python');
|
|
49
|
+
if (/pytest/i.test(body)) { frameworks.add('pytest'); add('unit', 'Existing Python test framework', name); }
|
|
50
|
+
if (/langchain|llama.index|sentence.transformers/i.test(body)) add('ai-rag-evaluation', 'AI/retrieval dependency; inspect actual requirements and datasets', name);
|
|
51
|
+
} else languages.add(name === 'go.mod' ? 'go' : 'rust');
|
|
52
|
+
}
|
|
53
|
+
for (const name of ['openapi.json','openapi.yaml','openapi.yml']) {
|
|
54
|
+
if (read(root, name) !== null) {
|
|
55
|
+
signals.push({ source: name, fact: 'API contract present; does not prove a running service' });
|
|
56
|
+
add('contract', 'Existing interface contract', name); add('api', 'Exercise applicable contract scenarios through authorized host tools', name);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const contract = loadArtifactContract(root), env = loadEnvironment(root);
|
|
60
|
+
for (const [id, a] of Object.entries(contract.artifacts.inputs)) {
|
|
61
|
+
signals.push({ source: 'input:' + id, fact: 'Declared source; availability/content not verified', location: a.location });
|
|
62
|
+
if (a.kind === 'business-workflow') add('business-workflow', 'Declared workflow source; inspect transitions and AC before choosing a pattern', 'input:' + id);
|
|
63
|
+
}
|
|
64
|
+
if (detected.adapters.includes('astro') || read(root, 'index.html') !== null) {
|
|
65
|
+
add('build', 'Static site must build or validate its output', 'static-site metadata');
|
|
66
|
+
add('accessibility', 'Review applicable static-site accessibility requirements', 'static-site metadata');
|
|
67
|
+
}
|
|
68
|
+
if (detected.adapters.includes('react-nextjs')) add('component', 'UI stack detected; inspect feature and existing tests', 'adapter:react-nextjs');
|
|
69
|
+
if (detected.adapters.includes('react-native')) add('component', 'Mobile stack detected; device E2E only when needed and available', 'adapter:react-native');
|
|
70
|
+
if (!methods.size) add('manual-review', 'No supported test entry point discovered; inspect source and clarify essential gaps', 'project discovery');
|
|
71
|
+
return { status: 'planned', executed: false, discovery: { adapters: detected.adapters, languages: [...languages],
|
|
72
|
+
frameworks: [...frameworks], signals, commands: Object.keys(env.shared.commands).map(id => ({ id, source: '.harness/environment.json#commands.' + id })) },
|
|
73
|
+
methods: [...methods.values()], connections: Object.entries(contract.integrations.connections).map(([id]) => ({ id, availability: 'unverified' })),
|
|
74
|
+
unknowns: ['Inspect scoped source to determine architecture, routes/auth, database/service dependencies and business patterns.',
|
|
75
|
+
'Check actual tools, fixture isolation and permission before executing; metadata is not evidence of environment readiness.',
|
|
76
|
+
'Requirements determine integration/E2E/auth/security/regression scope; never force every method or install a missing framework automatically.'],
|
|
77
|
+
note: 'Read-only heuristic plan. Preserve existing frameworks and project commands; host executes tests. No network, shell, database or model calls.' };
|
|
78
|
+
}
|
|
@@ -14,3 +14,5 @@ No arbitrary coverage target or implementation-mirroring tests. Do not mark unex
|
|
|
14
14
|
## Handoff
|
|
15
15
|
State change ID, affected paths, decisions, evidence, outstanding questions and next owner.
|
|
16
16
|
Load the relevant skill and adapter. Respect the host's delegation policy; roles can run sequentially.
|
|
17
|
+
|
|
18
|
+
For proportional checks and evidence integrity, use `.harness/core/workflows/adaptive-verification.md` and `harness-verification`.
|
|
@@ -72,6 +72,31 @@
|
|
|
72
72
|
"Reviewed artifact-impact coverage with docs/spec/UI diffs or explicit blocked dependencies"
|
|
73
73
|
],
|
|
74
74
|
"execution": "manual"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"id": "adaptive-evidence-review",
|
|
78
|
+
"title": "Review proportional verification and selective docs",
|
|
79
|
+
"command": [],
|
|
80
|
+
"when_file": null,
|
|
81
|
+
"evidence": [
|
|
82
|
+
"Applicable project methods and actual host limitations",
|
|
83
|
+
"Requirement-linked raw evidence, business assertions and owned cleanup",
|
|
84
|
+
"Static UNVERIFIED claims and affected-section source policy"
|
|
85
|
+
],
|
|
86
|
+
"execution": "manual"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"id": "continuous-development",
|
|
90
|
+
"title": "Review baseline continuity and scoped completion",
|
|
91
|
+
"command": [],
|
|
92
|
+
"when_file": null,
|
|
93
|
+
"evidence": [
|
|
94
|
+
"Current vs handoff revisions, authority decisions and invalidated stale evidence",
|
|
95
|
+
"Artifact create/update/unchanged reasons, section diffs/proposals and pre-write revision recheck",
|
|
96
|
+
"Stable requirement/spec/code/test links with AC results and BLOCKED/NOT_RUN limits",
|
|
97
|
+
"Proposed feedback vs accepted scope; remaining work and distinct implementation/merge/release evidence"
|
|
98
|
+
],
|
|
99
|
+
"execution": "manual"
|
|
75
100
|
}
|
|
76
101
|
]
|
|
77
102
|
}
|
package/core/evals/cases.json
CHANGED
|
@@ -151,6 +151,87 @@
|
|
|
151
151
|
"Records actual output IDs/revisions and docs/spec/UI verification evidence"
|
|
152
152
|
],
|
|
153
153
|
"critical": true
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"id": "adaptive-evidence",
|
|
157
|
+
"prompt": "A static calculator has no API, a backend returned HTTP 200 with an application failure, and a network exception was caught. Report verification with no authorized live-model budget.",
|
|
158
|
+
"criteria": [
|
|
159
|
+
"Select proportional methods without inventing an API",
|
|
160
|
+
"Do not pass HTTP 200 or caught network exceptions",
|
|
161
|
+
"Link business assertions and raw evidence to AC",
|
|
162
|
+
"Report missing execution or model budget BLOCKED/NOT_RUN"
|
|
163
|
+
],
|
|
164
|
+
"critical": true
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"id": "continuous-feature",
|
|
168
|
+
"prompt": "Add the accepted CSV feature. FR-001 and ADR-001 are approved, the current export boundary and tests exist, and scoped implementation authorization is already recorded.",
|
|
169
|
+
"criteria": [
|
|
170
|
+
"Reads actual approved requirements/ADR/code revisions and reuses existing decisions without repeating approval",
|
|
171
|
+
"Maps stable FR/AC through scoped spec, code and test evidence",
|
|
172
|
+
"Maintains affected sections only with unchanged reasons and remaining-work handoff"
|
|
173
|
+
],
|
|
174
|
+
"critical": true
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"id": "continuous-small-bug",
|
|
178
|
+
"prompt": "Fix null optional label rendering. Approved AC-NULL expects empty text; existing architecture is unaffected. Only this bugfix is authorized.",
|
|
179
|
+
"criteria": [
|
|
180
|
+
"Uses current expected behavior and a compact existing issue/PR or change note",
|
|
181
|
+
"Adds or runs focused regression without forcing BRD/PRD/SRS/ADR or extra modules",
|
|
182
|
+
"Records relevant artifact impact and honest verification gaps; preserves unrelated edits"
|
|
183
|
+
],
|
|
184
|
+
"critical": true
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
"id": "continuous-business-rule",
|
|
188
|
+
"prompt": "Owner accepts changing BR-007 cap from 10 to 20. API schema, database constraint and importer all enforce 10. Apply this business rule change.",
|
|
189
|
+
"criteria": [
|
|
190
|
+
"Preserves BR-007 and records accepted source/decision plus explicit boundary AC",
|
|
191
|
+
"Inspects API/data/event consumers as applicable, compatibility/migration and regression including 19/20/21",
|
|
192
|
+
"Updates affected spec/TechSpec sections and requirement-linked tests/evidence without claiming unrun checks passed"
|
|
193
|
+
],
|
|
194
|
+
"critical": true
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
"id": "continuous-drift",
|
|
198
|
+
"prompt": "Approved BR-003 says retention 30 days; current code uses 60; a draft says 90. Fix the inconsistency; no accepted decision resolves the conflict.",
|
|
199
|
+
"criteria": [
|
|
200
|
+
"Cites conflicting source anchors/revisions and distinguishes approved/draft/superseded status",
|
|
201
|
+
"Identifies authority/owner and resolves disputed intent before editing that behavior rather than choosing code or docs silently",
|
|
202
|
+
"Continues independent authorized work and records conflict/blocker in existing decisions/impact"
|
|
203
|
+
],
|
|
204
|
+
"critical": true
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"id": "continuous-resume",
|
|
208
|
+
"prompt": "Continue change X. Its handoff says code A and FR-002 rev 2 with PASS at A. Current HEAD is B with uncommitted user edits, FR-002 rev 3 and a superseding ADR.",
|
|
209
|
+
"criteria": [
|
|
210
|
+
"Re-reads current code/docs/ADR and working tree instead of trusting old summary",
|
|
211
|
+
"Reconciles changed assumptions and re-runs affected impact/checks; does not reuse old PASS as current proof",
|
|
212
|
+
"Preserves user edits and updates existing tasks/design/map with evidence and next step instead of a new context store"
|
|
213
|
+
],
|
|
214
|
+
"critical": true
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
"id": "continuous-read-only",
|
|
218
|
+
"prompt": "Maintain docs for a change. Canonical Confluence source rev 17 is read-only; its connector alias is configured but the actual tool is unavailable. Git derived docs are accessible. A later source write attempt sees rev 18 instead of 17.",
|
|
219
|
+
"criteria": [
|
|
220
|
+
"Does not treat alias as access, invent unknown revisions/content, mutate read-only source or create a second canonical master",
|
|
221
|
+
"Proposes known section changes with source links; reports unavailable baseline/publication dependencies BLOCKED and distinguishes proposal-only completion",
|
|
222
|
+
"Rechecks revision before writes, reconciles concurrent edits preserving unrelated text or returns a proposal if safe concurrency guard is missing"
|
|
223
|
+
],
|
|
224
|
+
"critical": true
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
"id": "continuous-feedback",
|
|
228
|
+
"prompt": "Triage UAT-12 duplicating an existing null-label defect, UAT-13 requesting bulk import outside accepted release scope, and a supplied operating error report. No new implementation or release is authorized.",
|
|
229
|
+
"criteria": [
|
|
230
|
+
"Deduplicates in the existing backlog/proposal with source, expected/observed and requirement links",
|
|
231
|
+
"Separates defect from proposed new scope and seeks only missing owner decisions; does not implement feedback automatically or promise dates",
|
|
232
|
+
"Records evidence-based risks/next steps and separates implementation complete, merged and released"
|
|
233
|
+
],
|
|
234
|
+
"critical": true
|
|
154
235
|
}
|
|
155
236
|
]
|
|
156
237
|
}
|
|
@@ -43,6 +43,21 @@
|
|
|
43
43
|
"PM plans dependent value slices without invented dates, and hands IDs/decisions/evidence to OpenSpec without self-approval"
|
|
44
44
|
],
|
|
45
45
|
"critical": true
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"id": "continuous-role-handoff",
|
|
49
|
+
"requires": [
|
|
50
|
+
"capability:product",
|
|
51
|
+
"capability:architecture",
|
|
52
|
+
"capability:delivery"
|
|
53
|
+
],
|
|
54
|
+
"prompt": "Continue an accepted business-rule change after API/data baseline drift; UAT also proposes bulk import. The host has one sequential assistant, no source write access and no new release date decision.",
|
|
55
|
+
"criteria": [
|
|
56
|
+
"BA/PO preserves accepted IDs and separates UAT proposal from active scope",
|
|
57
|
+
"SA reconciles current contracts/ADR and required regression impact; PM records actual dependencies/risks without invented dates",
|
|
58
|
+
"Single host uses only relevant existing skills and carries evidence/proposals/blockers in the same change; no fake independent approval, publication, merge or release"
|
|
59
|
+
],
|
|
60
|
+
"critical": true
|
|
46
61
|
}
|
|
47
62
|
]
|
|
48
63
|
}
|
package/core/rules/context.md
CHANGED
|
@@ -13,3 +13,7 @@ coordination convention, not a guarantee that dependencies are available.
|
|
|
13
13
|
|
|
14
14
|
Begin document retrieval with search and explicit paths. Introduce RAG only when retrieval measurements
|
|
15
15
|
show a need. Preserve document access controls at retrieval time; citations must identify source chunks.
|
|
16
|
+
|
|
17
|
+
For a new change or resumed session, apply `.harness/core/workflows/continuous-development.md`.
|
|
18
|
+
Compare current source revisions, scoped working-tree edits and evidence with the previous handoff.
|
|
19
|
+
Refresh affected assumptions in the existing change/project map; stale summaries never override sources.
|
|
@@ -18,3 +18,9 @@ Reproduction, supported cause, minimal patch, before/after evidence and unresolv
|
|
|
18
18
|
## Constraints
|
|
19
19
|
Do not expose secrets or request production credentials. Ask for missing evidence when access blocks diagnosis.
|
|
20
20
|
Do not call a speculative edit a confirmed fix.
|
|
21
|
+
|
|
22
|
+
## Continuous changes
|
|
23
|
+
Start with `.harness/core/workflows/continuous-development.md`: verify expected behavior against
|
|
24
|
+
current approved requirements and actual code revision, not only the old handoff. Preserve a compact
|
|
25
|
+
bug note, regression evidence and affected artifacts with unchanged reasons; avoid unrelated BRD/PRD/ADR.
|
|
26
|
+
Return newly discovered out-of-scope defects as proposed backlog items, not automatic extra work.
|
|
@@ -20,3 +20,9 @@ Base/head diff, change spec, selected adapters and test evidence.
|
|
|
20
20
|
Findings ordered by severity; requirement coverage; actual checks; residual risk; review recommendation.
|
|
21
21
|
## Constraints
|
|
22
22
|
No style churn without a project rule. No self-approval claims or automatic merge. No findings is not a security guarantee.
|
|
23
|
+
|
|
24
|
+
## Continuous changes
|
|
25
|
+
Use `.harness/core/workflows/continuous-development.md` to review baseline freshness, source authority,
|
|
26
|
+
stable requirement → spec → code → tests/evidence links and selective documentation diffs/proposals.
|
|
27
|
+
Check required maintenance blockers and remaining-work handoff. Separate implementation complete,
|
|
28
|
+
merged and released; neither a passing test nor this review supplies business approval.
|
|
@@ -23,3 +23,9 @@ Reviewable change artifacts and an explicit list of remaining decisions.
|
|
|
23
23
|
## Constraints
|
|
24
24
|
Do not mark tasks complete before evidence. Do not archive until associated changes are merged.
|
|
25
25
|
Draft creation does not grant permission to modify another repo or access a service.
|
|
26
|
+
|
|
27
|
+
## Continuous changes
|
|
28
|
+
Apply `.harness/core/workflows/continuous-development.md` first: compare actual baseline to handoff,
|
|
29
|
+
reuse the active change and stable IDs, and record affected-section impact plus unchanged reasons.
|
|
30
|
+
Do not silently resolve spec–code drift; record authoritative owner/source decisions. For a small
|
|
31
|
+
compatible fix, an existing issue/PR note can replace a full OpenSpec pack with a scope rationale.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: harness-verification
|
|
3
|
+
description: Select proportional project checks and report requirement-linked runtime evidence without false PASS claims.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Adaptive verification
|
|
7
|
+
|
|
8
|
+
## Input
|
|
9
|
+
Approved requirements/AC, scoped code and contracts, existing project tests/commands, artifact sources and actual host permissions.
|
|
10
|
+
|
|
11
|
+
## Procedure
|
|
12
|
+
1. Discover languages, frameworks, architecture, routes/auth, data dependencies, existing docs and test entry points. `aih verify --adaptive` supplies metadata hints only; inspect scoped source and record unknowns.
|
|
13
|
+
2. Select needed unit, integration, API/contract, backend/browser/mobile E2E, authorization/security, regression or AI/RAG evaluation. Reuse existing frameworks. A static site needs no invented API; a mobile app needs no forced browser suite.
|
|
14
|
+
3. Derive scenarios from requirements: CRUD, approval/roles, state transitions, uploads, asynchronous events, transactions or external integrations only when applicable. Record preconditions, isolated fixtures, steps, expected business assertions, cleanup and evidence.
|
|
15
|
+
4. Check actual tools, permissions and environment. Declare BLOCKED for missing infrastructure/access; NOT_RUN for skipped scope. Agree consequential gaps using existing clarification workflow.
|
|
16
|
+
5. Execute through authorized host tools with bounded timeouts/retries. Assert transport plus business/schema/state/authorization semantics. Expected errors require exact HTTP/application assertions; timeout/network exceptions never pass by default.
|
|
17
|
+
6. Capture redacted raw observations, digests, executed command/tool, revision, timestamp/environment, expected/observed, error category and fixture cleanup. Record cost/tokens only from actual measurements. Use the report contract in the guide and `aih verify --report` for consistency validation.
|
|
18
|
+
7. Report requirement coverage VERIFIED only with linked passing evidence; otherwise UNVERIFIED. Review raw execution independently and hand affected documentation to Product TechSpec maintenance.
|
|
19
|
+
|
|
20
|
+
## Output
|
|
21
|
+
Proportional verification plan, PASSED/FAILED/BLOCKED/NOT_RUN scenario report, VERIFIED/UNVERIFIED requirement coverage and unresolved limitations.
|
|
22
|
+
|
|
23
|
+
## Constraints
|
|
24
|
+
No killing by port, production/shared database fixture edits, MAX(ID)+1 IDs, embedded credentials or blanket catch-as-success. Use test-owned IDs and cleanup only owned fixtures. Permission enforcement belongs to the host. Static inspection and producer-declared receipts are not independent runtime proof. Reuse harness-tdd/debugging/ai-evaluation rather than creating a runner or making paid model calls each PR.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Adaptive verification
|
|
2
|
+
|
|
3
|
+
Load `harness-verification` after scoped discovery and before review. Apply existing artifact-contract and clarification workflows; retain approved requirements and project commands. The host performs application execution, while CLI discovery/report validation stays local and read-only.
|
|
4
|
+
|
|
5
|
+
Choose applicable verification methods from feature risk and existing tooling, retain negative and regression scenarios, isolate fixtures, and record exact business assertions. Link results and gaps to requirement IDs. Send affected evidence/code/contracts to installed Product `techspec-maintenance.md`; without Product, attach evidence to the existing OpenSpec change. Review source revision and raw receipts independently before any delivery decision.
|
|
6
|
+
|
|
7
|
+
On resume, use `continuous-development.md` to compare the tested revision with the current baseline.
|
|
8
|
+
Re-run affected checks after code/spec changes; a previous PASS does not verify a new revision.
|
|
@@ -51,3 +51,8 @@ record the blocked dependency; do not claim completion while required maintenanc
|
|
|
51
51
|
Before code, review the impact plan. Before handoff, inspect evidence and source revisions.
|
|
52
52
|
`aih ready` checks declarations/coverage/completion only, not semantic consistency or truthful evidence.
|
|
53
53
|
After associated PRs merge, sync accepted repository specs and archive via the normal OpenSpec flow.
|
|
54
|
+
|
|
55
|
+
For change-by-change application and resume checks use `continuous-development.md`. Read-only
|
|
56
|
+
sources stay unchanged; link a separate maintenance proposal in the impact reason/evidence. A
|
|
57
|
+
proposal-only assignment may be delivered as a proposal, but required canonical updates remain
|
|
58
|
+
blocked. Do not mark a proposed source patch as an actual publication.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Continuous development and living documentation
|
|
2
|
+
|
|
3
|
+
## Entry and depth
|
|
4
|
+
Use this workflow for each feature, bugfix, business-rule change or resumed session in an idea-driven
|
|
5
|
+
or existing-code/document project. It coordinates spec-to-code, artifact-contract, solution-framing
|
|
6
|
+
and adaptive-verification; it does not replace them or require a new role, runtime or configuration.
|
|
7
|
+
|
|
8
|
+
Choose depth from impact, not task wording. A small compatible bugfix can use the existing issue/PR
|
|
9
|
+
or change note: expected behavior, baseline, minimal impact, regression evidence and next step.
|
|
10
|
+
Do not create BRD/PRD/SRS/ADR or run full-change readiness just to fix a null check. Security-sensitive,
|
|
11
|
+
contract/data or consequential business changes need explicit AC and an OpenSpec change. A small
|
|
12
|
+
new tool can use PRD-lite or equivalent intent + scoped spec/tasks; load only relevant capabilities.
|
|
13
|
+
|
|
14
|
+
## 1. Baseline discovery (including every resume)
|
|
15
|
+
- Confirm Git root, branch, HEAD and relevant uncommitted edits; inspect actual scoped code/tests.
|
|
16
|
+
- Read canonical requirements, specs, ADRs, existing project map, active OpenSpec change, decisions
|
|
17
|
+
and latest evidence. Record source/section, observed revision, owner and approval status; unknown
|
|
18
|
+
stays unknown. Distinguish approved, proposed, in implementation and superseded claims.
|
|
19
|
+
- Compare the prior handoff's revisions with current files/source versions and actual PR/check state.
|
|
20
|
+
On changes, invalidate affected assumptions/evidence, re-run impact analysis and reverify affected
|
|
21
|
+
behavior. Preserve unrelated user work. An old summary or a green run on an older revision is not
|
|
22
|
+
current truth. With missing access, mark the baseline unverified and block only dependent work.
|
|
23
|
+
- Reuse design.md for change-local baseline/impact, tasks.md for progress/handoff, decisions.json
|
|
24
|
+
for consequential questions and source-backed answers; use the existing project map/decision log
|
|
25
|
+
for durable shared facts. Link these records, do not create a parallel context database or log.
|
|
26
|
+
|
|
27
|
+
## 2. Impact analysis and decisions
|
|
28
|
+
Trace stable requirement IDs through spec → code/contracts → tests/evidence. Inspect callers,
|
|
29
|
+
data/API/event consumers, NFR, compatibility, migration and regression impact at the affected boundary.
|
|
30
|
+
Use only needed perspectives; the host can perform them sequentially:
|
|
31
|
+
|
|
32
|
+
| Perspective | Activate when | Existing skill / result |
|
|
33
|
+
| --- | --- | --- |
|
|
34
|
+
| BA | Requirements/rules/use cases/AC change | Product business-analysis and acceptance-criteria; source-linked delta |
|
|
35
|
+
| PO / Product Manager | Value, priority, MVP/release scope or feedback changes | Product backlog-prioritization; proposed scope and actual owner decision |
|
|
36
|
+
| Project Manager | Dependencies, sequencing, risks or progress change | Delivery scope-change/planning; evidence-linked plan delta, no promised dates |
|
|
37
|
+
| SA | Architecture, data/API/event contracts, NFR or compatibility changes | Architecture change-impact/decision-records; affected map/contracts/ADR |
|
|
38
|
+
| Dev / QA | Implementation or behavior changes | Core spec/debugging/tdd/verification/review; regression and drift evidence |
|
|
39
|
+
|
|
40
|
+
These are existing skills when their modules are installed, not mandatory capability dependencies.
|
|
41
|
+
Core-only hosts capture the relevant perspective in the change note. Do not install modules or spawn
|
|
42
|
+
agents just to satisfy the table. Reuse existing authorization and decisions; clarify only unresolved
|
|
43
|
+
consequential choices. If docs and code disagree, cite both revisions and concrete differences,
|
|
44
|
+
identify the authorized source/owner and record the resolution before changing disputed behavior.
|
|
45
|
+
Neither newer code nor an approved-but-superseded document automatically wins; do independent work.
|
|
46
|
+
|
|
47
|
+
## 3. Update spec and implement
|
|
48
|
+
Keep approved intent distinct from proposed changes. Reuse the active OpenSpec change for the same
|
|
49
|
+
scope; split independent/unaccepted feedback into proposed backlog items. Preserve stable IDs and
|
|
50
|
+
superseded decision history. Update only affected scenarios/design/tasks before implementing the
|
|
51
|
+
accepted slice with harness-spec, harness-tdd or harness-debugging and the relevant adapter.
|
|
52
|
+
Use spec-to-code readiness for full changes, not as business approval or a small-fix paperwork gate.
|
|
53
|
+
|
|
54
|
+
## 4. Verification and selective documentation maintenance
|
|
55
|
+
Use adaptive-verification and harness-verification from the existing bundle. Compare each AC with
|
|
56
|
+
actual results at the tested revision/environment. Keep runtime PASSED/FAILED/BLOCKED/NOT_RUN and
|
|
57
|
+
static inspection distinct; never promote static analysis into runtime PASS or business approval.
|
|
58
|
+
|
|
59
|
+
For each change list artifacts to create, update, supersede or leave unchanged, with concrete reasons.
|
|
60
|
+
With configured outputs reuse artifact-impact.json for every output and affected input; without them
|
|
61
|
+
use the existing change/PR note. Reference exact affected sections, stable IDs, canonical destinations
|
|
62
|
+
and policies in artifacts.json/integrations.json. Ask storage only if it is still unknown and docs are
|
|
63
|
+
needed. Do not reinterpret configured aliases as access, or duplicate an external canonical source.
|
|
64
|
+
|
|
65
|
+
Use Product techspec-maintenance when installed; otherwise maintain the existing scoped docs/spec.
|
|
66
|
+
Preserve unrelated sections and user edits. Immediately before any source write, re-read its current
|
|
67
|
+
revision/hash and compare to the observed baseline. If changed, reconcile the section diff first;
|
|
68
|
+
if no safe concurrency guard is available, return a proposal. The host enforces access and performs
|
|
69
|
+
calls: read-only means no source mutation, propose means a reviewable patch/handoff, write still
|
|
70
|
+
requires existing bounded authorization and actual tool support.
|
|
71
|
+
|
|
72
|
+
Read-only source: leave that source unchanged and link a separate section-level proposal and owner
|
|
73
|
+
handoff in the impact reason/evidence. Do not record its canonical update as done. A proposal can
|
|
74
|
+
complete a proposal-only assignment; if canonical publication is required, report that dependency
|
|
75
|
+
BLOCKED. For unavailable sources, do not invent revisions/content or silently create a local master.
|
|
76
|
+
Existing artifact-impact status remains pending/done/blocked: done describes the recorded action,
|
|
77
|
+
not approval/publication. Detailed verification statuses live in the linked report. Legacy
|
|
78
|
+
verification.json uses passed/failed/skipped; encode BLOCKED/NOT_RUN as skipped with the explicit
|
|
79
|
+
reason and report link, never as passed. No JSON schema or new lifecycle registry is required.
|
|
80
|
+
|
|
81
|
+
## 5. Feedback, review and continuity
|
|
82
|
+
Capture supplied bug reports, UAT findings, user feedback and operational evidence in the existing
|
|
83
|
+
backlog/issue or a reviewable proposal under its write policy. Deduplicate by source/requirement,
|
|
84
|
+
record observed vs expected, source/revision, severity/value, affected IDs, owner and proposed action.
|
|
85
|
+
Distinguish defect against accepted AC from a new request. Feedback is proposed until an authorized
|
|
86
|
+
owner accepts it; do not expand active scope, promise release dates or invent operating measurements.
|
|
87
|
+
|
|
88
|
+
Track proposed → clarifying → implementing → verification → review in existing tasks/decision notes;
|
|
89
|
+
mark blockers at the relevant step. Report implementation complete, merged and released separately,
|
|
90
|
+
with actual PR merge SHA and release artifact/deployment evidence when available. Unknown is unknown.
|
|
91
|
+
No auto-merge/release; archive only after the existing OpenSpec merge gate.
|
|
92
|
+
|
|
93
|
+
Before handoff, require AC-to-result links, necessary checks with evidence or explicit BLOCKED/NOT_RUN,
|
|
94
|
+
affected-doc updates/proposals consistent with policy, and remaining work/risks/next step. Missing
|
|
95
|
+
mandatory checks or required publication prevent an unconditional completion claim. State the
|
|
96
|
+
completed scope and limitations, not simply “done”. Update the existing tasks.md handoff with current
|
|
97
|
+
baseline, decisions, evidence revision, blockers, remaining work, next action/owner and distinct
|
|
98
|
+
implementation/merge/release status. On the next session, start again at baseline discovery.
|
|
@@ -37,3 +37,8 @@ them sequentially. Respect the host's delegation rules.
|
|
|
37
37
|
Small documentation edits or obvious low-risk fixes may skip a full spec with a rationale in the PR.
|
|
38
38
|
Security-sensitive or externally visible behavior changes need explicit acceptance scenarios.
|
|
39
39
|
Never archive an unmerged proposal as implemented. CI remains authoritative for actual check results.
|
|
40
|
+
|
|
41
|
+
For proportional checks and evidence integrity, use `.harness/core/workflows/adaptive-verification.md` and `harness-verification`.
|
|
42
|
+
|
|
43
|
+
For successive changes and resumed sessions, enter through `continuous-development.md` for baseline
|
|
44
|
+
reconciliation, selective artifact maintenance, feedback triage and evidence-linked handoff.
|
package/docs/README.md
CHANGED
|
@@ -39,3 +39,7 @@ Chỉ đọc phần phù hợp với công việc đang làm.
|
|
|
39
39
|
|
|
40
40
|
[Contributing](../CONTRIBUTING.md) · [Bảo trì & ma trận ảnh hưởng](harness-maintenance.md) · [Kiến trúc](architecture.md) · [Thêm adapter](adapters.md).
|
|
41
41
|
[Release policy](release-policy.md) · [Phát hành npm](npm-release.md) · [Versioning & migration](versioning.md) · [Changelog](../CHANGELOG.md).
|
|
42
|
+
|
|
43
|
+
See [Adaptive verification and TechSpec](adaptive-verification.md) for read-only discovery, evidence reports and selective technical documentation.
|
|
44
|
+
|
|
45
|
+
[Continuous development & living documentation](continuous-development.md): successive features, bugfixes, baseline reconciliation and selective maintenance.
|