@inixiative/foundry-core 0.5.3 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/feedback/experiment-gate.ts +32 -3
- package/src/index.ts +1 -0
package/package.json
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
* Oracle's replay runner: a wide run (more than TINY_MOMENTS moments, or whatever else the caller
|
|
4
4
|
* counts as wide) needs `--experiment <design.md>` whose pre-registration sections are filled and
|
|
5
5
|
* whose `<design>.review.md` says `verdict: go` for this exact design (`design-sha256:` of its
|
|
6
|
-
* bytes). A tiny test runs without one.
|
|
6
|
+
* bytes). A tiny test runs without one. When a `<design>.decisions.md` companion sits beside the
|
|
7
|
+
* design (run pins and answers that are filled after review, so the design's hash stays fixed), the
|
|
8
|
+
* run is refused while it still says `TBD`, and its path and hash are recorded too.
|
|
7
9
|
*/
|
|
8
10
|
import { createHash } from 'node:crypto';
|
|
9
11
|
import { existsSync, readFileSync } from 'node:fs';
|
|
@@ -24,9 +26,16 @@ export const DESIGN_SECTIONS = [
|
|
|
24
26
|
'What would make the result wrong',
|
|
25
27
|
] as const;
|
|
26
28
|
|
|
27
|
-
export type ExperimentRecord = {
|
|
29
|
+
export type ExperimentRecord = {
|
|
30
|
+
design: string;
|
|
31
|
+
designSha256: string;
|
|
32
|
+
review: string;
|
|
33
|
+
decisions?: string;
|
|
34
|
+
decisionsSha256?: string;
|
|
35
|
+
};
|
|
28
36
|
|
|
29
37
|
export const reviewPathOf = (design: string) => design.replace(/\.md$/, '.review.md');
|
|
38
|
+
export const decisionsPathOf = (design: string) => design.replace(/\.md$/, '.decisions.md');
|
|
30
39
|
|
|
31
40
|
const sha256 = (path: string) => createHash('sha256').update(readFileSync(path)).digest('hex');
|
|
32
41
|
|
|
@@ -54,6 +63,16 @@ export const experimentProblems = (designPath: string): string[] => {
|
|
|
54
63
|
problems.push(`section "## ${name}" is empty`);
|
|
55
64
|
}
|
|
56
65
|
if (text.includes('<fill')) problems.push('unfilled <fill: …> placeholders remain');
|
|
66
|
+
const decisions = decisionsPathOf(design);
|
|
67
|
+
if (existsSync(decisions)) {
|
|
68
|
+
const open = readFileSync(decisions, 'utf8')
|
|
69
|
+
.split('\n')
|
|
70
|
+
.flatMap((line, i) => (/\bTBD\b/.test(line) ? [i + 1] : []));
|
|
71
|
+
if (open.length)
|
|
72
|
+
problems.push(
|
|
73
|
+
`${decisions} still says TBD (line${open.length > 1 ? 's' : ''} ${open.join(', ')})`,
|
|
74
|
+
);
|
|
75
|
+
}
|
|
57
76
|
const review = reviewPathOf(design);
|
|
58
77
|
if (!existsSync(review)) return [...problems, `no adversarial review at ${review}`];
|
|
59
78
|
const reviewText = readFileSync(review, 'utf8');
|
|
@@ -85,5 +104,15 @@ export const requireExperiment = (
|
|
|
85
104
|
'see .claude/skills/experiment/SKILL.md',
|
|
86
105
|
);
|
|
87
106
|
const design = resolve(experiment);
|
|
88
|
-
|
|
107
|
+
const record: ExperimentRecord = {
|
|
108
|
+
design,
|
|
109
|
+
designSha256: sha256(design),
|
|
110
|
+
review: reviewPathOf(design),
|
|
111
|
+
};
|
|
112
|
+
const decisions = decisionsPathOf(design);
|
|
113
|
+
if (existsSync(decisions)) {
|
|
114
|
+
record.decisions = decisions;
|
|
115
|
+
record.decisionsSha256 = sha256(decisions);
|
|
116
|
+
}
|
|
117
|
+
return record;
|
|
89
118
|
};
|