@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,87 @@
|
|
|
1
|
+
# A minimal Tiphys delivery plan that validates against schemas/plan.schema.json.
|
|
2
|
+
# Kernel plan M3, M3-P1 step 7. It is a TEACHING instance: every required
|
|
3
|
+
# field is present and carries a realistic value, so a plan writer copying it
|
|
4
|
+
# starts from a shape the validator accepts.
|
|
5
|
+
kind: plan
|
|
6
|
+
status: approved
|
|
7
|
+
baseline-commit: be84c6d
|
|
8
|
+
binding-rule: >-
|
|
9
|
+
If it is not written here, it is not being made. Unanswered questions go to
|
|
10
|
+
the orchestrator.
|
|
11
|
+
process-summary: >-
|
|
12
|
+
Orchestrated delivery: verified plan, adversarial plan review, one phase per
|
|
13
|
+
branch, clean-room review before merge, milestone exit tests as hard gates.
|
|
14
|
+
standing-context: |
|
|
15
|
+
What previous runs bought: the fleet layout, the lease lock, the watcher and
|
|
16
|
+
the gate contract. What is already fixed: nothing ships without a red
|
|
17
|
+
witness. Deploy state: none, this is a library.
|
|
18
|
+
report-code-disagreement:
|
|
19
|
+
- phase: M9-P1
|
|
20
|
+
claim: the report says the importer retries on a 429, and the code does not
|
|
21
|
+
verified: false
|
|
22
|
+
phases:
|
|
23
|
+
- id: M9-P1
|
|
24
|
+
branch: claude/m9-p1-importer-retry
|
|
25
|
+
intent: Make the importer's retry behaviour match what the report claims.
|
|
26
|
+
grounding: >-
|
|
27
|
+
The importer is on main at be84c6d and has one call site. The report's
|
|
28
|
+
retry claim has not been confirmed against it.
|
|
29
|
+
severity: high
|
|
30
|
+
verified-root-cause: >-
|
|
31
|
+
To be established by step 1, which is why step 1 is verification-first
|
|
32
|
+
and the fill-in below is unfilled.
|
|
33
|
+
steps:
|
|
34
|
+
- kind: verification-first
|
|
35
|
+
text: >-
|
|
36
|
+
Confirm whether the importer retries a 429 at all, capture the
|
|
37
|
+
observed behaviour, and write it down before changing anything.
|
|
38
|
+
- text: Implement the retry the verification shows is missing.
|
|
39
|
+
files-to-touch:
|
|
40
|
+
- src/importer.ts
|
|
41
|
+
- test/importer.test.ts
|
|
42
|
+
- "`src/cli.ts` (edit only if step 4 requires it)"
|
|
43
|
+
extras:
|
|
44
|
+
- delivery/requirements/clause-map.json
|
|
45
|
+
acceptance:
|
|
46
|
+
- id: "1"
|
|
47
|
+
criterion: >-
|
|
48
|
+
node --test test/importer.test.ts exits 0 and reports 4 tests, 0
|
|
49
|
+
failing.
|
|
50
|
+
- id: "2"
|
|
51
|
+
criterion: >-
|
|
52
|
+
A staged 429 response is retried exactly twice and the third failure
|
|
53
|
+
propagates, asserted against captured server output.
|
|
54
|
+
hazard-classes:
|
|
55
|
+
- id: H1
|
|
56
|
+
statement: >-
|
|
57
|
+
A retry that masks a permanent failure, so a broken import reports
|
|
58
|
+
success after three attempts.
|
|
59
|
+
addressed-by: criterion 2
|
|
60
|
+
- id: H2
|
|
61
|
+
statement: >-
|
|
62
|
+
Retry storms under concurrent imports, which no state this milestone
|
|
63
|
+
reaches can produce.
|
|
64
|
+
addressed-by: "state-not-entered: M10"
|
|
65
|
+
migrations: none
|
|
66
|
+
conflicts-with: []
|
|
67
|
+
parallelizable: false
|
|
68
|
+
citations:
|
|
69
|
+
- R-012
|
|
70
|
+
- T-003
|
|
71
|
+
fill-in:
|
|
72
|
+
filled: false
|
|
73
|
+
root-cause: ""
|
|
74
|
+
fix-shape: ""
|
|
75
|
+
files: []
|
|
76
|
+
decisions:
|
|
77
|
+
- id: D-1
|
|
78
|
+
statement: >-
|
|
79
|
+
The retry count is two rather than five, because the importer's caller
|
|
80
|
+
already has a job-level retry and five would multiply to twenty-five.
|
|
81
|
+
open-questions:
|
|
82
|
+
- DR-0021
|
|
83
|
+
parked:
|
|
84
|
+
- item: A circuit breaker in front of the importer.
|
|
85
|
+
reason: >-
|
|
86
|
+
No measured instance of the failure it prevents; building it now is the
|
|
87
|
+
shape risk 1 exists to stop.
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
# Tiphys report, worked example.
|
|
2
|
+
#
|
|
3
|
+
# FILLED WITH REAL CONTENT FROM THIS REPOSITORY, not with placeholders
|
|
4
|
+
# (kernel plan M3, M3-P4 step 4 and the hazard row on authoring cost). The
|
|
5
|
+
# hazard this phase cannot test is that an honest record might be more
|
|
6
|
+
# expensive to write than a dishonest one; nothing here measures that ratio,
|
|
7
|
+
# and the only thing the plan can do about it is pay the cost of one honest
|
|
8
|
+
# record once, in the open, so a reader can see what it costs. This is that
|
|
9
|
+
# record. Every command quoted below was run, and every exit code is the one
|
|
10
|
+
# it returned.
|
|
11
|
+
|
|
12
|
+
kind: report
|
|
13
|
+
role: implementer
|
|
14
|
+
task: >-
|
|
15
|
+
Deliver M3-P4: the report contract, the final-report shape, the work-history
|
|
16
|
+
contract and the environment-warnings template, so that every later role
|
|
17
|
+
brief has a validated output format to point at instead of describing one in
|
|
18
|
+
prose.
|
|
19
|
+
verdict: >-
|
|
20
|
+
Delivered on the branch, with two residues stated rather than closed and one
|
|
21
|
+
declared deviation from criterion 2(e)'s letter.
|
|
22
|
+
|
|
23
|
+
findings:
|
|
24
|
+
- id: VF-1
|
|
25
|
+
severity: high
|
|
26
|
+
source-pinned: true
|
|
27
|
+
pinned-evidence: origin/main at c7a7ce97e03fc0788c92b401de92f0f4a7b8ee0d
|
|
28
|
+
evidence:
|
|
29
|
+
- path: src/validate.ts
|
|
30
|
+
lines: "568"
|
|
31
|
+
note: >-
|
|
32
|
+
compileSchema built a fresh Ajv per document and registered nothing
|
|
33
|
+
beside it, so a reference leaving the document failed compilation.
|
|
34
|
+
- path: src/validate.ts
|
|
35
|
+
lines: "642"
|
|
36
|
+
note: >-
|
|
37
|
+
The reference is classified as remote or unresolved and either way
|
|
38
|
+
the compilation fails closed.
|
|
39
|
+
analysis: |
|
|
40
|
+
Plan step 3 requires the work-history schema to share the report
|
|
41
|
+
schema's claims and fix-round definitions by $ref rather than restating
|
|
42
|
+
them, and requires a registered test that both resolve to the same
|
|
43
|
+
definition object. As shipped at the merge base, no schema could reach
|
|
44
|
+
another document at all, so shipping the $ref without a change to the
|
|
45
|
+
compile path would have made `tiphys validate --type work-history` fail
|
|
46
|
+
on this phase's own example, which is acceptance criterion 1.
|
|
47
|
+
outcome: >-
|
|
48
|
+
Closed by a declared COMPANION_TABLE in src/commands/validate.ts and an
|
|
49
|
+
optional companions argument on compileSchema, so the set of documents a
|
|
50
|
+
schema may reach is declared in one auditable place rather than derived
|
|
51
|
+
from the reference.
|
|
52
|
+
|
|
53
|
+
- id: VF-2
|
|
54
|
+
severity: medium
|
|
55
|
+
source-pinned: false
|
|
56
|
+
evidence:
|
|
57
|
+
- path: src/gates/coverage.ts
|
|
58
|
+
lines: "599"
|
|
59
|
+
note: checkFindingOutcomeParity is an exported function.
|
|
60
|
+
- path: src/gates/coverage.ts
|
|
61
|
+
command: node src/gates/coverage.ts --help
|
|
62
|
+
exit-code: 64
|
|
63
|
+
note: >-
|
|
64
|
+
The gate CLI answers with its usage line, which accepts only
|
|
65
|
+
--result, --evidence and --config.
|
|
66
|
+
|
|
67
|
+
analysis: |
|
|
68
|
+
Acceptance criterion 4 asks for the M2-P6 coverage checker run in
|
|
69
|
+
finding-to-outcome parity mode against the final-report template, with
|
|
70
|
+
an exit code on both arms. The checker has no CLI flag that reaches that
|
|
71
|
+
mode, and src/gates/coverage.ts is not on this phase's declaration.
|
|
72
|
+
outcome: >-
|
|
73
|
+
Discharged by invoking the exported checker in a subprocess from the
|
|
74
|
+
registered test, so the exit code is a real process exit code and the
|
|
75
|
+
checker itself is unmodified.
|
|
76
|
+
|
|
77
|
+
- id: VF-3
|
|
78
|
+
severity: low
|
|
79
|
+
source-pinned: false
|
|
80
|
+
counter-experiment: >-
|
|
81
|
+
Removing minLength from the field and re-validating the whitespace-only
|
|
82
|
+
instance, which then passes, is the experiment that would falsify this.
|
|
83
|
+
evidence:
|
|
84
|
+
- path: schemas/report.schema.json
|
|
85
|
+
command: node bin/tiphys.ts validate --type report templates/report.example.yaml
|
|
86
|
+
exit-code: 0
|
|
87
|
+
analysis: |
|
|
88
|
+
Every field in these three schemas whose value is the point rather than
|
|
89
|
+
its presence carries minLength 1 and a non-whitespace pattern, because
|
|
90
|
+
required alone is satisfied by the empty string. The inventory of those
|
|
91
|
+
fields is written into the work history as a list, since which fields
|
|
92
|
+
were considered is a judgment made once at authoring time.
|
|
93
|
+
outcome: Closed; the field inventory is in delivery/work-history/m3-p4.md.
|
|
94
|
+
|
|
95
|
+
claims:
|
|
96
|
+
- id: C-1
|
|
97
|
+
kind: open-question
|
|
98
|
+
statement: >-
|
|
99
|
+
I did not find a way to make a gate result record a todo bucket without
|
|
100
|
+
breaking the parity rule, because the plan's five-field count vocabulary
|
|
101
|
+
has no field for it.
|
|
102
|
+
|
|
103
|
+
- id: C-2
|
|
104
|
+
kind: impossibility
|
|
105
|
+
statement: >-
|
|
106
|
+
A relative $ref into a sibling schema cannot be compiled by this
|
|
107
|
+
validator unless the caller registers that sibling as a companion.
|
|
108
|
+
settled-by:
|
|
109
|
+
executed-construction:
|
|
110
|
+
command: >-
|
|
111
|
+
node --input-type=module -e "import {compileSchema} from
|
|
112
|
+
'./src/validate.ts'; const s = JSON.parse(await
|
|
113
|
+
(await import('node:fs/promises')).readFile('schemas/work-history.schema.json','utf8'));
|
|
114
|
+
const r = compileSchema(s); console.log(r.ok ? 'compiled' : r.reason);"
|
|
115
|
+
exit-code: 0
|
|
116
|
+
output: |
|
|
117
|
+
INVALID # schema reference report.schema.json#/$defs/gateResult does not resolve
|
|
118
|
+
|
|
119
|
+
- id: C-3
|
|
120
|
+
kind: coverage
|
|
121
|
+
statement: >-
|
|
122
|
+
The derived check report-parity-arithmetic reddens on a gate result
|
|
123
|
+
whose sum exceeds discovered, and not only on one where discovered
|
|
124
|
+
exceeds the sum.
|
|
125
|
+
settled-by:
|
|
126
|
+
executed-construction:
|
|
127
|
+
command: node --test --test-name-pattern "parity" test/report-contract.test.ts
|
|
128
|
+
exit-code: 0
|
|
129
|
+
output: |
|
|
130
|
+
# tests 2
|
|
131
|
+
# suites 0
|
|
132
|
+
# pass 2
|
|
133
|
+
# fail 0
|
|
134
|
+
# cancelled 0
|
|
135
|
+
# skipped 0
|
|
136
|
+
# todo 0
|
|
137
|
+
|
|
138
|
+
- id: C-4
|
|
139
|
+
kind: remedy
|
|
140
|
+
statement: >-
|
|
141
|
+
Registering report.schema.json as a companion makes the work-history
|
|
142
|
+
schema compile and its example validate.
|
|
143
|
+
settled-by:
|
|
144
|
+
executed-construction:
|
|
145
|
+
command: node bin/tiphys.ts validate --type work-history templates/work-history.example.yaml
|
|
146
|
+
exit-code: 0
|
|
147
|
+
output: |
|
|
148
|
+
(no output; the command exits 0 with nothing on either stream)
|
|
149
|
+
|
|
150
|
+
- id: C-5
|
|
151
|
+
kind: universal
|
|
152
|
+
statement: >-
|
|
153
|
+
Every field in these schemas whose value carries the meaning has both
|
|
154
|
+
minLength and a non-whitespace pattern.
|
|
155
|
+
settled-by:
|
|
156
|
+
counter-experiment: >-
|
|
157
|
+
The falsifying experiment is a grep for minLength without an adjacent
|
|
158
|
+
pattern in the three schema documents; it is recorded with its output
|
|
159
|
+
in delivery/work-history/m3-p4.md.
|
|
160
|
+
|
|
161
|
+
fix-round:
|
|
162
|
+
mechanism: >-
|
|
163
|
+
A schema document compiled without the sibling documents its references
|
|
164
|
+
reach, so a reference that leaves the document fails closed at
|
|
165
|
+
compilation rather than resolving.
|
|
166
|
+
derivation:
|
|
167
|
+
command: "grep -rn 'compileSchema(\\|validateInstance(\\|validateToLines(' src/ bin/ | grep -v '^src/validate.ts:'"
|
|
168
|
+
output: |
|
|
169
|
+
src/gates/run.ts:361: const diagnostics = formatDiagnostics(validateInstance(schema, decoded.value));
|
|
170
|
+
src/gates/validate.ts:524: return validateInstance(schema, instance) as Diagnostic[];
|
|
171
|
+
src/gates/validate.ts:528:export function validateToLines(
|
|
172
|
+
src/commands/mode.ts:125: const lines = formatDiagnostics(validateInstance(loadTypeSchema(MODES_TYPE), read.raw));
|
|
173
|
+
src/commands/validate.ts:273: const diagnostics = validateInstance(
|
|
174
|
+
src/commands/status.ts:127: const diagnostics = validateInstance(loadTypeSchema("status-line"), record);
|
|
175
|
+
not-covered: >-
|
|
176
|
+
The search covered src/ and bin/ only. It did NOT cover test/, where the
|
|
177
|
+
same three functions are called through a computed dynamic import and a
|
|
178
|
+
literal grep for the call would find the import rather than the call; it
|
|
179
|
+
did not cover scripts/, which reaches the validator only through
|
|
180
|
+
src/gates/result.ts and never compiles a schema of its own; and it did not
|
|
181
|
+
cover dist/, which is generated and is never committed. The six sites
|
|
182
|
+
listed are the ones a companion-needing schema could reach today, and only
|
|
183
|
+
src/commands/validate.ts:273 was changed, because it is the only one that
|
|
184
|
+
resolves a type through the type table.
|
|
185
|
+
|
|
186
|
+
deviations:
|
|
187
|
+
- plan-clause: M3-P4 acceptance criterion 2(e)
|
|
188
|
+
why: >-
|
|
189
|
+
The criterion calls for an if/then over a pattern on the same object.
|
|
190
|
+
The finding object already spends its one if/then slot on T-004's
|
|
191
|
+
source-pinned coupling, allOf is outside the declared authoring
|
|
192
|
+
vocabulary, and two independent conditional rules cannot share one slot,
|
|
193
|
+
so the universal-quantifier rule is expressed as a two-branch oneOf. It
|
|
194
|
+
remains Kind A and its guarding keyword is witnessed by removal and
|
|
195
|
+
restoration.
|
|
196
|
+
|
|
197
|
+
honest-failures:
|
|
198
|
+
- cause: >-
|
|
199
|
+
The first copy of this phase's work history was created in the working
|
|
200
|
+
tree and not committed, and it disappeared within twenty-one minutes,
|
|
201
|
+
together with HEAD moving back to main.
|
|
202
|
+
exposure-window: >-
|
|
203
|
+
Twenty-one minutes, from the file's creation at 10:37 to the empty git
|
|
204
|
+
status at 10:58. Nothing was pushed in that window, so no branch outside
|
|
205
|
+
this container ever saw the misplaced commit.
|
|
206
|
+
structural-fix: >-
|
|
207
|
+
The beacon is committed in the same turn it is created, and the branch
|
|
208
|
+
is pushed early rather than at the end, so the beacon lives in git
|
|
209
|
+
rather than only in a working tree another process can reset.
|
|
210
|
+
|
|
211
|
+
environmental-claims:
|
|
212
|
+
- claim: >-
|
|
213
|
+
The build fails at build:runtime-deps on a checkout whose node_modules
|
|
214
|
+
predates M3-P3, because commonmark is a new dependency.
|
|
215
|
+
evidence:
|
|
216
|
+
- path: package.json
|
|
217
|
+
command: npm run build
|
|
218
|
+
exit-code: 1
|
|
219
|
+
note: >-
|
|
220
|
+
Error ENOENT no such file or directory, open
|
|
221
|
+
node_modules/commonmark/package.json
|
|
222
|
+
- path: package-lock.json
|
|
223
|
+
command: npm ci
|
|
224
|
+
exit-code: 0
|
|
225
|
+
note: After npm ci the same build command exits 0.
|
|
226
|
+
|
|
227
|
+
gate-results:
|
|
228
|
+
- gate: suite
|
|
229
|
+
result: green
|
|
230
|
+
wrapper-exit-code: 0
|
|
231
|
+
discovered: 507
|
|
232
|
+
passed: 505
|
|
233
|
+
failed: 0
|
|
234
|
+
skipped: 2
|
|
235
|
+
todo: 0
|
|
236
|
+
did-not-run: 0
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Environment warnings
|
|
2
|
+
|
|
3
|
+
This is R-083a's template half; its accumulation half is the work-history
|
|
4
|
+
schema's `environment-warnings[]`.
|
|
5
|
+
|
|
6
|
+
Place this file at the fleet root as `warnings.md`. `tiphys spawn` appends it
|
|
7
|
+
VERBATIM to every brief it assembles (`src/brief.ts`, R-083b), so what is
|
|
8
|
+
written here is what every agent reads. No heading is added, no banner, no
|
|
9
|
+
rewriting; the only byte the kernel may insert is one newline between the
|
|
10
|
+
brief and this file.
|
|
11
|
+
|
|
12
|
+
Markdown rather than YAML is a justified exception recorded in kernel plan M3
|
|
13
|
+
section 1.5: the only consumer appends it into instruction prose, so a
|
|
14
|
+
structured form would need a renderer whose sole output is the prose this file
|
|
15
|
+
already holds.
|
|
16
|
+
|
|
17
|
+
## What belongs here
|
|
18
|
+
|
|
19
|
+
One entry per environment fact that has already cost someone time. Each entry
|
|
20
|
+
states the fact, how it was MEASURED, and what to do instead. A warning with no
|
|
21
|
+
measurement behind it is a rumour, and a brief full of rumours is skimmed.
|
|
22
|
+
|
|
23
|
+
An entry is added the moment it is discovered, not at the end of a phase. The
|
|
24
|
+
matching field in the work-history contract is `environment-warnings[]`
|
|
25
|
+
(`schemas/work-history.schema.json`), which is the accumulation half of the
|
|
26
|
+
same requirement this template is the template half of.
|
|
27
|
+
|
|
28
|
+
## Entries, as they stand in this repository
|
|
29
|
+
|
|
30
|
+
These are real and are kept here as the worked example rather than as
|
|
31
|
+
placeholders. Replace them with your own project's; do not ship them unread.
|
|
32
|
+
|
|
33
|
+
1. **Several node versions may be installed and which one you get depends on
|
|
34
|
+
how the shell was started.** Measured: a login shell resolved `node` to
|
|
35
|
+
v22.22.2, and a stripped environment (`env -i bash -c`, and some subagent
|
|
36
|
+
and hook contexts) resolved it to v20.20.2. Node 20 has no TypeScript type
|
|
37
|
+
stripping, so a TypeScript test suite fails there in a way that does not
|
|
38
|
+
look like a version problem. Check `node --version` in the shell that
|
|
39
|
+
actually runs the command, and prefer an absolute path or an explicit PATH
|
|
40
|
+
prefix over trusting the ambient one.
|
|
41
|
+
|
|
42
|
+
2. **Running the suite without building first can silently skip tests while
|
|
43
|
+
still exiting 0.** Measured at one head on node v26.6.0: with `dist/` built,
|
|
44
|
+
504 tests, 504 pass, 0 skipped; with `dist/` removed, 504 tests, 495 pass,
|
|
45
|
+
9 skipped. Both runs exit 0. A skipped test is not a passing test, so quote
|
|
46
|
+
the SKIPPED count beside the pass count. The complete sentence names the
|
|
47
|
+
toolchain, the build state and the invocation, because the three axes skip
|
|
48
|
+
different tests and they compose.
|
|
49
|
+
|
|
50
|
+
3. **`git checkout --` is destructive in a tree holding uncommitted work,
|
|
51
|
+
including when it names a single path.** An implementer used it to clean up
|
|
52
|
+
one probe file and lost four rounds of uncommitted edits, having read a
|
|
53
|
+
warning about it beforehand. There is no safe narrow form: commit, or copy
|
|
54
|
+
out of the tree, before experimenting.
|
|
55
|
+
|
|
56
|
+
4. **A mutation harness killed by a timeout leaves the mutant installed.** A
|
|
57
|
+
modified source file is exactly what a mutation round expects to see, so the
|
|
58
|
+
one available signal is the one you have trained yourself to ignore. Restore
|
|
59
|
+
by copying from a pristine copy rather than from git, put the restore in a
|
|
60
|
+
shell `trap`, and print AND COMPARE a checksum on both sides.
|
|
61
|
+
|
|
62
|
+
5. **Concurrent git operations against one clone contend on ref locks**, and
|
|
63
|
+
the real transient message names a ref rather than a lock file. Never derive
|
|
64
|
+
a retry signature from a hand-written example; capture real stderr under
|
|
65
|
+
forced contention.
|
|
66
|
+
|
|
67
|
+
6. **A tool may be absent locally and present in CI.** Use a deterministic
|
|
68
|
+
PATH in tests rather than assuming either, and do not read an authenticated
|
|
69
|
+
API path and a git path as having the same authority: they can differ in one
|
|
70
|
+
container.
|
|
71
|
+
|
|
72
|
+
7. **Tests that create scratch git repositories must set command-scoped
|
|
73
|
+
`GIT_AUTHOR_*` and `GIT_COMMITTER_*`**, because CI runners have no git
|
|
74
|
+
identity, and must never touch user or global configuration.
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# Tiphys work history, worked example.
|
|
2
|
+
#
|
|
3
|
+
# FILLED WITH REAL CONTENT FROM THIS REPOSITORY (kernel plan M3, M3-P4 step 4):
|
|
4
|
+
# this is M3-P4's own record, in the machine-readable form the contract
|
|
5
|
+
# defines. The prose work history at delivery/work-history/m3-p4.md is the
|
|
6
|
+
# same phase's record in the form this repository's own process uses; the two
|
|
7
|
+
# are kept in step deliberately, because a template nobody fills is a template
|
|
8
|
+
# nobody can tell has drifted.
|
|
9
|
+
#
|
|
10
|
+
# THE claims[], fix-round[] AND gate-evidence[] SECTIONS BELOW ARE THE REPORT
|
|
11
|
+
# SCHEMA'S OWN DEFINITIONS, reached by $ref rather than restated, so the
|
|
12
|
+
# honesty contract has one definition and not two that can drift.
|
|
13
|
+
|
|
14
|
+
kind: work-history
|
|
15
|
+
phase: M3-P4
|
|
16
|
+
|
|
17
|
+
prompt: |
|
|
18
|
+
You are the IMPLEMENTER for M3-P4 in the Tiphys kernel repository. You do
|
|
19
|
+
not open pull requests and you do not merge. You implement, commit, push,
|
|
20
|
+
and hand back. Your full brief is at the dispatch brief path; read it FIRST
|
|
21
|
+
and follow it. It carries ten lessons M3-P3 paid ten rounds for, and they
|
|
22
|
+
are repeated there rather than left to CLAUDE.md because a brief that only
|
|
23
|
+
says "read CLAUDE.md" is how they get skipped.
|
|
24
|
+
|
|
25
|
+
files-touched:
|
|
26
|
+
- schemas/report.schema.json
|
|
27
|
+
- schemas/final-report.schema.json
|
|
28
|
+
- schemas/work-history.schema.json
|
|
29
|
+
- templates/report.example.yaml
|
|
30
|
+
- templates/final-report.example.yaml
|
|
31
|
+
- templates/work-history.example.yaml
|
|
32
|
+
- templates/warnings.md
|
|
33
|
+
- test/report-contract.test.ts
|
|
34
|
+
- test/work-history.test.ts
|
|
35
|
+
- test/fixtures/wrapper-capture.counts.json
|
|
36
|
+
- test/fixtures/wrapper-capture.stdout.txt
|
|
37
|
+
- test/fixtures/wrapper-capture.invocation.json
|
|
38
|
+
- src/validate.ts
|
|
39
|
+
- src/checks.ts
|
|
40
|
+
- src/commands/validate.ts
|
|
41
|
+
- delivery/requirements/clause-map.json
|
|
42
|
+
- test/behaviors.json
|
|
43
|
+
- delivery/work-history/m3-p4.md
|
|
44
|
+
|
|
45
|
+
per-step-commits:
|
|
46
|
+
- sha: "9fd800a"
|
|
47
|
+
subject: "M3-P4: open the work history beacon"
|
|
48
|
+
- sha: "b1ddc1b"
|
|
49
|
+
subject: "M3-P4: record the misplaced beacon commit, and the report schema first draft"
|
|
50
|
+
|
|
51
|
+
key-decisions:
|
|
52
|
+
- decision: >-
|
|
53
|
+
Add a declared COMPANION_TABLE beside the type table and an optional
|
|
54
|
+
companions argument to compileSchema, rather than bundling the shared
|
|
55
|
+
definitions into the work-history document at load time.
|
|
56
|
+
why: >-
|
|
57
|
+
The plan requires the two schemas to resolve to the SAME definition
|
|
58
|
+
object rather than to two equal ones. Bundling would satisfy that by a
|
|
59
|
+
caching accident; a declared companion satisfies it because there is one
|
|
60
|
+
physical definition and the second document points at it. It also keeps
|
|
61
|
+
the property DR-0013 clause 4 protects: the set of documents a schema
|
|
62
|
+
may reach is declared in one auditable place and is never derived from
|
|
63
|
+
the reference itself.
|
|
64
|
+
- decision: >-
|
|
65
|
+
Record the pre-existing RangeError in collectUnits rather than fix it.
|
|
66
|
+
why: >-
|
|
67
|
+
Its red witness would have to live in test/checks.test.ts, which is not
|
|
68
|
+
on this phase's declaration, and a fix with no witness is the shape the
|
|
69
|
+
red-witness rule exists to forbid. It is re-measured at this head so the
|
|
70
|
+
record is a measurement rather than an inherited claim.
|
|
71
|
+
- decision: >-
|
|
72
|
+
Express the universal-quantifier rule as a two-branch oneOf rather than
|
|
73
|
+
the if/then the criterion's letter names.
|
|
74
|
+
why: >-
|
|
75
|
+
One object level carries one if/then, the finding object already spends
|
|
76
|
+
it on T-004's source-pinned coupling, and allOf is outside the declared
|
|
77
|
+
authoring vocabulary. Declared as a deviation rather than done quietly.
|
|
78
|
+
|
|
79
|
+
verification-first:
|
|
80
|
+
- finding: >-
|
|
81
|
+
compileSchema builds a fresh Ajv per document and registers nothing
|
|
82
|
+
beside it, and makeAjv withholds loadSchema on purpose, so a $ref that
|
|
83
|
+
leaves the document fails compilation. Shipping the plan's cross-document
|
|
84
|
+
$ref without a change to the compile path would fail acceptance
|
|
85
|
+
criterion 1 on this phase's own example.
|
|
86
|
+
contradicts-plan: true
|
|
87
|
+
stopped-and-reported: >-
|
|
88
|
+
Reported in delivery/work-history/m3-p4.md as VF-1 before any schema was
|
|
89
|
+
authored, with the decision and its reasoning recorded above rather than
|
|
90
|
+
taken silently.
|
|
91
|
+
- finding: >-
|
|
92
|
+
The M2-P6 coverage checker exposes checkFindingOutcomeParity as a
|
|
93
|
+
function and its CLI accepts only --result, --evidence and --config, so
|
|
94
|
+
there is no flag that reaches finding-to-outcome parity mode.
|
|
95
|
+
contradicts-plan: false
|
|
96
|
+
|
|
97
|
+
deviations:
|
|
98
|
+
- plan-clause: M3-P4 acceptance criterion 2(e)
|
|
99
|
+
why: >-
|
|
100
|
+
The criterion calls for an if/then over a pattern on the same object;
|
|
101
|
+
the object's one if/then slot is spent on T-004's coupling and allOf is
|
|
102
|
+
outside the declared authoring vocabulary, so the rule is a two-branch
|
|
103
|
+
oneOf. It remains Kind A and is witnessed by removing and restoring
|
|
104
|
+
oneOf.
|
|
105
|
+
- plan-clause: M3-P4 acceptance criterion 4
|
|
106
|
+
why: >-
|
|
107
|
+
The criterion says the M2-P6 coverage checker is RUN in
|
|
108
|
+
finding-to-outcome parity mode with an exit code on both arms. That mode
|
|
109
|
+
has no CLI flag and src/gates/coverage.ts is not on this phase's
|
|
110
|
+
declaration, so the registered test invokes the exported checker in a
|
|
111
|
+
subprocess. The checker itself is unmodified and the exit code is a real
|
|
112
|
+
process exit code.
|
|
113
|
+
|
|
114
|
+
gate-evidence:
|
|
115
|
+
- gate: suite
|
|
116
|
+
result: green
|
|
117
|
+
wrapper-exit-code: 0
|
|
118
|
+
discovered: 507
|
|
119
|
+
passed: 505
|
|
120
|
+
failed: 0
|
|
121
|
+
skipped: 2
|
|
122
|
+
todo: 0
|
|
123
|
+
did-not-run: 0
|
|
124
|
+
|
|
125
|
+
claims:
|
|
126
|
+
- id: W-1
|
|
127
|
+
kind: open-question
|
|
128
|
+
statement: >-
|
|
129
|
+
I did not find a way to express "this array is empty" in the declared
|
|
130
|
+
authoring vocabulary, so the rule that a report with no findings must
|
|
131
|
+
carry a no-findings-statement is not schema-enforced.
|
|
132
|
+
|
|
133
|
+
- id: W-2
|
|
134
|
+
kind: coverage
|
|
135
|
+
statement: >-
|
|
136
|
+
Registering report.schema.json as a companion is what makes the
|
|
137
|
+
work-history schema compile; without it the compilation fails closed.
|
|
138
|
+
settled-by:
|
|
139
|
+
executed-construction:
|
|
140
|
+
command: >-
|
|
141
|
+
node --input-type=module -e "import {compileSchema} from
|
|
142
|
+
'./src/validate.ts'; import {readFileSync} from 'node:fs'; const s =
|
|
143
|
+
JSON.parse(readFileSync('schemas/work-history.schema.json','utf8'));
|
|
144
|
+
const r = compileSchema(s); console.log(r.ok ? 'compiled' : r.reason);"
|
|
145
|
+
exit-code: 0
|
|
146
|
+
output: |
|
|
147
|
+
INVALID # schema reference report.schema.json#/$defs/gateResult does not resolve
|
|
148
|
+
|
|
149
|
+
fix-round:
|
|
150
|
+
- mechanism: >-
|
|
151
|
+
A schema document compiled without the sibling documents its references
|
|
152
|
+
reach, so a reference that leaves the document fails closed at
|
|
153
|
+
compilation rather than resolving.
|
|
154
|
+
derivation:
|
|
155
|
+
command: "grep -rn 'compileSchema(\\|validateInstance(\\|validateToLines(' src/ bin/ | grep -v '^src/validate.ts:'"
|
|
156
|
+
output: |
|
|
157
|
+
src/gates/run.ts:361: const diagnostics = formatDiagnostics(validateInstance(schema, decoded.value));
|
|
158
|
+
src/gates/validate.ts:524: return validateInstance(schema, instance) as Diagnostic[];
|
|
159
|
+
src/gates/validate.ts:528:export function validateToLines(
|
|
160
|
+
src/commands/mode.ts:125: const lines = formatDiagnostics(validateInstance(loadTypeSchema(MODES_TYPE), read.raw));
|
|
161
|
+
src/commands/validate.ts:273: const diagnostics = validateInstance(
|
|
162
|
+
src/commands/status.ts:127: const diagnostics = validateInstance(loadTypeSchema("status-line"), record);
|
|
163
|
+
not-covered: >-
|
|
164
|
+
The search covered src/ and bin/ only. It did NOT cover test/, where the
|
|
165
|
+
same functions are reached through a computed dynamic import and a
|
|
166
|
+
literal grep would find the import rather than the call; it did not cover
|
|
167
|
+
scripts/, which reaches the validator only through src/gates/result.ts
|
|
168
|
+
and compiles no schema of its own; and it did not cover dist/, which is
|
|
169
|
+
generated and never committed.
|
|
170
|
+
|
|
171
|
+
environment-warnings:
|
|
172
|
+
- warning: >-
|
|
173
|
+
A checkout whose node_modules predates M3-P3 fails npm run build at
|
|
174
|
+
build:runtime-deps, because commonmark is a dependency added by that
|
|
175
|
+
phase and the copy step reads its package.json directly.
|
|
176
|
+
evidence: >-
|
|
177
|
+
npm run build exited 1 with ENOENT on node_modules/commonmark/package.json;
|
|
178
|
+
npm ci then npm run build exited 0.
|
|
179
|
+
- warning: >-
|
|
180
|
+
This container's default toolchain is node v22.22.2, below the declared
|
|
181
|
+
engine floor, so EBADENGINE warnings appear on every npm operation and
|
|
182
|
+
two floor-gated tests skip.
|
|
183
|
+
evidence: >-
|
|
184
|
+
node --version printed v22.22.2 in the shell that ran the suite, and the
|
|
185
|
+
captured wrapper run reports 507 reported, 505 pass, 2 skipped.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# tuition/
|
|
2
|
+
|
|
3
|
+
The tuition feed: one document per failure mode a delivery paid for, and the
|
|
4
|
+
mechanism index projected out of them.
|
|
5
|
+
|
|
6
|
+
**`tuition/mechanism-index.yaml` is the index. Read it before you use a
|
|
7
|
+
mechanism.** It is GENERATED by `tiphys tuition index` from the `mechanisms[]`
|
|
8
|
+
field of the entries beside it, so a rule is recorded once, in the entry that
|
|
9
|
+
paid for it. Do not edit it by hand; `tiphys tuition index --check` exits
|
|
10
|
+
nonzero on any drift and names the mechanism and the entry it came from. It
|
|
11
|
+
supersedes the interim markdown table this repository kept at its root until
|
|
12
|
+
M3-P8, which was deleted rather than kept for reference, because two indexes is
|
|
13
|
+
the state T-005 exists to prevent and a file kept for reference is a file
|
|
14
|
+
someone will edit. Git history keeps it losslessly, and a verbatim capture of
|
|
15
|
+
it lives at test/fixtures/mechanisms-interim.md:1 as the independent source a
|
|
16
|
+
registered test uses to prove no row was dropped.
|
|
17
|
+
|
|
18
|
+
## What is here
|
|
19
|
+
|
|
20
|
+
| Path | What it is |
|
|
21
|
+
|---|---|
|
|
22
|
+
| `T-nnn.yaml` | one tuition entry, validated by `schemas/tuition.schema.json` |
|
|
23
|
+
| `mechanism-index.yaml` | the generated projection, validated by `schemas/mechanism-index.schema.json` |
|
|
24
|
+
|
|
25
|
+
Two layers, deliberately. The INDEX is the read layer: dense, consulted at
|
|
26
|
+
every dispatch. The ENTRIES are the archive layer: longer, read when a rule is
|
|
27
|
+
disputed.
|
|
28
|
+
|
|
29
|
+
## The commands
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
tiphys validate --type tuition --context . tuition/T-005.yaml
|
|
33
|
+
tiphys tuition add --file <entry> # validate, then file it under its id
|
|
34
|
+
tiphys tuition list [--kernel-relevant] # id, date, target count
|
|
35
|
+
tiphys tuition index [--check] # regenerate, or fail on drift
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`add` writes with an exclusive create, so an id already in the feed is a loud
|
|
39
|
+
refusal rather than an overwrite. A `T-nnn` id is never renumbered and never
|
|
40
|
+
reused after retirement, and this feed shares that one id space with the
|
|
41
|
+
delivering project's own log.
|
|
42
|
+
|
|
43
|
+
## Two rules that are not negotiable
|
|
44
|
+
|
|
45
|
+
**A rule with no citation is not a rule.** Every `mechanisms[]` entry requires
|
|
46
|
+
a non-empty `evidence[]`, and the schema rejects one without it. That is
|
|
47
|
+
T-005's checkability rule as a validation failure rather than as advice.
|
|
48
|
+
|
|
49
|
+
**An entry that claims kernel relevance and proposes no change to any kernel
|
|
50
|
+
artifact is not tuition, it is an anecdote.** `kernel-relevant: true` requires
|
|
51
|
+
at least one `structural-consequence`, each carrying the artifact it targets
|
|
52
|
+
and whether the change is `proposed`, `applied` or `ticketed`.
|
|
53
|
+
|
|
54
|
+
## R-070: a pipeline flaw is fixed immediately
|
|
55
|
+
|
|
56
|
+
**When the flaw is in the DELIVERY PROCESS rather than in the product, the fix
|
|
57
|
+
is a hotfix promoted to next in queue, not a backlog item.** A process defect
|
|
58
|
+
keeps charging rent: every phase dispatched between discovering it and fixing
|
|
59
|
+
it pays for it again, which is why deferring it is more expensive than it
|
|
60
|
+
looks. File the tuition entry when you discover it, not at the end, and carry
|
|
61
|
+
the fix in the same queue position as a production defect.
|
|
62
|
+
|
|
63
|
+
The orchestrator's half of this rule (who promotes, and what happens to work
|
|
64
|
+
already in flight) is stated in the orchestrator brief shipped by M3-P9, whose
|
|
65
|
+
clause id is reserved here as `hotfix-promotion`. The checkable half that
|
|
66
|
+
exists today is the retention check below.
|
|
67
|
+
|
|
68
|
+
## R-098: the retention duty
|
|
69
|
+
|
|
70
|
+
A project charter declares `retention` paths for its work histories, its
|
|
71
|
+
evidence and its tuition. `tiphys doctor` reads them and reports `CHECK
|
|
72
|
+
retention`: a declared path that is absent, or that is git-ignored in the fleet
|
|
73
|
+
or the project repository, is a FAIL naming the path, because evidence that is
|
|
74
|
+
ignored is evidence that will not survive the next clone. A fleet whose charter
|
|
75
|
+
declares no retention at all is a WARN under the generic profile and a FAIL
|
|
76
|
+
under `--for full`, never a silent pass.
|