@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,430 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ROLE BRIEFS: frontmatter, the shared clause include, the clause round trip,
|
|
3
|
+
* and the phase projection `tiphys brief compose` emits (kernel plan M3,
|
|
4
|
+
* M3-P5 step 6).
|
|
5
|
+
*
|
|
6
|
+
* A role brief is markdown with YAML frontmatter, which section 1.5 of the
|
|
7
|
+
* plan grants as a JUSTIFIED EXCEPTION to the structured-artifact rule: a
|
|
8
|
+
* brief's effect comes from argument, ordering and emphasis, and splitting it
|
|
9
|
+
* into fields produces either one giant string or a set of fragments no agent
|
|
10
|
+
* reads as an argument. The frontmatter carries everything enumerable and is
|
|
11
|
+
* schema-validated; this module is what makes the BODY checkable in the one
|
|
12
|
+
* respect a machine can reach.
|
|
13
|
+
*
|
|
14
|
+
* THREE MECHANISMS LIVE HERE AND THEY ARE DELIBERATELY SEPARATE.
|
|
15
|
+
*
|
|
16
|
+
* 1. Frontmatter split. A brief is decoded before it is validated, exactly
|
|
17
|
+
* as `tiphys validate` decodes before it validates: a malformed
|
|
18
|
+
* frontmatter block names the decode, a failing contract names the
|
|
19
|
+
* pointer, and neither produces a stack trace.
|
|
20
|
+
* 2. The include. `$include: <name>` on a line of its own is resolved
|
|
21
|
+
* against the brief's own directory. It exists because M3-P5's three
|
|
22
|
+
* briefs and M3-P6's two carry the SAME dispatch-contract clause text,
|
|
23
|
+
* and five independently editable copies of a rule drift into five
|
|
24
|
+
* different rules. There is one copy, `roles/_shared-dispatch-contract.md`.
|
|
25
|
+
* 3. The clause round trip. Every id in `clauses[]` occurs exactly once as a
|
|
26
|
+
* body heading anchor of the include-expanded body, and every anchor
|
|
27
|
+
* occurs in `clauses[]`. This is what stops a clause id being a label
|
|
28
|
+
* with nothing behind it, which would make the clause map a rubber stamp.
|
|
29
|
+
* It proves PRESENCE and never content: whether the text under a heading
|
|
30
|
+
* says the opposite of the row it discharges is judgment, and the phase's
|
|
31
|
+
* own hazard-class table records that no criterion reaches it.
|
|
32
|
+
*
|
|
33
|
+
* D-M3-27 BINDS EVERY PATH THIS MODULE TOUCHES. Composition's whole job is
|
|
34
|
+
* resolving and reading paths it did not create, so every one of them goes
|
|
35
|
+
* through `classifyEntry` and `refuseOpenForWrite` in src/task.ts. A named
|
|
36
|
+
* pipe at a mandated-reading path is a reported refusal naming the path and
|
|
37
|
+
* the observed entry type, never a blocked open. This module adds no bare
|
|
38
|
+
* `readFileSync` and does not patch `src/brief.ts`, which is M1-P4's and
|
|
39
|
+
* carries its own open instance of that class.
|
|
40
|
+
*/
|
|
41
|
+
import type { Diagnostic } from "./validate.ts";
|
|
42
|
+
/**
|
|
43
|
+
* The six roles of blueprint section 6 and of the process document's role
|
|
44
|
+
* table. Identical to `schemas/role-brief.schema.json`'s `role` enum and to
|
|
45
|
+
* `role-model-config.yaml`'s `role` values; test/roles.test.ts asserts the
|
|
46
|
+
* three agree rather than trusting this comment.
|
|
47
|
+
*/
|
|
48
|
+
export declare const ROLE_IDS: readonly string[];
|
|
49
|
+
/** The fence a role brief's YAML frontmatter block is delimited by. */
|
|
50
|
+
export declare const FRONTMATTER_FENCE = "---";
|
|
51
|
+
/** The include directive, on a line of its own. */
|
|
52
|
+
export declare const INCLUDE_PATTERN: RegExp;
|
|
53
|
+
/**
|
|
54
|
+
* A body heading anchor: `## clause <id>` with an optional `: title`.
|
|
55
|
+
*
|
|
56
|
+
* DELIBERATELY EXPLICIT. An anchor form that guessed (say, "a heading whose
|
|
57
|
+
* text looks like an identifier") would classify ordinary headings such as
|
|
58
|
+
* `## Scope` as anchors and redden every brief that has one. The word
|
|
59
|
+
* `clause` is the marker, and a heading without it is prose.
|
|
60
|
+
*/
|
|
61
|
+
export declare const CLAUSE_ANCHOR_PATTERN: RegExp;
|
|
62
|
+
export type RoleBriefSplit = {
|
|
63
|
+
ok: true;
|
|
64
|
+
frontmatter: string;
|
|
65
|
+
body: string;
|
|
66
|
+
} | {
|
|
67
|
+
ok: false;
|
|
68
|
+
reason: string;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Split a role brief into its frontmatter text and its body.
|
|
72
|
+
*
|
|
73
|
+
* The document must OPEN with the fence. A markdown file with a `---` rule
|
|
74
|
+
* somewhere in the middle is not a role brief with frontmatter, and reading
|
|
75
|
+
* it as one is how a horizontal rule becomes a contract.
|
|
76
|
+
*/
|
|
77
|
+
export declare function splitFrontmatter(text: string, label: string): RoleBriefSplit;
|
|
78
|
+
export type IncludeExpansion = {
|
|
79
|
+
ok: true;
|
|
80
|
+
text: string;
|
|
81
|
+
included: string[];
|
|
82
|
+
} | {
|
|
83
|
+
ok: false;
|
|
84
|
+
reason: string;
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Resolve every `$include:` directive in a body against `baseDirectory`.
|
|
88
|
+
*
|
|
89
|
+
* ONE LEVEL, NOT RECURSIVE, and that is a decision rather than an omission: a
|
|
90
|
+
* nested include is a second place the shared text could come from, and the
|
|
91
|
+
* whole point of the shared block is that there is exactly one. An include
|
|
92
|
+
* inside an included file is refused by name.
|
|
93
|
+
*/
|
|
94
|
+
export declare function expandIncludes(body: string, baseDirectory: string, label: string): IncludeExpansion;
|
|
95
|
+
/** Every clause anchor in a body, in the order they occur, duplicates kept. */
|
|
96
|
+
export declare function clauseAnchors(body: string): string[];
|
|
97
|
+
/**
|
|
98
|
+
* The round trip, in both directions, as diagnostics in the same
|
|
99
|
+
* `INVALID <pointer> <message>` contract the schema validator emits.
|
|
100
|
+
*
|
|
101
|
+
* A frontmatter clause with no anchor is ORPHANED: the id is declared, the
|
|
102
|
+
* clause map resolves it because the id occurs somewhere in the file, and
|
|
103
|
+
* there is no text behind it. A stray anchor is the mirror failure: text
|
|
104
|
+
* exists under a clause id nothing declared, so nothing tracks it.
|
|
105
|
+
*/
|
|
106
|
+
export declare function clauseRoundTripDiagnostics(clauses: readonly string[], body: string): Diagnostic[];
|
|
107
|
+
/**
|
|
108
|
+
* THE OUTPUT CONTRACT CHECK (M3-P5 fix round 1, clean-room finding 1).
|
|
109
|
+
*
|
|
110
|
+
* Every artifact type a brief declares in `outputs[]` has a schema document
|
|
111
|
+
* that governs it, and the brief must put that document on its
|
|
112
|
+
* `mandated-reading` list. A brief that does not is a brief whose agent is
|
|
113
|
+
* never told where the shape of its own deliverable is written.
|
|
114
|
+
*
|
|
115
|
+
* THE MECHANISM, NOT THE INSTANCE. The instance found in review was
|
|
116
|
+
* `roles/investigator.md` declaring `outputs: [report]` while its reading list
|
|
117
|
+
* carried `schemas/finding.schema.json`, the contract of a DIFFERENT role's
|
|
118
|
+
* artifact. Repairing that one list leaves the method that produced it, and
|
|
119
|
+
* three correct lists that can drift are worth less than one check that cannot
|
|
120
|
+
* be forgotten. M3-P6 ships two more briefs; this runs on them the day they
|
|
121
|
+
* land, with nobody having to remember it.
|
|
122
|
+
*
|
|
123
|
+
* WHY A CHECK AND NOT A DERIVATION, which was the alternative considered.
|
|
124
|
+
* `resolveMandatedReading` could have INJECTED `schemas/<type>.schema.json`
|
|
125
|
+
* into the list from `outputs[]`, making the omission impossible rather than
|
|
126
|
+
* merely refused. Rejected, for three reasons that are properties of the
|
|
127
|
+
* artifact rather than preferences. (1) It would split the truth in two: the
|
|
128
|
+
* brief file on disk would say one thing and the composed brief another, so a
|
|
129
|
+
* reader of `roles/investigator.md` could no longer see what its agent reads,
|
|
130
|
+
* and `tiphys validate --type role-brief` (which reads the file) and
|
|
131
|
+
* `tiphys brief compose` (which would read the file plus an injection) would
|
|
132
|
+
* hold two different opinions about one property. (2) The list is ORDERED and
|
|
133
|
+
* the order is authored; an injected entry has no authored position, and
|
|
134
|
+
* criterion 3 asserts the composed output's ordering. (3) Injection makes the
|
|
135
|
+
* defect invisible instead of absent: the wrong entry that pointed the
|
|
136
|
+
* investigator at the wrong document would still be sitting on the list,
|
|
137
|
+
* silently, with the right one bolted on beside it. The check makes the author
|
|
138
|
+
* fix the file, which is the artifact a consumer of the kernel reads.
|
|
139
|
+
*
|
|
140
|
+
* WHAT IT DOES NOT REACH, stated at the definition site. An `outputs` entry
|
|
141
|
+
* naming a type NO schema is registered for is SKIPPED rather than refused:
|
|
142
|
+
* there is no document to mandate, and schemas/role-brief.schema.json declares
|
|
143
|
+
* that residue deliberately (an enum there would serialise M3-P6, M3-P7 and
|
|
144
|
+
* M3-P8 against one file). It reaches the FRONTMATTER only: a brief whose body
|
|
145
|
+
* prose describes the wrong output shape passes this, and that is the judgment
|
|
146
|
+
* case the plan's hazard table hands to M3-P7's `clause-text-matches-row`
|
|
147
|
+
* probe. And it is one sub-case of the hazard row at
|
|
148
|
+
* delivery/plan/kernel-plan-m3.md:3021 ("nothing can compute which document a
|
|
149
|
+
* role NEEDS"); the output contract is the part of that which IS computable,
|
|
150
|
+
* and the rest of the row stands.
|
|
151
|
+
*/
|
|
152
|
+
/**
|
|
153
|
+
* THE ONE CANONICAL FORM OF A MANDATED-READING ENTRY (fix round 2, D-3).
|
|
154
|
+
*
|
|
155
|
+
* Entries are kernel-root-relative by definition
|
|
156
|
+
* (schemas/role-brief.schema.json:60 says resolution is "against the kernel
|
|
157
|
+
* root"), so `schemas/report.schema.json`, `./schemas/report.schema.json` and
|
|
158
|
+
* `schemas/../schemas/report.schema.json` are three spellings of one document.
|
|
159
|
+
*
|
|
160
|
+
* IT EXISTS BECAUSE TWO COMMANDS WERE COMPARING THE SAME ENTRY DIFFERENTLY.
|
|
161
|
+
* `outputContractDiagnostics` tested raw string membership while
|
|
162
|
+
* `resolveMandatedReading` resolved with `join`, which normalises; so a brief
|
|
163
|
+
* writing `./schemas/report.schema.json` COMPOSED cleanly and was REFUSED by
|
|
164
|
+
* `tiphys validate --type role-brief`. That divergence is fail-safe (the
|
|
165
|
+
* refusal is the strict side) and it is still the shape this round's own
|
|
166
|
+
* argument against injecting the entry rejected: two commands holding two
|
|
167
|
+
* opinions about one property. Both now ask this function.
|
|
168
|
+
*
|
|
169
|
+
* A LEADING `/` IS STRIPPED rather than treated as an absolute path, because
|
|
170
|
+
* `join(root, "/schemas/x")` already resolves to `<root>/schemas/x`: stripping
|
|
171
|
+
* makes the comparison agree with the resolution that was always happening,
|
|
172
|
+
* instead of introducing a form the two commands read differently. This
|
|
173
|
+
* function changes what is COMPARED; it changes nothing about what is OPENED.
|
|
174
|
+
*/
|
|
175
|
+
export declare function canonicalReadingEntry(entry: string): string;
|
|
176
|
+
export declare function outputContractDiagnostics(outputs: readonly string[], reading: readonly string[], schemaFileForType: (type: string) => string | undefined): Diagnostic[];
|
|
177
|
+
/**
|
|
178
|
+
* Locate the installed kernel root by walking UP from this module and testing
|
|
179
|
+
* for a `roles/` directory holding at least one brief.
|
|
180
|
+
*
|
|
181
|
+
* Counting `..` would be right in exactly one of the two layouts this code
|
|
182
|
+
* runs in (`src/` from source, `dist/src/` from the built entry), which is
|
|
183
|
+
* the layout-dependent break `schemasDirectory` in src/commands/validate.ts
|
|
184
|
+
* already documents. Walking up and TESTING is right in both, and in a
|
|
185
|
+
* relocated copy as well.
|
|
186
|
+
*/
|
|
187
|
+
export declare function kernelRoot(): string;
|
|
188
|
+
export type ReadingResolution = {
|
|
189
|
+
ok: true;
|
|
190
|
+
paths: string[];
|
|
191
|
+
} | {
|
|
192
|
+
ok: false;
|
|
193
|
+
reason: string;
|
|
194
|
+
};
|
|
195
|
+
/**
|
|
196
|
+
* Resolve every mandated-reading path against the kernel root, IN ORDER, and
|
|
197
|
+
* stop at the first one that is not a regular file.
|
|
198
|
+
*
|
|
199
|
+
* THE PATH IS NEVER OPENED. Existence and type are established by
|
|
200
|
+
* `classifyEntry`, so a named pipe at a mandated-reading path is refused with
|
|
201
|
+
* its observed type in bounded time instead of blocking this command forever.
|
|
202
|
+
* A MISSING path and a NON-REGULAR path are different states with different
|
|
203
|
+
* failure modes and they are reported differently on purpose (criteria 2 and
|
|
204
|
+
* 6c, which the plan is explicit are not the same criterion).
|
|
205
|
+
*/
|
|
206
|
+
export declare function resolveMandatedReading(reading: readonly string[], root: string): ReadingResolution;
|
|
207
|
+
/**
|
|
208
|
+
* A body SECTION anchor: `## section <id>` with an optional `: title`.
|
|
209
|
+
*
|
|
210
|
+
* A SECOND MARKER RATHER THAN A REUSE OF THE CLAUSE ONE, and the separation is
|
|
211
|
+
* the point. A clause discharges a requirement row and round-trips against
|
|
212
|
+
* `clauses[]`; a section is a structural part of the brief that R-033a
|
|
213
|
+
* enumerates, and it has no frontmatter list to round-trip against. Marking
|
|
214
|
+
* both with `clause` would mean either declaring six section ids in `clauses[]`
|
|
215
|
+
* (where the clause map would then try to resolve them as rows) or exempting
|
|
216
|
+
* six anchors from the round trip, which is a hole in the check that exists to
|
|
217
|
+
* stop labels with nothing behind them.
|
|
218
|
+
*/
|
|
219
|
+
export declare const SECTION_ANCHOR_PATTERN: RegExp;
|
|
220
|
+
/**
|
|
221
|
+
* The six sections R-033a enumerates, IN THE ORDER THE ROW GIVES THEM.
|
|
222
|
+
*
|
|
223
|
+
* HAND-WRITTEN, and there is nowhere to derive it from: R-033a is a row of a
|
|
224
|
+
* markdown table in a plan document, and parsing a requirement row's prose to
|
|
225
|
+
* recover six section names would be the "deciding what another program will
|
|
226
|
+
* do by pattern-matching the text of a file" mechanism, applied to a file that
|
|
227
|
+
* is not even machine-readable. The list is short, closed, and named in the
|
|
228
|
+
* plan; a phase that changes it changes this line and the criterion that
|
|
229
|
+
* witnesses it.
|
|
230
|
+
*/
|
|
231
|
+
export declare const R033A_SECTIONS: readonly string[];
|
|
232
|
+
/** Every section anchor in a body, in order, duplicates kept. */
|
|
233
|
+
export declare function sectionAnchors(body: string): string[];
|
|
234
|
+
/**
|
|
235
|
+
* The text under one section anchor: everything from the line after the anchor
|
|
236
|
+
* up to the next heading of any level, or the end of the body.
|
|
237
|
+
*/
|
|
238
|
+
export declare function sectionBody(body: string, section: string): string | undefined;
|
|
239
|
+
/**
|
|
240
|
+
* Why an include-expanded implementer body does not satisfy R-033a, or the
|
|
241
|
+
* empty list when it does.
|
|
242
|
+
*
|
|
243
|
+
* NON-EMPTY IS CHECKED, NOT ONLY PRESENT, and criterion 2 says so in as many
|
|
244
|
+
* words. A section reduced to its heading is the dangerous state here rather
|
|
245
|
+
* than a deleted one: the brief still has six anchors, still composes, still
|
|
246
|
+
* looks complete, and instructs nobody. A check that only counted anchors
|
|
247
|
+
* would be green against exactly that.
|
|
248
|
+
*/
|
|
249
|
+
export declare function missingRequiredSections(body: string): string[];
|
|
250
|
+
/**
|
|
251
|
+
* The markers delimiting the generated gate list inside a brief.
|
|
252
|
+
*
|
|
253
|
+
* THE MODE IS IN THE BEGIN MARKER, which is where the brief DECLARES which
|
|
254
|
+
* mode's gate set it carries. It cannot go in the frontmatter: the frontmatter
|
|
255
|
+
* schema is closed (`additionalProperties: false`) and belongs to M3-P5, and a
|
|
256
|
+
* phase that needed a new frontmatter key would be editing another phase's
|
|
257
|
+
* merged contract. The marker is body text, it is visible to a reader of the
|
|
258
|
+
* brief, and `scripts/check-brief-drift.mjs` reads the mode back out of it, so
|
|
259
|
+
* the declaration and the rendering cannot disagree about which mode was meant.
|
|
260
|
+
*
|
|
261
|
+
* HTML comments, so they are invisible in rendered markdown and unambiguous to
|
|
262
|
+
* a line scanner, and they name the producing script so the next person to edit
|
|
263
|
+
* the block by hand is told what to edit instead. The same shape M3-P2 used for
|
|
264
|
+
* CLAUDE.md, deliberately: two drift checks that look different are two things
|
|
265
|
+
* to learn.
|
|
266
|
+
*/
|
|
267
|
+
export declare function briefGateBlockBeginMarker(mode: string): string;
|
|
268
|
+
export declare const BRIEF_GATE_BLOCK_END_MARKER = "<!-- END GENERATED GATE LIST -->";
|
|
269
|
+
/**
|
|
270
|
+
* THE MODE THE SHIPPED BRIEF'S GATE BLOCK MUST DECLARE, pinned HERE and not in
|
|
271
|
+
* the brief (M3-P6 fix round 1, CV-1).
|
|
272
|
+
*
|
|
273
|
+
* The mechanism this closes, stated as a mechanism rather than as the instance
|
|
274
|
+
* that exposed it: A CHECK WHOSE SUBJECT IS SELECTED BY A VALUE READ FROM THE
|
|
275
|
+
* ARTIFACT IT AUDITS CAN BE SILENTLY NARROWED BY EDITING THAT ARTIFACT. The
|
|
276
|
+
* mode above is read out of the brief's own begin marker, deliberately, so that
|
|
277
|
+
* no CALLER can point the comparison at a mode the brief never claimed. That
|
|
278
|
+
* left the EDITOR of the brief holding the same power: switching the marker to
|
|
279
|
+
* a narrower mode and re-rendering produces a brief advertising five gates
|
|
280
|
+
* instead of fifteen with the drift check green, which is an instruction-surface
|
|
281
|
+
* defect every future implementer reads.
|
|
282
|
+
*
|
|
283
|
+
* Two clean-room contracts reached this from different directions on the same
|
|
284
|
+
* head, one by forcing the narrowing and one by deriving it from the unit
|
|
285
|
+
* arithmetic below, and neither was pointed at it.
|
|
286
|
+
*
|
|
287
|
+
* WHY IT IS A CONSTANT HERE AND NOT A REGISTRY KEY. `gate-registry.yaml` is
|
|
288
|
+
* closed (`additionalProperties: false`) and its schema belongs to M3-P2, so a
|
|
289
|
+
* registry key would be this phase editing another phase's merged contract, the
|
|
290
|
+
* same reasoning that put the mode in the marker rather than in the frontmatter.
|
|
291
|
+
* WHY `full` IS THE RIGHT VALUE is not asserted here as a bare literal: the
|
|
292
|
+
* registered test derives from the registry that this mode selects every gate
|
|
293
|
+
* any mode selects, so narrowing is the only direction the value can move.
|
|
294
|
+
*/
|
|
295
|
+
export declare const BRIEF_GATE_BLOCK_MODE = "full";
|
|
296
|
+
export type GateBlockLocation = {
|
|
297
|
+
ok: true;
|
|
298
|
+
mode: string;
|
|
299
|
+
block: string;
|
|
300
|
+
begin: number;
|
|
301
|
+
end: number;
|
|
302
|
+
} | {
|
|
303
|
+
ok: false;
|
|
304
|
+
reason: string;
|
|
305
|
+
};
|
|
306
|
+
/**
|
|
307
|
+
* Locate the generated block in a brief, or say why it cannot be located.
|
|
308
|
+
*
|
|
309
|
+
* A MISSING MARKER IS A REFUSAL AND NEVER A SILENT "NO DRIFT". A check that
|
|
310
|
+
* reports clean because it could not find the thing it compares is the
|
|
311
|
+
* guard-condition failure this repository has recorded twice: the watchdog that
|
|
312
|
+
* tested existence instead of freshness, and the byte check that could not see
|
|
313
|
+
* the one byte it existed to catch.
|
|
314
|
+
*/
|
|
315
|
+
export declare function locateGateBlock(text: string, path: string): GateBlockLocation;
|
|
316
|
+
interface RegistryPreflightEntry {
|
|
317
|
+
command: string[];
|
|
318
|
+
note: string;
|
|
319
|
+
}
|
|
320
|
+
interface RegistryGateEntry {
|
|
321
|
+
id: string;
|
|
322
|
+
applicability: string;
|
|
323
|
+
unitLabel: string;
|
|
324
|
+
modes: string[];
|
|
325
|
+
"verified-by": string;
|
|
326
|
+
probe?: string;
|
|
327
|
+
}
|
|
328
|
+
export interface GateRegistryDocument {
|
|
329
|
+
preflight: RegistryPreflightEntry[];
|
|
330
|
+
gates: RegistryGateEntry[];
|
|
331
|
+
}
|
|
332
|
+
export interface GateBlockRendering {
|
|
333
|
+
text: string;
|
|
334
|
+
/**
|
|
335
|
+
* How many GATE ROWS the rendering produced. The gate's `units`, so M2-C-2
|
|
336
|
+
* bites, and it counts the thing the gate's `unitLabel` names.
|
|
337
|
+
*
|
|
338
|
+
* IT USED TO INCLUDE THE PREFLIGHT STEPS AND THAT MADE THE VACUITY GUARD
|
|
339
|
+
* UNREACHABLE (M3-P6 fix round 1, CV-1's second face). `preflight` is
|
|
340
|
+
* mode-independent and always non-empty, so `preflight.length + selected.length`
|
|
341
|
+
* had a floor it could never fall below: a rendering that selected ZERO gates
|
|
342
|
+
* still reported three units, and M2-C-2 rewrites green-with-zero-units and
|
|
343
|
+
* nothing else. The check could therefore report `green (3 generated brief
|
|
344
|
+
* gate rows compared)` over a gate table holding a header, a separator and
|
|
345
|
+
* NOTHING ELSE, and the header's promise that "a run that compared ZERO rows
|
|
346
|
+
* becomes error with vacuous: true" was true of the plumbing and false of the
|
|
347
|
+
* behaviour.
|
|
348
|
+
*
|
|
349
|
+
* The general shape is the one this repository keeps paying for: a count that
|
|
350
|
+
* does not measure what its label names cannot make a guard fire.
|
|
351
|
+
*/
|
|
352
|
+
units: number;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Render the brief's gate-list block from the registry ALONE, for one mode.
|
|
356
|
+
*
|
|
357
|
+
* IT DERIVES, IT DOES NOT READ THE BLOCK. The hazard the plan names for this
|
|
358
|
+
* criterion by name is "a generated gate-list block whose drift check compares
|
|
359
|
+
* the block TO ITSELF rather than to the registry", and that check is green
|
|
360
|
+
* forever. This function takes the decoded registry and a mode string, and
|
|
361
|
+
* nothing else; the brief file is opened only to compare against or write into.
|
|
362
|
+
*
|
|
363
|
+
* ONE RENDERER, TWO CALLERS. `scripts/check-brief-drift.mjs` calls it to
|
|
364
|
+
* compare and to write, and the registered test calls it to assert the composed
|
|
365
|
+
* brief is byte-identical to the registry's rendering. A second copy of this
|
|
366
|
+
* table in the test would be the test asserting agreement with itself.
|
|
367
|
+
*/
|
|
368
|
+
export declare function renderBriefGateBlock(registry: GateRegistryDocument, mode: string): GateBlockRendering;
|
|
369
|
+
/**
|
|
370
|
+
* The two review contracts of `assurance-modes.yaml`'s `review-contracts`.
|
|
371
|
+
*
|
|
372
|
+
* TWO CONTRACTS, NOT TWO REVIEWERS, and the two are different axes that full
|
|
373
|
+
* mode requires both of. The measured evidence is that both reviews of one
|
|
374
|
+
* phase walked all fifteen acceptance criteria and agreed on every mechanical
|
|
375
|
+
* fact, and the one briefed on hazards found a high-severity defect the other's
|
|
376
|
+
* report does not name.
|
|
377
|
+
*/
|
|
378
|
+
export declare const REVIEW_CONTRACTS: readonly string[];
|
|
379
|
+
/** The clause id carrying one contract's instructions. */
|
|
380
|
+
export declare function reviewContractClause(contract: string): string;
|
|
381
|
+
/**
|
|
382
|
+
* The role whose brief carries a contract per value. Named rather than assumed,
|
|
383
|
+
* because `--review-contract` on any other role is a usage error and the check
|
|
384
|
+
* that says so needs something to compare against.
|
|
385
|
+
*/
|
|
386
|
+
export declare const REVIEW_CONTRACT_ROLE = "clean-room-reviewer";
|
|
387
|
+
export type ContractSelection = {
|
|
388
|
+
ok: true;
|
|
389
|
+
text: string;
|
|
390
|
+
} | {
|
|
391
|
+
ok: false;
|
|
392
|
+
reason: string;
|
|
393
|
+
};
|
|
394
|
+
/**
|
|
395
|
+
* Keep the selected contract's clause block and DROP the others.
|
|
396
|
+
*
|
|
397
|
+
* The composed brief is what a dispatched reviewer reads, and a brief carrying
|
|
398
|
+
* both contracts has told the reviewer to start from the criteria and not to
|
|
399
|
+
* start from the criteria. Dropping happens at COMPOSE time and never in the
|
|
400
|
+
* file: the file declares both clause ids and carries both blocks, so the
|
|
401
|
+
* clause round trip still sees a complete brief and `tiphys validate` still
|
|
402
|
+
* checks both texts. A design that split the two into two files would have put
|
|
403
|
+
* the shared four-fifths of the brief in two places.
|
|
404
|
+
*/
|
|
405
|
+
export declare function selectReviewContract(body: string, contract: string): ContractSelection;
|
|
406
|
+
/**
|
|
407
|
+
* THE FIELDS OF A PLAN PHASE THAT `brief compose` RENDERS, in order.
|
|
408
|
+
*
|
|
409
|
+
* HAND-WRITTEN ON PURPOSE, AND THE TEST THAT GUARDS IT IS NOT. Criterion 3b
|
|
410
|
+
* requires the rendered phase text to be a COMPLETE projection of the phase
|
|
411
|
+
* object, and requires the assertion to be driven FROM
|
|
412
|
+
* `schemas/plan.schema.json`'s phase `required` array rather than from a
|
|
413
|
+
* hand-written list. If this list were also derived from the schema the two
|
|
414
|
+
* would move together and the test could never redden, which is the shape of
|
|
415
|
+
* a guard whose condition does not test the property that matters.
|
|
416
|
+
*
|
|
417
|
+
* So: the SCHEMA is the test's source and this list is the renderer's, they
|
|
418
|
+
* are independent, and a later phase adding a required phase field reddens
|
|
419
|
+
* `brief compose renders every required field of the plan schema's phase` until
|
|
420
|
+
* this list is extended. The dangerous state the criterion names is the
|
|
421
|
+
* realistic one, a renderer that silently drops a field while the composed
|
|
422
|
+
* output still contains a mandated-reading list, a body and SOME phase text,
|
|
423
|
+
* and deleting an entry from this list is exactly that state.
|
|
424
|
+
*/
|
|
425
|
+
export declare const PHASE_FIELD_ORDER: readonly string[];
|
|
426
|
+
/** Render one field value as markdown lines. */
|
|
427
|
+
export declare function renderFieldValue(value: unknown, indent: string): string[];
|
|
428
|
+
/** Render one plan phase as the brief's phase section. */
|
|
429
|
+
export declare function renderPhase(phase: Record<string, unknown>): string[];
|
|
430
|
+
export {};
|