@bongos/core 1.19.1036 → 1.19.1037

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 (35) hide show
  1. package/.bongos-core.json +43 -48
  2. package/.claude/skills/grade-recover/SKILL.md +1 -1
  3. package/docs/adr/0302-the-third-identical-failure-stops-the-session-and-asks.md +3 -2
  4. package/docs/adr/0329-the-rendered-fit-check-is-a-kit-floor-and-an-advisory-ship-check-row.md +2 -2
  5. package/docs/adr/README.md +1 -1
  6. package/docs/module-api-changelog.md +2 -0
  7. package/modules/economy/credits.js +1 -1
  8. package/modules/grading/grader-config.js +3 -12
  9. package/modules/grading/grader-no-artifact.js +227 -2
  10. package/modules/grading/grader-prompt.js +1 -1
  11. package/modules/grading/grader-rubric.json +1 -86
  12. package/modules/grading/grader-score.js +1 -169
  13. package/modules/grading/grader-subagent.js +1 -51
  14. package/modules/grading/grader.js +26 -211
  15. package/modules/lifecycle/db-ship.js +3 -3
  16. package/package-lock.json +2 -2
  17. package/package.json +1 -1
  18. package/release-notes.json +10 -0
  19. package/scripts/gds/claim.js +2 -1
  20. package/scripts/gds/grade-smoke.js +3 -3
  21. package/scripts/gds/render-check.js +1 -1
  22. package/scripts/gds/ship-check.js +1 -1
  23. package/scripts/gds/ship-flow.js +1 -1
  24. package/scripts/gds/ship-grade-steps.js +2 -2
  25. package/scripts/gds/visual-review-nudge.js +2 -1
  26. package/src/module-api.js +1 -1
  27. package/tests/adr_0162_gate_citation.mjs +167 -0
  28. package/tests/grader.mjs +48 -126
  29. package/tests/grader_unbacked_score.mjs +1 -1
  30. package/tests/regrade_actual_minutes.mjs +18 -17
  31. package/tests/render_check.mjs +1 -1
  32. package/tests/skill_grade_audit.mjs +3 -3
  33. package/tests/skill_grader_health.mjs +2 -2
  34. package/scripts/gds/audit-ships.js +0 -319
  35. package/tests/audit_ships_git_argv.mjs +0 -173
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.1036",
6
- "core_contract": "1.19.1036",
7
- "source_commit": "19197b1c05f3e07896458dc0e71d7e41529d10d1",
5
+ "core_version": "1.19.1037",
6
+ "core_contract": "1.19.1037",
7
+ "source_commit": "fc8861f3a11ffc5ecf0eb8625adaa18f22232afc",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-09-26T07:30:38.514Z",
9
+ "built_at": "2026-09-26T07:41:37.582Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
12
  "docs_redacted": 542,
13
13
  "agent_docs_stubbed": 26,
14
- "functional_verbatim": 2491,
14
+ "functional_verbatim": 2490,
15
15
  "rules": 3,
16
16
  "gate_literals": 3,
17
17
  "gate": "passed"
18
18
  },
19
- "file_count": 3060,
20
- "tree_sha256": "871996fc2ebf4d378610236e8e594e2a024b36fec0ed2a8f8a2971ef43a2b1c3",
19
+ "file_count": 3059,
20
+ "tree_sha256": "0ed4394afb862d1a8286d75da8f8d8ea947c47b9d26842004c92fe4f2a2825df",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/ask-for-help/SKILL.md",
@@ -162,7 +162,7 @@
162
162
  {
163
163
  "path": ".claude/skills/grade-recover/SKILL.md",
164
164
  "mode": "0000644",
165
- "sha256": "a67c7c68c41756607afcb44f6b6254314c0eda87ba570c20933b1ef8c64552ef"
165
+ "sha256": "e707dd0146a124d1c01e80cad56c8585603aa1cff306c9ea8a2a0a14a25a564d"
166
166
  },
167
167
  {
168
168
  "path": ".claude/skills/grader-health/SKILL.md",
@@ -2007,7 +2007,7 @@
2007
2007
  {
2008
2008
  "path": "docs/adr/0302-the-third-identical-failure-stops-the-session-and-asks.md",
2009
2009
  "mode": "0000644",
2010
- "sha256": "08ea781a488d7454ca49b17e9540bb4c7bb9f1925aedf8ad4634057a89dd0d22"
2010
+ "sha256": "e3e4da22403be74a696493a732ce5ef4a374df404598ff0325eaf4955f140085"
2011
2011
  },
2012
2012
  {
2013
2013
  "path": "docs/adr/0303-provisioning-verifies-the-base-caddyfile-and-never-edits-it.md",
@@ -2142,7 +2142,7 @@
2142
2142
  {
2143
2143
  "path": "docs/adr/0329-the-rendered-fit-check-is-a-kit-floor-and-an-advisory-ship-check-row.md",
2144
2144
  "mode": "0000644",
2145
- "sha256": "e340529dfadefde589ac92a24e2c0d0e52729c3c54e2350ee8e201ff52679c9e"
2145
+ "sha256": "77f53f6be0e27b12428994f2c1357c19cd1e027bf94cfa96dcb15b1b2a289ff3"
2146
2146
  },
2147
2147
  {
2148
2148
  "path": "docs/adr/0330-an-ask-is-answered-where-it-was-asked.md",
@@ -2197,7 +2197,7 @@
2197
2197
  {
2198
2198
  "path": "docs/adr/README.md",
2199
2199
  "mode": "0000644",
2200
- "sha256": "9d611061b85a56b85f33ea9e0638239b1765cb251761b5f56f63ea82387ac01f"
2200
+ "sha256": "716aeb75baa0afcbbd2090b07119954102d74ac53ac4c430371f38b6ed7f9678"
2201
2201
  },
2202
2202
  {
2203
2203
  "path": "docs/api-reference.md",
@@ -2767,7 +2767,7 @@
2767
2767
  {
2768
2768
  "path": "docs/module-api-changelog.md",
2769
2769
  "mode": "0000644",
2770
- "sha256": "6ef6f0678f191a2d3210235fd6d56466f7de506bb9054d1213ebdf99385d2dd9"
2770
+ "sha256": "db77f43319c78e54f21709f88f82b7b27392a99cfcdf61a6dc25552a8be6c90f"
2771
2771
  },
2772
2772
  {
2773
2773
  "path": "docs/modules-contract.md",
@@ -4352,7 +4352,7 @@
4352
4352
  {
4353
4353
  "path": "modules/economy/credits.js",
4354
4354
  "mode": "0000644",
4355
- "sha256": "736eed2c89863d6eb28072627a40ac4f8945832cfb7b1d1aba10e6cc65483901"
4355
+ "sha256": "6b5700a6e1d7689496e93d5f1de9f9c32766842a389571135b4f3af950278ce0"
4356
4356
  },
4357
4357
  {
4358
4358
  "path": "modules/economy/idea-brightness.js",
@@ -4657,7 +4657,7 @@
4657
4657
  {
4658
4658
  "path": "modules/grading/grader-config.js",
4659
4659
  "mode": "0000644",
4660
- "sha256": "9f06f2521e00f675c74a09538d086f6cdf362dfbb08bbc96464b6db10c2d5d2b"
4660
+ "sha256": "d55c697c85143f8bf5c8014a7841264fb965c72780bdc1750467913ae9b408be"
4661
4661
  },
4662
4662
  {
4663
4663
  "path": "modules/grading/grader-model.js",
@@ -4667,27 +4667,27 @@
4667
4667
  {
4668
4668
  "path": "modules/grading/grader-no-artifact.js",
4669
4669
  "mode": "0000644",
4670
- "sha256": "ab20c06268f30d0ed7198774d7435237f63440550235bdc5b926870db56886e7"
4670
+ "sha256": "4c66cba74d89e7f07f9984c0b846bff6210af7aa8a3a45219139246e4b975a22"
4671
4671
  },
4672
4672
  {
4673
4673
  "path": "modules/grading/grader-prompt.js",
4674
4674
  "mode": "0000644",
4675
- "sha256": "8443aeba1325a03db37b2d0c466a270d4be89c510707a7f437aee75835ec5bac"
4675
+ "sha256": "d845b8785b39c89777e9cb9cdf5e869b51e8eae11c76288d9be4790239fd5e13"
4676
4676
  },
4677
4677
  {
4678
4678
  "path": "modules/grading/grader-rubric.json",
4679
4679
  "mode": "0000644",
4680
- "sha256": "de0ca17fedb33bd54d73759e14e6813cd9f2c8c85ef2180e49c54794c7a63a3d"
4680
+ "sha256": "a2c5ea5298e20b53ec03a5f047a3c5ae46fbaaedf9809d2b533ef7f81763f3dc"
4681
4681
  },
4682
4682
  {
4683
4683
  "path": "modules/grading/grader-score.js",
4684
4684
  "mode": "0000644",
4685
- "sha256": "e0f665b760e2b299a7aa9098e1ab967aa330ff20f7430e0aa23d9c7c57aa0d70"
4685
+ "sha256": "a2c6efcbdcff7631f711b0b156ec8ded0f8d4f9f8f6e565b39961894e2e7342d"
4686
4686
  },
4687
4687
  {
4688
4688
  "path": "modules/grading/grader-subagent.js",
4689
4689
  "mode": "0000644",
4690
- "sha256": "b092ee77b0b19d07940a50ea3768908a82d1372f55062139854c4f5b199dc173"
4690
+ "sha256": "4a185832e6bd6bce5bc7ad58d3f53f377a09b997a65037cb97714617cc6e0740"
4691
4691
  },
4692
4692
  {
4693
4693
  "path": "modules/grading/grader-workers/efficiency.js",
@@ -4747,7 +4747,7 @@
4747
4747
  {
4748
4748
  "path": "modules/grading/grader.js",
4749
4749
  "mode": "0000644",
4750
- "sha256": "a3ed3eaf70f1a1101630d7f2fc9adb71779c2385d8539ffe80c2edccd616a0ad"
4750
+ "sha256": "e223155c25f1fe4a66d7e3dd03b10632b76d4a7b851182df4afd05f5ae9d40bd"
4751
4751
  },
4752
4752
  {
4753
4753
  "path": "modules/grading/module.json",
@@ -5977,7 +5977,7 @@
5977
5977
  {
5978
5978
  "path": "modules/lifecycle/db-ship.js",
5979
5979
  "mode": "0000644",
5980
- "sha256": "c239b8cb88087f7bdb860c876e3e924bc1efef3cdba0ddec0374f71f7f2082d5"
5980
+ "sha256": "a774d51dd8bc9d6b1e1bd52f9b0da0f240d0881ff2ab4218a2ffe7af56366fc6"
5981
5981
  },
5982
5982
  {
5983
5983
  "path": "modules/lifecycle/db-tasks.js",
@@ -8442,12 +8442,12 @@
8442
8442
  {
8443
8443
  "path": "package-lock.json",
8444
8444
  "mode": "0000644",
8445
- "sha256": "8bc4159c82c66d02c808e07894e32b1f60f12e46384d9d535c4b603605e5420f"
8445
+ "sha256": "656579d0a1b5572cb3af67d5224a450c34175a8cc0804c68149f653aec7e77d7"
8446
8446
  },
8447
8447
  {
8448
8448
  "path": "package.json",
8449
8449
  "mode": "0000644",
8450
- "sha256": "64ebac363a5645b7b24781ef504f245cc3ebbda68eab36cff10bdc9a2d9c2716"
8450
+ "sha256": "a5dd2e4c5f4ae817b4c34e70319307e79b4b0ff119bd56e3d4db4f933512b45d"
8451
8451
  },
8452
8452
  {
8453
8453
  "path": "public-docs/index.html",
@@ -8467,7 +8467,7 @@
8467
8467
  {
8468
8468
  "path": "release-notes.json",
8469
8469
  "mode": "0000644",
8470
- "sha256": "f6742c6fe0101e4c11797f7f8ad2933b4012ff0a8f6f04b77a4ee0e91b7a234c"
8470
+ "sha256": "5eff67626993ed0c57101af392a9943d2e19c59571f6497ebc38a4d5d799afdb"
8471
8471
  },
8472
8472
  {
8473
8473
  "path": "scripts/bongos-mcp.js",
@@ -8609,11 +8609,6 @@
8609
8609
  "mode": "0000644",
8610
8610
  "sha256": "937db2bca1f94713fb02857b2e31c3ee86c53cc51d7bd4d81b08f10df7e4b579"
8611
8611
  },
8612
- {
8613
- "path": "scripts/gds/audit-ships.js",
8614
- "mode": "0000644",
8615
- "sha256": "891e795c68d43d11958a2e68af0cfb1fcd5a1f3308c821f86ff37512326ef72d"
8616
- },
8617
8612
  {
8618
8613
  "path": "scripts/gds/autobongos-digest.js",
8619
8614
  "mode": "0000644",
@@ -8787,7 +8782,7 @@
8787
8782
  {
8788
8783
  "path": "scripts/gds/claim.js",
8789
8784
  "mode": "0000644",
8790
- "sha256": "9fe328a1f512464b142d77db2c05e3db7fbdfe3d466f74590d724022931c6500"
8785
+ "sha256": "fa32e8470869dc7af8e8b016a28d52bf1b53ba80a89d894bf7615a92d0440c73"
8791
8786
  },
8792
8787
  {
8793
8788
  "path": "scripts/gds/classify-discipline.js",
@@ -9172,7 +9167,7 @@
9172
9167
  {
9173
9168
  "path": "scripts/gds/grade-smoke.js",
9174
9169
  "mode": "0000644",
9175
- "sha256": "14bc150d985492f180c5a22cadfffcfa355be2543ba54d7f20876dd6a4d364ee"
9170
+ "sha256": "46e6cc10c3fb6c75b59eca551c12db815d62c98d89b1cb01acda14a590ce2df2"
9176
9171
  },
9177
9172
  {
9178
9173
  "path": "scripts/gds/home-isolation-guard.js",
@@ -9552,7 +9547,7 @@
9552
9547
  {
9553
9548
  "path": "scripts/gds/render-check.js",
9554
9549
  "mode": "0000644",
9555
- "sha256": "f7e3a3fd8aec3b23ffa146b15410836be42c61fa9e0c03a5215247c7f6ae8944"
9550
+ "sha256": "22ccdd2e3d0e63f426410febbc674d376d878f3bee9ebc7530dacf525edcc3a3"
9556
9551
  },
9557
9552
  {
9558
9553
  "path": "scripts/gds/render-ideas.js",
@@ -9817,7 +9812,7 @@
9817
9812
  {
9818
9813
  "path": "scripts/gds/ship-check.js",
9819
9814
  "mode": "0000644",
9820
- "sha256": "230a6ee6d37952e380e4cdeecfabea14258d0877c35ca2c4c71de9e4eb7f0b69"
9815
+ "sha256": "40322d95339d20fd0ab0dcf6bd528736b815d895b31ca6a54490fb31c769a480"
9821
9816
  },
9822
9817
  {
9823
9818
  "path": "scripts/gds/ship-deploy-target.js",
@@ -9837,7 +9832,7 @@
9837
9832
  {
9838
9833
  "path": "scripts/gds/ship-flow.js",
9839
9834
  "mode": "0000644",
9840
- "sha256": "3be3d4d57854896fa639cee47c3781c3f202293dcd6f1e46d6d8acb0f7eedfc7"
9835
+ "sha256": "ecf43a2c1e8149bb383c10213fd45f7b7bd15bb44d4f14ce078e4ff249efa007"
9841
9836
  },
9842
9837
  {
9843
9838
  "path": "scripts/gds/ship-git.js",
@@ -9847,7 +9842,7 @@
9847
9842
  {
9848
9843
  "path": "scripts/gds/ship-grade-steps.js",
9849
9844
  "mode": "0000644",
9850
- "sha256": "3a37ac4af0628539a058a757c0709c98740cc93f56c81687c98efb11b276ada2"
9845
+ "sha256": "89025445be960efd1faedbea57dc6ffdef42bdd637e47409d42671eb3744ffd1"
9851
9846
  },
9852
9847
  {
9853
9848
  "path": "scripts/gds/ship-grade.js",
@@ -10087,7 +10082,7 @@
10087
10082
  {
10088
10083
  "path": "scripts/gds/visual-review-nudge.js",
10089
10084
  "mode": "0000644",
10090
- "sha256": "38e98180ddfd59189dedc3d3655d0a0672bde9a364cbaea5846aa4f16296107e"
10085
+ "sha256": "cf034e9c4c5887dde47951272dba1e31b9b94a212640181de1cc3086e225b357"
10091
10086
  },
10092
10087
  {
10093
10088
  "path": "scripts/gds/worktree-claim-guard.js",
@@ -10527,7 +10522,7 @@
10527
10522
  {
10528
10523
  "path": "src/module-api.js",
10529
10524
  "mode": "0000644",
10530
- "sha256": "aa1249f6836cac45e41de0aa8047758dd0c271301a0c2ca986ed440d165f2318"
10525
+ "sha256": "7d7946d420008189ad09b1871574c396acb3e7b24b0961e0118e381dd01e4c9d"
10531
10526
  },
10532
10527
  {
10533
10528
  "path": "src/module-loader/catalog.js",
@@ -10664,6 +10659,11 @@
10664
10659
  "mode": "0000644",
10665
10660
  "sha256": "0f2a8a6be741613eaf9f6cb9e771ad97d15764ddfd7bff2732449dff3136de3e"
10666
10661
  },
10662
+ {
10663
+ "path": "tests/adr_0162_gate_citation.mjs",
10664
+ "mode": "0000644",
10665
+ "sha256": "ee9766e953ebee654d1addab7de9952424ba20383c796ad050dde21ffc403c2f"
10666
+ },
10667
10667
  {
10668
10668
  "path": "tests/adr_renumber_integrity.mjs",
10669
10669
  "mode": "0000644",
@@ -10879,11 +10879,6 @@
10879
10879
  "mode": "0000644",
10880
10880
  "sha256": "4973872431cb0e5e7aedb978f4d5b28f804fe33aa8288f16d2656a28c85befbe"
10881
10881
  },
10882
- {
10883
- "path": "tests/audit_ships_git_argv.mjs",
10884
- "mode": "0000644",
10885
- "sha256": "bb7f06a866ccea00a88d2f373c70f7e4bc0a3aa5e658c61346046b83637baa35"
10886
- },
10887
10882
  {
10888
10883
  "path": "tests/auth_admission_gate.mjs",
10889
10884
  "mode": "0000644",
@@ -12457,7 +12452,7 @@
12457
12452
  {
12458
12453
  "path": "tests/grader.mjs",
12459
12454
  "mode": "0000644",
12460
- "sha256": "fd1ba73b702d61774275e8a7d4af7a8f14173505d98e966744d17a17321c49e0"
12455
+ "sha256": "53846b08eea7bf6fd65b6875c6fbefad8b7d732bc8144b99d816b54fe38e8c8e"
12461
12456
  },
12462
12457
  {
12463
12458
  "path": "tests/grader_bypass.mjs",
@@ -12517,7 +12512,7 @@
12517
12512
  {
12518
12513
  "path": "tests/grader_unbacked_score.mjs",
12519
12514
  "mode": "0000644",
12520
- "sha256": "2414709a2d99d5a4be9de7fd71b06c27713e8230155c4021b4efcfd4e0ef9347"
12515
+ "sha256": "6e834f3cf75dd34ba30795c46bc401098053a56c967da8661128f34db71ff8c3"
12521
12516
  },
12522
12517
  {
12523
12518
  "path": "tests/guild_namespace_reserved.mjs",
@@ -14162,7 +14157,7 @@
14162
14157
  {
14163
14158
  "path": "tests/regrade_actual_minutes.mjs",
14164
14159
  "mode": "0000644",
14165
- "sha256": "ad6d883fcb09f31dc7c06a2334ad807c15bd1effba43ef12b5fbdbf0ab141041"
14160
+ "sha256": "f65c6c88be028b3bff54a88a98f4045f0b86505267722faa405d9974573ee5d4"
14166
14161
  },
14167
14162
  {
14168
14163
  "path": "tests/regrade_eligibility.mjs",
@@ -14197,7 +14192,7 @@
14197
14192
  {
14198
14193
  "path": "tests/render_check.mjs",
14199
14194
  "mode": "0000644",
14200
- "sha256": "978608685d648729a2c324858a92d583cb4763b9355f40760b7408235e20d064"
14195
+ "sha256": "88d6f0edf277344787be817885a6c78a811f01a300d94accbe1e16ed8d6230c3"
14201
14196
  },
14202
14197
  {
14203
14198
  "path": "tests/render_prefs.mjs",
@@ -14712,7 +14707,7 @@
14712
14707
  {
14713
14708
  "path": "tests/skill_grade_audit.mjs",
14714
14709
  "mode": "0000644",
14715
- "sha256": "679a890baa82da9cf6c05e63c5a53294e6786145b5ceffee81b7f38d4f4b6064"
14710
+ "sha256": "7deff847f2caa66d6956bc759c1e2dc59dc4169e2d25ced1cb4273237397e84a"
14716
14711
  },
14717
14712
  {
14718
14713
  "path": "tests/skill_grade_recover.mjs",
@@ -14722,7 +14717,7 @@
14722
14717
  {
14723
14718
  "path": "tests/skill_grader_health.mjs",
14724
14719
  "mode": "0000644",
14725
- "sha256": "d3b9cf9eb60bd1140a388f4d725aa27edba253e061b85e924aab4d7aa909ef48"
14720
+ "sha256": "37d75d31bc14671b2a9a974b941997f624dd4668a4d9d76472915436b2ef567e"
14726
14721
  },
14727
14722
  {
14728
14723
  "path": "tests/skill_lint.mjs",
@@ -73,7 +73,7 @@ A grade block naming protected surfaces above your rank is an authorization wall
73
73
 
74
74
  ## Constraints
75
75
 
76
- - **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.
76
+ - **It recovers; it adds nothing to pass.** This skill describes and recovers a stalled ship. It never inserts a human-approval step into the ship path (ADR 0162 retired those) and never invents a checkpoint of its own: a recovery tool that added a step would be one more thing to recover from.
77
77
  - **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.
78
78
  - **`--regrade` is claim-scoped**: most-recent claim holder or Archon. If you are neither, the recovery belongs to whoever is.
79
79
  - **Honest re-grade before any override.** The override-request path is for a grade that is *wrong*, not a grade that is *inconvenient*.
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Status:** accepted · **Date:** 2026-09-17 · **Task:** [task 1003990](https://cloudbongos.com/builders#/task/1003990) (goal 1000095 — BONGOS-V2)
4
4
 
5
- **Related:** [ADR 0301](0301-a-red-pr-names-its-failing-tests-in-a-commit-status.md) (a red PR names its failing tests) · [ADR 0291](0291-the-accessibility-dimension-scores-the-transcript-not-the-diff.md) (accessibility is scored after the ship) · [ADR 0162](0162-review-gates-retired-rank-consistent-ci-only.md) (no new gates on the ship path) · [ADR 0043](0043-git-ssh-trust-boundary-and-rank-floor-on-permission-paths.md) (cooperative, fail-open hook layer)
5
+ **Related:** [ADR 0301](0301-a-red-pr-names-its-failing-tests-in-a-commit-status.md) (a red PR names its failing tests) · [ADR 0291](0291-the-accessibility-dimension-scores-the-transcript-not-the-diff.md) (accessibility is scored after the ship) · [ADR 0162](0162-review-gates-retired-rank-consistent-ci-only.md) (review gates retired: no human approval in the land path) · [ADR 0043](0043-git-ssh-trust-boundary-and-rank-floor-on-permission-paths.md) (cooperative, fail-open hook layer)
6
6
 
7
7
  ## Context
8
8
 
@@ -46,7 +46,8 @@ computed after the ship.
46
46
 
47
47
  - **Count any repeated failing command.** Red → green on a test *is* the same command failing
48
48
  repeatedly; the detector would fire on ordinary work and become wallpaper.
49
- - **Block the fourth attempt.** That is a new gate on the ship path (ADR 0162), and a wrong
49
+ - **Block the fourth attempt.** That is a new gate on the ship path with no escape hatch the
50
+ stuck session can use (the admissibility test ADR 0241 draws from ADR 0162), and a wrong
50
51
  signature match would strand a builder behind the tool meant to unstick them.
51
52
  - **Server-side detection.** The server sees refused claims but not guard blocks or local red
52
53
  runs, and cannot speak into the session at the moment of the retry.
@@ -2,13 +2,13 @@
2
2
 
3
3
  - **Status:** Accepted (2026-09-23)
4
4
  - **Task:** [task 1004203](https://cloudbongos.com/builders#/task/1004203) (goal 1000095 — UI quality)
5
- - **Relates to:** [ADR 0162](0162-review-gates-retired-rank-consistent-ci-only.md) (no new gates), [ADR 0197](0197-the-ui-design-module.md) (the kit), [ADR 0223](0223-the-detector-is-two-tiers-in-the-kit.md) (floors and tells), [ADR 0241](0241-the-artist-gate-is-a-per-project-deploy-gate-that-reads-a-state.md) (the artist gate holds the deploy)
5
+ - **Relates to:** [ADR 0162](0162-review-gates-retired-rank-consistent-ci-only.md) (review gates retired: no human approval in the land path), [ADR 0197](0197-the-ui-design-module.md) (the kit), [ADR 0223](0223-the-detector-is-two-tiers-in-the-kit.md) (floors and tells), [ADR 0241](0241-the-artist-gate-is-a-per-project-deploy-gate-that-reads-a-state.md) (the artist gate holds the deploy)
6
6
 
7
7
  ## Context
8
8
 
9
9
  Nothing in the pipeline renders a page. The grader reads the diff, so a layout bug that looks right in code ships unseen. Two did in September 2026: goal titles clipped to a character count still ran past their cards, on the goal forest ([task 1003480](https://cloudbongos.com/builders#/task/1003480)) and on the goal map ([task 1004204](https://cloudbongos.com/builders#/task/1004204)); and a second child in a `#view-manage .mSec` card would have landed on the first, because every `.mSec > div` takes the same grid cell (caught by hand in [task 1003078](https://cloudbongos.com/builders#/task/1003078)). Both were found only by opening a browser. The owner's rule since then is that every page change gets a before/after review by a person, and the deploy holds on an open artist review (ADR 0241). This check is the machine half of that: something that looks at the rendered page before a person has to.
10
10
 
11
- The task left open where the check should live: an advisory row in `/ship-check`, a grader worker whose findings ride the panel, or both. It had to stay a signal (ADR 0162).
11
+ The task left open where the check should live: an advisory row in `/ship-check`, a grader worker whose findings ride the panel, or both. It had to stay a signal: the task asked for an advisory check, and the human look at a page change is the artist review that holds the deploy (ADR 0241). *Citation note (task 1004280): this sentence used to cite ADR 0162 for that, which 0162 does not say. 0162 retired gates that need a particular person's approval and keeps automatic gates that fail closed; why this check is not one is decisions 3 and 4 below.*
12
12
 
13
13
  ## Decision
14
14
 
@@ -420,7 +420,7 @@ This keeps the decision history honest and traceable.
420
420
  | 0326 | [**An upgrade may ADD a deny rule to a file the instance owns** ([task 1004156](https://cloudbongos.com/builders#/task/1004156), goal 1000090 — BONGOS-V2). Task 1003966 gave the instance starter its deny rules — no reading `.env` files, keys or session tokens, no shelving with the repo-global stash — and they reached **nobody who was already here**. The starter is written only when `.claude/settings.json` is ABSENT, and `bongos upgrade` materializes from the published package, which excludes that file on purpose; so an upgrade always takes the starter branch, always finds a settings.json already there, and left it alone. Every instance on the allow-only starter from task 1003962 — the live one included — kept it forever. That was deliberate ("rewriting a file the instance owns is the line task 1003962 drew"), and the recorded remedy was manual: re-run `bongos init`, or delete the file. **A manual remedy for a security gap protects the instances whose owners read release notes, which is not the set that needs protecting.** The owner's call: ADD the missing deny rules and NAME each one in the run output. The argument is that a deny rule is **monotonic in the safe direction** — an allow rule widens what the local agent may do, a deny rule can only narrow, so appending one cannot make any instance less safe than it was a moment earlier. That is what makes this the one merge worth doing without asking per-instance, and it extends [ADR 0121](0121-greenfield-vs-brownfield-onboarding-adopt-existing-repo.md) §2's already-licensed "merge OR leave-and-report" from `--adopt` to every materialize. "Never clobber" survives in the sense that was load-bearing: **nothing the instance wrote is removed, reordered or rewritten** — their allow rules, own denies, `ask` list, hooks, env and every key outside `permissions` come back exactly as they were, with new rules appended after. Deliberately NOT done: **no provenance**, so an owner who deletes a rule we add gets it back next upgrade and (deny beating allow in Claude Code's order) cannot override it with an allow — rejected as speculative machinery for a case nobody has hit, revisit on a real complaint; a file that will not parse, or whose `permissions`/`permissions.deny` is not the expected shape, is left BYTE-FOR-BYTE alone and reported, the posture task 1004023 took for the core's own file, because a half-understood rewrite of a permissions file is worse than the gap; and **the allow half is never topped up** — the safety argument is directionality and does not survive being applied to a rule that grants. `materializeClaude` gains `summary.settingsDenyAdded` + `settingsDenyUncheckable`, both printed through `log()` since `upgrade.js` does not iterate `summary.notes`. The test asserting an instance's settings.json comes back byte-identical is superseded by a strictly stronger one — every rule still there, unmoved, deny-only growth — the weaker spelling being what froze the gap in place. **AMENDED 2026-09-22 by [task 1004158](https://cloudbongos.com/builders#/task/1004158): the two shelf rules are now starter-only and the top-up asks for the CREDENTIAL half alone.** 0326 itself named this exclusion as the remedy if the rule ever bit; the owner took it ahead of that, because the monotonicity argument licenses a rule about reading a secret and does not reach one that guards a workflow — with no provenance and deny beating allow, an instance that loses the shelf cannot give it back. A fresh instance still gets both. The top-up only ever appends, so this is **forward-looking only**: an instance that already took them keeps them, live included.](0326-an-upgrade-may-add-a-deny-rule-to-a-file-the-instance-owns.md) | security / instance onboarding |
421
421
  | 0327 | [**A `cloud-host` runs on the owner's own account, and the key is borrowed, not stored** ([task 1004175](https://cloudbongos.com/builders#/task/1004175), goal 1000106 — BONGOS-V2). [ADR 0323](0323-hosting-is-three-shapes-and-we-are-not-the-landlord.md) moved a `cloud-host` to Render to stop being a landlord but left **whose account** unexamined; [ADR 0325](0325-the-managed-fleet-control-plane-is-the-hub-we-already-run.md) §4 then ruled the platform token is ours and "never per-customer". Standing it up disproved the premise: a Render API key is issued against a **user** and carries their rights in **every workspace they belong to** — the owner's reached three, one of them another builder's, holding their live production. The same check found `mercury` **already on Render**, run by its own owner, which 0323 would have migrated OFF a correct setup onto our bill. The remaining landlord relationship was never the servers; it was the **account**. **Decisions:** (1) each project brings its own platform key — we hold no billing relationship for anyone's compute, and a leaked key's blast radius is exactly its own owner's account, a property that comes from the decision and not from cryptography; (2) the key is **borrowed for standup and cleared**, never stored, because nothing afterwards needs it — Render auto-deploys from Git, the deploy door ([ADR 0293](0293-the-owners-deploy-door-is-an-intent-the-control-plane-drains.md)) is a push, liveness is the [ADR 0252](0252-the-self-hosted-visibility-report-is-a-pull-and-auto-appear-buys-a-retraction-lever.md) pull — so it rides the queue as a short-lived value encrypted with the existing `secret-box.js`, the [ADR 0133](0133-github-app-manifest-onboarding-signin.md) handshake's shape; (3) we **never destroy a customer's infrastructure** — teardown disconnects, the owner deletes their own services, a safety property first and the reason (2) works; (4) **two shapes, not three** (`dedicated-cloud-host` removed — on someone's own account a bigger plan is a setting, finishing 0323 §1's own "plan size, not a second code path"), and the **free tier is free**, 0323 §7's cap retired with its premise. **Deliberately NOT built, because nothing is stored:** an asymmetric sealing module, per-row credential binding, rotation/revocation, and the separate-unix-user precondition — each designed in full, then deleted when the retention question was asked instead of assumed. **Stated honestly:** encrypting the in-transit value protects it from a database dump, NOT from a compromised web tier, because the owner's key arrives there in plaintext first; that defence was never available at any retention length. **§5 records a measurement, fixed elsewhere:** [ADR 0111](0111-instance-hosting-provisioning-module.md) §2's boundary is enforced by the CODE, not the kernel — `cloudbongos.service` runs `User=lars` with no sandboxing and `/etc/cloudbongos/box.env` is mode 600 owned by `lars`, so the web tier CAN read the DigitalOcean, Cloudflare and platform tokens; 0325 §4's "root-only" is not what is on the box. (A second finding in the same section — a "mode 777" key file — was **void and is corrected in place**: the path is a symlink, whose mode display is meaningless, to a 600 target. It was inferred from an `ls` rather than an attempted read.) **Resolved 2026-09-23 by [task 1004176](https://cloudbongos.com/builders#/task/1004176)**, and more narrowly than §5 proposed — not the unix split (which would mean relocating the checkout, config dir, `web.env` and the secret-box master key the web tier legitimately needs), but a systemd drop-in with `InaccessiblePaths`, verified as the service user; proving it as **root** reports "no effect" against a working config, because `CAP_DAC_OVERRIDE` bypasses the mode-000 over-mount. It is emphatically NOT a precondition here — that is the point of storing nothing, and had we sealed per-project keys with a private key in that same file the two would have had to land together. **Consequences:** the migration shrinks to an **adoption**; the cost ledger's question inverts (our spend on a `cloud-host` is ~\$0 and correct — what an owner is worth telling is THEIR Render cost, a different column, [task 1004148](https://cloudbongos.com/builders#/task/1004148)); and metering loses its forcing function, cost *visibility* surviving as a feature while billing for hosting does not ([task 1001949](https://cloudbongos.com/builders#/task/1001949)). Rejected: storing each key sealed with a key pair (three days plus a live-site infra change, to keep a value needed once); one platform account holding every project (0325 §4 as written — keeps us the billing landlord and makes one credential reach every customer); generating a Blueprint and having the owner click once in Render (simplest, but the click is the exact friction `cloud-host` exists to remove); and keeping the key in the browser to call Render directly (standup is a runner job with retries and an audit trail, not a page that stays open).](0327-a-cloud-host-runs-on-the-owners-account-and-the-key-is-borrowed.md) | hosting / provisioning / credentials |
422
422
  | 0328 | [**A hosted project's authority is its membership row, not its owner column** ([task 1003882](https://cloudbongos.com/builders#/task/1003882), goal 1000094 — BONGOS-V2). The owner's decision (2026-09-13): every API action must name its project, and a non-member may only apply. Two "project" concepts exist and answer different questions: `provisioning_instances` (the hub's fleet registry, single `owner_builder_id`, [ADR 0325](0325-the-managed-fleet-control-plane-is-the-hub-we-already-run.md)) and `<redacted>` (`client_id, github_id, membership_kind ∈ {owner,member,visitor,pending}`, already correct, already backing `GET /my-projects`). The composition this needs already exists once, in the opposite direction: `provisioning.projectOwnedBy` is a published port (task 1003580) that `platform-identity/invite-authz.js` already consumes via `resolveOptional` to ask "does this builder own this project" without importing provisioning (ADR 0083). **The gap is that the module which owns the fact does not use it on itself, and has grown three separate local copies of it instead of one** — `instanceAccessDenied` (6 routes), `resolveOwnInstance` (4 routes) and `disconnect.js`'s own inline copy (1 route) all implement "owner OR archon", while 3 routes (`teardown`, `domain`, `github-app`) implement only "owner" with no archon override at all — an existing inconsistency between sibling routes in the same module, not just duplication, and none of the three implementations is visible to `route-rank-check.js`. Decision: (1) project scope stays the existing path segment, resolved through `slug` (the `client_id = slug` join key [ADR 0246](0246-catalog-membership-is-a-projection-not-a-federation-side-effect.md) already establishes); (2) Phase 1 extracts one local `requireProjectOwner` helper replacing all three implementations — a behavior-preserving swap for 11 routes and a stated, intentional archon-override widening for the 3 that lacked it — no new port needed since provisioning already holds the column; Phase 2 adds a new port `platform-identity.projectMembershipKind` and widens the same helper to admit `owner` OR `member`, falling back to the Phase 1 column check when platform-identity isn't installed (ADR 0083's degrade-gracefully contract) — a NEW parallel axis, not a fifth branch on `requirePermission`, mirroring why the ownership axis ([ADR 0151](0151-governance-permissions-as-atom-ranks-as-roles.md) §3, R100) is kept separate; (3) a caller with NO membership row still gets 404 `instance_not_found` (existence-hidden, unchanged), but a `pending`/`visitor` row gets 403 `project_membership_required` naming `POST /my-projects/join` (ADR 0141/0201/0247's existing apply flow) — the "apply to join it" the owner's decision names, routed into the flow that already ships rather than a second one; (4) `route-rank-check.js` gains a `project_scope_missing` finding (blocker on write, concerns on read) for any `/provisioning/instances/:id...` route missing the gate, the same structural read it already gives `requirePermission`; (5) migration order is the 14 evidenced routes only — the task's own "96 write routes" figure is the whole app's census, and the other ~82 act on a single-tenant instance's own Bongos board, which [ADR 0100](0100-two-repo-instance-model.md) §3 already isolates one-database-per-repo and has no project dimension to name. Filed: [task 1004159](https://cloudbongos.com/builders#/task/1004159) (the helper) · [task 1004160](https://cloudbongos.com/builders#/task/1004160) (route-rank-check.js, depends on 1004159) · [task 1004161](https://cloudbongos.com/builders#/task/1004161) (the membership port, depends on 1004159) · [task 1004162](https://cloudbongos.com/builders#/task/1004162) (the 403/404 split, depends on 1004161). Rejected: a second `provisioning_instance_members` table (the membership table already exists and joins on the same key — a second one repeats the mistake ADR 0325 already refused); folding project authority into `requirePermission` as a fifth axis (same reasoning R100 already applied to `.own` keys); migrating all 96 write routes (re-litigates ADR 0100's single-tenant model, not this decision); dropping 404 existence-hiding entirely (a total stranger should learn nothing, exactly as `invite-authz.js` already guarantees).](0328-a-hosted-projects-authority-is-its-membership-row-not-its-owner-column.md) | security / authorization / provisioning |
423
- | 0329 | [**The rendered fit check is a kit floor and an advisory ship-check row, not a grader worker** ([task 1004203](https://cloudbongos.com/builders#/task/1004203), goal 1000095 — UI quality). Nothing in the pipeline rendered a page, so titles clipped by character count ran past their cards (task 1003480, task 1004204) and a second `.mSec` child would have landed on the first (task 1003078), each found only in a browser. Two new kit floors, `text-fit` (text measured word by word past its box; SVG text past its card rect) and `sibling-overlap` (in-flow, block-level, text-bearing siblings), run in every `render.js` render; `scripts/gds/render-check.js` renders the pages a branch changed at 1280 + 390 and `/ship-check` shows them as an ADVISORY row that never flips its exit (ADR 0162). Not a grader worker: that would put a browser, fixtures and a harness on the grader host for signal the builder already saw; the artist gate (ADR 0241) stays the human look before deploy.](0329-the-rendered-fit-check-is-a-kit-floor-and-an-advisory-ship-check-row.md) | ui-design / kit + ship-check |
423
+ | 0329 | [**The rendered fit check is a kit floor and an advisory ship-check row, not a grader worker** ([task 1004203](https://cloudbongos.com/builders#/task/1004203), goal 1000095 — UI quality). Nothing in the pipeline rendered a page, so titles clipped by character count ran past their cards (task 1003480, task 1004204) and a second `.mSec` child would have landed on the first (task 1003078), each found only in a browser. Two new kit floors, `text-fit` (text measured word by word past its box; SVG text past its card rect) and `sibling-overlap` (in-flow, block-level, text-bearing siblings), run in every `render.js` render; `scripts/gds/render-check.js` renders the pages a branch changed at 1280 + 390 and `/ship-check` shows them as an ADVISORY row that never flips its exit. Not a grader worker: that would put a browser, fixtures and a harness on the grader host for signal the builder already saw; the artist gate (ADR 0241) stays the human look before deploy.](0329-the-rendered-fit-check-is-a-kit-floor-and-an-advisory-ship-check-row.md) | ui-design / kit + ship-check |
424
424
  | 0330 | [**An ask is answered where it was asked** ([task 1004216](https://cloudbongos.com/builders#/task/1004216), goal 1000095 — BONGOS-V2), amending [ADR 0187](0187-collab-four-decisions.md) §4a. `lifecycle_004` let a builder ASK for help and let the **asker** mark their own row answered; the person being **asked** had no write at all, so the answer happened somewhere Bongos cannot see and the row sat open until its author remembered it — six asks addressed to the owner had been open between four and thirteen days on 2026-09-23, every one of them answerable. That was not an oversight: §4a deferred conversation to the Agora and a test named *"there is deliberately NO reply thread"* enforced it. **The deferral lost its addressee** — task 1002946 is ABANDONED and goal 1000064 ARCHIVED (verified against the live DB), so the rule had stopped meaning "wait for the Agora" and started meaning "an ask stays unanswerable forever to keep a promise to something that does not exist". **Decisions:** (1) an ask carries a thread of replies, APPEND-ONLY in the SCHEMA rather than by convention — no `updated_at`, `edited_by`, `deleted_at` or `parent_reply_id`, no reactions, no mentions, and a trigger that refuses UPDATE and DELETE outright, because a thing you can edit, nest, react to and address at people is a chat and that is what §4a declined; any builder may reply, since the board read is already project-wide and the good case is somebody you did not ask knowing the answer; (2) the **ADDRESSEE** may close an ask (`answered`), widening an asker-only UPDATE that was coherent only while nothing could be said on the row — but `withdrawn` does NOT widen, since "I no longer need this" is the asker's sentence alone and widening it would be a way to make an ask vanish unanswered; `settled_by` records which of the two closed it, and ADR 0187 §3's consent posture is untouched — closing ends a question, it does not accept work; (3) `/collab-review` posts the reply and **leaves the ask open** (owner decision), since an answer the reader has not read is exactly what an unattended run must halt on. **Consequences:** a reply cannot be taken back, by design; the FK **RESTRICTS rather than cascades** — the first draft cascaded, which reads right and was wrong, because a cascade is a plain DELETE the trigger refuses, so deleting an answered ask failed outright (caught by applying the migration to a real Postgres, not by reading it); the old test was REPLACED, not deleted, so the record that the restraint was deliberate survives; and replies inherit the pull-not-push posture, so nothing still tells an asker they were answered. Rejected: a single `answer` column (cheapest and unambiguously not a chat, but a follow-up would have nowhere to go except a second ask, splitting one conversation across two rows); waiting for the Agora (abandoned — waiting means forever); letting anyone close any ask (an open question is somebody's, and a stranger ending it should not be one click away).](0330-an-ask-is-answered-where-it-was-asked.md) | collab / lifecycle / schema |
425
425
  | 0331 | [**The sky is the ideator's home, and the project sky takes the goal map's page** ([task 1004229](https://cloudbongos.com/builders#/task/1004229), goal 1000095 — BONGOS-V2), amending [ADR 0227](0227-a-task-network-map-is-refused-the-goal-graph-is-the-map.md) and decision 11 of `docs/specs/<redacted>.md`. The owner reviewed an interactive prototype of the ideator sky and the project sky over five rounds on 2026-09-24 and adopted it AS IS — copy, layout, colours, tour text, toggles, interactions — which contradicts two things already written down, so they are rewritten rather than leaving the build graded against a contract nobody means any more. **Decisions:** (1) the sky is the ideator's HOME surface — it replaces *Your thinking*, and the project sky replaces the goal map page — so "never load-bearing" and "arrives last" are DROPPED as a sequencing hedge from before there was a design to look at; the rule that survives at full force is the accessibility half, that the sky is never the ONLY path to anything it shows (the list drawer — the room — is one key away, and every drawn thing is a row in it); (2) ADR 0227 is AMENDED, not reversed — its measured refusal of a whole-corpus task map stands, and the project sky is §1's own prescription rather than its refusal: the goal graph is the entry point, tasks are drawn only INSIDE one goal past a zoom threshold (the per-goal drill-down §10.5 measured readable at 85.2px pitch worst case), below that they are dust density on the rings with NO identities, and the goal map's table survives as the sky's ledger drawer (§6's table equivalent kept); the nav slot the goal map was deliberately denied is GRANTED to the project sky, under Goals (owner, 2026-09-24), so part 4 changes the page and the test asserting no slot together; (3) the five states and the two channels are UNTOUCHED — criterion `ideator-sky-tells-the-truth` names a model, not a picture, and this amendment changes the picture's standing only; (4) the two HEURISTICS in the prototype — an idea's origin guessed from its text, and "born of a thought" found by scanning text for idea ids — must not ship as ledger facts: parts 3 and 4 hide both layers, part 5 replaces them with a `filed_via` column and a real born-of read. **Consequences:** `docs/design/mocks/sky/sky.template.html` is the PIXEL CONTRACT for parts 2–5, and every deviation a gate or the file ratchet forces is listed in that part's ship notes; no snapshot JSON or built page is ever committed (it carries real task and idea titles and this repo is public); ADR 0264's deleted goal "Living project sky" is superseded by this work under Working area 3. Rejected: shipping the sky as an extra and keeping "never load-bearing" (makes the adopted home surface unroutable); reversing ADR 0227 (its refusal is measured and still correct — the sky needs its drill-down shape, not its repeal); shipping the heuristics behind a disclaimer (a labelled guess is still a guess in a picture whose promise is that it cannot be faked).](0331-the-sky-is-the-ideators-home.md) | design / ideator / sky |
426
426
  | 0332 | [**Offboarding scrubs stored secrets: an event, not a direct write, and reactivation restores neither** (spike [task 1003338](https://cloudbongos.com/builders#/task/1003338), goal 1000110 — BONGOS-V2). `deactivateBuilder` revokes sessions but never scrubs the two third-party credentials the platform holds on a departing builder's behalf: the `github_oauth_tokens` row and the per-builder Gemini BYOK key (`gemini_key_enc`/`last4`/`set_at`, module-owned by `art-pipeline` per [ADR 0102](0102-finish-bounding-the-kernel.md)). **Decisions:** (1) `deleteGithubToken` is called synchronously inside `deactivateBuilder`'s existing transaction — the table is core's own; (2) a new best-effort event, `builder.secrets-scrub-needed`, is emitted post-commit (mirroring the existing `builder.box-reconcile-needed` pattern) so `art-pipeline` — or any future module storing a builder-keyed secret — can clear its own store without core reaching across the module boundary ADR 0102 drew; (3) reactivation restores NEITHER secret, symmetric with rank ("not auto-restored… re-promotes deliberately") — a returning builder re-enters their own key and re-derives a fresh GitHub token. **Rejected:** a direct `UPDATE` nulling the Gemini-key columns from core (re-opens the ADR 0102 leak); deleting the `builders` row to get `ON DELETE CASCADE` for free (breaks the explicit lossless design of graceful exit); a cron sweep (a new mechanism where an event already fits); auto-restoring the key on reactivation (a stored credential is not earned state). The core-side change (GitHub-token delete, event emission, contract doc, tests) shipped with this task; follow-up [task 1004239](https://cloudbongos.com/builders#/task/1004239) is narrowed to the `art-pipeline` module-side listener plus a periodic reconcile backstop.](0332-offboarding-secret-scrub-semantics.md) | security / privacy / modules |
@@ -2551,5 +2551,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
2551
2551
  landed since 1.19.1034 with no explicit bump. run 36226356336. (task 1002620)
2552
2552
  1.19.1036 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2553
2553
  landed since 1.19.1035 with no explicit bump. run 36226955285. (task 1002620)
2554
+ 1.19.1037 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2555
+ landed since 1.19.1036 with no explicit bump. run 36227523642. (task 1002620)
2554
2556
  ---------------------------------------------------------------------------
2555
2557
  ```
@@ -1048,7 +1048,7 @@ async function awardSessionTokenReward(
1048
1048
 
1049
1049
  // net-negative ship bonus — V3.R93 (#354). Simplification reward.
1050
1050
  //
1051
- // The v1 grader's scoreLocNetNegative concept (a ship that removes more lines
1051
+ // The retired v1 grader's loc-net-negative criterion (a ship that removes more lines
1052
1052
  // than it adds is a win) was only ever expressed as a rubric SCORE in the
1053
1053
  // deprecated deterministic grader — it never moved credits. Here we revive the
1054
1054
  // idea as a small, real credit bonus routed through the SAME credit_log path
@@ -16,19 +16,13 @@ const RUBRIC = JSON.parse(
16
16
  fs.readFileSync(path.join(__dirname, 'grader-rubric.json'), 'utf8')
17
17
  );
18
18
 
19
- // V4 = the active panel-based gate. V3 / V1 are kept under their fields for
20
- // the two paths that still read them: V3 = the trivial-diff multi-shot grader
21
- // (ship.js #513), V1 = the audit-ships.js retroactive deterministic path. The
22
- // v2 binding + its rubric block were dead (no reader) and removed in task 466.
19
+ // V4 = the active panel-based gate, and the only rubric block left. The v2 block
20
+ // was removed in task 466; v1 (with audit-ships.js, its only reader) and v3 (whose
21
+ // only live field was the unused 3-shot default) in task 1002842.
23
22
  const V4 = RUBRIC.v4;
24
- const V3 = RUBRIC.v3;
25
- const V1 = RUBRIC.v1;
26
23
  const THRESHOLD = V4.threshold;
27
24
  const VERSION = V4.version;
28
25
  const LOW_CONFIDENCE = V4.low_confidence_threshold;
29
- // DEFAULT_SHOTS is kept for the v3 multi-shot path (still exported for
30
- // diagnostics); v4 doesn't use shots — it uses workers.
31
- const DEFAULT_SHOTS = V3.shots || 3;
32
26
  const ASSUMED_BUILDER_MODEL = V4.assumed_builder_model || 'claude-fable-5';
33
27
  const DEFAULT_GRADER_MODEL = V4.default_model || 'claude-sonnet-5';
34
28
  const FALLTHROUGH_CONFIDENCE = V4.fallthrough_confidence ?? 0.3;
@@ -80,13 +74,10 @@ function routeRankPrePass(changedFiles) {
80
74
  module.exports = {
81
75
  ASSUMED_BUILDER_MODEL,
82
76
  DEFAULT_GRADER_MODEL,
83
- DEFAULT_SHOTS,
84
77
  FALLTHROUGH_CONFIDENCE,
85
78
  LOW_CONFIDENCE,
86
79
  RUBRIC,
87
80
  THRESHOLD,
88
- V1,
89
- V3,
90
81
  V4,
91
82
  VERSION,
92
83
  WORKER_MODEL_TIERS,