@tiphys/kernel 0.0.0 → 0.2.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 +663 -0
- package/LICENSE +202 -0
- package/assurance-modes.yaml +299 -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 +92 -0
- package/dist/src/adapters/load.d.ts +202 -0
- package/dist/src/adapters/load.js +440 -0
- package/dist/src/brief.d.ts +32 -0
- package/dist/src/brief.js +66 -0
- package/dist/src/checklists.d.ts +169 -0
- package/dist/src/checklists.js +310 -0
- package/dist/src/checks.d.ts +1539 -0
- package/dist/src/checks.js +5025 -0
- package/dist/src/cli.d.ts +9 -0
- package/dist/src/cli.js +68 -0
- package/dist/src/commands/brief.d.ts +92 -0
- package/dist/src/commands/brief.js +343 -0
- package/dist/src/commands/checklist.d.ts +42 -0
- package/dist/src/commands/checklist.js +168 -0
- package/dist/src/commands/cutover.d.ts +35 -0
- package/dist/src/commands/cutover.js +448 -0
- package/dist/src/commands/doctor.d.ts +264 -0
- package/dist/src/commands/doctor.js +1546 -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 +177 -0
- package/dist/src/commands/lock.d.ts +34 -0
- package/dist/src/commands/lock.js +340 -0
- package/dist/src/commands/mode.d.ts +40 -0
- package/dist/src/commands/mode.js +134 -0
- package/dist/src/commands/next.d.ts +130 -0
- package/dist/src/commands/next.js +597 -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 +139 -0
- package/dist/src/commands/resume.d.ts +1 -0
- package/dist/src/commands/resume.js +88 -0
- package/dist/src/commands/spawn.d.ts +1 -0
- package/dist/src/commands/spawn.js +195 -0
- package/dist/src/commands/status.d.ts +21 -0
- package/dist/src/commands/status.js +122 -0
- package/dist/src/commands/sync.d.ts +47 -0
- package/dist/src/commands/sync.js +341 -0
- package/dist/src/commands/teardown.d.ts +1 -0
- package/dist/src/commands/teardown.js +87 -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 +430 -0
- package/dist/src/commands/watch.d.ts +1 -0
- package/dist/src/commands/watch.js +172 -0
- package/dist/src/cutover.d.ts +584 -0
- package/dist/src/cutover.js +1444 -0
- package/dist/src/exclusion.d.ts +389 -0
- package/dist/src/exclusion.js +843 -0
- package/dist/src/exec/env.d.ts +278 -0
- package/dist/src/exec/env.js +334 -0
- package/dist/src/fleet.d.ts +223 -0
- package/dist/src/fleet.js +298 -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 +1169 -0
- package/dist/src/gates/coverage.d.ts +375 -0
- package/dist/src/gates/coverage.js +836 -0
- package/dist/src/gates/credentials.d.ts +233 -0
- package/dist/src/gates/credentials.js +752 -0
- package/dist/src/gates/deploy.d.ts +1 -0
- package/dist/src/gates/deploy.js +33 -0
- package/dist/src/gates/gate-classes.d.ts +56 -0
- package/dist/src/gates/gate-classes.js +633 -0
- package/dist/src/gates/manifest.d.ts +99 -0
- package/dist/src/gates/manifest.js +208 -0
- package/dist/src/gates/merge-preconditions.d.ts +319 -0
- package/dist/src/gates/merge-preconditions.js +932 -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 +482 -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 +614 -0
- package/dist/src/gates/run.js +1614 -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 +87 -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 +968 -0
- package/dist/src/gates/validate.d.ts +121 -0
- package/dist/src/gates/validate.js +414 -0
- package/dist/src/hooks.d.ts +84 -0
- package/dist/src/hooks.js +125 -0
- package/dist/src/index.d.ts +31 -0
- package/dist/src/index.js +30 -0
- package/dist/src/liveness.d.ts +321 -0
- package/dist/src/liveness.js +396 -0
- package/dist/src/lock.d.ts +256 -0
- package/dist/src/lock.js +792 -0
- package/dist/src/model-resolution.d.ts +159 -0
- package/dist/src/model-resolution.js +307 -0
- package/dist/src/modes.d.ts +149 -0
- package/dist/src/modes.js +258 -0
- package/dist/src/path-identity.d.ts +34 -0
- package/dist/src/path-identity.js +48 -0
- package/dist/src/plan.d.ts +73 -0
- package/dist/src/plan.js +153 -0
- package/dist/src/pool.d.ts +326 -0
- package/dist/src/pool.js +988 -0
- package/dist/src/roles.d.ts +461 -0
- package/dist/src/roles.js +776 -0
- package/dist/src/spawn.d.ts +482 -0
- package/dist/src/spawn.js +1003 -0
- package/dist/src/status.d.ts +116 -0
- package/dist/src/status.js +148 -0
- package/dist/src/task.d.ts +504 -0
- package/dist/src/task.js +307 -0
- package/dist/src/teardown.d.ts +39 -0
- package/dist/src/teardown.js +422 -0
- package/dist/src/tuition.d.ts +159 -0
- package/dist/src/tuition.js +311 -0
- package/dist/src/validate.d.ts +263 -0
- package/dist/src/validate.js +742 -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 +849 -0
- package/dist/src/witness/run.d.ts +299 -0
- package/dist/src/witness/run.js +1373 -0
- package/dist/src/witness/spec.d.ts +270 -0
- package/dist/src/witness/spec.js +475 -0
- package/dist/tsconfig.src.tsbuildinfo +1 -0
- package/gate-registry.yaml +526 -0
- package/gates.manifest.json +257 -0
- package/package.json +72 -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 +463 -0
- package/roles/investigator.md +138 -0
- package/roles/plan-writer.md +95 -0
- package/schemas/README.md +82 -0
- package/schemas/assurance-modes.schema.json +264 -0
- package/schemas/charter.schema.json +185 -0
- package/schemas/checklist.schema.json +114 -0
- package/schemas/cutover-state.schema.json +64 -0
- package/schemas/decision-record.schema.json +88 -0
- package/schemas/executor-record.schema.json +36 -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/model-resolution.schema.json +362 -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 +295 -0
- package/schemas/work-history.schema.json +183 -0
- package/schemas/write-bypass.schema.json +69 -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,159 @@
|
|
|
1
|
+
import type { Fleet } from "./fleet.ts";
|
|
2
|
+
/**
|
|
3
|
+
* THE MODEL-RESOLUTION RECORD, KERNEL SIDE (kernel plan M4, M4-P7;
|
|
4
|
+
* delivery/plan/kernel-plan-m4.md:1018, discharging M4-D-06's four parts at
|
|
5
|
+
* delivery/plan/m4-intake.md:732).
|
|
6
|
+
*
|
|
7
|
+
* WHAT THIS MODULE IS AND, MORE IMPORTANTLY, WHAT IT IS NOT. It READS a
|
|
8
|
+
* record a harness adapter wrote. It holds NO vocabulary: no tier-to-model
|
|
9
|
+
* table, no model-to-family table, and no vendor name of any kind. The whole
|
|
10
|
+
* vocabulary lives in the plugin (plugin/src/vocabulary.ts) and this module
|
|
11
|
+
* dereferences a vocabulary's IDENTITY and never its CONTENT. That single
|
|
12
|
+
* property is what makes a second harness plugin possible at all: a mapping
|
|
13
|
+
* here would close off every harness that is not the one it names
|
|
14
|
+
* (delivery/plan/m4-intake.md:377), and `test/schemas.test.ts` already asserts
|
|
15
|
+
* the absence over the whole shipped surface rather than trusting this
|
|
16
|
+
* paragraph.
|
|
17
|
+
*
|
|
18
|
+
* THE ORDER OF THE CHECKS IS PART OF THE CONTRACT, and it is the release
|
|
19
|
+
* record's order (src/gates/release.ts): the SUBJECT ECHO is compared field by
|
|
20
|
+
* field BEFORE anything reads the resolved identity. A record about another
|
|
21
|
+
* task is not a record with a wrong answer, it is a record about something
|
|
22
|
+
* else, and reading its answer first is how a misattributed family token
|
|
23
|
+
* reaches a decorrelation check as though it belonged there.
|
|
24
|
+
*
|
|
25
|
+
* WHY `observed` IS NOT `attested`, stated here because the vocabulary is the
|
|
26
|
+
* thing most likely to be widened later by someone who did not read M4-P1.
|
|
27
|
+
* The probe measured that the observation channel is harness-written, that it
|
|
28
|
+
* can be EMPTY at hook time under load, and that a process at the agent's own
|
|
29
|
+
* uid can rewrite it in place so the result is byte-shaped exactly like the
|
|
30
|
+
* truth (delivery/verification/m4-prototype-probes.md:410). So `observed`
|
|
31
|
+
* ranks above `self-reported`, which costs nothing to forge, and below any
|
|
32
|
+
* notion of attestation, which would need a signer this environment has not
|
|
33
|
+
* been shown to have.
|
|
34
|
+
*/
|
|
35
|
+
/** The record's file name inside the task directory. */
|
|
36
|
+
export declare const MODEL_RESOLUTION_RECORD_NAME = "model-resolution.json";
|
|
37
|
+
/** The contract versions this kernel accepts. */
|
|
38
|
+
export declare const MODEL_RESOLUTION_CONTRACT_VERSIONS: readonly string[];
|
|
39
|
+
/**
|
|
40
|
+
* Where the record lives: `tasks/<id>/model-resolution.json`, NEVER inside the
|
|
41
|
+
* worktree (M4-P7 criterion 5, src/task.ts:31 and FM-059). The task directory
|
|
42
|
+
* sits outside the worktree precisely so the pool's dirty check needs no
|
|
43
|
+
* exemption list for the kernel's own injected files, and a record written
|
|
44
|
+
* into the worktree would be indistinguishable from the agent's own work.
|
|
45
|
+
*/
|
|
46
|
+
export declare function modelResolutionPath(fleet: Fleet, taskId: string): string;
|
|
47
|
+
/** The launch request fields the record's subject echo is compared against. */
|
|
48
|
+
export interface ModelResolutionSubject {
|
|
49
|
+
taskId: string;
|
|
50
|
+
role: string;
|
|
51
|
+
requestedTier: string;
|
|
52
|
+
}
|
|
53
|
+
export interface VocabularyIdentity {
|
|
54
|
+
id: string;
|
|
55
|
+
version: number;
|
|
56
|
+
}
|
|
57
|
+
/** What one read of the record produced. */
|
|
58
|
+
export type ModelResolutionRead = {
|
|
59
|
+
kind: "read";
|
|
60
|
+
record: Record<string, unknown>;
|
|
61
|
+
} | {
|
|
62
|
+
kind: "error";
|
|
63
|
+
reason: string;
|
|
64
|
+
};
|
|
65
|
+
/** What one acceptance decision produced. */
|
|
66
|
+
export type ModelResolutionAcceptance = {
|
|
67
|
+
kind: "accepted";
|
|
68
|
+
family: string | undefined;
|
|
69
|
+
provenance: string;
|
|
70
|
+
} | {
|
|
71
|
+
kind: "refused";
|
|
72
|
+
reason: string;
|
|
73
|
+
};
|
|
74
|
+
/** What one cross-record family comparison produced. */
|
|
75
|
+
export type FamilyComparison = {
|
|
76
|
+
kind: "compared";
|
|
77
|
+
differ: boolean;
|
|
78
|
+
families: [string, string];
|
|
79
|
+
} | {
|
|
80
|
+
kind: "refused";
|
|
81
|
+
reason: string;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Read the record for a task.
|
|
85
|
+
*
|
|
86
|
+
* AN ABSENT RECORD IS AN ERROR AND IS NEVER GREEN AND NEVER NOT-APPLICABLE
|
|
87
|
+
* (M4-P7 criterion 5). This is not a new rule and deliberately not a second
|
|
88
|
+
* implementation of one: src/gates/release.ts:609 already produces the
|
|
89
|
+
* sentence for the same hazard on the release seam, and the wording is kept
|
|
90
|
+
* in the same shape so that a reader who has met one meets the other.
|
|
91
|
+
* `test/model-resolution.test.ts` drives the real release gate to capture that
|
|
92
|
+
* sentence and derives its assertion from the capture, rather than pinning a
|
|
93
|
+
* hand-written copy of it.
|
|
94
|
+
*
|
|
95
|
+
* THE READ GOES THROUGH `readRegularFileIfPresent`, which is M2-C-6 and the
|
|
96
|
+
* mechanism-index row `reading-a-path-whose-type-is-not-established`: a named
|
|
97
|
+
* pipe at this path is a REPORTED refusal, never a blocked open.
|
|
98
|
+
*/
|
|
99
|
+
export declare function readModelResolutionRecord(path: string, writerExitCode: number): ModelResolutionRead;
|
|
100
|
+
/**
|
|
101
|
+
* The vocabulary IDENTITY of a record, and nothing else about the vocabulary.
|
|
102
|
+
*
|
|
103
|
+
* TWO FIELDS ARE READ AND THEY ARE NAMED HERE RATHER THAN SPREAD, which is
|
|
104
|
+
* the whole of criterion 4's mechanical half. A spread, an `Object.keys`, a
|
|
105
|
+
* `JSON.stringify` or a `structuredClone` of the vocabulary object would
|
|
106
|
+
* ENUMERATE it, and enumeration is dereferencing the content whatever the
|
|
107
|
+
* intent. `test/model-resolution.test.ts` hands this function a Proxy that
|
|
108
|
+
* records every property read and asserts the recorded set against these two
|
|
109
|
+
* names, so a later edit that reaches for a third reddens.
|
|
110
|
+
*/
|
|
111
|
+
export declare function vocabularyIdentity(record: Record<string, unknown>): VocabularyIdentity | undefined;
|
|
112
|
+
/**
|
|
113
|
+
* Accept or refuse one record against the launch request the kernel holds.
|
|
114
|
+
*
|
|
115
|
+
* FOUR REFUSALS, IN THIS ORDER, and the order is the point.
|
|
116
|
+
*
|
|
117
|
+
* 1. THE CONTRACT VERSION, because a record written to a contract this kernel
|
|
118
|
+
* does not know is not a record this kernel can read fields out of.
|
|
119
|
+
* 2. THE SUBJECT ECHO, FIELD BY FIELD, BEFORE THE OUTCOME IS READ. This is
|
|
120
|
+
* src/gates/schemas/release-record.schema.json:26's misattribution guard.
|
|
121
|
+
* 3. THE VOCABULARY IDENTITY, because a family token with no vocabulary is a
|
|
122
|
+
* token nobody can say the meaning of.
|
|
123
|
+
* 4. THE PROVENANCE, which is M4-P7 criterion 6 member TWO. Member one (a
|
|
124
|
+
* record claiming `observed` with no observation at all) is the schema's
|
|
125
|
+
* and is a missing field. THIS is the present-but-inconsistent half, and a
|
|
126
|
+
* schema-only guard passes it green: an observation about another task, or
|
|
127
|
+
* naming a model other than the one the record claims, is a self-report
|
|
128
|
+
* with a decoration on it.
|
|
129
|
+
*/
|
|
130
|
+
export declare function acceptModelResolution(record: Record<string, unknown>, subject: ModelResolutionSubject): ModelResolutionAcceptance;
|
|
131
|
+
/**
|
|
132
|
+
* Compare two accepted records' family tokens (M4-P7 criterion 3).
|
|
133
|
+
*
|
|
134
|
+
* TWO VOCABULARIES ARE NOT COMPARABLE AND THE REFUSAL NAMES BOTH IDS. A family
|
|
135
|
+
* token means whatever the vocabulary that minted it says it means, so
|
|
136
|
+
* comparing a token from one against a token from another is comparing two
|
|
137
|
+
* strings and calling the result a fact about models. That comparison is what
|
|
138
|
+
* `check-dual-review`'s decorrelation assertion rests on, and DR-0038 exists
|
|
139
|
+
* for exactly the environment where the two reviews come from different
|
|
140
|
+
* places, so a silent cross-vocabulary compare would make the assertion
|
|
141
|
+
* meaningless precisely where it is load-bearing.
|
|
142
|
+
*
|
|
143
|
+
* ONLY `id` IS READ HERE. The version is part of the identity a reader may
|
|
144
|
+
* print and is deliberately NOT part of the comparison: a vocabulary that
|
|
145
|
+
* added a family in v2 did not change what its v1 tokens mean, and refusing
|
|
146
|
+
* on version would turn a routine vocabulary revision into an outage.
|
|
147
|
+
*/
|
|
148
|
+
export declare function compareResolvedFamilies(left: Record<string, unknown>, right: Record<string, unknown>): FamilyComparison;
|
|
149
|
+
/**
|
|
150
|
+
* The value closeout copies into a verdict's `produced-by` (M4-P7 criterion 8).
|
|
151
|
+
*
|
|
152
|
+
* VERBATIM, AND THE FUNCTION EXISTS SO THAT "VERBATIM" IS TESTABLE. DR-0031
|
|
153
|
+
* requires a pull request to carry all its own evidence, so the family token
|
|
154
|
+
* has to reach the verdict document rather than being left in a task
|
|
155
|
+
* directory that no reviewer of the pull request can see. A copy that
|
|
156
|
+
* normalised, lowercased or prefixed the token would satisfy every reading of
|
|
157
|
+
* that sentence and would break the one comparison the token exists for.
|
|
158
|
+
*/
|
|
159
|
+
export declare function producedByFromRecord(record: Record<string, unknown>): string | undefined;
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { readRegularFileIfPresent, taskDir } from "./task.js";
|
|
3
|
+
/**
|
|
4
|
+
* THE MODEL-RESOLUTION RECORD, KERNEL SIDE (kernel plan M4, M4-P7;
|
|
5
|
+
* delivery/plan/kernel-plan-m4.md:1018, discharging M4-D-06's four parts at
|
|
6
|
+
* delivery/plan/m4-intake.md:732).
|
|
7
|
+
*
|
|
8
|
+
* WHAT THIS MODULE IS AND, MORE IMPORTANTLY, WHAT IT IS NOT. It READS a
|
|
9
|
+
* record a harness adapter wrote. It holds NO vocabulary: no tier-to-model
|
|
10
|
+
* table, no model-to-family table, and no vendor name of any kind. The whole
|
|
11
|
+
* vocabulary lives in the plugin (plugin/src/vocabulary.ts) and this module
|
|
12
|
+
* dereferences a vocabulary's IDENTITY and never its CONTENT. That single
|
|
13
|
+
* property is what makes a second harness plugin possible at all: a mapping
|
|
14
|
+
* here would close off every harness that is not the one it names
|
|
15
|
+
* (delivery/plan/m4-intake.md:377), and `test/schemas.test.ts` already asserts
|
|
16
|
+
* the absence over the whole shipped surface rather than trusting this
|
|
17
|
+
* paragraph.
|
|
18
|
+
*
|
|
19
|
+
* THE ORDER OF THE CHECKS IS PART OF THE CONTRACT, and it is the release
|
|
20
|
+
* record's order (src/gates/release.ts): the SUBJECT ECHO is compared field by
|
|
21
|
+
* field BEFORE anything reads the resolved identity. A record about another
|
|
22
|
+
* task is not a record with a wrong answer, it is a record about something
|
|
23
|
+
* else, and reading its answer first is how a misattributed family token
|
|
24
|
+
* reaches a decorrelation check as though it belonged there.
|
|
25
|
+
*
|
|
26
|
+
* WHY `observed` IS NOT `attested`, stated here because the vocabulary is the
|
|
27
|
+
* thing most likely to be widened later by someone who did not read M4-P1.
|
|
28
|
+
* The probe measured that the observation channel is harness-written, that it
|
|
29
|
+
* can be EMPTY at hook time under load, and that a process at the agent's own
|
|
30
|
+
* uid can rewrite it in place so the result is byte-shaped exactly like the
|
|
31
|
+
* truth (delivery/verification/m4-prototype-probes.md:410). So `observed`
|
|
32
|
+
* ranks above `self-reported`, which costs nothing to forge, and below any
|
|
33
|
+
* notion of attestation, which would need a signer this environment has not
|
|
34
|
+
* been shown to have.
|
|
35
|
+
*/
|
|
36
|
+
/** The record's file name inside the task directory. */
|
|
37
|
+
export const MODEL_RESOLUTION_RECORD_NAME = "model-resolution.json";
|
|
38
|
+
/** The contract versions this kernel accepts. */
|
|
39
|
+
export const MODEL_RESOLUTION_CONTRACT_VERSIONS = ["1"];
|
|
40
|
+
/**
|
|
41
|
+
* Where the record lives: `tasks/<id>/model-resolution.json`, NEVER inside the
|
|
42
|
+
* worktree (M4-P7 criterion 5, src/task.ts:31 and FM-059). The task directory
|
|
43
|
+
* sits outside the worktree precisely so the pool's dirty check needs no
|
|
44
|
+
* exemption list for the kernel's own injected files, and a record written
|
|
45
|
+
* into the worktree would be indistinguishable from the agent's own work.
|
|
46
|
+
*/
|
|
47
|
+
export function modelResolutionPath(fleet, taskId) {
|
|
48
|
+
return join(taskDir(fleet, taskId), MODEL_RESOLUTION_RECORD_NAME);
|
|
49
|
+
}
|
|
50
|
+
function asRecord(value) {
|
|
51
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
52
|
+
? value
|
|
53
|
+
: undefined;
|
|
54
|
+
}
|
|
55
|
+
function stringAt(container, field) {
|
|
56
|
+
const value = container?.[field];
|
|
57
|
+
return typeof value === "string" ? value : undefined;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Read the record for a task.
|
|
61
|
+
*
|
|
62
|
+
* AN ABSENT RECORD IS AN ERROR AND IS NEVER GREEN AND NEVER NOT-APPLICABLE
|
|
63
|
+
* (M4-P7 criterion 5). This is not a new rule and deliberately not a second
|
|
64
|
+
* implementation of one: src/gates/release.ts:609 already produces the
|
|
65
|
+
* sentence for the same hazard on the release seam, and the wording is kept
|
|
66
|
+
* in the same shape so that a reader who has met one meets the other.
|
|
67
|
+
* `test/model-resolution.test.ts` drives the real release gate to capture that
|
|
68
|
+
* sentence and derives its assertion from the capture, rather than pinning a
|
|
69
|
+
* hand-written copy of it.
|
|
70
|
+
*
|
|
71
|
+
* THE READ GOES THROUGH `readRegularFileIfPresent`, which is M2-C-6 and the
|
|
72
|
+
* mechanism-index row `reading-a-path-whose-type-is-not-established`: a named
|
|
73
|
+
* pipe at this path is a REPORTED refusal, never a blocked open.
|
|
74
|
+
*/
|
|
75
|
+
export function readModelResolutionRecord(path, writerExitCode) {
|
|
76
|
+
const read = readRegularFileIfPresent(path);
|
|
77
|
+
if (read.kind === "absent") {
|
|
78
|
+
return {
|
|
79
|
+
kind: "error",
|
|
80
|
+
reason: `fail-closed rule 1: adapter exited ${String(writerExitCode)} without ` +
|
|
81
|
+
`writing a model-resolution record at ${path}; exit 0 with no ` +
|
|
82
|
+
`record is error, not success`,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (read.kind === "refused") {
|
|
86
|
+
return { kind: "error", reason: read.reason };
|
|
87
|
+
}
|
|
88
|
+
let parsed;
|
|
89
|
+
try {
|
|
90
|
+
parsed = JSON.parse(read.body);
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
return {
|
|
94
|
+
kind: "error",
|
|
95
|
+
reason: `${path} is not readable as JSON: ${String(error).replace(/\s+/g, " ").trim()}`,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
const record = asRecord(parsed);
|
|
99
|
+
if (record === undefined) {
|
|
100
|
+
return { kind: "error", reason: `${path} does not hold a JSON object` };
|
|
101
|
+
}
|
|
102
|
+
return { kind: "read", record };
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* The vocabulary IDENTITY of a record, and nothing else about the vocabulary.
|
|
106
|
+
*
|
|
107
|
+
* TWO FIELDS ARE READ AND THEY ARE NAMED HERE RATHER THAN SPREAD, which is
|
|
108
|
+
* the whole of criterion 4's mechanical half. A spread, an `Object.keys`, a
|
|
109
|
+
* `JSON.stringify` or a `structuredClone` of the vocabulary object would
|
|
110
|
+
* ENUMERATE it, and enumeration is dereferencing the content whatever the
|
|
111
|
+
* intent. `test/model-resolution.test.ts` hands this function a Proxy that
|
|
112
|
+
* records every property read and asserts the recorded set against these two
|
|
113
|
+
* names, so a later edit that reaches for a third reddens.
|
|
114
|
+
*/
|
|
115
|
+
export function vocabularyIdentity(record) {
|
|
116
|
+
const resolved = asRecord(record["resolved"]);
|
|
117
|
+
const vocabulary = asRecord(resolved?.["vocabulary"]);
|
|
118
|
+
if (vocabulary === undefined) {
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
const id = vocabulary["id"];
|
|
122
|
+
const version = vocabulary["version"];
|
|
123
|
+
if (typeof id !== "string" || typeof version !== "number") {
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
return { id, version };
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Accept or refuse one record against the launch request the kernel holds.
|
|
130
|
+
*
|
|
131
|
+
* FOUR REFUSALS, IN THIS ORDER, and the order is the point.
|
|
132
|
+
*
|
|
133
|
+
* 1. THE CONTRACT VERSION, because a record written to a contract this kernel
|
|
134
|
+
* does not know is not a record this kernel can read fields out of.
|
|
135
|
+
* 2. THE SUBJECT ECHO, FIELD BY FIELD, BEFORE THE OUTCOME IS READ. This is
|
|
136
|
+
* src/gates/schemas/release-record.schema.json:26's misattribution guard.
|
|
137
|
+
* 3. THE VOCABULARY IDENTITY, because a family token with no vocabulary is a
|
|
138
|
+
* token nobody can say the meaning of.
|
|
139
|
+
* 4. THE PROVENANCE, which is M4-P7 criterion 6 member TWO. Member one (a
|
|
140
|
+
* record claiming `observed` with no observation at all) is the schema's
|
|
141
|
+
* and is a missing field. THIS is the present-but-inconsistent half, and a
|
|
142
|
+
* schema-only guard passes it green: an observation about another task, or
|
|
143
|
+
* naming a model other than the one the record claims, is a self-report
|
|
144
|
+
* with a decoration on it.
|
|
145
|
+
*/
|
|
146
|
+
export function acceptModelResolution(record, subject) {
|
|
147
|
+
const contractVersion = stringAt(record, "contractVersion");
|
|
148
|
+
if (contractVersion === undefined || !MODEL_RESOLUTION_CONTRACT_VERSIONS.includes(contractVersion)) {
|
|
149
|
+
return {
|
|
150
|
+
kind: "refused",
|
|
151
|
+
reason: `the record declares contract version ${String(contractVersion)}, and this ` +
|
|
152
|
+
`kernel accepts ${MODEL_RESOLUTION_CONTRACT_VERSIONS.join(", ")}`,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
const echo = asRecord(record["subject"]);
|
|
156
|
+
if (echo === undefined) {
|
|
157
|
+
return {
|
|
158
|
+
kind: "refused",
|
|
159
|
+
reason: "the record carries no subject echo, so what it is about could not be established",
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
const echoed = [
|
|
163
|
+
["taskId", stringAt(echo, "taskId")],
|
|
164
|
+
["role", stringAt(echo, "role")],
|
|
165
|
+
["requestedTier", stringAt(echo, "requestedTier")],
|
|
166
|
+
];
|
|
167
|
+
for (const [field, value] of echoed) {
|
|
168
|
+
if (value !== subject[field]) {
|
|
169
|
+
return {
|
|
170
|
+
kind: "refused",
|
|
171
|
+
reason: `the record's subject echo says ${field} is ${String(value)} and the ` +
|
|
172
|
+
`launch request says ${subject[field]}, so this record is about a ` +
|
|
173
|
+
`different subject`,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const identity = vocabularyIdentity(record);
|
|
178
|
+
if (identity === undefined) {
|
|
179
|
+
return {
|
|
180
|
+
kind: "refused",
|
|
181
|
+
reason: "the record carries no resolved.vocabulary identity, so its family token " +
|
|
182
|
+
"belongs to no stated vocabulary and cannot be compared with any other",
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
const resolved = asRecord(record["resolved"]);
|
|
186
|
+
const provenance = stringAt(resolved, "provenance");
|
|
187
|
+
const family = stringAt(resolved, "family");
|
|
188
|
+
const model = stringAt(resolved, "model");
|
|
189
|
+
if (provenance === "observed") {
|
|
190
|
+
const observation = asRecord(resolved?.["observation"]);
|
|
191
|
+
if (observation === undefined) {
|
|
192
|
+
return {
|
|
193
|
+
kind: "refused",
|
|
194
|
+
reason: "the record claims provenance observed and carries no observation, so " +
|
|
195
|
+
"the claim is a self-report wearing the word observed",
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
const observedTask = stringAt(observation, "taskId");
|
|
199
|
+
if (observedTask !== subject.taskId) {
|
|
200
|
+
return {
|
|
201
|
+
kind: "refused",
|
|
202
|
+
reason: `the record claims provenance observed and its observation is about ` +
|
|
203
|
+
`task ${String(observedTask)}, while the echoed request is about task ` +
|
|
204
|
+
`${subject.taskId}, so the observation contradicts the subject it is ` +
|
|
205
|
+
`offered as evidence for`,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
const observedModel = stringAt(observation, "model");
|
|
209
|
+
if (observedModel !== model) {
|
|
210
|
+
return {
|
|
211
|
+
kind: "refused",
|
|
212
|
+
reason: `the record claims model ${String(model)} with provenance observed and ` +
|
|
213
|
+
`its observation saw ${String(observedModel)}, so the claimed identity ` +
|
|
214
|
+
`is not the observed one`,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
else if (provenance === "self-reported") {
|
|
219
|
+
if (resolved?.["observation"] !== undefined) {
|
|
220
|
+
return {
|
|
221
|
+
kind: "refused",
|
|
222
|
+
reason: "the record ranks itself self-reported and carries an observation, so " +
|
|
223
|
+
"it claims evidence it also says it does not have",
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
else if (provenance === "unresolved") {
|
|
228
|
+
if (family !== undefined || model !== undefined) {
|
|
229
|
+
return {
|
|
230
|
+
kind: "refused",
|
|
231
|
+
reason: "the record reports the identity unresolved and still names a family " +
|
|
232
|
+
"or a model, which is the quiet fallback to the forgeable value that " +
|
|
233
|
+
"an unresolved observation exists to prevent",
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
return {
|
|
239
|
+
kind: "refused",
|
|
240
|
+
reason: `the record declares provenance ${String(provenance)}, which this kernel has no rule for`,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
return { kind: "accepted", family, provenance: provenance };
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Compare two accepted records' family tokens (M4-P7 criterion 3).
|
|
247
|
+
*
|
|
248
|
+
* TWO VOCABULARIES ARE NOT COMPARABLE AND THE REFUSAL NAMES BOTH IDS. A family
|
|
249
|
+
* token means whatever the vocabulary that minted it says it means, so
|
|
250
|
+
* comparing a token from one against a token from another is comparing two
|
|
251
|
+
* strings and calling the result a fact about models. That comparison is what
|
|
252
|
+
* `check-dual-review`'s decorrelation assertion rests on, and DR-0038 exists
|
|
253
|
+
* for exactly the environment where the two reviews come from different
|
|
254
|
+
* places, so a silent cross-vocabulary compare would make the assertion
|
|
255
|
+
* meaningless precisely where it is load-bearing.
|
|
256
|
+
*
|
|
257
|
+
* ONLY `id` IS READ HERE. The version is part of the identity a reader may
|
|
258
|
+
* print and is deliberately NOT part of the comparison: a vocabulary that
|
|
259
|
+
* added a family in v2 did not change what its v1 tokens mean, and refusing
|
|
260
|
+
* on version would turn a routine vocabulary revision into an outage.
|
|
261
|
+
*/
|
|
262
|
+
export function compareResolvedFamilies(left, right) {
|
|
263
|
+
const leftIdentity = vocabularyIdentity(left);
|
|
264
|
+
const rightIdentity = vocabularyIdentity(right);
|
|
265
|
+
if (leftIdentity === undefined || rightIdentity === undefined) {
|
|
266
|
+
return {
|
|
267
|
+
kind: "refused",
|
|
268
|
+
reason: "one of the two records carries no resolved.vocabulary identity, so the " +
|
|
269
|
+
"two family tokens belong to no stated common vocabulary",
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
if (leftIdentity.id !== rightIdentity.id) {
|
|
273
|
+
return {
|
|
274
|
+
kind: "refused",
|
|
275
|
+
reason: `the two records name different vocabularies, ${leftIdentity.id} and ` +
|
|
276
|
+
`${rightIdentity.id}, so their family tokens are not comparable and no ` +
|
|
277
|
+
`decorrelation claim can be made from them`,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
const leftFamily = stringAt(asRecord(left["resolved"]), "family");
|
|
281
|
+
const rightFamily = stringAt(asRecord(right["resolved"]), "family");
|
|
282
|
+
if (leftFamily === undefined || rightFamily === undefined) {
|
|
283
|
+
return {
|
|
284
|
+
kind: "refused",
|
|
285
|
+
reason: "one of the two records names no resolved family, so there is nothing to " +
|
|
286
|
+
"compare; an unresolved identity is not a difference and not a match",
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
return {
|
|
290
|
+
kind: "compared",
|
|
291
|
+
differ: leftFamily !== rightFamily,
|
|
292
|
+
families: [leftFamily, rightFamily],
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* The value closeout copies into a verdict's `produced-by` (M4-P7 criterion 8).
|
|
297
|
+
*
|
|
298
|
+
* VERBATIM, AND THE FUNCTION EXISTS SO THAT "VERBATIM" IS TESTABLE. DR-0031
|
|
299
|
+
* requires a pull request to carry all its own evidence, so the family token
|
|
300
|
+
* has to reach the verdict document rather than being left in a task
|
|
301
|
+
* directory that no reviewer of the pull request can see. A copy that
|
|
302
|
+
* normalised, lowercased or prefixed the token would satisfy every reading of
|
|
303
|
+
* that sentence and would break the one comparison the token exists for.
|
|
304
|
+
*/
|
|
305
|
+
export function producedByFromRecord(record) {
|
|
306
|
+
return stringAt(asRecord(record["resolved"]), "family");
|
|
307
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* READING THE SHIPPED ASSURANCE MODE DEFINITIONS (kernel plan M3, M3-P3
|
|
3
|
+
* step 5).
|
|
4
|
+
*
|
|
5
|
+
* `assurance-modes.yaml` ships at the package root, beside `gate-registry.yaml`
|
|
6
|
+
* and the `schemas/` directory. This module locates it, decodes it, and
|
|
7
|
+
* answers one question: what does a declared mode require. Nothing here
|
|
8
|
+
* RESOLVES a mode into behaviour and nothing here enforces one. M3 never
|
|
9
|
+
* executes `direct-pr` or `local-only`, and building an enforcement engine for
|
|
10
|
+
* a mode this milestone never enters is the M1-P3 failure the plan is trying
|
|
11
|
+
* not to repeat.
|
|
12
|
+
*
|
|
13
|
+
* NO VALIDATION HAPPENS HERE, deliberately. `tiphys validate --type
|
|
14
|
+
* assurance-modes` is the command that says whether the document is
|
|
15
|
+
* well-formed, and duplicating its rules in a reader would produce a second
|
|
16
|
+
* opinion to keep in sync. This module reads what is there and reports what it
|
|
17
|
+
* cannot find.
|
|
18
|
+
*/
|
|
19
|
+
/** The shipped document's basename, at the package root. */
|
|
20
|
+
export declare const MODES_FILENAME = "assurance-modes.yaml";
|
|
21
|
+
/**
|
|
22
|
+
* Locate the package root by walking UP from this module and testing for the
|
|
23
|
+
* shipped document.
|
|
24
|
+
*
|
|
25
|
+
* The depth differs between the two layouts this code runs in: from source it
|
|
26
|
+
* is `src/` and the root is one level up, and from the built entry it is
|
|
27
|
+
* `dist/src/` and the root is two levels up. Counting `..` would be right in
|
|
28
|
+
* exactly one of them, which is the layout-dependent break
|
|
29
|
+
* `schemasDirectory()` already documents. Walking up and TESTING is right in
|
|
30
|
+
* both, and in a relocated copy as well.
|
|
31
|
+
*/
|
|
32
|
+
export declare function packageRoot(): string;
|
|
33
|
+
/** One mode as the document declares it. Fields absent from the document stay absent. */
|
|
34
|
+
export interface Mode {
|
|
35
|
+
id: string;
|
|
36
|
+
declaredBy: string;
|
|
37
|
+
pipeline: string[];
|
|
38
|
+
skips: string[];
|
|
39
|
+
gateSets: string[];
|
|
40
|
+
mergeAuthority: string;
|
|
41
|
+
grantedBy?: string;
|
|
42
|
+
conditions?: string[];
|
|
43
|
+
reviewContracts?: string[];
|
|
44
|
+
escalationBounds?: Record<string, unknown>;
|
|
45
|
+
}
|
|
46
|
+
export type ModesRead =
|
|
47
|
+
/**
|
|
48
|
+
* `raw` is the DECODED DOCUMENT before this module projects it into `Mode`
|
|
49
|
+
* records. It is returned because a caller must be able to validate what it
|
|
50
|
+
* is about to serve, and the projection is lossy by design (it drops
|
|
51
|
+
* anything the projection does not name). Handing a caller only the
|
|
52
|
+
* projection would force it to validate a shape no schema describes.
|
|
53
|
+
*/
|
|
54
|
+
{
|
|
55
|
+
ok: true;
|
|
56
|
+
path: string;
|
|
57
|
+
raw: unknown;
|
|
58
|
+
modes: Mode[];
|
|
59
|
+
} | {
|
|
60
|
+
ok: false;
|
|
61
|
+
reason: string;
|
|
62
|
+
};
|
|
63
|
+
/** Read and decode the shipped document, or say why it could not be read. */
|
|
64
|
+
export declare function readModes(path?: string): ModesRead;
|
|
65
|
+
/**
|
|
66
|
+
* Where the rendered document came from. `shippedDocument` is true only when
|
|
67
|
+
* the reader was given no `--file` and therefore read the kernel's OWN
|
|
68
|
+
* `assurance-modes.yaml` from the package root.
|
|
69
|
+
*
|
|
70
|
+
* It is a REQUIRED parameter rather than an option with a default, because the
|
|
71
|
+
* execution-status line below is a claim about a specific document and a
|
|
72
|
+
* default would let a caller make that claim by omission.
|
|
73
|
+
*/
|
|
74
|
+
export interface RenderContext {
|
|
75
|
+
shippedDocument: boolean;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The execution status of one mode, DERIVED rather than looked up in a list of
|
|
79
|
+
* ids (CR-004 item 2, DR-0020).
|
|
80
|
+
*
|
|
81
|
+
* Two facts are available and both are checkable by the reader: whether this is
|
|
82
|
+
* the kernel's own document, and whether this mode IS the one blueprint section
|
|
83
|
+
* 8 names as the un-downgraded process, "The current proven process is the
|
|
84
|
+
* definition of `full`. Downgrades are declared, never improvised."
|
|
85
|
+
*
|
|
86
|
+
* WHY THE NAME AND NOT THE SKIP COUNT (CR-002, round 9). This function used
|
|
87
|
+
* `mode.skips.length === 0` as its proxy for "this is the un-downgraded mode".
|
|
88
|
+
* The proxy held only because `full` happened to be the only mode with an empty
|
|
89
|
+
* list, nothing enforced that, and `skips[]` is shipped DATA. Two measured
|
|
90
|
+
* consequences, both at exit 0 with every registry gate green: giving `full` one
|
|
91
|
+
* bogus `skips[]` entry made this function say that no phase of the tiphys
|
|
92
|
+
* project had ever been delivered under `full`, which is false about the mode
|
|
93
|
+
* this project has delivered every phase under; and giving `direct-pr` an empty
|
|
94
|
+
* `skips[]` made a mode nobody has ever entered claim to be the one the project
|
|
95
|
+
* follows, with `merge-authority: owner` printed beneath it, which is not the
|
|
96
|
+
* regime in force (DR-0015). Blueprint section 8 defines `full` BY NAME, so the
|
|
97
|
+
* name is the primary fact and the skip count is a consequence of it.
|
|
98
|
+
*
|
|
99
|
+
* THE COUNT IS STILL REPORTED, as a fact about the mode rather than as the
|
|
100
|
+
* ground of the claim. That distinction is the whole finding: a number may be
|
|
101
|
+
* shown without being believed.
|
|
102
|
+
*
|
|
103
|
+
* WHAT MAKES THE `full` SENTENCE TRUE IS DATA, AND IT IS GUARDED IN TWO PLACES
|
|
104
|
+
* THAT COVER DIFFERENT DOCUMENTS. Keying off the name moves the burden: the
|
|
105
|
+
* claim is only as good as the `full` in the document being served genuinely
|
|
106
|
+
* being un-downgraded.
|
|
107
|
+
*
|
|
108
|
+
* The VALIDATOR carries it for EVERY document (round 10, CRB9-02).
|
|
109
|
+
* `mode-no-undeclared-downgrade` rejects a `skips[]` entry that the same mode's
|
|
110
|
+
* pipeline runs, and also one that the reference does not run; on the reference
|
|
111
|
+
* those two exhaust the cases, so a `full` declaring any skipped stage at all is
|
|
112
|
+
* refused and this sentence is never printed over it. Until that second part
|
|
113
|
+
* existed, a `full` whose stage had MOVED from `pipeline` into `skips` was an
|
|
114
|
+
* HONEST downgrade that validated at exit 0, and `tiphys mode show --mode full`
|
|
115
|
+
* printed this sentence about fifteen lines above a `skips: deploy-verify` row.
|
|
116
|
+
*
|
|
117
|
+
* A REGISTERED TEST carries it for THIS repository's own document, asserting the
|
|
118
|
+
* shipped `full` declares no skipped stage. It is kept rather than superseded:
|
|
119
|
+
* a test guards the document, the check guards every other document, and the
|
|
120
|
+
* failure this pair exists to prevent is a property asserted where it is stated
|
|
121
|
+
* and not enforced where it is consumed.
|
|
122
|
+
*
|
|
123
|
+
* WHAT THIS DELIBERATELY DOES NOT SAY. It does not say that tiphys runs
|
|
124
|
+
* anything: nothing runs on tiphys before M4. The un-downgraded mode of the
|
|
125
|
+
* kernel's own document is the process the tiphys PROJECT follows for its own
|
|
126
|
+
* delivery; the downgraded ones have never been entered at all. And for a
|
|
127
|
+
* document that is not the kernel's own, the answer is that tiphys does not
|
|
128
|
+
* know, because it does not.
|
|
129
|
+
*/
|
|
130
|
+
export declare function executionStatus(mode: Mode, context: RenderContext): string;
|
|
131
|
+
/**
|
|
132
|
+
* The standing limits of this release, printed on every invocation.
|
|
133
|
+
*
|
|
134
|
+
* IT SAYS ONLY WHAT THE SHIPPED SCHEMAS DO. The vocabularies really are closed
|
|
135
|
+
* enums, so "a document naming any other id is rejected" is the enum's own
|
|
136
|
+
* behaviour and not a claim about intent. The M4 sentence is attributed to
|
|
137
|
+
* DR-0020 rather than stated as a property of the code.
|
|
138
|
+
*/
|
|
139
|
+
export declare const RELEASE_LIMITS: string;
|
|
140
|
+
/**
|
|
141
|
+
* Render one mode for a human or for a brief.
|
|
142
|
+
*
|
|
143
|
+
* THE SHAPE IS PART OF THE CONTRACT, because criterion 2 asserts over it: a
|
|
144
|
+
* section is a line ending in a colon at column zero, and its items are the
|
|
145
|
+
* lines indented by exactly two spaces beneath it. That makes "prints exactly
|
|
146
|
+
* the twelve stage ids in order" something a test can extract rather than
|
|
147
|
+
* something a reader has to eyeball.
|
|
148
|
+
*/
|
|
149
|
+
export declare function renderMode(mode: Mode, context: RenderContext): string[];
|