@bongos/core 1.19.33 → 1.19.35
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/.bongos-core.json +24 -14
- package/.claude/skills/grade-recover/SKILL.md +81 -0
- package/docs/file-map.md +1 -0
- package/modules/lifecycle/db.js +1 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/src/module-api.js +5 -1
- package/tests/migration_allocation.mjs +35 -0
- package/tests/skill_grade_recover.mjs +40 -0
package/.bongos-core.json
CHANGED
|
@@ -2,22 +2,22 @@
|
|
|
2
2
|
"artifact": "bongos-core",
|
|
3
3
|
"manifest_schema": 1,
|
|
4
4
|
"generator": "scripts/gds/package-core.js",
|
|
5
|
-
"core_version": "1.19.
|
|
6
|
-
"core_contract": "1.19.
|
|
7
|
-
"source_commit": "
|
|
5
|
+
"core_version": "1.19.35",
|
|
6
|
+
"core_contract": "1.19.35",
|
|
7
|
+
"source_commit": "ed10537c5e177fa94fe6d62f3d22010b21b96309",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-08-11T15:
|
|
9
|
+
"built_at": "2026-08-11T15:30:07.990Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
|
-
"docs_redacted":
|
|
12
|
+
"docs_redacted": 287,
|
|
13
13
|
"agent_docs_stubbed": 21,
|
|
14
|
-
"functional_verbatim":
|
|
14
|
+
"functional_verbatim": 1209,
|
|
15
15
|
"rules": 3,
|
|
16
16
|
"gate_literals": 3,
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
|
-
"file_count":
|
|
20
|
-
"tree_sha256": "
|
|
19
|
+
"file_count": 1517,
|
|
20
|
+
"tree_sha256": "5aed9fd6f14ef47f488c966238b31f4909eab157cc8052ddc3ff5279553f63b4",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/blocker-review/SKILL.md",
|
|
@@ -154,6 +154,11 @@
|
|
|
154
154
|
"mode": "0000644",
|
|
155
155
|
"sha256": "e789b9157c9817bac354eaeed8152b53f3013f677934b062bca1c8e07f1f2dc8"
|
|
156
156
|
},
|
|
157
|
+
{
|
|
158
|
+
"path": ".claude/skills/grade-recover/SKILL.md",
|
|
159
|
+
"mode": "0000644",
|
|
160
|
+
"sha256": "e0bf90fa006499aee0a7d75f10fe4b5972c9501129b1e432e7d6e192b367a54c"
|
|
161
|
+
},
|
|
157
162
|
{
|
|
158
163
|
"path": ".claude/skills/idea-triage/SKILL.md",
|
|
159
164
|
"mode": "0000644",
|
|
@@ -1352,7 +1357,7 @@
|
|
|
1352
1357
|
{
|
|
1353
1358
|
"path": "docs/file-map.md",
|
|
1354
1359
|
"mode": "0000644",
|
|
1355
|
-
"sha256": "
|
|
1360
|
+
"sha256": "a499551f07ce8f6382aba46641fb06fa8e499d486433ee3bf266f264abac29ca"
|
|
1356
1361
|
},
|
|
1357
1362
|
{
|
|
1358
1363
|
"path": "docs/handoff-template.md",
|
|
@@ -3362,7 +3367,7 @@
|
|
|
3362
3367
|
{
|
|
3363
3368
|
"path": "modules/lifecycle/db.js",
|
|
3364
3369
|
"mode": "0000644",
|
|
3365
|
-
"sha256": "
|
|
3370
|
+
"sha256": "77528182c408edf2b8f3e07382bb83f97a7d668b979e97e60e4ff0c2e1bc7109"
|
|
3366
3371
|
},
|
|
3367
3372
|
{
|
|
3368
3373
|
"path": "modules/lifecycle/done-when.js",
|
|
@@ -4012,12 +4017,12 @@
|
|
|
4012
4017
|
{
|
|
4013
4018
|
"path": "package-lock.json",
|
|
4014
4019
|
"mode": "0000644",
|
|
4015
|
-
"sha256": "
|
|
4020
|
+
"sha256": "5d9d99834a61e13a39b7a79c6c337259d36475945e2616810418464e9e27c3b2"
|
|
4016
4021
|
},
|
|
4017
4022
|
{
|
|
4018
4023
|
"path": "package.json",
|
|
4019
4024
|
"mode": "0000644",
|
|
4020
|
-
"sha256": "
|
|
4025
|
+
"sha256": "c5d824c553faff45e6fe3c4210711ba5bf898f876fcb7f87899912d0a335e6b6"
|
|
4021
4026
|
},
|
|
4022
4027
|
{
|
|
4023
4028
|
"path": "public-docs/index.html",
|
|
@@ -5637,7 +5642,7 @@
|
|
|
5637
5642
|
{
|
|
5638
5643
|
"path": "src/module-api.js",
|
|
5639
5644
|
"mode": "0000644",
|
|
5640
|
-
"sha256": "
|
|
5645
|
+
"sha256": "c1c97e893073f2c398cc2a792b338b28dd18cd78824186bcb875b279fc587ec1"
|
|
5641
5646
|
},
|
|
5642
5647
|
{
|
|
5643
5648
|
"path": "src/module-loader/loader.js",
|
|
@@ -6832,7 +6837,7 @@
|
|
|
6832
6837
|
{
|
|
6833
6838
|
"path": "tests/migration_allocation.mjs",
|
|
6834
6839
|
"mode": "0000644",
|
|
6835
|
-
"sha256": "
|
|
6840
|
+
"sha256": "08db201ebec44ea5a711e3c86e36dda63ec22881a400e910dd7c64961c80f6e9"
|
|
6836
6841
|
},
|
|
6837
6842
|
{
|
|
6838
6843
|
"path": "tests/migration_namespace.mjs",
|
|
@@ -7444,6 +7449,11 @@
|
|
|
7444
7449
|
"mode": "0000644",
|
|
7445
7450
|
"sha256": "0eeccae9320f419667cf9ede3c13671a5b03571f7f2f17067bff1857234ddf91"
|
|
7446
7451
|
},
|
|
7452
|
+
{
|
|
7453
|
+
"path": "tests/skill_grade_recover.mjs",
|
|
7454
|
+
"mode": "0000644",
|
|
7455
|
+
"sha256": "76bed8e6fae3bd77d4b45be14d9f80bda71b2f92323fa5697a7e4f07b65d3ba2"
|
|
7456
|
+
},
|
|
7447
7457
|
{
|
|
7448
7458
|
"path": "tests/skill_prefs.mjs",
|
|
7449
7459
|
"mode": "0000644",
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: grade-recover
|
|
3
|
+
description: Walk a stuck, unavailable, or wrongly-failed grade to resolution — the "my grade failed, now what" loop. Diagnoses which of three shapes parked the task at completed (grader outage, fabricated/server-shape fail, or genuine quality fail), names the right recovery, and runs it. Triggers when the user says "/grade-recover N", "my grade failed", "the grader bounced my ship", "grader unavailable", "recover the grade on task N", "why did task N fail its grade", or after a /builder-ship lands at completed with a non-pass grade. Describes and recovers only — it adds no gate to the ship path (ADR 0162).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You are recovering a task whose ship parked at `completed` because of its grade. Your job is to diagnose WHICH of three distinct shapes did it — they look similar in a terminal scrollback and need opposite responses — then run the right recovery. You never add a new approval step: everything here is a documented, existing path (ADR 0162).
|
|
7
|
+
|
|
8
|
+
## What this skill does
|
|
9
|
+
|
|
10
|
+
Reads the persisted grade, branches on `panel_outcome` FIRST, then walks exactly one of three recovery branches. The re-grade command every branch eventually reaches is:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
node scripts/gds/ship.js <id> --regrade
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`--regrade` re-runs ONLY the grade step (no smoke/scanner re-run), reads **committed history, not the working tree**, applies only to a task at `completed`, is gated to the task's most-recent claim holder or an Archon, and has no attempt cap.
|
|
17
|
+
|
|
18
|
+
## Step 1 — Read the grade
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
node scripts/gds/api.js GET "/api/gds/tasks/<id>?include=grade,last_claim"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- Task not at `completed` → stop; there is nothing to recover. `confirmed`/`shipped` means the grade passed (a `confirmed` strand lands via the ~5-min reconciler; `/merge-mode` is the rare manual fallback). `active` means ship first.
|
|
25
|
+
- `grade: null` → the ship never reached the grade step; re-run `/builder-ship`, not `--regrade`.
|
|
26
|
+
- Otherwise diagnose from the grade row: `signals.panel_outcome`, `signals.server_guard`, `passed`, `rubric_scores`, `issues[]`.
|
|
27
|
+
|
|
28
|
+
## Step 2 — Diagnose, in this order
|
|
29
|
+
|
|
30
|
+
### Branch A — grader outage: `panel_outcome='unavailable'`
|
|
31
|
+
|
|
32
|
+
The panel could not run (worker infra outage or a pre-spawn bypass). This is **not a quality verdict** — no quality signal was produced, there are no findings to fix, and nothing about the work is being judged. Grade aggregates exclude these rounds (`n_unavailable`); an outage never counts as a zero.
|
|
33
|
+
|
|
34
|
+
1. Do NOT edit code. There is nothing to fix.
|
|
35
|
+
2. Check the grader can run now: the panel spawns `claude -p` subprocesses locally, so confirm the CLI is present and authenticated, and the instance API is reachable (`signals.grader_unavailable_reason` usually names the leg that died).
|
|
36
|
+
3. Re-grade: `node scripts/gds/ship.js <id> --regrade`.
|
|
37
|
+
|
|
38
|
+
### Branch B — fabricated / server-shape fail: the guard tripped or an axis was forged by an error
|
|
39
|
+
|
|
40
|
+
Two known sub-shapes, both recognizable because the "fail" carries **no substantive findings**:
|
|
41
|
+
|
|
42
|
+
- **Server-guard trip** (`signals.server_guard.tripped` non-empty, e.g. `implausible_pass`): the server downgraded a client-asserted pass it found implausible — historically this guard has fired on genuinely clean, unanimous zero-issue passes. Explain the downgrade honestly, then re-grade: `node scripts/gds/ship.js <id> --regrade`.
|
|
43
|
+
- **A FAIL scored around 4.5/10 with zero issues and a null/zero axis** (the errored-worker class): a worker error was forwarded as a real axis score. Same response — re-grade; the panel rerun replaces the forged shape with a real verdict.
|
|
44
|
+
|
|
45
|
+
If an honest re-grade re-trips the guard on a diff you can defend, use the **auditable override path** — file an override-request with a real rationale (≥20 chars; only the task's most-recent claim holder or an Archon may file; an Archon then decides it):
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
node scripts/gds/api.js POST /api/gds/tasks/<id>/override-request --body '{"rationale":"<why this grade is wrong, specifically>"}'
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Never volunteer the raw Archon confirm curl.** The override-request is the sanctioned exit precisely because it records who asked, why, and who decided — the raw confirm records none of that.
|
|
52
|
+
|
|
53
|
+
### Branch C — genuine quality fail: real findings in `issues[]`
|
|
54
|
+
|
|
55
|
+
The panel ran and rejected the work. Recover by fixing, not by re-rolling:
|
|
56
|
+
|
|
57
|
+
1. **Group `issues[]` by severity, then by worker.** Nit/minor findings are advisory by rubric policy — they cannot have caused the fail on their own, so do not start there. The fail came from blocker/major findings (or a gating axis under threshold).
|
|
58
|
+
2. **For each blocker/major finding, add a checked-in `tests/*.mjs` case** that reproduces it, then fix until green. The grader treats throwaway verification as unverified — the committed test is what makes the fix real.
|
|
59
|
+
3. **Fix real findings once; do not chase re-worded restatements** of a point you already answered (answer it in the commit or with a tracked task ref instead).
|
|
60
|
+
4. Commit on the claim branch — the grader reads committed history — then:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
node scripts/gds/ship.js <id> --regrade
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Not recoverable here — `REFUSED (authorization)`
|
|
67
|
+
|
|
68
|
+
A grade block naming protected surfaces above your rank is an authorization wall, not a quality verdict: no re-grade at your rank can land that diff as-is. Split the protected files out of the diff and re-ship the rest, or hand the task to a builder at/above the floor the refusal names.
|
|
69
|
+
|
|
70
|
+
## Constraints
|
|
71
|
+
|
|
72
|
+
- **ADR 0162 — no new gates.** This skill describes and recovers; it never inserts a human-approval step into the ship path, and it never invents a new checkpoint.
|
|
73
|
+
- **Diagnose before touching code.** Editing code in response to an outage (Branch A) or a guard trip (Branch B) wastes a panel round and muddies the audit trail.
|
|
74
|
+
- **`--regrade` is claim-scoped**: most-recent claim holder or Archon. If you are neither, the recovery belongs to whoever is.
|
|
75
|
+
- **Honest re-grade before any override.** The override-request path is for a grade that is *wrong*, not a grade that is *inconvenient*.
|
|
76
|
+
|
|
77
|
+
## Files this skill touches
|
|
78
|
+
|
|
79
|
+
- Reads: `GET /api/gds/tasks/:id?include=grade,last_claim` (the persisted grade row + regrade eligibility).
|
|
80
|
+
- Runs: `node scripts/gds/ship.js <id> --regrade` (the grade step only).
|
|
81
|
+
- Writes (Branch B escalation only): `POST /api/gds/tasks/:id/override-request`.
|
package/docs/file-map.md
CHANGED
|
@@ -350,6 +350,7 @@ tests/
|
|
|
350
350
|
├── fix-task/SKILL.md ← /fix-task N — claim, fix (test-first), verify, and ship a single GDS task by id end to end; defers to /builder-claim + /builder-ship for their own mechanics
|
|
351
351
|
├── goal-create/SKILL.md ← /goal-create — plan and create ONE goal (the module-scoped workspace between version and criteria, ADR 0086) in one session: <redacted>, scope wall, 2-4 criteria, seed tasks; also the auto-pickup when a task is created with no goal to live in (goal_advisory); Metic+ (Archon for a protected-module scope)
|
|
352
352
|
├── goal-review/SKILL.md ← /goal-review — walk the criterion review queue: each auto-flagged 'met — pending review' criterion gets confirm / reject / defer; confirming a goal's last criterion auto-achieves it (ADR 0086 §6); Metic+
|
|
353
|
+
├── grade-recover/SKILL.md ← /grade-recover N — the 'my grade failed, now what' loop: diagnose outage vs fabricated fail vs genuine fail from the persisted grade, then run the right recovery (--regrade or the auditable override-request); adds no ship-path gate (ADR 0162, task 1002655)
|
|
353
354
|
├── idea-triage/SKILL.md ← /idea-triage — daily walk through the GDS idea_inbox (promote / discard / merge); Metic+
|
|
354
355
|
├── ideate/SKILL.md ← /ideate — ideation-session playbook for ideator-discipline tasks; inverts the loop (human drives, Claude is the sounding board) ([#1267](https://example.com/builders#/task/1267))
|
|
355
356
|
├── merge-mode/SKILL.md ← /merge-mode — manual fallback for the auto-merge: land every confirmed task (merge + smoke + deploy)
|
package/modules/lifecycle/db.js
CHANGED
|
@@ -1474,6 +1474,7 @@ async function findTaskBySourceRef({ source, sourceRef } = {}, deps = {}) {
|
|
|
1474
1474
|
|
|
1475
1475
|
const TASK_SETTER_COLUMNS = new Set([
|
|
1476
1476
|
'kind', 'discipline', 'newcomer_friendly', 'security_sensitive', 'parallel_safe', 'automation_tag',
|
|
1477
|
+
'needs_migration', 'module_key',
|
|
1477
1478
|
]);
|
|
1478
1479
|
|
|
1479
1480
|
async function updateTaskColumn(id, column, value) {
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.35",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.19.
|
|
9
|
+
"version": "1.19.35",
|
|
10
10
|
"license": "AGPL-3.0-or-later",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"express": "^4.21.2",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.35",
|
|
4
4
|
"description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"main": "src/platform-server.js",
|
package/src/module-api.js
CHANGED
|
@@ -493,8 +493,12 @@ const { validateOrRespond, LIMITS, parseId, asyncHandler, corsPublicGet, parsePa
|
|
|
493
493
|
// landed since 1.19.31 with no explicit bump. run 31504858325. (task 1002620)
|
|
494
494
|
// 1.19.33 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
495
495
|
// landed since 1.19.32 with no explicit bump. run 31505528205. (task 1002620)
|
|
496
|
+
// 1.19.34 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
497
|
+
// landed since 1.19.33 with no explicit bump. run 31505952506. (task 1002620)
|
|
498
|
+
// 1.19.35 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
499
|
+
// landed since 1.19.34 with no explicit bump. run 31507293725. (task 1002620)
|
|
496
500
|
// ---------------------------------------------------------------------------
|
|
497
|
-
const CORE_VERSION = '1.19.
|
|
501
|
+
const CORE_VERSION = '1.19.35'; // CI auto-patch carrier (ADR 0161); see changelog above
|
|
498
502
|
|
|
499
503
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
500
504
|
// Usage: const log = api.logger('dev-box'); log.info('mounted');
|
|
@@ -177,6 +177,41 @@ function shouldReserveMigrationNumber(task) {
|
|
|
177
177
|
}
|
|
178
178
|
});
|
|
179
179
|
|
|
180
|
+
// Runtime wiring, not source text: every column setter must clear the
|
|
181
|
+
// TASK_SETTER_COLUMNS allowlist inside updateTaskColumn. The needs_migration
|
|
182
|
+
// setter shipped throwing at runtime because only a source-regex test covered
|
|
183
|
+
// it — and the same gap had silently broken updateTaskModuleKey (module_key
|
|
184
|
+
// was never allowlisted). Stub the shared pool and drive the real functions.
|
|
185
|
+
await test('every task column setter clears the updateTaskColumn allowlist at runtime', async () => {
|
|
186
|
+
const { pool } = require('../src/bongos/pool.js');
|
|
187
|
+
const realQuery = pool.query;
|
|
188
|
+
const seen = [];
|
|
189
|
+
pool.query = async (sql, params) => { seen.push({ sql, params }); return { rows: [{}] }; };
|
|
190
|
+
try {
|
|
191
|
+
const db = require('../modules/lifecycle/db.js');
|
|
192
|
+
const setters = [
|
|
193
|
+
[() => db.updateTaskKind(1, 'bug'), 'kind'],
|
|
194
|
+
[() => db.updateTaskDiscipline(1, 'engineer'), 'discipline'],
|
|
195
|
+
[() => db.updateTaskNewcomerFriendly(1, true), 'newcomer_friendly'],
|
|
196
|
+
[() => db.updateTaskParallelSafe(1, true), 'parallel_safe'],
|
|
197
|
+
[() => db.updateTaskAutomationTag(1, 'live-only'), 'automation_tag'],
|
|
198
|
+
[() => db.updateTaskNeedsMigration(1, false), 'needs_migration'],
|
|
199
|
+
[() => db.updateTaskModuleKey(1, null), 'module_key'],
|
|
200
|
+
];
|
|
201
|
+
for (const [call, column] of setters) {
|
|
202
|
+
const before = seen.length;
|
|
203
|
+
await call(); // throws here if the column is missing from the allowlist
|
|
204
|
+
assert.ok(seen.length > before, `${column} setter must reach pool.query`);
|
|
205
|
+
assert.ok(
|
|
206
|
+
seen[seen.length - 1].sql.includes(`SET ${column} =`),
|
|
207
|
+
`${column} setter must UPDATE its own column`
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
} finally {
|
|
211
|
+
pool.query = realQuery;
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
|
|
180
215
|
await test('PATCH /tasks/:id accepts needs_migration so a wrong flag is correctable', () => {
|
|
181
216
|
assert.ok(
|
|
182
217
|
/needs_migration: \{ type: 'boolean' \}/.test(routesSrc),
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// tests/skill_grade_recover.mjs — the /grade-recover skill exists and handles
|
|
2
|
+
// the three diagnosis branches from the grader-hardening evaluation §6
|
|
3
|
+
// (task 1002655): outage (panel_outcome='unavailable'), fabricated/server-shape
|
|
4
|
+
// fail, and genuine fail — naming --regrade as the recovery and the auditable
|
|
5
|
+
// override-request path, while never volunteering the raw /confirm curl.
|
|
6
|
+
import assert from 'node:assert/strict';
|
|
7
|
+
import { test } from 'node:test';
|
|
8
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
|
|
12
|
+
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
13
|
+
const SKILL = path.join(ROOT, '.claude', 'skills', 'grade-recover', 'SKILL.md');
|
|
14
|
+
|
|
15
|
+
// .claude/skills is INSTANCE-materialized; a neutral core checkout carries none
|
|
16
|
+
// (task 1002470) — skip there, with the same guard shape as file_map.mjs.
|
|
17
|
+
const skillsDirExists = existsSync(path.join(ROOT, '.claude', 'skills'));
|
|
18
|
+
|
|
19
|
+
test('/grade-recover exists and handles the three diagnosis branches', (t) => {
|
|
20
|
+
if (!skillsDirExists) return t.skip('.claude/skills not materialized in this checkout');
|
|
21
|
+
assert.ok(existsSync(SKILL), '.claude/skills/grade-recover/SKILL.md must exist (task 1002655)');
|
|
22
|
+
const md = readFileSync(SKILL, 'utf8');
|
|
23
|
+
|
|
24
|
+
// Branch A — outage: unavailable is named and distinguished from a quality verdict.
|
|
25
|
+
assert.ok(md.includes("panel_outcome='unavailable'"), 'names the outage branch by its signal');
|
|
26
|
+
assert.match(md, /not a quality (verdict|rejection)/i, 'says an outage is not a quality verdict');
|
|
27
|
+
|
|
28
|
+
// Branch B — fabricated / server-shape fail: server guard + the auditable override path.
|
|
29
|
+
assert.match(md, /server[_ -]guard|implausible_pass/i, 'names the server-guard trip shape');
|
|
30
|
+
assert.match(md, /override-request/, 'names the auditable override-request path');
|
|
31
|
+
|
|
32
|
+
// Branch C — genuine fail: severity/worker grouping and a test per real finding.
|
|
33
|
+
assert.match(md, /severity/i, 'genuine-fail branch groups findings by severity');
|
|
34
|
+
assert.match(md, /tests\/\*?\.?mjs|checked-in test/i, 'requires a checked-in test per real finding');
|
|
35
|
+
|
|
36
|
+
// The recovery command is named literally, and the raw confirm curl is never volunteered.
|
|
37
|
+
assert.match(md, /node scripts\/gds\/ship\.js <(?:task-)?id> --regrade/, 'names the --regrade recovery command');
|
|
38
|
+
assert.match(md, /never volunteer/i, 'states the never-volunteer rule for the raw confirm');
|
|
39
|
+
assert.ok(!/curl[^\n]*\/confirm/.test(md), 'must not carry a ready-to-paste raw /confirm curl');
|
|
40
|
+
});
|