@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,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
role: plan-writer
|
|
3
|
+
lifetime: One plan
|
|
4
|
+
sees:
|
|
5
|
+
- The input report
|
|
6
|
+
- The code
|
|
7
|
+
mandated-reading:
|
|
8
|
+
- roles/_shared-dispatch-contract.md
|
|
9
|
+
- schemas/plan.schema.json
|
|
10
|
+
- templates/plan.example.yaml
|
|
11
|
+
- gate-registry.yaml
|
|
12
|
+
never:
|
|
13
|
+
- Decides product questions
|
|
14
|
+
- Writes feature code
|
|
15
|
+
- Plans a phase on an unverified claim without marking it verification-first
|
|
16
|
+
verifiers:
|
|
17
|
+
- citations
|
|
18
|
+
outputs:
|
|
19
|
+
- plan
|
|
20
|
+
model-tier: strongest
|
|
21
|
+
clauses:
|
|
22
|
+
- R-005
|
|
23
|
+
- R-010a
|
|
24
|
+
- incremental-output
|
|
25
|
+
- beacon-is-not-a-claim
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
# Plan writer
|
|
29
|
+
|
|
30
|
+
You have been given ONE plan to write. You see the input report and the code.
|
|
31
|
+
Your output is a plan instance that validates against
|
|
32
|
+
`schemas/plan.schema.json`, and the binding rule of that document applies to
|
|
33
|
+
everything downstream of you: if it is not written in the plan, it is not being
|
|
34
|
+
made.
|
|
35
|
+
|
|
36
|
+
That rule is what keeps ten agents from improvising, and it puts the whole
|
|
37
|
+
weight on you: an omission in the plan is not a gap someone fills in later, it
|
|
38
|
+
is work that does not happen. Write the phase you would want to be handed.
|
|
39
|
+
|
|
40
|
+
Every acceptance criterion is FALSIFIABLE. "Works correctly" is banned. The
|
|
41
|
+
register is "node --test exits 0 and reports N tests, N greater than zero", or
|
|
42
|
+
"this command exits 64 and prints this line to stderr". A criterion nobody can
|
|
43
|
+
fail is a criterion nobody has to meet.
|
|
44
|
+
|
|
45
|
+
## clause R-005: never decide a product question, flag it
|
|
46
|
+
|
|
47
|
+
You do not decide product questions. When the input report leaves a choice that
|
|
48
|
+
is genuinely a choice, you FLAG it as a decision record and plan around the
|
|
49
|
+
flag rather than picking an answer and burying it in a step.
|
|
50
|
+
|
|
51
|
+
The test for whether something is a decision record is not "is it important".
|
|
52
|
+
It is: are two or more options genuinely comparable, AND is the consequence
|
|
53
|
+
high impact and costly to reverse. If your own analysis yields a recommendation
|
|
54
|
+
you would defend, the options are NOT comparable and there is nothing to ask.
|
|
55
|
+
Decide it, record the reasoning, and say what you decided. Write your
|
|
56
|
+
recommendation first; doing that is what reveals whether a question was ever a
|
|
57
|
+
question.
|
|
58
|
+
|
|
59
|
+
Raising a question whose answer was already obvious is a failure of the system
|
|
60
|
+
and not a display of care, because it spends the owner's attention, which is
|
|
61
|
+
the scarcest thing in the process. Raising an irreversible choice you quietly
|
|
62
|
+
made is the worse failure, and it is the one this clause exists against.
|
|
63
|
+
|
|
64
|
+
A flagged question does not stall the plan. The phase is planned around the
|
|
65
|
+
fill-in: the acceptance criteria, the tests and the gates are fixed regardless
|
|
66
|
+
of which way the question resolves, and the slot that depends on the answer is
|
|
67
|
+
declared as a slot.
|
|
68
|
+
|
|
69
|
+
## clause R-010a: verify every input claim against the code before planning a phase
|
|
70
|
+
|
|
71
|
+
Before a single phase is planned, every claim in the input report gets a
|
|
72
|
+
CODE-LEVEL VERIFICATION PASS, each claim checked against actual file:line
|
|
73
|
+
evidence. The output is the section where the report and the code disagree,
|
|
74
|
+
and it is the most load-bearing part of the plan.
|
|
75
|
+
|
|
76
|
+
This is not a formality. In one measured run, five of eleven report assessments
|
|
77
|
+
did not survive contact with the code: features declared missing that had
|
|
78
|
+
shipped, display bugs that were schema-level projects, one-line bugs hiding
|
|
79
|
+
under grand theories. A plan built on the unverified report would have spent
|
|
80
|
+
five phases on work that did not exist.
|
|
81
|
+
|
|
82
|
+
A claim that FAILS verification does not get dropped and does not get believed.
|
|
83
|
+
It becomes a VERIFICATION-FIRST STEP: the owning phase's step 1 is "confirm
|
|
84
|
+
which of these failures this actually is, write it down, and only then build".
|
|
85
|
+
The plan schema carries that as a step kind, and a derived check requires the
|
|
86
|
+
step to exist in the phase the unverified claim names, so an unverified claim
|
|
87
|
+
with no verification-first step makes the plan invalid rather than making it
|
|
88
|
+
optimistic.
|
|
89
|
+
|
|
90
|
+
Citations resolve or they are not citations. The form is `path.ext:LINE`, in
|
|
91
|
+
prose and outside backticks; a bare path is not a citation and a path inside
|
|
92
|
+
backticks is quoted rather than asserted. The citation linter is the verifier
|
|
93
|
+
attached to this role.
|
|
94
|
+
|
|
95
|
+
$include: _shared-dispatch-contract.md
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Tiphys artifact schemas
|
|
2
|
+
|
|
3
|
+
Every kernel artifact type that is validated has one JSON Schema document
|
|
4
|
+
here. `tiphys validate --type <t> <file>` resolves a type to a document in
|
|
5
|
+
this directory; `--type auto` resolves it from the instance's `kind` field.
|
|
6
|
+
|
|
7
|
+
## The dialect, and why it is declared in every file
|
|
8
|
+
|
|
9
|
+
Every document declares
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
DR-0013 clause 3. It is asserted by a registered test over EVERY file in this
|
|
16
|
+
directory (`test/schemas.test.ts`, behavior `schemas-declare-2020-12-dialect`)
|
|
17
|
+
rather than by inspection, so a schema a later phase adds without the
|
|
18
|
+
declaration fails a gate rather than a reading.
|
|
19
|
+
|
|
20
|
+
## The engine
|
|
21
|
+
|
|
22
|
+
Ajv 8.20.0 exact, Draft 2020-12, instantiated in `src/validate.ts` with strict
|
|
23
|
+
mode, all errors, schema and meta-schema validation, and no coercion, no
|
|
24
|
+
inserted defaults, no removal of additional properties, no mutation of the
|
|
25
|
+
validated input and no automatic loading of remote schemas (DR-0013 clause 4).
|
|
26
|
+
Unknown or invalidly combined keywords fail schema COMPILATION.
|
|
27
|
+
|
|
28
|
+
Ajv is an INTERNAL IMPLEMENTATION DETAIL. Its wording is never a public
|
|
29
|
+
contract: every error is mapped, by keyword, into
|
|
30
|
+
`INVALID <json-pointer> <message>` with a deterministic order.
|
|
31
|
+
|
|
32
|
+
## The declared authoring vocabulary (DR-0013 clause 7)
|
|
33
|
+
|
|
34
|
+
Ajv supplies Draft 2020-12 entire. This list is what a Tiphys schema is
|
|
35
|
+
allowed to USE, so a keyword outside it is a deliberate, documented expansion
|
|
36
|
+
rather than an accident. Every keyword here has both a positive and a negative
|
|
37
|
+
test (`test/schemas.test.ts`).
|
|
38
|
+
|
|
39
|
+
| Keyword | Note |
|
|
40
|
+
|---|---|
|
|
41
|
+
| `type` | one type name per node |
|
|
42
|
+
| `required` | strict mode requires every named property to be declared in `properties` at the same level |
|
|
43
|
+
| `properties` | |
|
|
44
|
+
| `additionalProperties` | boolean only, and set to `false` at EVERY object level |
|
|
45
|
+
| `enum` | |
|
|
46
|
+
| `const` | |
|
|
47
|
+
| `items` | |
|
|
48
|
+
| `minItems` | |
|
|
49
|
+
| `minLength` | |
|
|
50
|
+
| `pattern` | |
|
|
51
|
+
| `$ref` | local references only; a remote reference fails compilation |
|
|
52
|
+
| `oneOf` | |
|
|
53
|
+
| `if` / `then` | |
|
|
54
|
+
| `contains` | in the vocabulary and used by no document shipped in M3-P1; its positive, negative and discriminating tests run against a fixture schema in `test/fixtures/` |
|
|
55
|
+
|
|
56
|
+
Annotations that carry no constraint and are permitted anywhere: `$schema`,
|
|
57
|
+
`$id`, `$comment`, `title`, `description`, `$defs`.
|
|
58
|
+
|
|
59
|
+
Expanding this list is a deliberate act and is recorded here, per DR-0013
|
|
60
|
+
clause 7. Prohibiting an otherwise-valid keyword is a POLICY LINTER, never a
|
|
61
|
+
reimplementation of keyword semantics; `src/gates/validate.ts`'s `loadSchema`
|
|
62
|
+
is the one that exists today, and it enforces M2's narrower closed set over
|
|
63
|
+
the M2 gate schemas only.
|
|
64
|
+
|
|
65
|
+
## Kind A and Kind B
|
|
66
|
+
|
|
67
|
+
A schema expresses properties of ONE document that a keyword reaches (Kind A).
|
|
68
|
+
Properties that compare array elements to each other, resolve a reference into
|
|
69
|
+
another document, compute arithmetic over sibling fields or touch the
|
|
70
|
+
filesystem are Kind B and live in `src/checks.ts` as named derived checks
|
|
71
|
+
(kernel plan M3 section 2.3, DR-0013 clause 8). They are never encoded as Ajv
|
|
72
|
+
extensions.
|
|
73
|
+
|
|
74
|
+
## `$comment` carries clause ids
|
|
75
|
+
|
|
76
|
+
Every requirement row an artifact discharges appears in that artifact as a
|
|
77
|
+
clause id, here as a `$comment` tag or a property name.
|
|
78
|
+
`scripts/check-clause-map.mjs` fails when a row owned by a phase that is in
|
|
79
|
+
force has no entry, when an entry names a row the plan's inventory does not
|
|
80
|
+
contain, when a named artifact does not exist, or when the clause id does not
|
|
81
|
+
occur inside it.
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://tiphys.dev/schemas/assurance-modes.schema.json",
|
|
4
|
+
"title": "Tiphys assurance modes",
|
|
5
|
+
"$comment": "R-024, R-096. Blueprint section 8 fixes three modes and their merge authority; this document is the machine-readable form of that table plus the pipeline the process document actually runs. Kernel plan M3, M3-P3 step 1. WHAT THIS SCHEMA CANNOT SEE, said here rather than left to be discovered: a mode that omits a stage `full` contains while declaring nothing in `skips[]` is a CROSS-OBJECT comparison, and the relative position of two entries in a variable-length array is not a keyword property (M3R-002). Those are Kind B and live in src/checks.ts as `mode-no-undeclared-downgrade` and `mode-stage-order`; the gate-set references and the charter enum are Kind B too, as `mode-gate-sets-resolve` and `charter-mode-enum-matches-modes`. This schema's own share is field presence, item type and the closed vocabularies.",
|
|
6
|
+
"description": "One document per repository. Which assurance modes exist, which pipeline stages each runs, which gates it selects from gate-registry.yaml, who may merge under it, and which stages it declares itself to skip.",
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"required": ["kind", "version", "modes"],
|
|
10
|
+
"properties": {
|
|
11
|
+
"kind": {
|
|
12
|
+
"description": "The artifact type, so `tiphys validate --type auto` resolves this document without being told.",
|
|
13
|
+
"type": "string",
|
|
14
|
+
"const": "assurance-modes"
|
|
15
|
+
},
|
|
16
|
+
"note": {
|
|
17
|
+
"description": "Free prose for this document's own readers.",
|
|
18
|
+
"type": "string"
|
|
19
|
+
},
|
|
20
|
+
"version": {
|
|
21
|
+
"$comment": "A closed set rather than a minimum, because the authoring vocabulary of schemas/README.md has no `minimum` keyword and a bare `type: integer` would admit 0 and negatives. Same shape as gate-registry.schema.json.",
|
|
22
|
+
"type": "integer",
|
|
23
|
+
"enum": [1]
|
|
24
|
+
},
|
|
25
|
+
"modes": {
|
|
26
|
+
"description": "Every mode this repository declares. Append-only in practice: adding one is what makes charter-mode-enum-matches-modes earn its place.",
|
|
27
|
+
"type": "array",
|
|
28
|
+
"minItems": 1,
|
|
29
|
+
"uniqueItems": true,
|
|
30
|
+
"items": {
|
|
31
|
+
"$ref": "#/$defs/mode"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"$defs": {
|
|
36
|
+
"stageId": {
|
|
37
|
+
"$comment": "THE CLOSED STAGE VOCABULARY. The first twelve are `full`'s pipeline, which is the process document's own sequence enumerated (process doc section 9 item 3, R-096), with `fix-round-verification` present because T-003 made it structural rather than discretionary. `orchestrator-diff-review` is the thirteenth and belongs to local-only alone: blueprint section 8 names it in that row (\"implement, orchestrator diff review, local fast-forward\") and a vocabulary without it would force local-only to be described as something it is not. CONSTRAINTS C-2 AND C-3 BIND THIS LIST: no stage is completed, detected or excluded by process liveness, by a signal, or by a detached long-running process. A registered test scans this file and assurance-modes.yaml for the four tokens C-2 and C-3 are written in and requires ZERO hits, which is why those four tokens do not appear here even as a disclaimer (M3-P3 criterion 5). It is a fixed-token presence check and is not stronger than that: a stage whose completion were liveness-detected WITHOUT using any of the four words would pass it, which the plan's hazard map states in the open rather than papering over. CLOSED VOCABULARY AT v0.1.0 (DR-0020): these are the tiphys kernel's OWN stage ids. This enum rejects every other value, so a consuming project cannot name a stage of its own at v0.1.0. Extension is an M4 question, deferred to a real pilot consumer for the same reversibility reason as the mode-id enum.",
|
|
38
|
+
"type": "string",
|
|
39
|
+
"enum": [
|
|
40
|
+
"intake",
|
|
41
|
+
"verification-pass",
|
|
42
|
+
"plan",
|
|
43
|
+
"adversarial-plan-review",
|
|
44
|
+
"implement",
|
|
45
|
+
"clean-room-review",
|
|
46
|
+
"fix-round",
|
|
47
|
+
"fix-round-verification",
|
|
48
|
+
"merge-on-green",
|
|
49
|
+
"orchestrator-diff-review",
|
|
50
|
+
"deploy-verify",
|
|
51
|
+
"migration-verify",
|
|
52
|
+
"final-report"
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
"mode": {
|
|
56
|
+
"$comment": "FOUR conditional rules, chained through $ref rather than stacked in one object, because JSON Schema allows one `if`/`then` pair per schema object and `allOf` is outside the authoring vocabulary of schemas/README.md. Same construction as gate-registry.schema.json's `gate`. This link is M3-P3 criterion 3(c) and criterion 4c: `full` is the reference pipeline every other mode is measured against, so it must CONTAIN the fix-round verification stage T-003 made structural, and it must carry the stop-rather-than-grind bound rather than leaving it in an orchestrator's discipline (blueprint principle 6 calls prompt-only state temporary).",
|
|
57
|
+
"$ref": "#/$defs/modeAuthorityRule",
|
|
58
|
+
"if": {
|
|
59
|
+
"type": "object",
|
|
60
|
+
"required": ["id"],
|
|
61
|
+
"properties": {
|
|
62
|
+
"id": {
|
|
63
|
+
"const": "full"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"then": {
|
|
68
|
+
"type": "object",
|
|
69
|
+
"required": ["pipeline", "escalation-bounds"],
|
|
70
|
+
"properties": {
|
|
71
|
+
"pipeline": {
|
|
72
|
+
"type": "array",
|
|
73
|
+
"contains": {
|
|
74
|
+
"const": "fix-round-verification"
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"escalation-bounds": {
|
|
78
|
+
"$ref": "#/$defs/escalationBounds"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"modeAuthorityRule": {
|
|
84
|
+
"$comment": "M3-P3 criterion 4b. `delegated-under-conditions` is the regime the owner has actually granted once, in DR-0012, and a grant with no conditions and no record reference is an authority downgrade with nothing behind it: exactly the improvisation blueprint section 8 forbids, applied to who may merge rather than to which stages run. `conditions` is minItems 1 so an EMPTY list is a rejection, not a technicality.",
|
|
85
|
+
"$ref": "#/$defs/modeReviewContractRule",
|
|
86
|
+
"if": {
|
|
87
|
+
"type": "object",
|
|
88
|
+
"required": ["merge-authority"],
|
|
89
|
+
"properties": {
|
|
90
|
+
"merge-authority": {
|
|
91
|
+
"const": "delegated-under-conditions"
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"then": {
|
|
96
|
+
"type": "object",
|
|
97
|
+
"required": ["conditions", "granted-by"],
|
|
98
|
+
"properties": {
|
|
99
|
+
"conditions": {
|
|
100
|
+
"type": "array",
|
|
101
|
+
"minItems": 1,
|
|
102
|
+
"items": {
|
|
103
|
+
"type": "string",
|
|
104
|
+
"minLength": 1
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"granted-by": {
|
|
108
|
+
"$ref": "#/$defs/decisionRecordReference"
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
"modeReviewContractRule": {
|
|
114
|
+
"$comment": "M3-P3 criterion 4d (T-007, D-M3-32). A mode that runs clean-room review declares its review CONTRACTS, not a reviewer count. T-007's measurement is why this is a schema rule: two reviewers on different model families walked all fifteen of M1-P5's acceptance criteria, agreed on every mechanical fact, and one returned APPROVE while the other found a high-severity defect that live-locks four commands, because the second was briefed on hazards rather than on criteria. Had both been briefed on the criteria, both would have approved, on any two models. The `uniqueItems` on modeShape's `review-contracts` is what stops two entries both named `criteria` from satisfying this `minItems` and reproducing exactly that failure; the two keywords live at ONE SITE EACH, because a duplicate of either would keep rejecting after the other was defanged and a red witness that stayed red for the wrong reason proves nothing about the keyword it names. DR-0012's requirement of two model FAMILIES is orthogonal and is checked elsewhere.",
|
|
115
|
+
"$ref": "#/$defs/modeShape",
|
|
116
|
+
"if": {
|
|
117
|
+
"type": "object",
|
|
118
|
+
"required": ["pipeline"],
|
|
119
|
+
"properties": {
|
|
120
|
+
"pipeline": {
|
|
121
|
+
"type": "array",
|
|
122
|
+
"contains": {
|
|
123
|
+
"const": "clean-room-review"
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
"then": {
|
|
129
|
+
"type": "object",
|
|
130
|
+
"required": ["review-contracts"],
|
|
131
|
+
"properties": {
|
|
132
|
+
"review-contracts": {
|
|
133
|
+
"type": "array",
|
|
134
|
+
"minItems": 2,
|
|
135
|
+
"items": {
|
|
136
|
+
"type": "string",
|
|
137
|
+
"minLength": 1
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
"modeShape": {
|
|
144
|
+
"type": "object",
|
|
145
|
+
"additionalProperties": false,
|
|
146
|
+
"required": [
|
|
147
|
+
"id",
|
|
148
|
+
"declared-by",
|
|
149
|
+
"pipeline",
|
|
150
|
+
"skips",
|
|
151
|
+
"gate-sets",
|
|
152
|
+
"merge-authority"
|
|
153
|
+
],
|
|
154
|
+
"properties": {
|
|
155
|
+
"$comment": {
|
|
156
|
+
"description": "Clause ids this entry discharges, per schemas/README.md.",
|
|
157
|
+
"type": "string"
|
|
158
|
+
},
|
|
159
|
+
"id": {
|
|
160
|
+
"$comment": "The three ids of blueprint section 8. Closed here and closed again in gate-registry.schema.json's `modes` item enum and in schemas/charter.schema.json's `delivery-mode` enum, which is three copies of one list; `charter-mode-enum-matches-modes` is what keeps the charter copy honest, and test/gate-registry.test.ts already binds the registry copy. CLOSED VOCABULARY AT v0.1.0 (DR-0020): these three are the tiphys kernel's OWN mode ids. This enum rejects every other value, so a consuming project cannot declare a mode of its own name at v0.1.0. Whether to open it, and to what, is an M4 question to be answered by a real pilot consumer rather than guessed; widening an enum later is backward compatible and closing an open one is not, which is why it ships closed.",
|
|
161
|
+
"type": "string",
|
|
162
|
+
"enum": ["full", "direct-pr", "local-only"]
|
|
163
|
+
},
|
|
164
|
+
"declared-by": {
|
|
165
|
+
"description": "Where this mode's definition comes from. Prose with document references, so a reader can check the mode against its source rather than trusting it.",
|
|
166
|
+
"type": "string",
|
|
167
|
+
"minLength": 1
|
|
168
|
+
},
|
|
169
|
+
"pipeline": {
|
|
170
|
+
"description": "The stages this mode runs, IN ORDER. Order is load-bearing: R-024 says an adversarial plan review happens before anyone builds, and that is a property of the sequence, not of the set.",
|
|
171
|
+
"type": "array",
|
|
172
|
+
"minItems": 1,
|
|
173
|
+
"uniqueItems": true,
|
|
174
|
+
"items": {
|
|
175
|
+
"$ref": "#/$defs/stageId"
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
"skips": {
|
|
179
|
+
"$comment": "Blueprint section 8: \"Downgrades are declared, never improvised.\" This is the declaration. It is REQUIRED and may be empty, so a mode that omits a stage and says nothing is distinguishable from a mode that omits nothing; `mode-no-undeclared-downgrade` is what makes the difference cost something. THE CHECK RUNS IN THREE PARTS AND THE SCHEMA CAN SEE NONE OF THEM: an omitted stage missing from this list is a violation (completeness); an entry in this list that the SAME mode's `pipeline` still runs is a violation (soundness A); and an entry that the REFERENCE mode `full` does not run either is a violation too (soundness B), because this list is defined relative to `full`'s pipeline and not to the mode's own. All three are cross-property comparisons and none is a keyword property, and soundness B is a comparison against a DIFFERENT object in the same document, which is further outside the vocabulary still. Soundness A was added after a review measured that a list constrained in one direction only is not constrained at all: one bogus entry on `full` validated at exit 0 and made `tiphys mode show` state the opposite of the truth about this project's own delivery. Soundness B was added a round later, when a delta verification measured that the round adding A had written THIS SENTENCE claiming both directions were covered while an entry naming a stage nothing runs still validated at exit 0. On `full` A and B together force this list to be EMPTY, which is what lets `tiphys mode show` call `full` the un-downgraded process by name.",
|
|
180
|
+
"type": "array",
|
|
181
|
+
"uniqueItems": true,
|
|
182
|
+
"items": {
|
|
183
|
+
"$ref": "#/$defs/stageId"
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
"gate-sets": {
|
|
187
|
+
"$comment": "The gate ids from gate-registry.yaml this mode selects. `set` is the blueprint's word for the per-mode gate selection; here it is enumerated by id rather than named indirectly, so `mode-gate-sets-resolve` can check each entry against the registry with --context and a reference that resolves to nothing cannot pass by never being looked up.",
|
|
188
|
+
"type": "array",
|
|
189
|
+
"minItems": 1,
|
|
190
|
+
"uniqueItems": true,
|
|
191
|
+
"items": {
|
|
192
|
+
"type": "string",
|
|
193
|
+
"pattern": "^[a-z0-9][a-z0-9-]*$"
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
"merge-authority": {
|
|
197
|
+
"$comment": "Blueprint section 8's third column, plus the value the owner has actually granted. `owner-approves-orchestrator-merges` is SC-008 and plan v1 D-6's reading of blueprint section 8's local-only row. IT DESCRIBES A REGIME THIS PROJECT HAS LEFT (DR-0015, 2026-08-05): for the Tiphys kernel the owner is not an approval step anywhere in execution, milestone boundaries included, and dual cross-model clean review is the signature. The value is kept representable rather than deleted because a future project may declare any of the three and the kernel is not the place to make another project's governance unrepresentable.",
|
|
198
|
+
"type": "string",
|
|
199
|
+
"enum": [
|
|
200
|
+
"owner",
|
|
201
|
+
"owner-approves-orchestrator-merges",
|
|
202
|
+
"delegated-under-conditions"
|
|
203
|
+
]
|
|
204
|
+
},
|
|
205
|
+
"conditions": {
|
|
206
|
+
"$comment": "Required, and required to be NON-EMPTY, when merge-authority is delegated-under-conditions. The `minItems` lives in modeAuthorityRule's `then` and NOWHERE ELSE: a second copy here would keep rejecting an empty list after the conditional rule was defanged, which would make the conditional rule's witness green for the wrong reason and hide a rule that had stopped working. Quoted from the decision record rather than summarized.",
|
|
207
|
+
"type": "array",
|
|
208
|
+
"items": {
|
|
209
|
+
"type": "string",
|
|
210
|
+
"minLength": 1
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
"granted-by": {
|
|
214
|
+
"$ref": "#/$defs/decisionRecordReference"
|
|
215
|
+
},
|
|
216
|
+
"review-contracts": {
|
|
217
|
+
"$comment": "T-007, D-M3-32. The STARTING QUESTION each clean-room review is given, by id. Two contracts is not two reviewers: `criteria` walks the phase's acceptance criteria and `hazard` is handed the phase's declared hazard classes and works outward from them.",
|
|
218
|
+
"type": "array",
|
|
219
|
+
"uniqueItems": true,
|
|
220
|
+
"items": {
|
|
221
|
+
"type": "string",
|
|
222
|
+
"minLength": 1
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
"escalation-bounds": {
|
|
226
|
+
"$ref": "#/$defs/escalationBounds"
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
"decisionRecordReference": {
|
|
231
|
+
"description": "A decision record id, for example DR-0012. The record itself lives in the project's decisions directory; this is the reference that makes a grant checkable against it.",
|
|
232
|
+
"type": "string",
|
|
233
|
+
"pattern": "^DR-[0-9]{4}$"
|
|
234
|
+
},
|
|
235
|
+
"onExceeded": {
|
|
236
|
+
"$comment": "DR-0016. `fresh-implementer-and-third-contract` is the response that was measured to work: a fresh implementer plus a third review contract dispatched IMMEDIATELY, with the owner notified asynchronously. `escalate-to-owner` remains in the enum because DR-0016's residual guardrail is real: if the round after the fresh implementer also fails, the phase goes to the owner.",
|
|
237
|
+
"type": "string",
|
|
238
|
+
"enum": ["fresh-implementer-and-third-contract", "escalate-to-owner"]
|
|
239
|
+
},
|
|
240
|
+
"escalationBounds": {
|
|
241
|
+
"$comment": "DR-0012's stop-rather-than-grind limits, made data, plus DR-0016's response. THIS IS DATA THE ORCHESTRATOR BRIEF CITES (M3-P9), NOT AN ENFORCEMENT ENGINE: nothing in M3 counts fix rounds and nothing in M3 classifies a finding's component, and the plan's section 4.5 records that as unproven rather than implying otherwise. `on-exceeded` is in this object's OWN `required` list, which is what makes it required exactly when `escalation-bounds` is present, with no conditional rule to go vacuous. A bound that records the LIMIT but not the RESPONSE encodes the regime DR-0016 measured and replaced: DR-0012's bound was a stop-and-wait, that stop cost 4.7 hours on M1-P5 alone, it fired three times, all three times the owner chose the option the orchestrator had already recommended, and the intervention that actually broke the spiral was the FRESH IMPLEMENTER dispatched afterwards, which derived eleven call sites where the review had listed eight.",
|
|
242
|
+
"type": "object",
|
|
243
|
+
"additionalProperties": false,
|
|
244
|
+
"required": [
|
|
245
|
+
"max-fix-rounds-after-review",
|
|
246
|
+
"recurrence-of-high-in-one-component",
|
|
247
|
+
"on-exceeded"
|
|
248
|
+
],
|
|
249
|
+
"properties": {
|
|
250
|
+
"max-fix-rounds-after-review": {
|
|
251
|
+
"description": "How many fix rounds may follow the first dual review before the bound fires. DR-0012: \"more than two fix rounds after its first dual review\", so two.",
|
|
252
|
+
"type": "integer"
|
|
253
|
+
},
|
|
254
|
+
"recurrence-of-high-in-one-component": {
|
|
255
|
+
"description": "How many times a high-severity finding may recur in one component across rounds before the bound fires. DR-0012 treats any recurrence as the trigger, so one.",
|
|
256
|
+
"type": "integer"
|
|
257
|
+
},
|
|
258
|
+
"on-exceeded": {
|
|
259
|
+
"$ref": "#/$defs/onExceeded"
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://tiphys.dev/schemas/charter.schema.json",
|
|
4
|
+
"title": "Tiphys project charter",
|
|
5
|
+
"description": "Blueprint section 7. The charter is what a project realizes the kernel against. A missing required field BLOCKS realization, which is what this document's required list means.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": [
|
|
9
|
+
"kind",
|
|
10
|
+
"identity",
|
|
11
|
+
"delivery-mode",
|
|
12
|
+
"assurance-tier",
|
|
13
|
+
"yolo-permissions",
|
|
14
|
+
"irreversible-decisions",
|
|
15
|
+
"product-intent",
|
|
16
|
+
"constraints",
|
|
17
|
+
"escalation-contract",
|
|
18
|
+
"release-verification",
|
|
19
|
+
"retention"
|
|
20
|
+
],
|
|
21
|
+
"properties": {
|
|
22
|
+
"kind": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"const": "charter"
|
|
25
|
+
},
|
|
26
|
+
"identity": {
|
|
27
|
+
"type": "object",
|
|
28
|
+
"additionalProperties": false,
|
|
29
|
+
"required": ["name", "repo", "kernel-version-pin"],
|
|
30
|
+
"properties": {
|
|
31
|
+
"name": { "type": "string", "minLength": 1 },
|
|
32
|
+
"repo": { "type": "string", "minLength": 1 },
|
|
33
|
+
"kernel-version-pin": {
|
|
34
|
+
"$comment": "An exact version, never a range. A range makes the delivery process a moving target.",
|
|
35
|
+
"type": "string",
|
|
36
|
+
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+(-[0-9A-Za-z.-]+)?$"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"delivery-mode": {
|
|
41
|
+
"$comment": "The enum is declared HERE and the mode DEFINITIONS are owned by M3-P3's assurance-modes.yaml. The derived check charter-mode-enum-matches-modes (M3-P3) asserts the two agree, so the duplication cannot drift. M3-P1's placeholder list (full, standard, fast, yolo) was REPLACED by M3-P3 with the three ids blueprint section 8 actually declares; `standard`, `fast` and `yolo` named no mode definition anywhere and a charter could select one and get a delivery mode with no pipeline behind it. CLOSED VOCABULARY AT v0.1.0 (DR-0020): the three values are the tiphys kernel's OWN mode ids and this enum rejects every other value, so a consuming project's charter cannot select a delivery mode of its own name at v0.1.0. Extension is an M4 question, deferred to a real pilot consumer.",
|
|
42
|
+
"type": "string",
|
|
43
|
+
"enum": ["full", "direct-pr", "local-only"]
|
|
44
|
+
},
|
|
45
|
+
"assurance-tier": {
|
|
46
|
+
"$comment": "The SAME vocabulary as delivery-mode and watched by the same check. M3-P1 shipped the identical placeholder enum on both fields, so a check that watched only one would leave the other free to drift, which is the hazard rather than a smaller version of it. CLOSED VOCABULARY AT v0.1.0 (DR-0020): the same closed set as delivery-mode, with the same consequence for a consuming project and the same M4 deferral.",
|
|
47
|
+
"type": "string",
|
|
48
|
+
"enum": ["full", "direct-pr", "local-only"]
|
|
49
|
+
},
|
|
50
|
+
"yolo-permissions": {
|
|
51
|
+
"type": "object",
|
|
52
|
+
"additionalProperties": false,
|
|
53
|
+
"required": ["enabled", "scope"],
|
|
54
|
+
"properties": {
|
|
55
|
+
"enabled": { "type": "boolean" },
|
|
56
|
+
"scope": {
|
|
57
|
+
"type": "array",
|
|
58
|
+
"items": { "type": "string", "minLength": 1 }
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"irreversible-decisions": {
|
|
63
|
+
"$comment": "Blueprint section 7's named list. Every one of the seven is required, because an irreversible decision left unstated is one the delivery process will improvise.",
|
|
64
|
+
"type": "object",
|
|
65
|
+
"additionalProperties": false,
|
|
66
|
+
"required": [
|
|
67
|
+
"stack",
|
|
68
|
+
"language",
|
|
69
|
+
"framework",
|
|
70
|
+
"core-data-model",
|
|
71
|
+
"tenancy",
|
|
72
|
+
"auth",
|
|
73
|
+
"deployment-topology"
|
|
74
|
+
],
|
|
75
|
+
"properties": {
|
|
76
|
+
"stack": { "type": "string", "minLength": 1 },
|
|
77
|
+
"language": { "type": "string", "minLength": 1 },
|
|
78
|
+
"framework": { "type": "string", "minLength": 1 },
|
|
79
|
+
"core-data-model": { "type": "string", "minLength": 1 },
|
|
80
|
+
"tenancy": { "type": "string", "minLength": 1 },
|
|
81
|
+
"auth": { "type": "string", "minLength": 1 },
|
|
82
|
+
"deployment-topology": { "type": "string", "minLength": 1 }
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
"product-intent": {
|
|
86
|
+
"$comment": "One page, authored as a YAML block scalar.",
|
|
87
|
+
"type": "string",
|
|
88
|
+
"minLength": 1
|
|
89
|
+
},
|
|
90
|
+
"constraints": {
|
|
91
|
+
"type": "array",
|
|
92
|
+
"items": { "type": "string", "minLength": 1 }
|
|
93
|
+
},
|
|
94
|
+
"escalation-contract": {
|
|
95
|
+
"$comment": "R-022 and R-090: owner decisions are never pre-empted.",
|
|
96
|
+
"type": "object",
|
|
97
|
+
"additionalProperties": false,
|
|
98
|
+
"required": ["stop-for", "route"],
|
|
99
|
+
"properties": {
|
|
100
|
+
"stop-for": {
|
|
101
|
+
"$comment": "Its DEFAULT entries, shipped in templates/charter.example.yaml, are 'any irreversible choice the charter is silent on' and 'a change from a declared release verification to `none`'. They are defaults rather than schema constants because the charter is the owner's document; the second one is what makes turning verification off an owner decision instead of an implementer's edit (delivery/verification/release-verification-interface.md section 4.1).",
|
|
102
|
+
"type": "array",
|
|
103
|
+
"minItems": 1,
|
|
104
|
+
"items": { "type": "string", "minLength": 1 }
|
|
105
|
+
},
|
|
106
|
+
"route": { "type": "string", "minLength": 1 }
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"release-verification": {
|
|
110
|
+
"$comment": "RESERVED, NOT DESIGNED (DR-0014, D-M3-29). The field's real shape is NOT decided here. delivery/verification/release-verification-interface.md section 8 item 4: 'the charter field is M3's, and M3 should reserve the space rather than design it', settled by the first real project charter at M4's pilot. This schema enumerates no adapters, models no N verifications, expresses no outcome enum, and carries no charter coherence check. The two currently-valid shapes are the oneOf below; any other shape is a rejection, which is the guard that stops a project inventing the field's real shape before M4's pilot decides it.",
|
|
111
|
+
"type": "object",
|
|
112
|
+
"additionalProperties": false,
|
|
113
|
+
"required": ["mode"],
|
|
114
|
+
"properties": {
|
|
115
|
+
"mode": {
|
|
116
|
+
"type": "string",
|
|
117
|
+
"enum": ["none", "reserved"]
|
|
118
|
+
},
|
|
119
|
+
"reason": { "type": "string", "minLength": 1 },
|
|
120
|
+
"note": { "type": "string", "minLength": 1 }
|
|
121
|
+
},
|
|
122
|
+
"if": {
|
|
123
|
+
"$comment": "Investigation defence 2: silence is never permission. Disabling verification costs visibility, so mode none REQUIRES a stated reason.",
|
|
124
|
+
"type": "object",
|
|
125
|
+
"required": ["mode"],
|
|
126
|
+
"properties": { "mode": { "const": "none" } }
|
|
127
|
+
},
|
|
128
|
+
"then": {
|
|
129
|
+
"type": "object",
|
|
130
|
+
"required": ["reason"],
|
|
131
|
+
"properties": { "reason": { "type": "string", "minLength": 1 } }
|
|
132
|
+
},
|
|
133
|
+
"oneOf": [
|
|
134
|
+
{
|
|
135
|
+
"type": "object",
|
|
136
|
+
"additionalProperties": false,
|
|
137
|
+
"required": ["mode", "reason"],
|
|
138
|
+
"properties": {
|
|
139
|
+
"mode": { "type": "string", "const": "none" },
|
|
140
|
+
"reason": { "type": "string", "minLength": 1 }
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"type": "object",
|
|
145
|
+
"additionalProperties": false,
|
|
146
|
+
"required": ["mode", "note"],
|
|
147
|
+
"properties": {
|
|
148
|
+
"mode": { "type": "string", "const": "reserved" },
|
|
149
|
+
"note": { "type": "string", "minLength": 1 }
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
]
|
|
153
|
+
},
|
|
154
|
+
"retention": {
|
|
155
|
+
"$comment": "Consumed by M3-P8 for R-098.",
|
|
156
|
+
"type": "object",
|
|
157
|
+
"additionalProperties": false,
|
|
158
|
+
"required": ["work-history", "evidence", "tuition"],
|
|
159
|
+
"properties": {
|
|
160
|
+
"work-history": { "type": "string", "minLength": 1 },
|
|
161
|
+
"evidence": { "type": "string", "minLength": 1 },
|
|
162
|
+
"tuition": { "type": "string", "minLength": 1 }
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|