@sentropic/harness 0.1.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -11
- package/dist/artifacts/work-event.d.ts +28 -0
- package/dist/artifacts/work-event.d.ts.map +1 -0
- package/dist/artifacts/work-event.js +9 -0
- package/dist/artifacts/work-event.js.map +1 -0
- package/dist/cli/args.d.ts +10 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +32 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/mechanical-verbs.d.ts +9 -0
- package/dist/cli/mechanical-verbs.d.ts.map +1 -0
- package/dist/cli/mechanical-verbs.js +124 -0
- package/dist/cli/mechanical-verbs.js.map +1 -0
- package/dist/cli/method-verbs.d.ts +14 -0
- package/dist/cli/method-verbs.d.ts.map +1 -0
- package/dist/cli/method-verbs.js +174 -0
- package/dist/cli/method-verbs.js.map +1 -0
- package/dist/cli/run.d.ts +4 -3
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +51 -66
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/scope.d.ts +12 -0
- package/dist/cli/scope.d.ts.map +1 -0
- package/dist/cli/scope.js +31 -0
- package/dist/cli/scope.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/run/work-event.d.ts +25 -0
- package/dist/run/work-event.d.ts.map +1 -0
- package/dist/run/work-event.js +27 -0
- package/dist/run/work-event.js.map +1 -0
- package/dist/skills/manifest.d.ts +14 -0
- package/dist/skills/manifest.d.ts.map +1 -0
- package/dist/skills/manifest.js +25 -0
- package/dist/skills/manifest.js.map +1 -0
- package/package.json +3 -2
- package/skills/adopt/SKILL.md +32 -0
- package/skills/brainstorm/SKILL.md +39 -0
- package/skills/debug/SKILL.md +33 -0
- package/skills/plan/SKILL.md +35 -0
- package/skills/review/SKILL.md +33 -0
- package/skills/test/SKILL.md +44 -0
- package/skills/using-harness/SKILL.md +46 -0
package/dist/cli/run.js
CHANGED
|
@@ -1,55 +1,32 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs';
|
|
2
|
-
import { parseBranchMd } from '../branch-md/parse.js';
|
|
3
|
-
import { checkScope } from '../checks/scope-check.js';
|
|
4
1
|
import { checkBranch } from '../checks/branch-check.js';
|
|
5
2
|
import { toVerificationRun } from '../run/emit.js';
|
|
6
3
|
import { sentropicProfile } from '../profile/sentropic.js';
|
|
7
4
|
import { stubProfile } from '../profile/stub.js';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
function str(v) {
|
|
31
|
-
return typeof v === 'string' ? v : undefined;
|
|
32
|
-
}
|
|
33
|
-
function list(v) {
|
|
34
|
-
const s = str(v);
|
|
35
|
-
return s ? s.split(/[\s,]+/).filter(Boolean) : [];
|
|
36
|
-
}
|
|
37
|
-
const USAGE = 'usage: harness check <scope|branch> [--current-branch <b>] [--expected-branch <b>] ' +
|
|
38
|
-
'[--staged-files <list>] [--branch-md <path>] [--profile sentropic|stub] [--json]';
|
|
39
|
-
/**
|
|
40
|
-
* Pure, arg-based CLI driver — reads everything from `argv`, writes via `out`, returns an exit code.
|
|
41
|
-
* No internal git calls (the caller supplies branch + staged files), no `process.exit`.
|
|
42
|
-
* Advisory (D5 Layer A): a failing check returns 0; only a usage error returns non-zero.
|
|
43
|
-
* Acquiring git state under Docker-first (the `make scope-check` passthrough) is a separate,
|
|
44
|
-
* to-be-double-reviewed concern.
|
|
45
|
-
*/
|
|
46
|
-
export function runHarnessCli(argv, out) {
|
|
47
|
-
const { positionals, flags } = parseFlags(argv);
|
|
48
|
-
const command = positionals[0];
|
|
5
|
+
import { parseFlags, str } from './args.js';
|
|
6
|
+
import { scopeFromFlags } from './scope.js';
|
|
7
|
+
import { handleMethodVerb } from './method-verbs.js';
|
|
8
|
+
import { handleMechanicalVerb } from './mechanical-verbs.js';
|
|
9
|
+
const USAGE = [
|
|
10
|
+
'usage: harness check <scope|branch> [--current-branch <b>] [--expected-branch <b>] ' +
|
|
11
|
+
'[--staged-files <list>] [--branch-md <path>] [--profile sentropic|stub] [--json]',
|
|
12
|
+
' harness verify [--category static|unit|integration|e2e|ci|uat] [--staged-files <list>] ' +
|
|
13
|
+
'[--current-branch <b>] [--expected-branch <b>] [--branch-md <path>] [--profile sentropic|stub] [--json]',
|
|
14
|
+
' harness init [--profile sentropic|stub] [--json]',
|
|
15
|
+
' harness audit [--staged-files <list>] [--branch-md <path>] [--profile sentropic|stub] [--json]',
|
|
16
|
+
' harness brainstorm [<topic>] [--peers <n>] [--ladder study|vol|evol] [--json]',
|
|
17
|
+
' harness test [<scope>] [--category unit|integration|e2e] [--watch] [--json]',
|
|
18
|
+
' harness debug [<symptom>] [--json]',
|
|
19
|
+
' harness review [<target>] [--consensus] [--peers <n>] [--json]',
|
|
20
|
+
' harness plan [<spec>] [--lots <n>] [--json]',
|
|
21
|
+
' harness branch <init|close> [<slug>] [--json]',
|
|
22
|
+
' harness skills install --host <claude|codex|gemini> [--json]',
|
|
23
|
+
].join('\n');
|
|
24
|
+
/** The `check scope|branch` static checks (C2/C1) — emit a neutral VerificationRun. */
|
|
25
|
+
function handleCheck(positionals, flags, out) {
|
|
49
26
|
const sub = positionals[1];
|
|
50
|
-
if (
|
|
27
|
+
if (sub !== 'scope' && sub !== 'branch') {
|
|
51
28
|
out(USAGE);
|
|
52
|
-
return
|
|
29
|
+
return 2;
|
|
53
30
|
}
|
|
54
31
|
const profile = str(flags.profile) === 'stub' ? stubProfile : sentropicProfile;
|
|
55
32
|
const category = 'static';
|
|
@@ -59,27 +36,12 @@ export function runHarnessCli(argv, out) {
|
|
|
59
36
|
if (sub === 'scope') {
|
|
60
37
|
code = 'C2';
|
|
61
38
|
commandLabel = 'harness check scope';
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
parsed = parseBranchMd(readFileSync(branchMdPath, 'utf8'));
|
|
67
|
-
}
|
|
68
|
-
catch {
|
|
69
|
-
out(`harness: cannot read plan file: ${branchMdPath}`);
|
|
70
|
-
return 2;
|
|
71
|
-
}
|
|
39
|
+
const outcome = scopeFromFlags(flags, profile);
|
|
40
|
+
if (outcome.unreadable !== undefined) {
|
|
41
|
+
out(`harness: cannot read plan file: ${outcome.unreadable}`);
|
|
42
|
+
return 2;
|
|
72
43
|
}
|
|
73
|
-
result =
|
|
74
|
-
stagedFiles: list(flags['staged-files']),
|
|
75
|
-
boundary: {
|
|
76
|
-
allowed: parsed?.allowedPaths ?? [],
|
|
77
|
-
forbidden: parsed?.forbiddenPaths ?? [],
|
|
78
|
-
conditional: parsed?.conditionalPaths ?? [],
|
|
79
|
-
},
|
|
80
|
-
profile,
|
|
81
|
-
declaredExceptions: parsed?.exceptions ?? [],
|
|
82
|
-
});
|
|
44
|
+
result = outcome.result;
|
|
83
45
|
}
|
|
84
46
|
else {
|
|
85
47
|
code = 'C1';
|
|
@@ -113,4 +75,27 @@ export function runHarnessCli(argv, out) {
|
|
|
113
75
|
}
|
|
114
76
|
return 0;
|
|
115
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Pure, arg-based CLI driver — reads everything from `argv`, writes via `out`, returns an exit code.
|
|
80
|
+
* No internal git calls (the caller supplies branch + staged files), no `process.exit`, no fs writes.
|
|
81
|
+
* Advisory (D5 Layer A): a failing check returns 0; only a usage error returns non-zero.
|
|
82
|
+
*
|
|
83
|
+
* Verb families: `check` (C1/C2 → VerificationRun); method/recorder verbs (brainstorm/test/debug/
|
|
84
|
+
* review/plan/branch/skills → WorkEvent + skill pointer, see `method-verbs.ts`).
|
|
85
|
+
*/
|
|
86
|
+
export function runHarnessCli(argv, out) {
|
|
87
|
+
const { positionals, flags } = parseFlags(argv);
|
|
88
|
+
const command = positionals[0];
|
|
89
|
+
if (command === 'check') {
|
|
90
|
+
return handleCheck(positionals, flags, out);
|
|
91
|
+
}
|
|
92
|
+
const mechanicalCode = handleMechanicalVerb(positionals, flags, out);
|
|
93
|
+
if (mechanicalCode !== null)
|
|
94
|
+
return mechanicalCode;
|
|
95
|
+
const methodCode = handleMethodVerb(positionals, flags, out);
|
|
96
|
+
if (methodCode !== null)
|
|
97
|
+
return methodCode;
|
|
98
|
+
out(USAGE);
|
|
99
|
+
return command === undefined ? 0 : 2;
|
|
100
|
+
}
|
|
116
101
|
//# sourceMappingURL=run.js.map
|
package/dist/cli/run.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CheckResult } from '../artifacts/verification-run.js';
|
|
2
|
+
import type { HarnessProfile } from '../profile/profile.js';
|
|
3
|
+
import { type FlagValue } from './args.js';
|
|
4
|
+
export interface ScopeOutcome {
|
|
5
|
+
/** The scope CheckResult, when inputs resolved. */
|
|
6
|
+
result?: CheckResult;
|
|
7
|
+
/** The unreadable plan-file path, when `--branch-md` could not be read. */
|
|
8
|
+
unreadable?: string;
|
|
9
|
+
}
|
|
10
|
+
/** Resolve `--branch-md` + `--staged-files` into a C2 scope CheckResult (pure but for the file read). */
|
|
11
|
+
export declare function scopeFromFlags(flags: Record<string, FlagValue>, profile: HarnessProfile): ScopeOutcome;
|
|
12
|
+
//# sourceMappingURL=scope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../src/cli/scope.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtD,MAAM,WAAW,YAAY;IAC3B,mDAAmD;IACnD,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,yGAAyG;AACzG,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,cAAc,GAAG,YAAY,CAqBtG"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Shared scope-check input resolution — used by `check scope`, `verify`, and `audit` so the
|
|
2
|
+
// BRANCH.md parsing + boundary wiring lives in ONE place (no duplicated file IO).
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
import { parseBranchMd } from '../branch-md/parse.js';
|
|
5
|
+
import { checkScope } from '../checks/scope-check.js';
|
|
6
|
+
import { list, str } from './args.js';
|
|
7
|
+
/** Resolve `--branch-md` + `--staged-files` into a C2 scope CheckResult (pure but for the file read). */
|
|
8
|
+
export function scopeFromFlags(flags, profile) {
|
|
9
|
+
const branchMdPath = str(flags['branch-md']);
|
|
10
|
+
let parsed;
|
|
11
|
+
if (branchMdPath) {
|
|
12
|
+
try {
|
|
13
|
+
parsed = parseBranchMd(readFileSync(branchMdPath, 'utf8'));
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return { unreadable: branchMdPath };
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const result = checkScope({
|
|
20
|
+
stagedFiles: list(flags['staged-files']),
|
|
21
|
+
boundary: {
|
|
22
|
+
allowed: parsed?.allowedPaths ?? [],
|
|
23
|
+
forbidden: parsed?.forbiddenPaths ?? [],
|
|
24
|
+
conditional: parsed?.conditionalPaths ?? [],
|
|
25
|
+
},
|
|
26
|
+
profile,
|
|
27
|
+
declaredExceptions: parsed?.exceptions ?? [],
|
|
28
|
+
});
|
|
29
|
+
return { result };
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope.js","sourceRoot":"","sources":["../../src/cli/scope.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,kFAAkF;AAElF,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAGtD,OAAO,EAAE,IAAI,EAAE,GAAG,EAAkB,MAAM,WAAW,CAAC;AAStD,yGAAyG;AACzG,MAAM,UAAU,cAAc,CAAC,KAAgC,EAAE,OAAuB;IACtF,MAAM,YAAY,GAAG,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;IAC7C,IAAI,MAAoD,CAAC;IACzD,IAAI,YAAY,EAAE,CAAC;QACjB,IAAI,CAAC;YACH,MAAM,GAAG,aAAa,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;QAC7D,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC;QACtC,CAAC;IACH,CAAC;IACD,MAAM,MAAM,GAAG,UAAU,CAAC;QACxB,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QACxC,QAAQ,EAAE;YACR,OAAO,EAAE,MAAM,EAAE,YAAY,IAAI,EAAE;YACnC,SAAS,EAAE,MAAM,EAAE,cAAc,IAAI,EAAE;YACvC,WAAW,EAAE,MAAM,EAAE,gBAAgB,IAAI,EAAE;SAC5C;QACD,OAAO;QACP,kBAAkB,EAAE,MAAM,EAAE,UAAU,IAAI,EAAE;KAC7C,CAAC,CAAC;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export declare const HARNESS_PACKAGE: "@sentropic/harness";
|
|
2
2
|
export type { VerificationRun, VerificationCheck, VerificationCategory, Violation, ViolationSeverity, CheckResult, } from './artifacts/verification-run.js';
|
|
3
|
+
export type { WorkEvent, WorkEventVerb, WorkEventStatus, WorkEventValue, } from './artifacts/work-event.js';
|
|
4
|
+
export { toWorkEvent } from './run/work-event.js';
|
|
5
|
+
export type { WorkEventInput, WorkEventContext } from './run/work-event.js';
|
|
3
6
|
export type { HarnessProfile } from './profile/profile.js';
|
|
4
7
|
export { sentropicProfile } from './profile/sentropic.js';
|
|
5
8
|
export { stubProfile } from './profile/stub.js';
|
|
@@ -13,5 +16,7 @@ export { checkScope } from './checks/scope-check.js';
|
|
|
13
16
|
export type { ScopeCheckInput } from './checks/scope-check.js';
|
|
14
17
|
export { toVerificationRun } from './run/emit.js';
|
|
15
18
|
export type { NamedCheck, VerificationContext } from './run/emit.js';
|
|
19
|
+
export { HARNESS_SKILLS, HOST_SKILL_DIR, isHostId } from './skills/manifest.js';
|
|
20
|
+
export type { SkillEntry, HostId } from './skills/manifest.js';
|
|
16
21
|
export { runHarnessCli } from './cli/run.js';
|
|
17
22
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,eAAe,sBAAgC,CAAC;AAG7D,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,SAAS,EACT,iBAAiB,EACjB,WAAW,GACZ,MAAM,iCAAiC,CAAC;AAGzC,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrF,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAClF,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAG1E,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,YAAY,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,YAAY,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAGrE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,eAAe,sBAAgC,CAAC;AAG7D,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,SAAS,EACT,iBAAiB,EACjB,WAAW,GACZ,MAAM,iCAAiC,CAAC;AAGzC,YAAY,EACV,SAAS,EACT,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAG5E,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrF,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAClF,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAG1E,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,YAAY,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,YAAY,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAGrE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChF,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAG/D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// Tooling-only: no product-runtime imports (no Drizzle/Hono/Svelte/Mistral), no
|
|
4
4
|
// `@sentropic/*` deps, and NO track import — harness only EMITS neutral artifacts.
|
|
5
5
|
export const HARNESS_PACKAGE = '@sentropic/harness';
|
|
6
|
+
export { toWorkEvent } from './run/work-event.js';
|
|
6
7
|
export { sentropicProfile } from './profile/sentropic.js';
|
|
7
8
|
export { stubProfile } from './profile/stub.js';
|
|
8
9
|
// BRANCH.md parser.
|
|
@@ -13,6 +14,8 @@ export { classifyPath, matchGlob, globToRegExp } from './scope/scope-boundary.js
|
|
|
13
14
|
export { checkBranch } from './checks/branch-check.js';
|
|
14
15
|
export { checkScope } from './checks/scope-check.js';
|
|
15
16
|
export { toVerificationRun } from './run/emit.js';
|
|
17
|
+
// Harness skill-pack inventory — the native superpowers-surface replacement.
|
|
18
|
+
export { HARNESS_SKILLS, HOST_SKILL_DIR, isHostId } from './skills/manifest.js';
|
|
16
19
|
// Pure, arg-based CLI driver (the `harness` bin is a thin wrapper over this).
|
|
17
20
|
export { runHarnessCli } from './cli/run.js';
|
|
18
21
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,EAAE;AACF,gFAAgF;AAChF,mFAAmF;AAEnF,MAAM,CAAC,MAAM,eAAe,GAAG,oBAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,EAAE;AACF,gFAAgF;AAChF,mFAAmF;AAEnF,MAAM,CAAC,MAAM,eAAe,GAAG,oBAA6B,CAAC;AAmB7D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAKlD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,oBAAoB;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,wBAAwB;AACxB,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGlF,uDAAuD;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGlD,6EAA6E;AAC7E,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGhF,8EAA8E;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { WorkEvent, WorkEventStatus, WorkEventValue, WorkEventVerb } from '../artifacts/work-event.js';
|
|
2
|
+
export interface WorkEventInput {
|
|
3
|
+
verb: WorkEventVerb;
|
|
4
|
+
status: WorkEventStatus;
|
|
5
|
+
subject?: string;
|
|
6
|
+
skill?: string;
|
|
7
|
+
refs?: Record<string, string>;
|
|
8
|
+
detail?: Record<string, WorkEventValue>;
|
|
9
|
+
}
|
|
10
|
+
export interface WorkEventContext {
|
|
11
|
+
runId: string;
|
|
12
|
+
commit: string;
|
|
13
|
+
branch: string;
|
|
14
|
+
env: string;
|
|
15
|
+
runner: string;
|
|
16
|
+
/** ISO-8601 timestamp (injected by the caller — the pure driver passes a placeholder). */
|
|
17
|
+
at: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Assemble a NEUTRAL `WorkEvent` from a method/branch act. harness EMITS this artifact and never
|
|
21
|
+
* writes into `@sentropic/track` — a track-side adapter ingests it (no track import here). Pure and
|
|
22
|
+
* deterministic: `subject`/`skill` are dropped when absent so the JSON stays minimal and stable.
|
|
23
|
+
*/
|
|
24
|
+
export declare function toWorkEvent(input: WorkEventInput, ctx: WorkEventContext): WorkEvent;
|
|
25
|
+
//# sourceMappingURL=work-event.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"work-event.d.ts","sourceRoot":"","sources":["../../src/run/work-event.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,eAAe,EACf,cAAc,EACd,aAAa,EACd,MAAM,4BAA4B,CAAC;AAEpC,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,eAAe,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,0FAA0F;IAC1F,EAAE,EAAE,MAAM,CAAC;CACZ;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,gBAAgB,GAAG,SAAS,CAkBnF"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Assemble a NEUTRAL `WorkEvent` from a method/branch act. harness EMITS this artifact and never
|
|
3
|
+
* writes into `@sentropic/track` — a track-side adapter ingests it (no track import here). Pure and
|
|
4
|
+
* deterministic: `subject`/`skill` are dropped when absent so the JSON stays minimal and stable.
|
|
5
|
+
*/
|
|
6
|
+
export function toWorkEvent(input, ctx) {
|
|
7
|
+
const event = {
|
|
8
|
+
schemaVersion: 1,
|
|
9
|
+
kind: 'work-event',
|
|
10
|
+
verb: input.verb,
|
|
11
|
+
status: input.status,
|
|
12
|
+
refs: input.refs ?? {},
|
|
13
|
+
detail: input.detail ?? {},
|
|
14
|
+
runId: ctx.runId,
|
|
15
|
+
commit: ctx.commit,
|
|
16
|
+
branch: ctx.branch,
|
|
17
|
+
env: ctx.env,
|
|
18
|
+
runner: ctx.runner,
|
|
19
|
+
at: ctx.at,
|
|
20
|
+
};
|
|
21
|
+
if (input.subject !== undefined)
|
|
22
|
+
event.subject = input.subject;
|
|
23
|
+
if (input.skill !== undefined)
|
|
24
|
+
event.skill = input.skill;
|
|
25
|
+
return event;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=work-event.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"work-event.js","sourceRoot":"","sources":["../../src/run/work-event.ts"],"names":[],"mappings":"AA0BA;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,KAAqB,EAAE,GAAqB;IACtE,MAAM,KAAK,GAAc;QACvB,aAAa,EAAE,CAAC;QAChB,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE;QACtB,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE;QAC1B,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,EAAE,EAAE,GAAG,CAAC,EAAE;KACX,CAAC;IACF,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;QAAE,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC/D,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IACzD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type HostId = 'claude' | 'codex' | 'gemini';
|
|
2
|
+
export interface SkillEntry {
|
|
3
|
+
/** Skill id; loaded by a host under the `harness/<name>` namespace. */
|
|
4
|
+
name: string;
|
|
5
|
+
/** One-line purpose. */
|
|
6
|
+
summary: string;
|
|
7
|
+
/** The superpowers skill this supersedes (drives the supersede directive), if any. */
|
|
8
|
+
supersedes?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare const HARNESS_SKILLS: SkillEntry[];
|
|
11
|
+
/** Host → the skills directory `skills install` copies the pack into. */
|
|
12
|
+
export declare const HOST_SKILL_DIR: Record<HostId, string>;
|
|
13
|
+
export declare function isHostId(s: string | undefined): s is HostId;
|
|
14
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/skills/manifest.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEnD,MAAM,WAAW,UAAU;IACzB,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,wBAAwB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,sFAAsF;IACtF,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,cAAc,EAAE,UAAU,EAQtC,CAAC;AAEF,yEAAyE;AACzE,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAIjD,CAAC;AAEF,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,CAAC,IAAI,MAAM,CAE3D"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Canonical inventory of the harness skill pack — the NATIVE superpowers-surface replacement.
|
|
2
|
+
//
|
|
3
|
+
// `harness skills install --host <h>` reports this plan; the pack ships in the npm tarball under
|
|
4
|
+
// `skills/<name>/SKILL.md` (see `package.json` `files`). The host loads each as `harness/<name>`.
|
|
5
|
+
// `using-harness` MUST be loaded first — it carries the supersede directive that makes `harness/*`
|
|
6
|
+
// take precedence over the superpowers skills it replaces.
|
|
7
|
+
export const HARNESS_SKILLS = [
|
|
8
|
+
{ name: 'using-harness', summary: 'index + supersede directive (load FIRST)', supersedes: 'using-superpowers' },
|
|
9
|
+
{ name: 'brainstorm', summary: 'spec-ladder STUDY→VOL→EVOL + ≥2-peer review + batched decisions', supersedes: 'brainstorming' },
|
|
10
|
+
{ name: 'test', summary: 'test-pyramid + scoped-test loop (not "tdd")', supersedes: 'test-driven-development' },
|
|
11
|
+
{ name: 'debug', summary: 'generic root-cause loop', supersedes: 'systematic-debugging' },
|
|
12
|
+
{ name: 'review', summary: '≥2-peer consensus review', supersedes: 'requesting-code-review' },
|
|
13
|
+
{ name: 'plan', summary: 'spec-ladder + BRANCH.md lots; completes with track', supersedes: 'writing-plans' },
|
|
14
|
+
{ name: 'adopt', summary: 'adapt the harness method to ANY repo (profile)' },
|
|
15
|
+
];
|
|
16
|
+
/** Host → the skills directory `skills install` copies the pack into. */
|
|
17
|
+
export const HOST_SKILL_DIR = {
|
|
18
|
+
claude: '.claude/skills',
|
|
19
|
+
codex: '.codex/skills',
|
|
20
|
+
gemini: '.gemini/skills',
|
|
21
|
+
};
|
|
22
|
+
export function isHostId(s) {
|
|
23
|
+
return s === 'claude' || s === 'codex' || s === 'gemini';
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/skills/manifest.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,EAAE;AACF,iGAAiG;AACjG,kGAAkG;AAClG,mGAAmG;AACnG,2DAA2D;AAa3D,MAAM,CAAC,MAAM,cAAc,GAAiB;IAC1C,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,0CAA0C,EAAE,UAAU,EAAE,mBAAmB,EAAE;IAC/G,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,iEAAiE,EAAE,UAAU,EAAE,eAAe,EAAE;IAC/H,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,6CAA6C,EAAE,UAAU,EAAE,yBAAyB,EAAE;IAC/G,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,yBAAyB,EAAE,UAAU,EAAE,sBAAsB,EAAE;IACzF,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,0BAA0B,EAAE,UAAU,EAAE,wBAAwB,EAAE;IAC7F,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,oDAAoD,EAAE,UAAU,EAAE,eAAe,EAAE;IAC5G,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,gDAAgD,EAAE;CAC7E,CAAC;AAEF,yEAAyE;AACzE,MAAM,CAAC,MAAM,cAAc,GAA2B;IACpD,MAAM,EAAE,gBAAgB;IACxB,KAAK,EAAE,eAAe;IACtB,MAAM,EAAE,gBAAgB;CACzB,CAAC;AAEF,MAAM,UAAU,QAAQ,CAAC,CAAqB;IAC5C,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,OAAO,IAAI,CAAC,KAAK,QAAQ,CAAC;AAC3D,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentropic/harness",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Neutral, host-agnostic code-work / PR-workflow tooling for AI dev: branch/scope/
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "Neutral, host-agnostic code-work / PR-workflow tooling for AI dev: a homogeneous `harness <verb>` method layer (branch/scope/verify/test/debug/review/brainstorm/plan), the native superpowers replacement. Tooling-only, zero product-runtime deps. (BR-42h)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"files": [
|
|
24
24
|
"dist",
|
|
25
|
+
"skills",
|
|
25
26
|
"README.md",
|
|
26
27
|
"LICENSE"
|
|
27
28
|
],
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: adopt
|
|
3
|
+
description: Use when bringing the harness method to a NEW or non-sentropic repo — maps the repo's conventions into a harness profile so the same scope/branch/verify kernel applies anywhere.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# harness/adopt
|
|
7
|
+
|
|
8
|
+
Native repo-onboarding. The harness engine (parser, C1/C2 checks, verify) is generic; all repo-specific
|
|
9
|
+
policy is DATA in a profile. `adopt` maps a foreign repo onto that SPI so the method runs unchanged.
|
|
10
|
+
|
|
11
|
+
## Steps
|
|
12
|
+
|
|
13
|
+
1. **Scaffold** — `harness init [--profile sentropic|stub] [--json]` prints a profile descriptor. Save it
|
|
14
|
+
as `harness.profile.json` at the repo root and edit it to fit:
|
|
15
|
+
- `forbiddenPathDefaults` — globs forbidden unless a BRANCH.md explicitly Allows them.
|
|
16
|
+
- `exceptionIdPattern` — the grammar of a valid scope-exception id (e.g. `^BR\d+-EX\d+$`).
|
|
17
|
+
- `conditionalRequiresException` — whether a Conditional path needs a matching declared exception.
|
|
18
|
+
- `branchMatch` — `exact` or `prefix` for the C1 branch check.
|
|
19
|
+
2. **Map the repo's reality** — translate the repo's conventions, not sentropic's: which paths are
|
|
20
|
+
off-limits, what its BRANCH.md grammar is (or whether one must be introduced), the command runner
|
|
21
|
+
(`make` vs `npm`/`nx`), and the environment data-lifecycle (which envs are disposable vs protected).
|
|
22
|
+
3. **Audit** — `harness audit --staged-files "<changed files>" --branch-md <path> --json` diffs the repo
|
|
23
|
+
against the active profile and emits a `VerificationRun (static)` listing drift: forbidden touches,
|
|
24
|
+
undeclared (unknown) paths, missing scope declaration.
|
|
25
|
+
4. **Wire** — add a `scope-check`/`verify` step to the repo's pre-commit or CI using the profile, so the
|
|
26
|
+
method is enforced, not just documented.
|
|
27
|
+
|
|
28
|
+
## Principle
|
|
29
|
+
|
|
30
|
+
A second `stub` profile diverging from `sentropic` on a checked dimension is the proof-of-genericity:
|
|
31
|
+
the same kernel yields different, correct verdicts per profile. Adoption succeeds when a third repo can
|
|
32
|
+
declare its OWN profile and the unchanged engine governs it.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: brainstorm
|
|
3
|
+
description: Use before any creative/design work (a feature, a package, an evolution) — explores intent and design via the spec-ladder with multi-peer adversarial review BEFORE implementation.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# harness/brainstorm
|
|
7
|
+
|
|
8
|
+
Native sentropic ideation. Stronger than a single-pass brainstorm: it climbs the **spec-ladder** and
|
|
9
|
+
gates each design step with **≥2 independent adversarial peers** and **batched** owner decisions.
|
|
10
|
+
|
|
11
|
+
Open the act: `harness brainstorm "<topic>" [--peers <n>] [--ladder study|vol|evol]` (records a WorkEvent).
|
|
12
|
+
|
|
13
|
+
## The spec-ladder
|
|
14
|
+
|
|
15
|
+
Pick the rung that matches the uncertainty, write the artifact under `spec/`:
|
|
16
|
+
|
|
17
|
+
- **STUDY** (`SPEC_STUDY_<TOPIC>.md`) — open question, options, trade-offs. No commitment yet.
|
|
18
|
+
- **VOL** (volition) — the chosen direction + rationale, still reversible.
|
|
19
|
+
- **EVOL** (`SPEC_EVOL_<TOPIC>.md`) — the committed design with numbered decisions (D1…Dn) ready to plan.
|
|
20
|
+
|
|
21
|
+
Don't skip rungs for a genuinely open problem; don't over-ceremony a reversible one.
|
|
22
|
+
|
|
23
|
+
## Multi-peer adversarial review (the differentiator)
|
|
24
|
+
|
|
25
|
+
Before presenting decisions, get **≥2 independent reviews from distinct angles** (e.g. Opus 4.8 + Codex
|
|
26
|
+
5.5-xhigh, or distinct lenses: correctness / risk / user-value). Reconcile divergences explicitly — a
|
|
27
|
+
lone reviewer rationalises; a panel surfaces failure modes. Reversible calls: decide solo. Blocking /
|
|
28
|
+
irreversible calls: escalate.
|
|
29
|
+
|
|
30
|
+
## Batched decisions
|
|
31
|
+
|
|
32
|
+
Present owner decisions as a **clean full dossier (never a delta)**, THEN ask in **lots of ≤4** questions.
|
|
33
|
+
Each question carries its own context inline (source + stakes + consequence) — an id like "D5" alone
|
|
34
|
+
carries no meaning. Once answered, treat all answers final; do re-examination in prose, don't re-poll.
|
|
35
|
+
|
|
36
|
+
## Done
|
|
37
|
+
|
|
38
|
+
A ladder artifact exists, peers reconciled, decisions captured. Hand off to `harness/plan` to turn the
|
|
39
|
+
EVOL decisions into BRANCH.md lots.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: debug
|
|
3
|
+
description: Use on any bug, test failure, or unexpected behaviour BEFORE proposing a fix — runs the generic evidence-first root-cause loop.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# harness/debug
|
|
7
|
+
|
|
8
|
+
Native sentropic debugging. Open it with `harness debug "<symptom>"` (records a WorkEvent), then run the
|
|
9
|
+
loop. No fix is proposed before the root cause is proven by evidence.
|
|
10
|
+
|
|
11
|
+
## The loop
|
|
12
|
+
|
|
13
|
+
1. **Reproduce** — a deterministic, minimal repro. If you can't reproduce it, you can't fix it.
|
|
14
|
+
2. **Evidence** — gather facts with the tools, never assume: `make logs-<service>`, `make db-query
|
|
15
|
+
QUERY="…"`, container state (`make ps`), `grep`/`diff`. Read the actual error, the actual state.
|
|
16
|
+
3. **One hypothesis** — the single most-likely cause that the evidence supports. Write it down.
|
|
17
|
+
4. **One fix** — the smallest change that addresses THAT cause. No shotgun edits, no "while I'm here".
|
|
18
|
+
5. **Re-observe** — rerun the repro. Confirm the symptom is gone AND the evidence changed as predicted.
|
|
19
|
+
6. **Regression test** — promote the repro into a test (`harness/test`) so it can't silently return.
|
|
20
|
+
|
|
21
|
+
## Rules
|
|
22
|
+
|
|
23
|
+
- No "probably" / "maybe" / "should be" — verify with a tool before asserting. A claim without evidence
|
|
24
|
+
is a guess.
|
|
25
|
+
- Change ONE thing at a time; if the symptom persists, revert it before trying the next.
|
|
26
|
+
- A failing assertion is data, not noise — read the diff, don't loosen the assertion.
|
|
27
|
+
- Live surfaces (UI/stream/API/extension) have a dev-lane bootstrap (Playwright/probe targets); use it to
|
|
28
|
+
observe the real behaviour rather than reasoning in the abstract.
|
|
29
|
+
|
|
30
|
+
## Done
|
|
31
|
+
|
|
32
|
+
Root cause named + evidenced, minimal fix in place, repro green as a regression test, no collateral
|
|
33
|
+
change. Hand verification to `harness verify`.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plan
|
|
3
|
+
description: Use when you have a spec/decisions and need an executable plan — writes a lot-based BRANCH.md from the template and completes with track for realization state.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# harness/plan
|
|
7
|
+
|
|
8
|
+
Native sentropic planning. Turns an EVOL spec's decisions into an executable, scoped `BRANCH.md`. Open it
|
|
9
|
+
with `harness plan "<spec>" [--lots <n>]` (records a WorkEvent; harness writes BRANCH.md, then
|
|
10
|
+
`track branch import` indexes it).
|
|
11
|
+
|
|
12
|
+
## Write BRANCH.md from the template
|
|
13
|
+
|
|
14
|
+
Use `plan/BRANCH_TEMPLATE.md` strictly — checkboxes only, no prose, no `###`. First iteration must be
|
|
15
|
+
detailed:
|
|
16
|
+
|
|
17
|
+
- **Objective** + **Scope / Guardrails**.
|
|
18
|
+
- **Branch Scope Boundaries**: `Allowed` / `Forbidden` / `Conditional` paths (default forbidden: `Makefile`,
|
|
19
|
+
`docker-compose*.yml`, `.cursor/rules/**`). Exceptions via `BRxx-EXn` (reason + impact + rollback).
|
|
20
|
+
- **Lot-based plan**: each lot is one logical change with a file-level test list and a lot gate.
|
|
21
|
+
- **Feedback Loop** for blockers/decisions.
|
|
22
|
+
|
|
23
|
+
## Lots & commit discipline
|
|
24
|
+
|
|
25
|
+
- One logical change per lot/commit; max ~10–15 files and **under 150 lines** per commit.
|
|
26
|
+
- Selective staging (`git add <files>` — never `git add .`); commit via `make commit MSG="type: …"`.
|
|
27
|
+
- Update `BRANCH.md` checkboxes WITHIN each commit.
|
|
28
|
+
- Multi-need work → multi-branch with a root `PLAN.md` (waves ≤4 orthogonal branches).
|
|
29
|
+
|
|
30
|
+
## Completes with track
|
|
31
|
+
|
|
32
|
+
harness OWNS the BRANCH.md (the master plan artifact) and EMITS `WorkEvent`s; **track** ingests them and
|
|
33
|
+
owns the realization state — Items, links, Decisions, acceptance, and the AWAITED / DROPPED / DONE / TO-DO
|
|
34
|
+
projections. Don't duplicate status in BRANCH.md prose — let track project it. Execute lots in order
|
|
35
|
+
autonomously; only interrupt for a real fork or blocker.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: review
|
|
3
|
+
description: Use when completing a feature, a design step, or before merging — runs a ≥2-peer consensus review and reconciles the findings, instead of a single rubber-stamp pass.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# harness/review
|
|
7
|
+
|
|
8
|
+
Native sentropic code/design review. Stronger than a single review: **≥2 independent peers**, distinct
|
|
9
|
+
lenses, reconciled. Open it with `harness review "<target>" --consensus [--peers <n>]` (records a
|
|
10
|
+
WorkEvent).
|
|
11
|
+
|
|
12
|
+
## Consensus protocol
|
|
13
|
+
|
|
14
|
+
1. **Dispatch ≥2 independent peers** on the SAME diff/design — ideally different models or angles
|
|
15
|
+
(e.g. Opus 4.8 + Codex 5.5-xhigh), each blind to the others.
|
|
16
|
+
2. **Distinct lenses** when a finding can fail in more than one way: correctness · security · performance ·
|
|
17
|
+
does-it-actually-reproduce. Diversity catches what redundancy can't.
|
|
18
|
+
3. **Refute by default** — each peer tries to REFUTE the change / a claimed finding. A finding survives
|
|
19
|
+
only if it withstands the skeptics; a kill needs a majority.
|
|
20
|
+
4. **Reconcile** — merge findings, surface disagreements explicitly, classify accept / reject / defer with
|
|
21
|
+
a one-line rationale each. Don't average; adjudicate.
|
|
22
|
+
|
|
23
|
+
## Receiving review (technical rigor, not performative agreement)
|
|
24
|
+
|
|
25
|
+
Before implementing a suggestion, verify it. If feedback is unclear or technically questionable, push back
|
|
26
|
+
with evidence rather than complying blindly. Apply what's correct; refute what's wrong; ask when genuinely
|
|
27
|
+
ambiguous.
|
|
28
|
+
|
|
29
|
+
## Severity & gate
|
|
30
|
+
|
|
31
|
+
Findings that gate a lot escalate to a `VerificationRun` (`harness verify --category static`). Narrative
|
|
32
|
+
findings stay a `WorkEvent`. Blocking findings must be resolved before merge; non-blocking are logged in
|
|
33
|
+
`BRANCH.md` `## Feedback Loop` with owner + status.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test
|
|
3
|
+
description: Use when adding or evolving tests for a feature/bugfix — applies the sentropic test-pyramid, scoped-test loop, environment isolation, and AI-flaky policy.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# harness/test
|
|
7
|
+
|
|
8
|
+
Native sentropic testing discipline (NOT "tdd" ritual — the act is `test`). Open it with
|
|
9
|
+
`harness test [<scope>] [--category unit|integration|e2e] [--watch]` (records a WorkEvent), then follow
|
|
10
|
+
the loop.
|
|
11
|
+
|
|
12
|
+
## Pyramid
|
|
13
|
+
|
|
14
|
+
70% unit · 20% integration · 10% e2e. Test behaviour, not implementation — query by user-visible
|
|
15
|
+
elements (text/role/label) over test ids. Names: "should <behaviour> when <condition>".
|
|
16
|
+
|
|
17
|
+
## Scoped-test loop (while developing)
|
|
18
|
+
|
|
19
|
+
Run ONLY the test under evolution, on a dedicated test ENV — never `dev`:
|
|
20
|
+
|
|
21
|
+
- API: `make test-api-<suite> SCOPE=tests/<file>.spec.ts ENV=test-<slug>`
|
|
22
|
+
- UI: `make test-ui SCOPE=tests/<file>.spec.ts ENV=test-<slug>`
|
|
23
|
+
- E2E: `make test-e2e E2E_SPEC=tests/<file>.spec.ts API_PORT=… UI_PORT=… MAILDEV_UI_PORT=… ENV=e2e-<slug>`
|
|
24
|
+
|
|
25
|
+
Full gates only at end of lot/branch: `make test-api`, `make test-ui`, `make clean test-e2e`.
|
|
26
|
+
|
|
27
|
+
## Environment isolation (MANDATORY)
|
|
28
|
+
|
|
29
|
+
- NEVER run test campaigns on `ENV=dev` — afterEach hooks purge real data.
|
|
30
|
+
- Branch tests live in the isolated worktree on `ENV=test-<slug>` / `ENV=e2e-<slug>`; `ENV` is the LAST
|
|
31
|
+
make argument.
|
|
32
|
+
- NEVER add timeouts to make a flaky e2e pass — a timeout failure is a real bug (bad selector, race,
|
|
33
|
+
regression). UI waits are <2s except AI generation.
|
|
34
|
+
|
|
35
|
+
## AI-flaky allowlist (non-blocking)
|
|
36
|
+
|
|
37
|
+
Only accept non-systematic provider/network/model nondeterminism, and only with ≥1 success on the same
|
|
38
|
+
commit + command. Record the exact command + failing file + failure signature in `BRANCH.md` and get
|
|
39
|
+
explicit user sign-off before merge. Everything else is blocking.
|
|
40
|
+
|
|
41
|
+
## CI is authority
|
|
42
|
+
|
|
43
|
+
CI was green on main → any branch failure IS a branch problem; never claim "pre-existing". Decide:
|
|
44
|
+
evolution (adapt the test) or regression (fix the code). Local-green / CI-red → trust CI.
|