@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 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.41",
6
- "core_contract": "1.19.41",
7
- "source_commit": "ef65ee2c6121ae010e5ad2c1ac67b349cf9b9161",
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-11T16:42:56.706Z",
9
+ "built_at": "2026-08-11T17:22:46.634Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
- "docs_redacted": 289,
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": 1523,
20
- "tree_sha256": "8bdaf758774aaff55446f0ca5ac714795f728937d893a1085e21cf14db853915",
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": "acaedbcf1451bdd23461b4d2e2e567678d1d5e4574ad615042a6c3d3db845fcc"
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": "f8b41b82ade21b6181411288f4d4dbec3510f7eea843fd111350a62a3fc259e2"
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": "3d5765b40ed913e05bea697ecb878e98fa799e667a5352d4d8f37236a0b671b4"
4035
+ "sha256": "db2480e2132dffe5cc11ccdcf5871afaeabd1fe07fcacd68acf85179ad5169f6"
4031
4036
  },
4032
4037
  {
4033
4038
  "path": "package.json",
4034
4039
  "mode": "0000644",
4035
- "sha256": "552a8ef2e0d6b1a69377cbf67bdc0b49574312a68b0ac4162bc606db5870afff"
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": "1de7bfa7bcd4201cc24b3ab3afb714b0356e175174767e77d2491bcbfab58508"
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": "33ed6d0a1a829b2312925e379bcc6f49282e707aec28377fbc23464e0d846a70"
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": "f1c39c1f5862092c57f1c5f5232dfce0a9ac41376838899c92c286df3178936f"
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": "b0af74bc3b3e203716b13fbf3fc174a90f51daf659d5c5e5400725e85a0da4fc"
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.
@@ -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 &ge;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
- // A client PASS with an empty issues[] on a non-trivial diff is not a credible
722
- // default-fail panel verdict. Downgrade to manual-confirm (a human lands it via
723
- // /confirm) rather than auto-confirm + auto-credit. Only escalates the verdict
724
- // (never de-escalates a Guard-1 hard FAIL).
725
- const issueCount = Array.isArray(base.issues) ? base.issues.length : 0;
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
- if (clientPassed && issueCount === 0 && nonTrivial) {
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 with empty issues[] on a non-trivial diff (${changeFiles} file(s), ${changeLines} line(s) > ${IMPLAUSIBLE_PASS_MAX_FILES}/${IMPLAUSIBLE_PASS_MAX_LINES}) is not a credible default-fail panel verdict → manual-confirm (SR-9)` });
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 enumerated issues on a ${changeFiles}-file / ${changeLines}-line change must be human-confirmed via /confirm`, worker: 'server-plausibility' });
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: { applied: ['route_rank', 'permission_path', 'permission_path_unprovable', 'implausible_pass', 'forged_net_negative'], ok: true, tripped: [] },
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.41",
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.41",
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.41",
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 + Archon audited forensic read',
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 · Archon-audited forensic read\\nyour memory follows you across machines & worktrees\\n/recall fetches only the relevant subset (ADR 0060)\\n(${memStatus})"]`,
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.41'; // CI auto-patch carrier (ADR 0161); see changelog above
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.