@bongos/core 1.19.41 → 1.19.43
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 +20 -15
- package/docs/adr/0164-implausible-pass-guard-substance-and-evidence.md +38 -0
- package/docs/adr/README.md +1 -0
- package/modules/grading/grader.js +64 -10
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/diagram-facts.js +1 -1
- package/scripts/gds/gen-diagrams.js +1 -1
- package/src/module-api.js +5 -1
- package/tests/grade_server_authoritative.mjs +86 -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.43",
|
|
6
|
+
"core_contract": "1.19.43",
|
|
7
|
+
"source_commit": "05c2bc1f374ff18405ce4b57b143272651a69fc4",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-08-
|
|
9
|
+
"built_at": "2026-08-11T17:22:46.634Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
|
-
"docs_redacted":
|
|
12
|
+
"docs_redacted": 290,
|
|
13
13
|
"agent_docs_stubbed": 21,
|
|
14
14
|
"functional_verbatim": 1213,
|
|
15
15
|
"rules": 3,
|
|
16
16
|
"gate_literals": 3,
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
|
-
"file_count":
|
|
20
|
-
"tree_sha256": "
|
|
19
|
+
"file_count": 1524,
|
|
20
|
+
"tree_sha256": "eb5d84a56e1d201e95d819069e5ded36815bf9fb42f87cc3e010519919ca6782",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/blocker-review/SKILL.md",
|
|
@@ -1289,10 +1289,15 @@
|
|
|
1289
1289
|
"mode": "0000644",
|
|
1290
1290
|
"sha256": "f1d673faaffd4d8a92709bafdc0d5c33b715131beac8f12c02dfa59880242a64"
|
|
1291
1291
|
},
|
|
1292
|
+
{
|
|
1293
|
+
"path": "docs/adr/0164-implausible-pass-guard-substance-and-evidence.md",
|
|
1294
|
+
"mode": "0000644",
|
|
1295
|
+
"sha256": "64fb6e129cf5484266e1b6a9cddd8ba88ff7438b9646c3f4d9ffd0cda3cce642"
|
|
1296
|
+
},
|
|
1292
1297
|
{
|
|
1293
1298
|
"path": "docs/adr/README.md",
|
|
1294
1299
|
"mode": "0000644",
|
|
1295
|
-
"sha256": "
|
|
1300
|
+
"sha256": "ceb8639779cb8f8f43c261800607ff47b90a70489d8f5b5c7e8e0e2c5244bdb1"
|
|
1296
1301
|
},
|
|
1297
1302
|
{
|
|
1298
1303
|
"path": "docs/api-reference.md",
|
|
@@ -2907,7 +2912,7 @@
|
|
|
2907
2912
|
{
|
|
2908
2913
|
"path": "modules/grading/grader.js",
|
|
2909
2914
|
"mode": "0000644",
|
|
2910
|
-
"sha256": "
|
|
2915
|
+
"sha256": "3d16940e2bb354bc029893abc5cdd1a3e4868d51c65e5fed22cabf6610c69533"
|
|
2911
2916
|
},
|
|
2912
2917
|
{
|
|
2913
2918
|
"path": "modules/grading/module.json",
|
|
@@ -4027,12 +4032,12 @@
|
|
|
4027
4032
|
{
|
|
4028
4033
|
"path": "package-lock.json",
|
|
4029
4034
|
"mode": "0000644",
|
|
4030
|
-
"sha256": "
|
|
4035
|
+
"sha256": "db2480e2132dffe5cc11ccdcf5871afaeabd1fe07fcacd68acf85179ad5169f6"
|
|
4031
4036
|
},
|
|
4032
4037
|
{
|
|
4033
4038
|
"path": "package.json",
|
|
4034
4039
|
"mode": "0000644",
|
|
4035
|
-
"sha256": "
|
|
4040
|
+
"sha256": "29562210449cebade43e9b7a27da435784bdabd3313f6b41e05ff0059f0bd2d3"
|
|
4036
4041
|
},
|
|
4037
4042
|
{
|
|
4038
4043
|
"path": "public-docs/index.html",
|
|
@@ -4662,7 +4667,7 @@
|
|
|
4662
4667
|
{
|
|
4663
4668
|
"path": "scripts/gds/diagram-facts.js",
|
|
4664
4669
|
"mode": "0000644",
|
|
4665
|
-
"sha256": "
|
|
4670
|
+
"sha256": "8c6d81c0495d05833bf5cb3d0be8ff6a29fabc24231206391f36b0c85f36b121"
|
|
4666
4671
|
},
|
|
4667
4672
|
{
|
|
4668
4673
|
"path": "scripts/gds/discipline-modes.json",
|
|
@@ -4762,7 +4767,7 @@
|
|
|
4762
4767
|
{
|
|
4763
4768
|
"path": "scripts/gds/gen-diagrams.js",
|
|
4764
4769
|
"mode": "0000644",
|
|
4765
|
-
"sha256": "
|
|
4770
|
+
"sha256": "569a06e7cb448dab63a3acbcbf9c5366e394252c38edbe477d4d58282a9984c4"
|
|
4766
4771
|
},
|
|
4767
4772
|
{
|
|
4768
4773
|
"path": "scripts/gds/gen-file-map.js",
|
|
@@ -5652,7 +5657,7 @@
|
|
|
5652
5657
|
{
|
|
5653
5658
|
"path": "src/module-api.js",
|
|
5654
5659
|
"mode": "0000644",
|
|
5655
|
-
"sha256": "
|
|
5660
|
+
"sha256": "ec430cc3f3ca679123babbd62b5e512bc542ac4c0ff28d3970450d226180c9f9"
|
|
5656
5661
|
},
|
|
5657
5662
|
{
|
|
5658
5663
|
"path": "src/module-loader/loader.js",
|
|
@@ -6617,7 +6622,7 @@
|
|
|
6617
6622
|
{
|
|
6618
6623
|
"path": "tests/grade_server_authoritative.mjs",
|
|
6619
6624
|
"mode": "0000644",
|
|
6620
|
-
"sha256": "
|
|
6625
|
+
"sha256": "9482e5e458023b691f8e5971e232c6492d5e3e2772e927e1f6639f95808c8149"
|
|
6621
6626
|
},
|
|
6622
6627
|
{
|
|
6623
6628
|
"path": "tests/grade_unavailable_display.mjs",
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# ADR 0164 — The implausible-pass guard reads substance + evidence, and the honor-system residual is explicit
|
|
2
|
+
|
|
3
|
+
- **Status:** accepted
|
|
4
|
+
- **Date:** 2026-08-11
|
|
5
|
+
- **Task:** task 1002658 (grader hardening, goal 1000056; evidence from the 14-agent grader evaluation)
|
|
6
|
+
- **Related:** ADR 0024 (the adversarial panel), ADR 0041 (Archon bypass floor), ADR 0042 (CI grade gate — deferred), ADR 0162 (no new human gates on the ship path)
|
|
7
|
+
|
|
8
|
+
## Context
|
|
9
|
+
|
|
10
|
+
`serverSideGuards` (modules/grading/grader.js) carries one plausibility check on the client-asserted grade: the `implausible_pass` guard. Its original form fired when a client PASS arrived with `issues.length === 0` on a non-trivial diff. The evaluation confirmed two structural defects:
|
|
11
|
+
|
|
12
|
+
1. **One fabricated `{}` defeated it.** The guard counted raw array length; a single junk element made a forged clean pass invisible. Worse, the magnitude inputs it reads (`diff_stats`, `committed_files`) are themselves client-supplied — the same forger authors them.
|
|
13
|
+
2. **Every real firing was a false positive.** Its in-sample firings (the eval's 2, task 1002643 twice, task 1002663 once) were all honest, unanimous, zero-issue panel passes on clean diffs — exactly the verdict a working panel produces on good small-to-medium work. The guard imposed its full manual-confirm cost on honest ships while offering ~zero adversarial value.
|
|
14
|
+
|
|
15
|
+
The structural constraint underneath both: **at grade time the server cannot re-derive the feature branch's diff** (the published tip is recorded at ci-land, after the grade). No client-arithmetic plausibility check can be made adversarially sound against a forger who authors every input.
|
|
16
|
+
|
|
17
|
+
## Decision
|
|
18
|
+
|
|
19
|
+
**1. Count substance, not entries.** An issue counts only when it has a known severity (`blocker|major|minor|nit`) and a non-empty summary (`isSubstantiveIssue`). An `issues[]` with entries but no substance is the *padded-issues forgery signature* and trips the guard regardless of anything else. This closes the `{}` bypass using only the submitted body — genuinely server-checkable.
|
|
20
|
+
|
|
21
|
+
**2. Waive the honest unanimous pass on panel evidence.** A zero-issue PASS on a non-trivial diff no longer downgrades when the submitted `signals.workers` carries the full per-worker panel shape (≥3 workers, each with a kind and a legal verdict or error tag — `hasPanelEvidence`). It stands, with an audit marker (`server_guard.implausible_pass_waived: 'panel_evidence'`) so /grade-audit can distinguish *waived* from *never evaluated*. A zero-issue pass with **no** evidence still downgrades to manual-confirm, as before.
|
|
22
|
+
|
|
23
|
+
**3. Name the residual instead of pretending to close it.** `signals.workers` is client-supplied; a determined Metic+ forger can fabricate the full panel shape. We accept this **explicitly as honor-system at grade time** for Metic+ builders, because the binding authorities on the *real* diff are land-time: the branch's CI `unit` run, the gate-review classification, and the post-push main audit — all of which read committed history the client cannot re-author. The grade-time guard's job is honest-mistake hygiene (a truncated body, a panel that silently didn't run, lazy padding), not adversarial defense. Sub-Metic builders remain covered by the hard guards (permission-path with its unprovable-input fail-closed branch, route-rank) which key on the server-known live rank.
|
|
24
|
+
|
|
25
|
+
**4. The CI grade-gate question goes to the owner.** ADR 0042's deferred CI-side grade gate (`grade-gate.yml` absent, `ci-grade.js` with zero callers) is the one mechanism that could move grade verification out of the client's hands entirely. Whether to land it or to correct ADR 0042 to record permanent deferral is an owner decision — filed as a GDS blocker from task 1002658, not decided here.
|
|
26
|
+
|
|
27
|
+
## Consequences
|
|
28
|
+
|
|
29
|
+
- The three confirmed false-positive shapes (unanimous zero-issue passes) now land without an Archon manual-confirm — removing the exact churn class that consumed panel rounds and human attention on tasks 1002643/1002663, and removing pressure to reach for the raw confirm.
|
|
30
|
+
- The lazy forgery class (`issues:[{}]` padding) is now caught; the sophisticated forgery class (full fabricated panel shape) is documented as accepted honor-system residual for Metic+, bounded by land-time authorities.
|
|
31
|
+
- No approval step was added or removed (ADR 0162): the change only re-aims an existing automatic downgrade.
|
|
32
|
+
- `server_guard.implausible_pass_waived` gives /grade-audit and /grader-health a queryable marker for zero-issue passes that stood on evidence.
|
|
33
|
+
|
|
34
|
+
## Alternatives considered
|
|
35
|
+
|
|
36
|
+
- **Gate on more client arithmetic** (worker cost/timing consistency, score-distribution checks): same trust hole — the forger authors the inputs; adds false-positive surface for no adversarial gain.
|
|
37
|
+
- **Drop the guard entirely:** loses the honest-mistake net (truncated bodies, silently-skipped panels) that costs nothing when the waiver works.
|
|
38
|
+
- **Block until a server-side diff exists at grade time:** requires restructuring ship so the server holds the branch before grading (the ADR 0055 server-mediated path does this for boxes) — the right long-term direction, but it is the CI grade-gate decision (owner blocker), not a guard tweak.
|
package/docs/adr/README.md
CHANGED
|
@@ -236,5 +236,6 @@ This keeps the decision history honest and traceable.
|
|
|
236
236
|
| 0162 | [**Review gates retired: rank-consistent CI checks only on `main`** ([task 1002635](https://cloudbongos.com/builders#/task/1002635); owner directive, idea 1000657). Amends ADR 0159. Within a day of task 1002619 arming the merge gates, the code-owner review requirement had stranded two graded-PASS wave-4 ships (PR 28 sat BLOCKED behind a review only the repo-owner account could give) and then blocked the fixes for the strands it caused — structurally, not incidentally: GitHub can only express the gate as *accounts* (no rank concept, no self-approval), so on a solo-archon instance it degenerates into "one named login must click every gate-surface PR" — identity-pinned authority, against ADR 0016's rank principle and the remediation's own goal. Decision: branch protection carries required status checks ONLY; `gating.js` `DEFAULT_PROTECTION` sets `required_pull_request_reviews: null` and `cmdOn` normalizes BOTH restore paths so a pre-retirement snapshot cannot resurrect the gate (`tests/gating_review_retired.mjs` pins it with a counter-example); the CODEOWNERS *file* is deleted while its *glob* stays in the hard-floor lists so reintroducing it is itself gate-flagged. Accepted trade, chosen explicitly by the owner: no pre-merge human approval on safety-machinery changes — the unit check, the fail-closed gate-review sandbox, the grader panel, and the every-push main-audit are the net, catching a compromised session's merge after the fact rather than before.](<redacted>.md) | governance / build pipeline |
|
|
237
237
|
|
|
238
238
|
| 0163 | [**Pre-197 display names: a transitional 'legacy' source, resolved at first sign-in** ([task 1002643](https://cloudbongos.com/builders#/task/1002643); idea 1000659). Amends [ADR 0156](<redacted>.md), whose migration defaulted every pre-existing row to `'github'` — false for builders who renamed after their last sign-in but before 197 landed, so their names kept reverting. No audit trail exists to backfill precisely, so `core_214` marks every pre-197 `'github'` row `'legacy'` (scoped by 197's `applied_at` on the instance — portable) and the upsert resolves each at its first sign-in: stored = incoming GitHub name → provably GitHub-derived → `'github'`; differs → treated as builder-set → kept, stamped `'user'`. Accepted misclassification: a GitHub-side rename in the window freezes a stale label (visible, self-fixable in Settings) — preferred over silently destroying deliberate renames. Rejected: `display_name <> github_login` heuristic (freezes nearly everyone), comparing forever on all `'github'` rows (turns every future GitHub rename into a frozen name).](<redacted>.md) | GDS / builder experience |
|
|
239
|
+
| 0164 | [**The implausible-pass guard reads substance + evidence; the Metic+ honor-system residual is explicit** ([task 1002658](https://cloudbongos.com/builders#/task/1002658); grader-hardening goal 1000056). The guard fired only on `issues.length===0` — one fabricated `{}` defeated it, its magnitude inputs are client-supplied, and every in-sample firing (eval 2-for-2, tasks 1002643 ×2, 1002663) was a false positive on an honest unanimous zero-issue panel PASS. Redesign: count only SUBSTANTIVE issues (known severity + non-empty summary — padding trips the guard regardless), and waive the zero-issue pass when `signals.workers` carries the full ≥3-worker panel shape, stamped `implausible_pass_waived` for /grade-audit. The residual is named, not hidden: every grade-time input is client-authored, so plausibility at grade time is honest-mistake hygiene; the binding authorities on the real diff are land-time (CI unit, gate-review, main audit) — Metic+ grade-time honesty is accepted honor-system per this ADR. The ADR-0042 CI grade-gate (land it vs record permanent deferral) goes to the owner as a blocker, not decided here. No approval step added or removed (ADR 0162).](<redacted>.md) | GDS / grading |
|
|
239
240
|
|
|
240
241
|
> ⚠️ **Numbering collision (known):** two ADRs share `0008`. The numbers were assigned in parallel sessions before the lock could be enforced. The files are kept under their existing filenames to preserve git history, but the table disambiguates them as `0008-a` / `0008-b`. New ADRs should resume at `0040` to avoid further collisions. (`0024` is also a real on-disk duplicate: the cloneable-repo/local-first-memory ADR and the multi-agent-system-architecture ADR were both numbered `0024` in parallel; both keep their filenames, disambiguated as `0024-a` / `0024-b` like `0008`. Likewise `0025` ended up with two on-disk files — the offsite-backup ADR and the structured-criterion↔task-link ADR — both kept under their existing filenames and disambiguated as `0025-a` / `0025-b`; separately, the BFG ADR had also claimed `0025` on 2026-05-30 and yielded to `0026`. A third happened 2026-06-06: `0036` was claimed in parallel by the builders-subdomain ADR ([#726](https://example.com/builders#/task/726)) and this Discord-channels ADR ([#727](https://example.com/builders#/task/727)); the Discord-channels ADR yielded to `0037`. A fourth landed 2026-06-10: `0044` was claimed in parallel by the palette-replacement ADR and the per-box game-preview ADR ([#897](https://example.com/builders#/task/897)); both keep their filenames, disambiguated as `0044-a` / `0044-b` like `0008`. A fifth was caught pre-land 2026-06-13: `0050` was claimed in parallel by the device-flow-admission ADR ([#1000](https://example.com/builders#/task/1000)) and the sandbox-for-everyone ADR ([#1001](https://example.com/builders#/task/1001)); the latter yielded to `0052` before merging, so there is no `0050` duplicate. A sixth was caught pre-land 2026-06-21: the tool-agnostic-design-layer ADR ([#1375](https://example.com/builders#/task/1375)) first collided at `0079` with the value-gated-autonomous-engagement ADR, then at `0080` with the llm-cache-api-transport ADR (both part of the 0075–0080 LLM-cost-reduction series, landed on `main` in parallel); it yielded to `0081` before merging, so there is no `0079`/`0080` design-layer duplicate. A seventh landed 2026-06-23: `0084` was claimed in parallel by the auto-derived-per-task-rank-floor ADR and the remove-default-spend-cap ADR (task 1499); the rank-floor ADR landed on `main` first, so the spend-cap ADR yielded to `0085`, leaving no `0084` duplicate. An eighth landed 2026-06-27: `0095` was claimed in parallel by the borrowed-memory-and-retrieval-concepts ADR (PR #459, landed first) and the cross-agent-context-management ADR ([#1651](https://example.com/builders#/task/1651), PR #460); both keep their filenames, disambiguated as `0095-a` / `0095-b` like `0008`. These two are companions — `0095-a` adopts the memory/retrieval concepts and explicitly defers the grep-vs-semantic question to `0095-b`.)
|
|
@@ -378,6 +378,32 @@ const isNarcErroredClean = (w) => {
|
|
|
378
378
|
};
|
|
379
379
|
const isNarcHealthy = (w) => !!w && w.kind === 'narc' && !w.error;
|
|
380
380
|
|
|
381
|
+
// task 1002658 (ADR 0164): a SUBSTANTIVE issue is one a real panel emits — a
|
|
382
|
+
// known severity + a non-empty summary. The old plausibility guard counted raw
|
|
383
|
+
// issues[].length, so one fabricated `{}` defeated it; substance-counting
|
|
384
|
+
// closes that lazy-forgery class using only the submitted body itself.
|
|
385
|
+
const ISSUE_SEVERITIES = new Set(['blocker', 'major', 'minor', 'nit']);
|
|
386
|
+
function isSubstantiveIssue(it) {
|
|
387
|
+
return !!it && typeof it === 'object'
|
|
388
|
+
&& ISSUE_SEVERITIES.has(String(it.severity || '').toLowerCase())
|
|
389
|
+
&& typeof it.summary === 'string' && it.summary.trim().length > 0;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// task 1002658 (ADR 0164): does the submitted signals block carry the full
|
|
393
|
+
// per-worker shape a real panel run produces — ≥3 workers, each with a kind
|
|
394
|
+
// and a legal verdict (or an error tag)? Client-forgeable like every
|
|
395
|
+
// grade-time input (the ADR's documented honor-system residual for Metic+);
|
|
396
|
+
// its job is separating "the panel ran and unanimously found nothing" (the
|
|
397
|
+
// guard's confirmed false-positive class) from "no evidence at all".
|
|
398
|
+
const WORKER_VERDICTS = new Set(['pass', 'concerns', 'fail']);
|
|
399
|
+
function hasPanelEvidence(signals) {
|
|
400
|
+
const ws = Array.isArray(signals?.workers) ? signals.workers : null;
|
|
401
|
+
if (!ws || ws.length < 3) return false;
|
|
402
|
+
return ws.every((w) => !!w && typeof w === 'object'
|
|
403
|
+
&& typeof w.kind === 'string' && w.kind.trim().length > 0
|
|
404
|
+
&& (WORKER_VERDICTS.has(String(w.verdict || '').toLowerCase()) || !!w.error));
|
|
405
|
+
}
|
|
406
|
+
|
|
381
407
|
// Validates ONE shot's subagent JSON and produces a per-shot grade-result.
|
|
382
408
|
// Never throws — malformed inputs produce a passed=false result with notes_md.
|
|
383
409
|
// The downstream aggregateShots collapses N of these into a final verdict.
|
|
@@ -717,20 +743,37 @@ function serverSideGuards(gradeResult, { committedFiles, builderRank, diffStats,
|
|
|
717
743
|
if (clientPassed) downgradeTo = 'fail';
|
|
718
744
|
}
|
|
719
745
|
|
|
720
|
-
// --- Guard 2: implausible client verdict (SR-9) ---
|
|
721
|
-
//
|
|
722
|
-
//
|
|
723
|
-
//
|
|
724
|
-
//
|
|
725
|
-
|
|
746
|
+
// --- Guard 2: implausible client verdict (SR-9 / task 1002658, ADR 0164) ---
|
|
747
|
+
// Redesigned around what the submitted body itself can prove. The old form
|
|
748
|
+
// (raw issues.length === 0) was defeated by one fabricated `{}` AND fired on
|
|
749
|
+
// every honest unanimous zero-issue panel PASS (its only in-sample firings —
|
|
750
|
+
// eval 2-for-2, tasks 1002643 ×2 and 1002663 — were ALL false positives).
|
|
751
|
+
// Now: count only SUBSTANTIVE issues; a padded issues[] (entries but no
|
|
752
|
+
// substance) is the forgery signature and trips regardless of evidence; a
|
|
753
|
+
// genuinely empty issues[] trips only when the body ALSO lacks the full
|
|
754
|
+
// per-worker panel shape — a real panel that ran and unanimously found
|
|
755
|
+
// nothing is waived with an audit marker instead of a manual-confirm. The
|
|
756
|
+
// magnitude inputs remain client-supplied; the binding authority on the real
|
|
757
|
+
// diff is land-time (gate-review CI + post-push main audit) — ADR 0164.
|
|
758
|
+
const rawIssueCount = Array.isArray(base.issues) ? base.issues.length : 0;
|
|
759
|
+
const substantiveIssueCount = (Array.isArray(base.issues) ? base.issues : [])
|
|
760
|
+
.filter(isSubstantiveIssue).length;
|
|
761
|
+
const paddedIssues = rawIssueCount > 0 && substantiveIssueCount === 0;
|
|
762
|
+
const panelEvidence = hasPanelEvidence(base.signals);
|
|
726
763
|
const { files: changeFiles, lines: changeLines } = changeMagnitude({ committedFiles, diffStats: ds });
|
|
727
764
|
const nonTrivial = changeFiles > IMPLAUSIBLE_PASS_MAX_FILES || changeLines > IMPLAUSIBLE_PASS_MAX_LINES;
|
|
728
|
-
|
|
765
|
+
let implausiblePassWaived = null;
|
|
766
|
+
if (clientPassed && nonTrivial && substantiveIssueCount === 0 && (paddedIssues || !panelEvidence)) {
|
|
767
|
+
const shape = paddedIssues
|
|
768
|
+
? `issues[] holds ${rawIssueCount} entr${rawIssueCount === 1 ? 'y' : 'ies'} with no substance (no known severity + summary) — the padded-issues forgery signature`
|
|
769
|
+
: 'empty issues[] with no per-worker panel evidence in signals';
|
|
729
770
|
guardsTripped.push({ guard: 'implausible_pass', severity: 'major',
|
|
730
|
-
summary: `client PASS
|
|
771
|
+
summary: `client PASS on a non-trivial diff (${changeFiles} file(s), ${changeLines} line(s) > ${IMPLAUSIBLE_PASS_MAX_FILES}/${IMPLAUSIBLE_PASS_MAX_LINES}): ${shape} — not a credible default-fail panel verdict → manual-confirm (SR-9 / ADR 0164)` });
|
|
731
772
|
extraIssues.push({ severity: 'major', file: '(grade)', summary:
|
|
732
|
-
`[server plausibility] a passing grade with no
|
|
773
|
+
`[server plausibility] a passing grade with no substantive findings and no panel evidence on a ${changeFiles}-file / ${changeLines}-line change must be human-confirmed via /confirm`, worker: 'server-plausibility' });
|
|
733
774
|
if (downgradeTo !== 'fail') downgradeTo = 'concerns';
|
|
775
|
+
} else if (clientPassed && nonTrivial && rawIssueCount === 0 && panelEvidence) {
|
|
776
|
+
implausiblePassWaived = 'panel_evidence';
|
|
734
777
|
}
|
|
735
778
|
|
|
736
779
|
// --- Guard 3: bound the credit/achievement signals (SR-18) ---
|
|
@@ -769,7 +812,15 @@ function serverSideGuards(gradeResult, { committedFiles, builderRank, diffStats,
|
|
|
769
812
|
...base,
|
|
770
813
|
signals: {
|
|
771
814
|
...(base.signals || {}),
|
|
772
|
-
server_guard: {
|
|
815
|
+
server_guard: {
|
|
816
|
+
applied: ['route_rank', 'permission_path', 'permission_path_unprovable', 'implausible_pass', 'forged_net_negative'],
|
|
817
|
+
ok: true,
|
|
818
|
+
tripped: [],
|
|
819
|
+
// task 1002658 / ADR 0164: the audit trail records WHY a zero-issue
|
|
820
|
+
// pass on a non-trivial diff stood (panel evidence), so /grade-audit
|
|
821
|
+
// can distinguish waived from never-evaluated.
|
|
822
|
+
...(implausiblePassWaived ? { implausible_pass_waived: implausiblePassWaived } : {}),
|
|
823
|
+
},
|
|
773
824
|
},
|
|
774
825
|
};
|
|
775
826
|
}
|
|
@@ -814,6 +865,7 @@ function serverSideGuards(gradeResult, { committedFiles, builderRank, diffStats,
|
|
|
814
865
|
// task 1002646: permission_path_unprovable is the same wall — the rank
|
|
815
866
|
// floor refusing an unverifiable diff — so it renders the same way.
|
|
816
867
|
authorization_refusal: guardsTripped.some((g) => g.guard === 'permission_path' || g.guard === 'permission_path_unprovable'),
|
|
868
|
+
...(implausiblePassWaived ? { implausible_pass_waived: implausiblePassWaived } : {}),
|
|
817
869
|
},
|
|
818
870
|
},
|
|
819
871
|
notes_md: `${base.notes_md || ''}${guardNote}`,
|
|
@@ -1837,6 +1889,8 @@ module.exports = {
|
|
|
1837
1889
|
routeRankPrePass, // deterministic route-rank pre-pass (#475)
|
|
1838
1890
|
permissionPathPrePass, // deterministic sub-Metic permission-path gate (SEC #863)
|
|
1839
1891
|
serverSideGuards, // SR-9 / SR-18: server-authoritative grade hardening (downgrade-only)
|
|
1892
|
+
isSubstantiveIssue, // task 1002658 / ADR 0164: substance-counted plausibility inputs
|
|
1893
|
+
hasPanelEvidence, // task 1002658 / ADR 0164: the zero-issue-pass waiver evidence shape
|
|
1840
1894
|
changeMagnitude, // SR-9 helper: file/line magnitude from committed_files + diff_stats
|
|
1841
1895
|
FALLTHROUGH_CONFIDENCE,
|
|
1842
1896
|
// v3 surface (kept exported for diagnostics + tests)
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.43",
|
|
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.43",
|
|
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.43",
|
|
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",
|
|
@@ -160,7 +160,7 @@ const CONCEPTUAL_TASK_IDS = {
|
|
|
160
160
|
273: 'R54 — builder_memory store schema',
|
|
161
161
|
274: 'R55 — sync-on-ship (push)',
|
|
162
162
|
275: 'R56 — pull-on-session-start',
|
|
163
|
-
276: 'R57 — per-builder isolation +
|
|
163
|
+
276: 'R57 — per-builder isolation + forensic read at Metic+ (ADR 0157)',
|
|
164
164
|
// 03-drachmae-karma — bounty.
|
|
165
165
|
284: 'R65 — bounty payout rate card (src/bongos/security.js + /builders)',
|
|
166
166
|
286: 'R67 — auto-confirmation flow that awards drachmae (the awarding gate)',
|
|
@@ -439,7 +439,7 @@ function architectureMmd(f) {
|
|
|
439
439
|
' CORE["@bongos/core — the build platform, VENDORED as a pinned dependency\\n(ADR 0108: central updates are a version-pin bump via `bongos upgrade`, not a merge)"]',
|
|
440
440
|
' DB["Postgres — tasks · claims · versions · builders.rank\\ncredit_log · grades · idea_inbox · builder_memory\\n(KING for work-state + permissions; CLAUDE.md only describes it)"]',
|
|
441
441
|
' RANK["auth.requireRank — checked per request, NO caching\\n(ADR 0016: a demotion takes effect on the next request)"]',
|
|
442
|
-
` SRVMEM["server-side builder_memory store\\n${memLead}: per-builder · isolated ·
|
|
442
|
+
` SRVMEM["server-side builder_memory store\\n${memLead}: per-builder · isolated · forensic read at Metic+ (ADR 0157)\\nyour memory follows you across machines & worktrees\\n/recall fetches only the relevant subset (ADR 0060)\\n(${memStatus})"]`,
|
|
443
443
|
` PUSHTOK["server-held push credential\\n(${pushCred} — the box never holds it)"]`,
|
|
444
444
|
' DEPLOY["auto-pull deploy (ADR 0129)\\na timer pulls THIS instance repo every ~2 min →\\nnpm ci if the pin changed → migrate → regenerate docs → restart → healthz"]',
|
|
445
445
|
' end',
|
package/src/module-api.js
CHANGED
|
@@ -509,8 +509,12 @@ const { validateOrRespond, LIMITS, parseId, asyncHandler, corsPublicGet, parsePa
|
|
|
509
509
|
// landed since 1.19.39 with no explicit bump. run 31513136724. (task 1002620)
|
|
510
510
|
// 1.19.41 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
511
511
|
// landed since 1.19.40 with no explicit bump. run 31513793491. (task 1002620)
|
|
512
|
+
// 1.19.42 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
513
|
+
// landed since 1.19.41 with no explicit bump. run 31515200576. (task 1002620)
|
|
514
|
+
// 1.19.43 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
515
|
+
// landed since 1.19.42 with no explicit bump. run 31517196176. (task 1002620)
|
|
512
516
|
// ---------------------------------------------------------------------------
|
|
513
|
-
const CORE_VERSION = '1.19.
|
|
517
|
+
const CORE_VERSION = '1.19.43'; // CI auto-patch carrier (ADR 0161); see changelog above
|
|
514
518
|
|
|
515
519
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
516
520
|
// Usage: const log = api.logger('dev-box'); log.info('mounted');
|
|
@@ -253,6 +253,92 @@ await test('empty-issues PASS on a large diff (by lines) → CONCERNS', () => {
|
|
|
253
253
|
assert.equal(g.signals.server_guard.downgraded_to, 'concerns');
|
|
254
254
|
});
|
|
255
255
|
|
|
256
|
+
// ---- task 1002658: the guard reads issue SUBSTANCE + panel evidence, not raw count ----
|
|
257
|
+
|
|
258
|
+
const FULL_PANEL = [
|
|
259
|
+
{ kind: 'narc', verdict: 'pass' },
|
|
260
|
+
{ kind: 'quality', verdict: 'pass' },
|
|
261
|
+
{ kind: 'hacker', verdict: 'pass' },
|
|
262
|
+
{ kind: 'efficiency', verdict: 'pass' },
|
|
263
|
+
];
|
|
264
|
+
|
|
265
|
+
await test('a single fabricated {} issue no longer defeats the guard → CONCERNS (task 1002658)', () => {
|
|
266
|
+
const g = grader.serverSideGuards(clientGrade({ issues: [{}] }), {
|
|
267
|
+
committedFiles: Array.from({ length: 10 }, (_, i) => `src/x${i}.js`),
|
|
268
|
+
builderRank: 'metic',
|
|
269
|
+
diffStats: { files_changed: 10, lines_added: 400, lines_removed: 0 },
|
|
270
|
+
});
|
|
271
|
+
assert.equal(g.passed, false, 'a padded-issues pass on a non-trivial diff cannot auto-confirm');
|
|
272
|
+
assert.equal(g.signals.server_guard.downgraded_to, 'concerns');
|
|
273
|
+
assert.ok(g.signals.server_guard.tripped.some((t) => t.guard === 'implausible_pass'));
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
await test('junk-shaped issues (no severity/summary) count as padding, not findings', () => {
|
|
277
|
+
const g = grader.serverSideGuards(
|
|
278
|
+
clientGrade({ issues: [{ severity: 'catastrophic', summary: '' }, { file: 'a.js' }] }),
|
|
279
|
+
{
|
|
280
|
+
committedFiles: Array.from({ length: 10 }, (_, i) => `src/x${i}.js`),
|
|
281
|
+
builderRank: 'metic',
|
|
282
|
+
diffStats: { files_changed: 10, lines_added: 400, lines_removed: 0 },
|
|
283
|
+
}
|
|
284
|
+
);
|
|
285
|
+
assert.equal(g.passed, false);
|
|
286
|
+
assert.ok(g.signals.server_guard.tripped.some((t) => t.guard === 'implausible_pass'));
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
await test('padded issues trip EVEN WITH full panel evidence (padding is the forgery signature)', () => {
|
|
290
|
+
const g = grader.serverSideGuards(
|
|
291
|
+
clientGrade({ issues: [{}], signals: { workers: FULL_PANEL } }),
|
|
292
|
+
{
|
|
293
|
+
committedFiles: Array.from({ length: 10 }, (_, i) => `src/x${i}.js`),
|
|
294
|
+
builderRank: 'metic',
|
|
295
|
+
diffStats: { files_changed: 10, lines_added: 400, lines_removed: 0 },
|
|
296
|
+
}
|
|
297
|
+
);
|
|
298
|
+
assert.equal(g.passed, false);
|
|
299
|
+
assert.ok(g.signals.server_guard.tripped.some((t) => t.guard === 'implausible_pass'));
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
await test('zero-issue PASS WITH full panel evidence is WAIVED — no downgrade, audit marker set (the task-1002663/1002643 false-positive class)', () => {
|
|
303
|
+
const g = grader.serverSideGuards(
|
|
304
|
+
clientGrade({ signals: { workers: FULL_PANEL } }),
|
|
305
|
+
{
|
|
306
|
+
committedFiles: Array.from({ length: 10 }, (_, i) => `src/x${i}.js`),
|
|
307
|
+
builderRank: 'metic',
|
|
308
|
+
diffStats: { files_changed: 10, lines_added: 400, lines_removed: 0 },
|
|
309
|
+
}
|
|
310
|
+
);
|
|
311
|
+
assert.equal(g.passed, true, 'a unanimous zero-issue panel PASS must stand');
|
|
312
|
+
assert.equal(g.signals.server_guard.implausible_pass_waived, 'panel_evidence');
|
|
313
|
+
assert.ok(!g.signals.server_guard.tripped.some((t) => t.guard === 'implausible_pass'));
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
await test('thin worker evidence (fewer than 3 workers) does NOT waive', () => {
|
|
317
|
+
const g = grader.serverSideGuards(
|
|
318
|
+
clientGrade({ signals: { workers: [{ kind: 'narc', verdict: 'pass' }] } }),
|
|
319
|
+
{
|
|
320
|
+
committedFiles: Array.from({ length: 10 }, (_, i) => `src/x${i}.js`),
|
|
321
|
+
builderRank: 'metic',
|
|
322
|
+
diffStats: { files_changed: 10, lines_added: 400, lines_removed: 0 },
|
|
323
|
+
}
|
|
324
|
+
);
|
|
325
|
+
assert.equal(g.passed, false);
|
|
326
|
+
assert.equal(g.signals.server_guard.downgraded_to, 'concerns');
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
await test('one substantive nit on a non-trivial PASS → no plausibility trip (unchanged)', () => {
|
|
330
|
+
const g = grader.serverSideGuards(
|
|
331
|
+
clientGrade({ issues: [{ severity: 'nit', file: 'a.js', summary: 'comment style' }] }),
|
|
332
|
+
{
|
|
333
|
+
committedFiles: Array.from({ length: 10 }, (_, i) => `src/x${i}.js`),
|
|
334
|
+
builderRank: 'metic',
|
|
335
|
+
diffStats: { files_changed: 10, lines_added: 400, lines_removed: 0 },
|
|
336
|
+
}
|
|
337
|
+
);
|
|
338
|
+
assert.equal(g.passed, true);
|
|
339
|
+
assert.ok(!g.signals.server_guard.tripped.some((t) => t.guard === 'implausible_pass'));
|
|
340
|
+
});
|
|
341
|
+
|
|
256
342
|
await test('a hard-FAIL guard takes precedence over the CONCERNS plausibility guard', () => {
|
|
257
343
|
// Both Guard 1 (sub-Metic protected) and Guard 2 (empty issues, large) trip;
|
|
258
344
|
// the verdict must be the stricter FAIL, not concerns.
|