@andresmassello/uscha 2.1.0 → 2.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.
Files changed (32) hide show
  1. package/README.md +21 -4
  2. package/package.json +1 -1
  3. package/uscha-kit/.claude/skills/uscha-adr-refine/SKILL.md +2 -0
  4. package/uscha-kit/.claude/skills/uscha-characterize/SKILL.md +2 -0
  5. package/uscha-kit/.claude/skills/uscha-devloop/SKILL.md +141 -8
  6. package/uscha-kit/.claude/skills/uscha-devloop/qa_ledger.py +1946 -74
  7. package/uscha-kit/.claude/skills/uscha-discovery/SKILL.md +58 -4
  8. package/uscha-kit/.claude/skills/uscha-mirador/SKILL.md +2 -0
  9. package/uscha-kit/.claude/skills/uscha-reverse-discovery/SKILL.md +2 -0
  10. package/uscha-kit/.claude/skills/uscha-rubric/SKILL.md +2 -0
  11. package/uscha-kit/.claude/skills/uscha-status/SKILL.md +40 -0
  12. package/uscha-kit/.claude/skills/uscha-sysdoc/SKILL.md +2 -0
  13. package/uscha-kit/.claude-plugin/plugin.json +2 -2
  14. package/uscha-kit/.codex-plugin/plugin.json +1 -1
  15. package/uscha-kit/README.md +229 -5
  16. package/uscha-kit/VERSION +1 -1
  17. package/uscha-kit/install-uscha.py +18 -2
  18. package/uscha-kit/skills/uscha-adr-refine/SKILL.md +2 -0
  19. package/uscha-kit/skills/uscha-characterize/SKILL.md +2 -0
  20. package/uscha-kit/skills/uscha-devloop/SKILL.md +141 -8
  21. package/uscha-kit/skills/uscha-devloop/qa_ledger.py +1946 -74
  22. package/uscha-kit/skills/uscha-discovery/SKILL.md +58 -4
  23. package/uscha-kit/skills/uscha-mirador/SKILL.md +2 -0
  24. package/uscha-kit/skills/uscha-reverse-discovery/SKILL.md +2 -0
  25. package/uscha-kit/skills/uscha-rubric/SKILL.md +2 -0
  26. package/uscha-kit/skills/uscha-status/SKILL.md +40 -0
  27. package/uscha-kit/skills/uscha-sysdoc/SKILL.md +2 -0
  28. package/uscha-kit/templates/CLAUDE.md +16 -0
  29. package/uscha-kit/templates/CONSTITUTION.md +45 -0
  30. package/uscha-kit/templates/docs/adr/README.md +15 -0
  31. package/uscha-kit/templates/scripts/smoke-report-example.json +24 -0
  32. package/uscha-kit/uscha.config.json +6 -1
@@ -19,6 +19,8 @@ shape.** Your job is to interrogate until there is a shared system shape, and to
19
19
  the documents as you go — not to ask the human to design the system for you.
20
20
 
21
21
  <!-- uscha:orientation-block:begin -->
22
+ <!-- uscha kit: 2.2.0 -- generated region: edit tools/skill-blocks/, then run `python tools/gen-skill-blocks.py` (never this block by hand) -->
23
+
22
24
  ## First contact (show ONCE, then never again)
23
25
 
24
26
  **Only when this project has no uscha artifacts yet** -- no `QA-LEDGER.json`, no `SPEC.md` or
@@ -94,9 +96,16 @@ Keep the CONTENT in the conversation's language, but keep the labels (`CLOSED`,
94
96
  that makes discovery work: you propose (entities, endpoints, architecture, a default
95
97
  decision), the human confirms or corrects. Never dump a list of 20 questions, and
96
98
  never ask the human to supply structure you can propose yourself.
97
- 2. **Explore instead of asking.** If a reference doc/URL/PDF, the existing codebase, or
98
- an existing `CONTEXT.md`/`docs/adr/` can answer a question, read it first. Only ask
99
- the human what genuinely requires their judgment.
99
+ **Close every question round item by item.** Before moving on, list what YOU decided in
100
+ that round and ask the human to confirm each one SEPARATELY — an "ok" over a twenty-item
101
+ summary is a rebound, not a decision, and it is exactly how a global default became a
102
+ tree-wide rename nobody had asked for. Write the answer onto the item as it arrives
103
+ (principle 6).
104
+ 2. **Explore instead of asking — ask for DECISIONS, never for INFORMATION** (ADR-044). If a
105
+ reference doc/URL/PDF, the existing codebase, or an existing `CONTEXT.md`/`docs/adr/`
106
+ can answer a question, read it first. The current version of a tracked file, what a
107
+ config says, whether a test exists: all information — READ it. Only ask the human what
108
+ genuinely requires their judgment.
100
109
  3. **Propose the shape.** From the idea + references, propose the core entities, the
101
110
  operation/API surface, and 2–3 architecture options with trade-offs. Walk the design
102
111
  tree branch by branch, resolving dependencies between decisions one at a time.
@@ -105,6 +114,14 @@ Keep the CONTENT in the conversation's language, but keep the labels (`CLOSED`,
105
114
  failed.
106
115
  5. **Write files lazily and inline.** Create a file only when you have something real to
107
116
  write, and update it the moment a decision crystallizes — don't batch to the end.
117
+ 6. **Mark what YOU decided: `origin: agent`.** Any acceptance criterion, ADR decision item
118
+ or HANDOFF rule that came from your proposal rather than from a human answer is written
119
+ with the marker on its own line — `(origin: agent)` while it is unconfirmed, and
120
+ `(origin: agent, confirmed: YYYY-MM-DD)` the moment the human confirms THAT item. Items
121
+ with no marker are human-origin by default; nothing already written is retro-tagged. An
122
+ unconfirmed item is NOT in scope: it is written down so it is visible, never so it is
123
+ agreed. `spec-check` names the unconfirmed ones with file:line (advisory — it changes no
124
+ exit code), and your close block lists them.
108
125
 
109
126
  ## Inputs
110
127
 
@@ -137,6 +154,17 @@ answer.
137
154
  1. **Purpose / value / why now.** What job does this remove? Cost of not doing it?
138
155
  2. **Domain model.** Propose the core entities and their relationships. ("From the domain
139
156
  I deduce these core entities: … do they work for you, or is one missing?")
157
+ Then ask, MANDATORY, before the round closes (ADR-046): **"what input comes from the REAL
158
+ world, and where is the corpus?"** In greenfield every test payload is invented by the agent
159
+ that writes the code, so a green suite can be silent about the inputs the world actually
160
+ produces — one field build shipped a parser that passed every test its author wrote and was
161
+ 96.96 % right on the real corpus. Name the real-input surfaces (files, payloads, messages,
162
+ documents), ask WHERE a sample with its expected outputs can be obtained, and record the path
163
+ as `repos[R].corpus` in `uscha.config.json` so `qa_ledger.py corpus-run` can score it.
164
+ **No corpus on day 1 is not a blocker — it is a HIGH risk in `RISKS.md` with an OWNER and a
165
+ date.** Do not invent one: a corpus the agent authored is the same invented input this
166
+ question exists to expose. The percentage gates nothing until the project declares a budget
167
+ (`corpus_threshold`), which is round 10's decision, not the kit's.
140
168
  3. **Operation / API surface.** Propose the endpoints/operations and their
141
169
  contracts (idempotency, status codes).
142
170
  4. **Stack and lifecycle (MANDATORY — before any stack/architecture decision is
@@ -187,6 +215,18 @@ answer.
187
215
  `spike/*` branch and its ONLY legitimate output is an **ADR with lessons**
188
216
  (facts that feed the SPEC) — never mergeable code. The contract is executable:
189
217
  `phase --require pr-ready` refuses any `spike/*` branch, INV-GOLDEN-01 style.
218
+ 12. **Operability — who owns the RUNBOOK and the seed? (kit 2.2.0, ADR-048).** Ask it on
219
+ DAY 1, with your recommended answer, because the cheapest moment to decide it is before
220
+ anything is built and the most expensive is the week before go-live: who writes and owns
221
+ the **RUNBOOK** (start/boot, config, rollback, smoke), who owns the **seed/reset**
222
+ command that puts a fresh environment into a known state, and who owns the **release
223
+ workflow** that publishes the artifact. Record the answers as they crystallize:
224
+ `defaults.operability.seed_command` (or `repos[R].operability.seed_command`) in
225
+ `uscha.config.json`, and the RUNBOOK at `docs/RUNBOOK.md`. This is MEASURED, not
226
+ narrated — `qa_ledger.py operability --repo <REPO>` reads the four facts out of the tree,
227
+ and on risk profiles C/D/E a missing one is a BLOCKER, so a project that defers them
228
+ cannot reach `pr-ready`. Two field projects discovered all four in their last week; the
229
+ question costs one minute here.
190
230
 
191
231
  ## Files to write (lazily, inline)
192
232
 
@@ -210,7 +250,9 @@ answer.
210
250
  `Rollback / Supersede Criteria`.
211
251
  - **`ACCEPTANCE.md`** — Definition of Done as `- [ ]` checkboxes + success metrics. This
212
252
  is the file the readiness KPI measures downstream. Give EVERY criterion a stable
213
- traceable ID: `- [ ] AC-01 — when X then Y` (sequential, never reused). Downstream,
253
+ traceable ID: `- [ ] AC-01 — when X then Y` (sequential, never reused); a criterion YOU
254
+ proposed also carries the `origin: agent` marker of principle 6 until the human confirms
255
+ it item by item. Downstream,
214
256
  a criterion only closes MEASURED when a green testcase carries its tag in the name
215
257
  (`test_ac1_x` / `testAC01X` / `"AC-01: ..."`) — write criteria so each one is
216
258
  coverable by at least one named test.
@@ -231,6 +273,18 @@ as explicit assumptions), every failure mode has defined behavior, out-of-scope
231
273
  explicit, and the DoD is checkable. State plainly that it converged, then write/finalize
232
274
  the package and the handoff.
233
275
 
276
+ **The close block names what is still unconfirmed.** Before you emit it, run
277
+
278
+ ```bash
279
+ python3 <path-to>/qa_ledger.py spec-check --spec SPEC.md --acceptance ACCEPTANCE.md
280
+ ```
281
+
282
+ and copy the `~ origin: N agent-origin item(s) unconfirmed` list into `Blocks:` — one item
283
+ per line, with its file and line. Those are the decisions the human still owes; converging
284
+ with them silently in the package is the failure this marker exists to prevent. `Produced:`
285
+ still lists the files. If the list is empty, `Blocks:` says `nothing` as it always did:
286
+ silence and an explicit `nothing` are not the same fact.
287
+
234
288
  ## Handoff
235
289
 
236
290
  End with the implementation handoff (works for a human, an agent, or CI):
@@ -18,6 +18,8 @@ Paints the REAL state of the project at a glance. It does not narrate or estimat
18
18
  wires the JSON the engine emits into the template. Read-only.
19
19
 
20
20
  <!-- uscha:orientation-block:begin -->
21
+ <!-- uscha kit: 2.2.0 -- generated region: edit tools/skill-blocks/, then run `python tools/gen-skill-blocks.py` (never this block by hand) -->
22
+
21
23
  ## Orientation markers (non-negotiable)
22
24
 
23
25
  The operator must never have to ask "where am I?" or "what happens now?".
@@ -24,6 +24,8 @@ evidence-classed, content-addressed, and promoted to the contract only by a per-
24
24
  human verdict (ADR-013).**
25
25
 
26
26
  <!-- uscha:orientation-block:begin -->
27
+ <!-- uscha kit: 2.2.0 -- generated region: edit tools/skill-blocks/, then run `python tools/gen-skill-blocks.py` (never this block by hand) -->
28
+
27
29
  ## First contact (show ONCE, then never again)
28
30
 
29
31
  **Only when this project has no uscha artifacts yet** -- no `QA-LEDGER.json`, no `SPEC.md` or
@@ -22,6 +22,8 @@ the grader — this skill just wraps the neutral prompt so Claude Code users get
22
22
  in one command. Never add Claude-specific behavior to the contract.
23
23
 
24
24
  <!-- uscha:orientation-block:begin -->
25
+ <!-- uscha kit: 2.2.0 -- generated region: edit tools/skill-blocks/, then run `python tools/gen-skill-blocks.py` (never this block by hand) -->
26
+
25
27
  ## First contact (show ONCE, then never again)
26
28
 
27
29
  **Only when this project has no uscha artifacts yet** -- no `QA-LEDGER.json`, no `SPEC.md` or
@@ -19,7 +19,47 @@ skill (**pull** — one screen when the human asks), and the **mirador** (bird's
19
19
  HTML). This skill exists because some surfaces never show a statusline; the answer
20
20
  is the same data, printed in chat when requested.
21
21
 
22
+ ## Before the readout: are the installed skills older than the kit? (2.2.0)
23
+
24
+ A field report found `~/.claude/skills/uscha-*` still on 1.54.0 while the kit in the repo was
25
+ 1.97.0. An entire discovery ran on prose three months stale and NOTHING said so, because a
26
+ SKILL.md carried no version to compare. Since 2.2.0 every generated orientation block opens with
27
+ `<!-- uscha kit: X.Y.Z ... -->`, so the comparison is mechanical. Do it FIRST, before the
28
+ breadcrumb:
29
+
30
+ 1. Run the engine's own check — it reads the marker out of every installed `SKILL.md` and
31
+ compares it against the kit's `VERSION`:
32
+
33
+ ```
34
+ python <kit>/.claude/skills/uscha-devloop/qa_ledger.py doctor --json
35
+ ```
36
+
37
+ Read `skills_installed`: one row per install root the installer writes to (Claude
38
+ `~/.claude/skills/`, Codex `~/plugins/uscha/skills/`, pi `~/.agents/skills/`, and the other
39
+ Agent-Skills roots), each with `status`, `installed` and `kit`. `doctor` exits 0 whether or
40
+ not anything is outdated — this reports, it never gates.
41
+ 2. If any row reads `outdated`, print exactly ONE line ABOVE the breadcrumb, then continue
42
+ normally:
43
+
44
+ ```
45
+ SKILLS OUTDATED: installed 1.54.0 < kit 2.2.0 -- run `python install-uscha.py install --target claude`
46
+ ```
47
+
48
+ Where the installed block predates 2.2.0 and carries no marker at all, `installed` is null:
49
+ say `installed <no kit: marker, pre-2.2.0>` rather than inventing a version.
50
+ 3. `not installed` is NOT a finding — the kit installs one agent at a time, and six absent roots
51
+ are the normal shape of a healthy machine. Say nothing about them.
52
+
53
+ Advisory, always: the line never blocks the readout, never changes a number, and the block below
54
+ prints exactly as it would have. What it removes is the silence.
55
+
56
+ Honest limit: an installed skill that predates 2.2.0 does not carry these instructions, so on
57
+ that surface the warning cannot come from the skill itself. The `doctor` seam is the instrument
58
+ that still works there — it runs from any kit checkout and reads the installs from outside.
59
+
22
60
  <!-- uscha:orientation-block:begin -->
61
+ <!-- uscha kit: 2.2.0 -- generated region: edit tools/skill-blocks/, then run `python tools/gen-skill-blocks.py` (never this block by hand) -->
62
+
23
63
  ## Orientation markers (non-negotiable)
24
64
 
25
65
  The operator must never have to ask "where am I?" or "what happens now?".
@@ -22,6 +22,8 @@ switch between at any time:
22
22
  coverage, known deferred issues.
23
23
 
24
24
  <!-- uscha:orientation-block:begin -->
25
+ <!-- uscha kit: 2.2.0 -- generated region: edit tools/skill-blocks/, then run `python tools/gen-skill-blocks.py` (never this block by hand) -->
26
+
25
27
  ## First contact (show ONCE, then never again)
26
28
 
27
29
  **Only when this project has no uscha artifacts yet** -- no `QA-LEDGER.json`, no `SPEC.md` or
@@ -33,6 +33,22 @@ each change lives in `SPEC.md` / `docs/adr/` / `ACCEPTANCE.md`, not here.
33
33
  forces a SPEC change, version it and go back to Ready.
34
34
  9. **Human gate.** Don't merge or release automatically. You stop at the PR; the merge and
35
35
  the smoke test in a real environment are decided by a person.
36
+ 10. **Ask for DECISIONS, never for INFORMATION — and mark what the agent decided.** What the
37
+ tree holds (the current version of a tracked file, what a config says, whether a test
38
+ exists) is READ, never asked. What the human has not decided is never entered silently:
39
+ every acceptance criterion, ADR decision item or `HANDOFF.md` rule the AGENT introduced
40
+ carries a trailing marker on its own line —
41
+
42
+ ```
43
+ - [ ] AC-12 — when X then Y. (origin: agent)
44
+ - [ ] AC-12 — when X then Y. (origin: agent, confirmed: 2026-09-07)
45
+ ```
46
+
47
+ Items with no marker are human-origin by default; nothing existing is retro-tagged. An
48
+ unconfirmed item is **not in scope**: it is confirmed ITEM BY ITEM, and a package-level
49
+ "ok" confirms none of them. `qa_ledger.py spec-check` names the unconfirmed ones with
50
+ file:line and `readiness` counts them on their own line — both advisory: they change no
51
+ exit code and cap no score.
36
52
 
37
53
  ## Truth hierarchy
38
54
 
@@ -154,6 +154,51 @@ enforcing the record is the engine's job. It is never resolved by "working aroun
154
154
  asserts and **new dependencies** (the "0 deps without approval" rule, made visible —
155
155
  kit 1.30.0) = review (or `--strict`). For high blast-radius a checker
156
156
  uncorrelated with the maker (different family/profile) is also required — that is process, not code.
157
+ - The **CI pipeline** is a FACT gate without an invariant of its own: `log-gate --kind ci
158
+ --verdict <pass|fail|not-run>` records what the pipeline actually did, with `--ref <run URL or
159
+ id>` as the receipt. A `fail` is a **BLOCKER** — readiness cap ≤ 65 and convergence blocked —
160
+ exactly like `gate-check`; a `not-run` records absence and leaves the last state standing.
161
+ `--verdict advisory` is REFUSED on it, as on every FACT gate. It is admitted to the closed
162
+ `--kind` vocabulary (ADR-014, INV-ADVISORY-01) because a pipeline either went green on a
163
+ commit or it did not: an LLM judgment does not become a gate by being important.
164
+ - The **Field truth** invariant (greenfield) is measured by `qa_ledger.py corpus-run`: a JSONL
165
+ corpus of REAL inputs with their real expected outputs, run through the real command, scored
166
+ as hits/total. In greenfield every test payload was invented by the agent that wrote the code,
167
+ so a green suite proves nothing about the inputs the world produces — and `characterize` has
168
+ no answer there, because there is no old code to be the truth. **Advisory by default**: the
169
+ percentage is measured and gates nothing until the project declares a budget (`--threshold`,
170
+ else `repos[R].corpus_threshold`, else `defaults.corpus_threshold`). With one declared, a run
171
+ under it is a **BLOCKER** — readiness cap ≤ 65, convergence blocked — exactly like
172
+ `gate-check`, persisted as `gate:corpus`. A corpus that is missing, empty or malformed is
173
+ **exit 2** naming the line, never a scored 0 %. `log-gate --kind corpus` is the parity door
174
+ for a run measured elsewhere and it DOES accept `--verdict advisory` — the third and last kind
175
+ that may, because the check's own default mode is advisory; every other FACT kind still
176
+ refuses it. `--ac AC-nn` stamps criteria on the record: a criterion whose only evidence is a
177
+ corpus record closes MEASURED iff that record passed (ADR-046).
178
+ - The **Smoke** invariant is measured by `qa_ledger.py smoke-ingest`: the smoke run is a
179
+ REPORT the project's own tool writes — `{"checks": [{"name": ..., "ok": true|false,
180
+ "status": ..., "latency_ms": ..., "evidence": ...}]}` — and never a sentence an agent
181
+ wrote. **Evidence is executed, not narrated**: "the endpoint answered 200" believed on an
182
+ agent's word is the failure mode this exists to remove, and it has already cost a release
183
+ (every run returned an empty list because the database had no rows). A failed check is a
184
+ **BLOCKER** — readiness cap ≤ 65, convergence blocked — persisted as `gate:smoke`, cleared
185
+ by a later clean report. A report that is missing, malformed, has no `checks`, holds an
186
+ EMPTY list, or carries a check without a `name` or a boolean `ok` is **exit 2** naming it:
187
+ a run that verified nothing is not a clean gate. `smoke` joins the closed `--kind`
188
+ vocabulary (ADR-014, INV-ADVISORY-01) as a FACT, and `--verdict advisory` is REFUSED on it
189
+ — a smoke check is binary, so there is no budget it could be measured against. A check
190
+ named `AC-nn ...` closes that criterion MEASURED when it is `ok` and its report passed; a
191
+ failed one vetoes it (ADR-047).
192
+ - The **Operability** invariant is measured by `qa_ledger.py operability --repo R` (ADR-048): four
193
+ FACTS read out of the tree — a `.github/workflows` step running the repo's **configured** test
194
+ command, a workflow that publishes or attaches a release asset, a `RUNBOOK.md` naming
195
+ start/config/rollback/smoke, and a declared `seed_command` whose script is on disk. Its own exit
196
+ code is always 0; the verdict is persisted as `gate:operability` and the POSTURE is the risk
197
+ profile's — **advisory** on A/B (caps nothing, blocks nothing, never counted as `ok`) and a
198
+ **BLOCKER** on C/D/E, where `defaults.operability.gate` is `true`: readiness cap ≤ 65,
199
+ convergence blocked, and `phase --require pr-ready` refuses naming the missing check. A CI
200
+ system this engine does not read is reported `unknown`, never green and never red. Release,
201
+ reset and the RUNBOOK are part of done, not of the last week.
157
202
  - The **Golden (INV-GOLDEN-01)** invariant is measured by `qa_ledger.py golden-diff`: any `.received`
158
203
  that does not match its `.approved` (or is unapproved) = **DIVERGE**, cutting the chain before judgment-day.
159
204
  The agent does not touch `.approved` (ideally a `PreToolUse` hook makes it impossible).
@@ -13,6 +13,21 @@ machine-readable `lifecycle:` frontmatter block (component / version / eol / sou
13
13
  that `spec-check` compares against the SPEC's declared `go_live` (ADR-040). Advisory: it reports,
14
14
  it never gates.
15
15
 
16
+ A **decision item the AGENT introduced** — one that came from the agent's proposal rather
17
+ than from a human answer — carries a trailing marker on its own line:
18
+
19
+ ```
20
+ - D-03 — the tree is renamed to English. (origin: agent)
21
+ - D-03 — the tree is renamed to English. (origin: agent, confirmed: 2026-09-07)
22
+ ```
23
+
24
+ Items with no marker are human-origin by default (nothing already written is retro-tagged).
25
+ An unconfirmed item is NOT in scope: it is confirmed one item at a time, never by a
26
+ package-level "ok". `spec-check` lists the unconfirmed ones with file:line and `readiness`
27
+ counts them on a line of their own; both are advisory — no exit code, no score changes. A
28
+ marker inside a fenced block or an inline code span (like the two above) is documentation and
29
+ is skipped.
30
+
16
31
  `Status: Experiment` is for a bounded, reversible hypothesis that needs real feedback.
17
32
  It must include: Hypothesis, Feedback Signal, Review By or Review Trigger, Promote
18
33
  Criteria, and Rollback / Supersede Criteria. Missing/expired metadata is advisory in
@@ -0,0 +1,24 @@
1
+ {
2
+ "checks": [
3
+ {
4
+ "name": "AC-01 the API serves /health under the real database",
5
+ "ok": true,
6
+ "status": 200,
7
+ "latency_ms": 6,
8
+ "evidence": "curl -sS http://localhost:8080/health -> {\"status\":\"UP\",\"db\":\"UP\"}"
9
+ },
10
+ {
11
+ "name": "the catalogue endpoint returns the seeded rows",
12
+ "ok": true,
13
+ "status": 200,
14
+ "latency_ms": 41,
15
+ "evidence": "GET /catalogue -> 128 items (the seed loads 128; an EMPTY list is the failure this check exists to catch)"
16
+ },
17
+ {
18
+ "name": "an unauthenticated write is rejected",
19
+ "ok": true,
20
+ "status": 401,
21
+ "evidence": "POST /catalogue with no token -> 401"
22
+ }
23
+ ]
24
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "_comment": "COMPREHENSIVE REFERENCE, not a project config. Every knob the engine and the skills understand, at the kit's own value, so a human can read what can be declared. `uscha init` does NOT copy this file: it GENERATES a minimal project config, because a copied default is an explicit declaration and an explicit declaration outranks the preset named by defaults.risk_profile (ADR-001, as amended). Copy a block from here into your project only when you mean to override the engine default or the preset. NOTE: no version string may be written into this comment -- the release script requires exactly one occurrence of the version in this file (I3), and a second one refuses the next release.",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "project": null,
5
5
  "defaults": {
6
6
  "coverage_threshold": 60,
@@ -84,6 +84,11 @@
84
84
  "allow_paths": [],
85
85
  "gate": false
86
86
  },
87
+ "operability": {
88
+ "runbook": "docs/RUNBOOK.md",
89
+ "seed_command": "make seed",
90
+ "gate": false
91
+ },
87
92
  "execution_policy": {
88
93
  "default": {
89
94
  "tier": "standard",