@tiphys/kernel 0.0.0 → 0.1.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/AGENTS.md +611 -0
- package/LICENSE +202 -0
- package/assurance-modes.yaml +278 -0
- package/checklists/clean-room.yaml +325 -0
- package/checklists/env-failure-diagnosis.yaml +68 -0
- package/checklists/flake-playbook.yaml +68 -0
- package/checklists/hazard-review.yaml +144 -0
- package/checklists/plan-review.yaml +103 -0
- package/dist/bin/tiphys.d.ts +2 -0
- package/dist/bin/tiphys.js +14 -0
- package/dist/src/brief.d.ts +32 -0
- package/dist/src/brief.js +59 -0
- package/dist/src/checklists.d.ts +169 -0
- package/dist/src/checklists.js +310 -0
- package/dist/src/checks.d.ts +828 -0
- package/dist/src/checks.js +3314 -0
- package/dist/src/cli.d.ts +9 -0
- package/dist/src/cli.js +57 -0
- package/dist/src/commands/brief.d.ts +92 -0
- package/dist/src/commands/brief.js +320 -0
- package/dist/src/commands/checklist.d.ts +42 -0
- package/dist/src/commands/checklist.js +168 -0
- package/dist/src/commands/doctor.d.ts +35 -0
- package/dist/src/commands/doctor.js +605 -0
- package/dist/src/commands/gates.d.ts +9 -0
- package/dist/src/commands/gates.js +360 -0
- package/dist/src/commands/init.d.ts +30 -0
- package/dist/src/commands/init.js +128 -0
- package/dist/src/commands/lock.d.ts +1 -0
- package/dist/src/commands/lock.js +229 -0
- package/dist/src/commands/mode.d.ts +40 -0
- package/dist/src/commands/mode.js +134 -0
- package/dist/src/commands/plan.d.ts +20 -0
- package/dist/src/commands/plan.js +105 -0
- package/dist/src/commands/pool.d.ts +1 -0
- package/dist/src/commands/pool.js +128 -0
- package/dist/src/commands/spawn.d.ts +1 -0
- package/dist/src/commands/spawn.js +146 -0
- package/dist/src/commands/status.d.ts +19 -0
- package/dist/src/commands/status.js +120 -0
- package/dist/src/commands/teardown.d.ts +1 -0
- package/dist/src/commands/teardown.js +79 -0
- package/dist/src/commands/tuition.d.ts +21 -0
- package/dist/src/commands/tuition.js +218 -0
- package/dist/src/commands/validate.d.ts +78 -0
- package/dist/src/commands/validate.js +360 -0
- package/dist/src/commands/watch.d.ts +1 -0
- package/dist/src/commands/watch.js +172 -0
- package/dist/src/exec/env.d.ts +128 -0
- package/dist/src/exec/env.js +190 -0
- package/dist/src/fleet.d.ts +51 -0
- package/dist/src/fleet.js +80 -0
- package/dist/src/gates/adapters/http-json.d.ts +5 -0
- package/dist/src/gates/adapters/http-json.js +283 -0
- package/dist/src/gates/adapters/migrations-command.d.ts +1 -0
- package/dist/src/gates/adapters/migrations-command.js +373 -0
- package/dist/src/gates/citations.d.ts +408 -0
- package/dist/src/gates/citations.js +1163 -0
- package/dist/src/gates/coverage.d.ts +284 -0
- package/dist/src/gates/coverage.js +701 -0
- package/dist/src/gates/credentials.d.ts +74 -0
- package/dist/src/gates/credentials.js +533 -0
- package/dist/src/gates/deploy.d.ts +1 -0
- package/dist/src/gates/deploy.js +33 -0
- package/dist/src/gates/manifest.d.ts +99 -0
- package/dist/src/gates/manifest.js +208 -0
- package/dist/src/gates/migrations.d.ts +1 -0
- package/dist/src/gates/migrations.js +36 -0
- package/dist/src/gates/pin.d.ts +114 -0
- package/dist/src/gates/pin.js +154 -0
- package/dist/src/gates/red-witness.d.ts +22 -0
- package/dist/src/gates/red-witness.js +390 -0
- package/dist/src/gates/release.d.ts +283 -0
- package/dist/src/gates/release.js +820 -0
- package/dist/src/gates/result.d.ts +116 -0
- package/dist/src/gates/result.js +91 -0
- package/dist/src/gates/run.d.ts +566 -0
- package/dist/src/gates/run.js +1536 -0
- package/dist/src/gates/schemas/citation-config.schema.json +59 -0
- package/dist/src/gates/schemas/coverage-config.schema.json +77 -0
- package/dist/src/gates/schemas/gate-manifest.schema.json +125 -0
- package/dist/src/gates/schemas/gate-result.schema.json +160 -0
- package/dist/src/gates/schemas/phase-declaration.schema.json +42 -0
- package/dist/src/gates/schemas/release-record.schema.json +119 -0
- package/dist/src/gates/schemas/verifier-config.schema.json +101 -0
- package/dist/src/gates/schemas/witness-spec.schema.json +110 -0
- package/dist/src/gates/scope.d.ts +131 -0
- package/dist/src/gates/scope.js +1018 -0
- package/dist/src/gates/suite.d.ts +217 -0
- package/dist/src/gates/suite.js +927 -0
- package/dist/src/gates/validate.d.ts +121 -0
- package/dist/src/gates/validate.js +414 -0
- package/dist/src/hooks.d.ts +32 -0
- package/dist/src/hooks.js +62 -0
- package/dist/src/liveness.d.ts +321 -0
- package/dist/src/liveness.js +396 -0
- package/dist/src/lock.d.ts +178 -0
- package/dist/src/lock.js +500 -0
- package/dist/src/modes.d.ts +149 -0
- package/dist/src/modes.js +258 -0
- package/dist/src/path-identity.d.ts +2 -0
- package/dist/src/path-identity.js +10 -0
- package/dist/src/plan.d.ts +73 -0
- package/dist/src/plan.js +153 -0
- package/dist/src/pool.d.ts +130 -0
- package/dist/src/pool.js +721 -0
- package/dist/src/roles.d.ts +430 -0
- package/dist/src/roles.js +734 -0
- package/dist/src/spawn.d.ts +177 -0
- package/dist/src/spawn.js +332 -0
- package/dist/src/status.d.ts +91 -0
- package/dist/src/status.js +119 -0
- package/dist/src/task.d.ts +264 -0
- package/dist/src/task.js +305 -0
- package/dist/src/teardown.d.ts +32 -0
- package/dist/src/teardown.js +314 -0
- package/dist/src/tuition.d.ts +159 -0
- package/dist/src/tuition.js +311 -0
- package/dist/src/validate.d.ts +230 -0
- package/dist/src/validate.js +732 -0
- package/dist/src/version.d.ts +3 -0
- package/dist/src/version.js +38 -0
- package/dist/src/watcher.d.ts +275 -0
- package/dist/src/watcher.js +859 -0
- package/dist/src/witness/run.d.ts +274 -0
- package/dist/src/witness/run.js +1327 -0
- package/dist/src/witness/spec.d.ts +102 -0
- package/dist/src/witness/spec.js +253 -0
- package/dist/tsconfig.src.tsbuildinfo +1 -0
- package/gate-registry.yaml +390 -0
- package/gates.manifest.json +195 -0
- package/package.json +57 -3
- package/role-model-config.yaml +88 -0
- package/roles/README.md +128 -0
- package/roles/_shared-dispatch-contract.md +87 -0
- package/roles/adversarial-plan-reviewer.md +80 -0
- package/roles/clean-room-reviewer.md +140 -0
- package/roles/implementer.md +460 -0
- package/roles/investigator.md +138 -0
- package/roles/plan-writer.md +95 -0
- package/schemas/README.md +81 -0
- package/schemas/assurance-modes.schema.json +264 -0
- package/schemas/charter.schema.json +166 -0
- package/schemas/checklist.schema.json +114 -0
- package/schemas/decision-record.schema.json +88 -0
- package/schemas/final-report.schema.json +90 -0
- package/schemas/finding.schema.json +106 -0
- package/schemas/gate-registry.schema.json +260 -0
- package/schemas/mechanism-index.schema.json +94 -0
- package/schemas/plan.schema.json +300 -0
- package/schemas/report.schema.json +579 -0
- package/schemas/role-brief.schema.json +105 -0
- package/schemas/role-model-config.schema.json +90 -0
- package/schemas/status-line.schema.json +40 -0
- package/schemas/tuition.schema.json +191 -0
- package/schemas/verdict.schema.json +289 -0
- package/schemas/work-history.schema.json +183 -0
- package/templates/charter.example.yaml +54 -0
- package/templates/decision-record.example.yaml +27 -0
- package/templates/final-report.example.yaml +80 -0
- package/templates/plan.example.yaml +87 -0
- package/templates/report.example.yaml +236 -0
- package/templates/warnings.md +74 -0
- package/templates/work-history.example.yaml +185 -0
- package/tuition/README.md +76 -0
- package/tuition/T-001.yaml +48 -0
- package/tuition/T-002.yaml +51 -0
- package/tuition/T-003.yaml +100 -0
- package/tuition/T-004.yaml +52 -0
- package/tuition/T-005.yaml +72 -0
- package/tuition/T-006.yaml +81 -0
- package/tuition/T-007.yaml +56 -0
- package/tuition/T-008.yaml +111 -0
- package/tuition/T-009.yaml +50 -0
- package/tuition/T-015.yaml +36 -0
- package/tuition/T-016.yaml +36 -0
- package/tuition/T-017.yaml +46 -0
- package/tuition/T-018.yaml +84 -0
- package/tuition/T-021.yaml +40 -0
- package/tuition/T-022.yaml +36 -0
- package/tuition/mechanism-index.yaml +256 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# THE ADVERSARIAL PLAN-REVIEW CHECKLIST (kernel plan M3, M3-P7 step 2).
|
|
2
|
+
#
|
|
3
|
+
# Run against a PLAN, before any of it is dispatched. The three canonical
|
|
4
|
+
# probes are R-026b, R-027 and R-028a, and each one is written to be
|
|
5
|
+
# unanswerable without opening something: R-027 carries the process document's
|
|
6
|
+
# own zero-amount-rows illustration, and R-028a names the artifact that counts
|
|
7
|
+
# as proof so a testability claim cannot be admired instead of tested.
|
|
8
|
+
kind: checklist
|
|
9
|
+
id: plan-review
|
|
10
|
+
applies-to: >-
|
|
11
|
+
a plan document before dispatch, read adversarially: the reviewer is looking
|
|
12
|
+
for the phase that cannot be built as written, not for reasons to approve.
|
|
13
|
+
|
|
14
|
+
probes:
|
|
15
|
+
# R-026b. Hidden dependencies and semantic coupling ABOVE the file-overlap
|
|
16
|
+
# floor. File overlap is what the M5 pre-pass computes mechanically; this
|
|
17
|
+
# probe is the part no pre-pass reaches.
|
|
18
|
+
- id: hidden-dependency-above-file-overlap
|
|
19
|
+
probe: >-
|
|
20
|
+
Which phases share MEANING rather than files? Two phases with disjoint
|
|
21
|
+
file lists still collide when one renames a key the other reads, changes
|
|
22
|
+
a value's vocabulary, moves an ordering another relies on, or changes
|
|
23
|
+
what a shared registry row means. The file-overlap pre-pass computes the
|
|
24
|
+
floor and cannot see any of those. Name each pair you found, the shared
|
|
25
|
+
concept, and the phase whose assumption breaks; then name the pairs you
|
|
26
|
+
examined and cleared, because a list of collisions with no stated scope
|
|
27
|
+
is indistinguishable from a search that looked in the wrong place.
|
|
28
|
+
applies-to: plan-structure
|
|
29
|
+
evidence-required: true
|
|
30
|
+
|
|
31
|
+
- id: grounding-names-a-real-artifact
|
|
32
|
+
probe: >-
|
|
33
|
+
Does each phase's `grounding` name artifacts that will EXIST when it
|
|
34
|
+
starts, and does its `blocked-by` follow from that rather than from
|
|
35
|
+
habit? A `blocked-by` naming a phase whose artifacts the grounding never
|
|
36
|
+
mentions is an ordering habit serialising work that could run in
|
|
37
|
+
parallel; the reverse, a grounding consuming a phase the `blocked-by`
|
|
38
|
+
does not name, is a phase that will be dispatched before its inputs
|
|
39
|
+
exist. Check both directions per phase and say which you found.
|
|
40
|
+
applies-to: plan-structure
|
|
41
|
+
evidence-required: true
|
|
42
|
+
|
|
43
|
+
# R-027. Probe every fix shape for THE STATE THAT CAN NO LONGER EXIT, with
|
|
44
|
+
# the process document's own illustration carried in the probe text so the
|
|
45
|
+
# question cannot be answered from the phrase alone.
|
|
46
|
+
- id: fix-shape-state-that-cannot-exit
|
|
47
|
+
probe: >-
|
|
48
|
+
For every fix this plan proposes, what state does it create that can no
|
|
49
|
+
longer be exited? The process document's own illustration: a repair that
|
|
50
|
+
writes rows with a ZERO amount leaves records that are structurally
|
|
51
|
+
valid, that every later query counts, and that no reconciliation can
|
|
52
|
+
distinguish from real ones, so the system can enter that state and never
|
|
53
|
+
leave it. Walk each fix and name the state, the transition INTO it, and
|
|
54
|
+
the transition OUT of it. A fix with no stated exit is the finding.
|
|
55
|
+
applies-to: fix-shapes
|
|
56
|
+
evidence-required: true
|
|
57
|
+
|
|
58
|
+
- id: fix-shape-partial-application
|
|
59
|
+
probe: >-
|
|
60
|
+
What does each fix leave behind if it is interrupted halfway? Name the
|
|
61
|
+
point of no return in each one, and whether re-running it from the start
|
|
62
|
+
is safe. A fix that is only correct when it completes is a fix that has
|
|
63
|
+
not been designed for the case it exists to handle.
|
|
64
|
+
applies-to: fix-shapes
|
|
65
|
+
evidence-required: true
|
|
66
|
+
|
|
67
|
+
# R-028a. TEST THE TESTABILITY CLAIMS. The accepted evidence is the M2-P2
|
|
68
|
+
# red-witness harness's own evidence file, not the plan's assertion that
|
|
69
|
+
# something is testable.
|
|
70
|
+
- id: testability-claim-tested
|
|
71
|
+
probe: >-
|
|
72
|
+
For every claim in this plan that something is testable, guarded or
|
|
73
|
+
witnessed, what is the accepted proof? The harness's captured evidence
|
|
74
|
+
file (`witness-records.json`, whose per-member `runs[].exitCode` and
|
|
75
|
+
`failedNamedTests` record what actually ran) is the proof; the plan's
|
|
76
|
+
own sentence is not. Where no such file can exist yet because the
|
|
77
|
+
behaviour is not built, say so in those words and mark the claim as
|
|
78
|
+
owed, rather than letting an untested assertion pass as a tested one.
|
|
79
|
+
applies-to: testability
|
|
80
|
+
evidence-required: true
|
|
81
|
+
|
|
82
|
+
- id: acceptance-criterion-is-falsifiable
|
|
83
|
+
probe: >-
|
|
84
|
+
Is each acceptance criterion FALSIFIABLE? "Works correctly" is banned;
|
|
85
|
+
the register is a command, its exit code and a count ("node --test exits
|
|
86
|
+
0 and reports N tests, N greater than zero"). Quote every criterion that
|
|
87
|
+
names no command, no observable output and no count, and propose the
|
|
88
|
+
falsifiable form. A criterion nobody can fail is a criterion nobody has
|
|
89
|
+
to meet.
|
|
90
|
+
applies-to: testability
|
|
91
|
+
evidence-required: true
|
|
92
|
+
|
|
93
|
+
- id: hazard-class-is-not-the-criteria-reworded
|
|
94
|
+
probe: >-
|
|
95
|
+
Does each phase's declared hazard class name something its own
|
|
96
|
+
acceptance criteria CANNOT reach? T-007 records a phase meeting fifteen
|
|
97
|
+
of fifteen executed criteria while live-locking every supervision
|
|
98
|
+
command. A hazard class that is the criteria list reworded reproduces
|
|
99
|
+
that failure while appearing to fix it. For each class, name the
|
|
100
|
+
criterion that reaches it or state that none does and name the
|
|
101
|
+
instrument that does.
|
|
102
|
+
applies-to: plan-structure
|
|
103
|
+
evidence-required: true
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { EX_USAGE, run } from "../src/cli.js";
|
|
3
|
+
function singleLine(text) {
|
|
4
|
+
return text.replace(/\s+/g, " ").trim();
|
|
5
|
+
}
|
|
6
|
+
try {
|
|
7
|
+
process.exitCode = await run(process.argv.slice(2));
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
const usage = error?.usage === true;
|
|
11
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12
|
+
process.stderr.write(`tiphys: ${singleLine(message)}\n`);
|
|
13
|
+
process.exitCode = usage ? EX_USAGE : 1;
|
|
14
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Fleet } from "./fleet.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Brief assembly (kernel plan v1, M1-P4 step 2; R-033b, R-083b).
|
|
4
|
+
*
|
|
5
|
+
* The brief for a task is written once, at spawn, to tasks/<id>/brief.md:
|
|
6
|
+
* the operator's brief file verbatim, followed by the fleet's
|
|
7
|
+
* environment-warnings file verbatim when the fleet has one. The
|
|
8
|
+
* warnings file is <fleet>/warnings.md (fleet root, tracked content, not
|
|
9
|
+
* the ignored state/ area). When no warnings file exists, brief.md is
|
|
10
|
+
* byte-identical to the brief file.
|
|
11
|
+
*
|
|
12
|
+
* Verbatim means verbatim: no heading, no banner, no rewriting. A brief
|
|
13
|
+
* is the durable instruction an implementer is judged against, and a
|
|
14
|
+
* kernel that edits it makes the audit trail lie. The only byte this
|
|
15
|
+
* module may add is a single newline between the two documents when the
|
|
16
|
+
* brief does not already end in one.
|
|
17
|
+
*/
|
|
18
|
+
/** The fleet's environment-warnings file, appended to every brief. */
|
|
19
|
+
export declare const WARNINGS_FILE = "warnings.md";
|
|
20
|
+
export declare function warningsPath(fleet: Fleet): string;
|
|
21
|
+
export type BriefResult = {
|
|
22
|
+
ok: true;
|
|
23
|
+
value: string;
|
|
24
|
+
} | {
|
|
25
|
+
ok: false;
|
|
26
|
+
reason: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Assemble tasks/<id>/brief.md from briefFile. Returns the written path.
|
|
30
|
+
* The task directory must already exist.
|
|
31
|
+
*/
|
|
32
|
+
export declare function assembleBrief(fleet: Fleet, taskId: string, briefFile: string): BriefResult;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { briefPath } from "./task.js";
|
|
4
|
+
/**
|
|
5
|
+
* Brief assembly (kernel plan v1, M1-P4 step 2; R-033b, R-083b).
|
|
6
|
+
*
|
|
7
|
+
* The brief for a task is written once, at spawn, to tasks/<id>/brief.md:
|
|
8
|
+
* the operator's brief file verbatim, followed by the fleet's
|
|
9
|
+
* environment-warnings file verbatim when the fleet has one. The
|
|
10
|
+
* warnings file is <fleet>/warnings.md (fleet root, tracked content, not
|
|
11
|
+
* the ignored state/ area). When no warnings file exists, brief.md is
|
|
12
|
+
* byte-identical to the brief file.
|
|
13
|
+
*
|
|
14
|
+
* Verbatim means verbatim: no heading, no banner, no rewriting. A brief
|
|
15
|
+
* is the durable instruction an implementer is judged against, and a
|
|
16
|
+
* kernel that edits it makes the audit trail lie. The only byte this
|
|
17
|
+
* module may add is a single newline between the two documents when the
|
|
18
|
+
* brief does not already end in one.
|
|
19
|
+
*/
|
|
20
|
+
/** The fleet's environment-warnings file, appended to every brief. */
|
|
21
|
+
export const WARNINGS_FILE = "warnings.md";
|
|
22
|
+
export function warningsPath(fleet) {
|
|
23
|
+
return join(fleet.root, WARNINGS_FILE);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Assemble tasks/<id>/brief.md from briefFile. Returns the written path.
|
|
27
|
+
* The task directory must already exist.
|
|
28
|
+
*/
|
|
29
|
+
export function assembleBrief(fleet, taskId, briefFile) {
|
|
30
|
+
let brief;
|
|
31
|
+
try {
|
|
32
|
+
brief = readFileSync(briefFile, "utf8");
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
return {
|
|
36
|
+
ok: false,
|
|
37
|
+
reason: `cannot read brief file ${briefFile}: ${error.message}`,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
let content = brief;
|
|
41
|
+
const warnings = warningsPath(fleet);
|
|
42
|
+
if (existsSync(warnings)) {
|
|
43
|
+
let warningsText;
|
|
44
|
+
try {
|
|
45
|
+
warningsText = readFileSync(warnings, "utf8");
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
return {
|
|
49
|
+
ok: false,
|
|
50
|
+
reason: `cannot read fleet warnings file ${warnings}: ${error.message}`,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const separator = content === "" || content.endsWith("\n") ? "" : "\n";
|
|
54
|
+
content = `${content}${separator}${warningsText}`;
|
|
55
|
+
}
|
|
56
|
+
const target = briefPath(fleet, taskId);
|
|
57
|
+
writeFileSync(target, content);
|
|
58
|
+
return { ok: true, value: target };
|
|
59
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* READING AND RESOLVING REVIEW CHECKLISTS (kernel plan M3, M3-P7 steps 2 to
|
|
3
|
+
* 5; R-054, T-001).
|
|
4
|
+
*
|
|
5
|
+
* `checklists/` ships at the package root beside `gate-registry.yaml`,
|
|
6
|
+
* `assurance-modes.yaml` and `schemas/`. This module locates it, decodes a
|
|
7
|
+
* checklist, merges a per-phase extra probe file into it, and orders the
|
|
8
|
+
* result under a declared framing. It answers one question: WHICH PROBES, IN
|
|
9
|
+
* WHICH ORDER, does this reviewer answer.
|
|
10
|
+
*
|
|
11
|
+
* NO VALIDATION HAPPENS HERE, deliberately, and this is the same split
|
|
12
|
+
* `src/modes.ts` documents: `tiphys validate --type checklist` decides whether
|
|
13
|
+
* a document is well formed, and duplicating its rules in a reader would
|
|
14
|
+
* produce a second opinion to keep in sync. The COMMAND validates before it
|
|
15
|
+
* serves (`src/commands/checklist.ts`), which is where the M3-P3 fix round put
|
|
16
|
+
* that duty after shipping a reader that printed without checking.
|
|
17
|
+
*
|
|
18
|
+
* THE MERGE FAILURES ARE FAILURES HERE AND NOT WARNINGS. An extra file
|
|
19
|
+
* reusing a canonical probe id is a COLLISION and names both sources; an
|
|
20
|
+
* extra probe missing `evidence-required` is a refusal; and, added in fix
|
|
21
|
+
* round 2, an extra file DECLARING A FRAMING is a refusal, because framings
|
|
22
|
+
* are read from the canonical checklist only and the entry point was
|
|
23
|
+
* previously dropped without a word. Last-wins and silent-drop are the same
|
|
24
|
+
* dangerous state seen from two sides: the phase's own hazard class names "an
|
|
25
|
+
* extra-probe merge that silently overrides a canonical probe instead of
|
|
26
|
+
* colliding", and a silent anything is how a per-phase file quietly diverges
|
|
27
|
+
* from the standing checklist.
|
|
28
|
+
*
|
|
29
|
+
* ORDERING IS BY SCOPE AND FILE POSITION, NEVER BY PROBE ID. A framing names
|
|
30
|
+
* `applies-to` scopes; probes in a named scope lead, scope by scope, and
|
|
31
|
+
* inside one scope the FILE ORDER decides. That is what makes CLAUDE.md's
|
|
32
|
+
* "the reviewer's FIRST check is item 3" falsifiable: move the probe later in
|
|
33
|
+
* the file and the resolved head changes. A framing that named probe ids
|
|
34
|
+
* would pin the head wherever the probe sat, which is the hazard class's
|
|
35
|
+
* "ordering expressed as a comment rather than as position" one level up.
|
|
36
|
+
*/
|
|
37
|
+
/** The shipped directory's basename, at the package root. */
|
|
38
|
+
export declare const CHECKLISTS_DIRNAME = "checklists";
|
|
39
|
+
/** One probe as the document declares it. */
|
|
40
|
+
export interface Probe {
|
|
41
|
+
id: string;
|
|
42
|
+
probe: string;
|
|
43
|
+
appliesTo: string;
|
|
44
|
+
evidenceRequired: boolean;
|
|
45
|
+
verifiesGate?: string;
|
|
46
|
+
/** Where this probe came from, for the collision message. */
|
|
47
|
+
source: string;
|
|
48
|
+
}
|
|
49
|
+
/** One declared entry point into the same probe list. */
|
|
50
|
+
export interface Framing {
|
|
51
|
+
id: string;
|
|
52
|
+
entryPoint: string;
|
|
53
|
+
ordersProbes: string[];
|
|
54
|
+
}
|
|
55
|
+
export interface Checklist {
|
|
56
|
+
id: string;
|
|
57
|
+
appliesTo: string;
|
|
58
|
+
probes: Probe[];
|
|
59
|
+
framings: Framing[];
|
|
60
|
+
/** The decoded document, for the validator to see unaltered. */
|
|
61
|
+
raw: unknown;
|
|
62
|
+
/** The file this was read from. */
|
|
63
|
+
path: string;
|
|
64
|
+
}
|
|
65
|
+
type Read<T> = {
|
|
66
|
+
ok: true;
|
|
67
|
+
value: T;
|
|
68
|
+
} | {
|
|
69
|
+
ok: false;
|
|
70
|
+
reason: string;
|
|
71
|
+
};
|
|
72
|
+
/** The shipped `checklists/` directory, found by walking up from this module. */
|
|
73
|
+
export declare function checklistsDirectory(): string;
|
|
74
|
+
/** Every checklist id the shipped directory declares, by filename, sorted. */
|
|
75
|
+
export declare function shippedChecklistIds(): string[];
|
|
76
|
+
/**
|
|
77
|
+
* Project a decoded checklist document into the shape the resolver uses.
|
|
78
|
+
*
|
|
79
|
+
* FIELDS ABSENT FROM THE DOCUMENT STAY ABSENT rather than becoming defaults,
|
|
80
|
+
* with one exception stated here so it is not a surprise: `evidence-required`
|
|
81
|
+
* is projected as `false` when it is absent, and the CALLER is what refuses
|
|
82
|
+
* such a probe. Defaulting it to `true` would let a probe missing the field
|
|
83
|
+
* merge in as though it carried the stronger obligation, which is R-054's
|
|
84
|
+
* second named failure passing silently.
|
|
85
|
+
*/
|
|
86
|
+
export declare function projectChecklist(document: unknown, path: string, source: string): Read<Checklist>;
|
|
87
|
+
/**
|
|
88
|
+
* Read a checklist document from an explicit path.
|
|
89
|
+
*
|
|
90
|
+
* The path is OPERATOR-SUPPLIED (D-M3-27), so it is classified before it is
|
|
91
|
+
* opened rather than opened and hoped about: a named pipe at `--extra` is a
|
|
92
|
+
* reported refusal, never a command that blocks forever.
|
|
93
|
+
*/
|
|
94
|
+
export declare function readChecklistFile(path: string, source: string): Read<Checklist>;
|
|
95
|
+
/** Read a shipped checklist by id, or say which ids exist. */
|
|
96
|
+
export declare function readShippedChecklist(id: string): Read<Checklist>;
|
|
97
|
+
export interface MergeProblem {
|
|
98
|
+
/** The probe id at fault. */
|
|
99
|
+
probe: string;
|
|
100
|
+
reason: string;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Merge an extra probe file into a canonical checklist.
|
|
104
|
+
*
|
|
105
|
+
* BOTH FAILURES ARE COLLECTED RATHER THAN THROWN AT THE FIRST, so an author
|
|
106
|
+
* fixing an extra file sees every problem in one run instead of one per
|
|
107
|
+
* invocation.
|
|
108
|
+
*/
|
|
109
|
+
export declare function mergeExtraProbes(canonical: Checklist, extra: Checklist): {
|
|
110
|
+
probes: Probe[];
|
|
111
|
+
problems: MergeProblem[];
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* An extra file may not declare a framing, and saying so is a REFUSAL.
|
|
115
|
+
*
|
|
116
|
+
* M3-P7 FIX ROUND 2, H-2 MEMBER 2. `resolveChecklist` reads
|
|
117
|
+
* `request.checklist.framings` and only that, so a framing declared in an
|
|
118
|
+
* `--extra` file was neither merged nor mentioned: the run exited 0 with an
|
|
119
|
+
* empty stderr and the author's entry point was gone. That is a SILENT NO-OP
|
|
120
|
+
* on R-054's own use case, and the extra file validates as a full checklist
|
|
121
|
+
* document, so declaring a framing in one is the natural thing to try.
|
|
122
|
+
*
|
|
123
|
+
* BOTH SHAPES ARE REFUSED, colliding and not, because the mechanism is the
|
|
124
|
+
* same one: the extra document's framings are never read. Refusing only the
|
|
125
|
+
* COLLIDING one would fix the instance the review constructed and leave the
|
|
126
|
+
* mechanism, which is exactly the fix-round failure CLAUDE.md's contract
|
|
127
|
+
* exists against. The two get different messages because the consequences
|
|
128
|
+
* differ: a collision is also the shape that would let a per-phase file
|
|
129
|
+
* shadow a standing entry point if the merge were ever added, and the
|
|
130
|
+
* message says which document wins today.
|
|
131
|
+
*
|
|
132
|
+
* IT IS A REFUSAL RATHER THAN A MERGE. Merging extra framings would be a new
|
|
133
|
+
* capability, and nothing asks for one; what was wrong was the silence.
|
|
134
|
+
* Nothing depends on the old behaviour: `framings` is not in the checklist
|
|
135
|
+
* schema's `required`, so an extra file that declares none is unaffected.
|
|
136
|
+
*/
|
|
137
|
+
export declare function extraFramingRefusals(canonical: Checklist, extra: Checklist): string[];
|
|
138
|
+
/**
|
|
139
|
+
* Order probes under a framing.
|
|
140
|
+
*
|
|
141
|
+
* Probes whose `applies-to` scope is named by the framing come first, scope
|
|
142
|
+
* by scope in the framing's order, and inside a scope in FILE ORDER. Every
|
|
143
|
+
* probe in no named scope follows, also in file order. NOTHING IS DROPPED: a
|
|
144
|
+
* framing changes what a reviewer reads first and never what they read at
|
|
145
|
+
* all, because a framing that filtered would let an entry point silently
|
|
146
|
+
* retire a probe.
|
|
147
|
+
*/
|
|
148
|
+
export declare function orderUnderFraming(probes: readonly Probe[], framing: Framing): Probe[];
|
|
149
|
+
export interface ResolveRequest {
|
|
150
|
+
checklist: Checklist;
|
|
151
|
+
extra?: Checklist;
|
|
152
|
+
framingId?: string;
|
|
153
|
+
}
|
|
154
|
+
export interface Resolution {
|
|
155
|
+
probes: Probe[];
|
|
156
|
+
framing?: Framing;
|
|
157
|
+
}
|
|
158
|
+
export type ResolveOutcome = {
|
|
159
|
+
ok: true;
|
|
160
|
+
value: Resolution;
|
|
161
|
+
} | {
|
|
162
|
+
ok: false;
|
|
163
|
+
reasons: string[];
|
|
164
|
+
};
|
|
165
|
+
/** Merge, then order. The two failures above and an unknown framing are refusals. */
|
|
166
|
+
export declare function resolveChecklist(request: ResolveRequest): ResolveOutcome;
|
|
167
|
+
/** The resolved list as lines, the framing's entry point at the head. */
|
|
168
|
+
export declare function renderResolution(checklist: Checklist, resolution: Resolution): string[];
|
|
169
|
+
export {};
|