@bongos/core 1.18.19 → 1.19.3
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 +547 -197
- package/.claude/skills/builder-box/SKILL.md +1 -1
- package/.claude/skills/builder-claim/SKILL.md +1 -1
- package/.claude/skills/goal-create/SKILL.md +1 -1
- package/.claude/skills/idea-triage/SKILL.md +1 -1
- package/.claude/skills/planning-session/SKILL.md +5 -5
- package/.claude/skills/scan-before-install/SKILL.md +165 -0
- package/bin/bongos.js +33 -7
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +63 -41
- package/clients/bongos-client/index.cjs +63 -41
- package/clients/bongos-client/index.d.ts +78 -44
- package/clients/bongos-client/index.mjs +63 -41
- package/docs/adr/0020-security-model-public-stub.md +1 -1
- package/docs/adr/0097-one-active-claim-per-session-and-worktree-binding.md +2 -0
- package/docs/adr/0137-upstream-publish-policy-manual-owner-gated.md +1 -1
- package/docs/adr/0144-devbox-rehome-onto-cloudbongos-plane.md +1 -1
- package/docs/adr/0151-governance-permissions-as-atom-ranks-as-roles.md +2 -1
- package/docs/adr/0155-adopt-private-repo-widen-oauth-scope.md +51 -0
- package/docs/adr/0156-user-set-display-name-wins.md +62 -0
- package/docs/adr/0157-archon-is-rank-and-identity-only.md +93 -0
- package/docs/adr/0158-choke-point-verdict-taxonomy.md +174 -0
- package/docs/adr/0159-merge-gate-reconciliation.md +88 -0
- package/docs/adr/0160-main-audit-repo-verifiable-caller.md +77 -0
- package/docs/adr/0161-publish-on-merge.md +34 -0
- package/docs/adr/README.md +9 -0
- package/docs/api/openapi.json +1209 -233
- package/docs/api-reference.md +61 -46
- package/docs/architecture.md +1 -1
- package/docs/canonical-permissions.md +61 -16
- package/docs/design/vanilla-hall-ui-redesign-scope.md +1 -1
- package/docs/file-map.md +4 -1
- package/docs/onboarding/diagrams/assertions.json +3 -3
- package/docs/recipes/core-release-pipeline.md +181 -0
- package/docs/recipes/packaging-the-core.md +2 -0
- package/docs/recipes/parallel-goal-waves.md +1 -3
- package/docs/recipes/private-npm-distribution.md +6 -2
- package/docs/recipes/upgrading-the-core.md +2 -0
- package/migrations/core_197_display_name_source.sql +56 -0
- package/migrations/core_204_rekey_active_claim_per_session_worktree.sql +77 -0
- package/migrations/core_205_versions_track_default.sql +28 -0
- package/modules/autonomy/routes/autonomy.js +1 -1
- package/modules/builder-settings/db.js +7 -1
- package/modules/dev-box/app/src/vendor/bongos-client.cjs +63 -41
- package/modules/dev-box/routes/box.js +11 -9
- package/modules/discord/auth.js +3 -1
- package/modules/discord/routes/discord.js +8 -2
- package/modules/discord/ship-broadcast.js +48 -1
- package/modules/governance/catalog.js +70 -20
- package/modules/governance/db.js +102 -0
- package/modules/governance/migrations/governance_006_version_create.sql +38 -0
- package/modules/governance/migrations/governance_007_delegate_archon_ops_to_metic.sql +72 -0
- package/modules/governance/routes/governance.js +235 -6
- package/modules/grading/grader-workers/index.js +18 -9
- package/modules/hall-ui/public/gate.js +6 -2
- package/modules/hall-ui/public/goals-page.js +6 -2
- package/modules/hall-ui/public/governance.css +100 -0
- package/modules/hall-ui/public/governance.html +77 -0
- package/modules/hall-ui/public/governance.js +353 -0
- package/modules/hall-ui/public/harbor.js +14 -8
- package/modules/hall-ui/public/instances-panel.js +3 -1
- package/modules/hall-ui/public/new-project-wizard.js +6 -0
- package/modules/hall-ui/public/people.html +51 -0
- package/modules/hall-ui/public/people.js +100 -0
- package/modules/hall-ui/public/profile.html +2 -1
- package/modules/hall-ui/public/profile.js +9 -3
- package/modules/hall-ui/public/sessions.js +4 -2
- package/modules/hall-ui/public/shell.js +28 -7
- package/modules/hall-ui/public/task-detail.js +6 -3
- package/modules/hall-ui/public/watch.js +17 -9
- package/modules/ideas/blockers.js +44 -7
- package/modules/ideas/routes/blockers.js +12 -7
- package/modules/ideas/routes/inbox.js +2 -2
- package/modules/lifecycle/db.js +84 -17
- package/modules/lifecycle/github-push.js +37 -10
- package/modules/lifecycle/publish-reconciler.js +128 -31
- package/modules/lifecycle/routes/claims.js +10 -4
- package/modules/lifecycle/routes/dependencies.js +2 -2
- package/modules/lifecycle/routes/done-when.js +4 -4
- package/modules/lifecycle/routes/gate-approvals.js +9 -3
- package/modules/lifecycle/routes/goals.js +5 -5
- package/modules/lifecycle/routes/tasks.js +99 -69
- package/modules/lifecycle/routes/versions.js +13 -2
- package/modules/lifecycle/ship-card.js +38 -7
- package/modules/memory/routes/memory.js +2 -2
- package/modules/onboarding/routes/access-requests.js +3 -3
- package/modules/platform-identity/routes/projects.js +10 -6
- package/modules/platform-identity/routes/scouting.js +2 -2
- package/modules/provisioning/migrations/provisioning_004_onboard_mode.sql +30 -0
- package/modules/provisioning/provisioning.js +24 -6
- package/modules/provisioning/routes/provisioning.js +24 -6
- package/modules/security/artifact-scan/aggregate.js +133 -0
- package/modules/security/artifact-scan/detectors/capabilities.js +53 -0
- package/modules/security/artifact-scan/detectors/config-obfuscation.js +41 -0
- package/modules/security/artifact-scan/detectors/credentials.js +112 -0
- package/modules/security/artifact-scan/detectors/dependencies.js +115 -0
- package/modules/security/artifact-scan/detectors/hooks.js +116 -0
- package/modules/security/artifact-scan/detectors/injection.js +118 -0
- package/modules/security/artifact-scan/detectors/mcp.js +102 -0
- package/modules/security/artifact-scan/detectors/network.js +67 -0
- package/modules/security/artifact-scan/detectors/npm-lifecycle.js +67 -0
- package/modules/security/artifact-scan/detectors/permissions.js +91 -0
- package/modules/security/artifact-scan/detectors/shared.js +219 -0
- package/modules/security/artifact-scan/fence-local.js +99 -0
- package/modules/security/artifact-scan/fetch.js +330 -0
- package/modules/security/artifact-scan/floor.js +319 -0
- package/modules/security/artifact-scan/limits.js +66 -0
- package/modules/security/artifact-scan/manifest.js +203 -0
- package/modules/security/artifact-scan/mirror.js +158 -0
- package/modules/security/artifact-scan/quarantine.js +149 -0
- package/modules/security/artifact-scan/rebuild-spec.js +120 -0
- package/modules/security/artifact-scan/report.js +155 -0
- package/modules/security/artifact-scan/sanitize.js +317 -0
- package/modules/security/migrations/security_001_tool_scans.sql +145 -0
- package/modules/security/module.json +2 -2
- package/modules/security/routes/reports.js +11 -7
- package/modules/security/routes/scans.js +115 -0
- package/modules/security/scan-store.js +214 -0
- package/modules/security/tests/aggregate.mjs +283 -0
- package/modules/security/tests/artifact_scan.mjs +591 -0
- package/modules/security/tests/floor.mjs +549 -0
- package/modules/security/tests/mirror.mjs +350 -0
- package/modules/security/tests/sanitize_rebuild.mjs +499 -0
- package/modules/security/tests/scan_store.mjs +250 -0
- package/modules/security/tests/tool_scans_migration.mjs +116 -0
- package/modules/sessions/routes/sessions.js +6 -5
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/public-landing/create.html +13 -3
- package/scripts/gds/abandon.js +1 -1
- package/scripts/gds/audit-authorship.sh +6 -0
- package/scripts/gds/box.js +1 -1
- package/scripts/gds/bump-version.js +76 -0
- package/scripts/gds/claim.js +15 -0
- package/scripts/gds/cli-lib.js +16 -4
- package/scripts/gds/gating.js +28 -13
- package/scripts/gds/gen-api-docs.js +1 -1
- package/scripts/gds/goal.js +234 -0
- package/scripts/gds/init.js +77 -15
- package/scripts/gds/main-audit.js +80 -11
- package/scripts/gds/mirror-redact.js +6 -0
- package/scripts/gds/newcomer-floor.js +2 -2
- package/scripts/gds/provision.js +230 -94
- package/scripts/gds/run-unit-tests.js +9 -1
- package/scripts/gds/sandbox-stage.js +66 -9
- package/scripts/gds/search-ingest-md.js +1 -0
- package/scripts/gds/sequence.js +67 -8
- package/scripts/gds/ship.js +183 -50
- package/scripts/hall-preview/server.js +1 -1
- package/scripts/migrate.sh +5 -5
- package/src/bongos/auth.js +129 -27
- package/src/bongos/db-kernel.js +66 -5
- package/src/bongos/db.js +6 -7
- package/src/bongos/github-repos.js +19 -7
- package/src/bongos/goal-scope-check.js +1 -1
- package/src/bongos/module-scope-map.js +3 -1
- package/src/bongos/permission-path-check.js +1 -1
- package/src/bongos/route-rank-check.js +73 -30
- package/src/bongos/routes/audit-log.js +4 -2
- package/src/bongos/routes/auth.js +8 -4
- package/src/bongos/routes/backup.js +7 -4
- package/src/bongos/routes/builders.js +23 -11
- package/src/bongos/routes/github.js +15 -4
- package/src/bongos/routes/llm-cache.js +5 -2
- package/src/bongos/routes/modules.js +9 -5
- package/src/bongos/routes/security.js +21 -12
- package/src/bongos/serve-internal.js +22 -7
- package/src/module-api.js +96 -13
- package/src/platform-server.js +14 -0
- package/tests/api_client.mjs +18 -2
- package/tests/api_path_404.mjs +3 -0
- package/tests/art_stage.mjs +2 -1
- package/tests/atlas.mjs +32 -4
- package/tests/auth_admission_gate.mjs +17 -5
- package/tests/auth_error_brand.mjs +41 -21
- package/tests/auth_resolve_failure.mjs +155 -0
- package/tests/blocker_link.mjs +88 -0
- package/tests/bongos_cli.mjs +91 -0
- package/tests/bongos_downloads.mjs +2 -1
- package/tests/box_dns_repoint.mjs +2 -0
- package/tests/box_ship_permissions.mjs +2 -0
- package/tests/box_terminal_ssrf.mjs +23 -17
- package/tests/bump_version.mjs +71 -0
- package/tests/claim_error_surface.mjs +23 -0
- package/tests/claude_materialize.mjs +4 -0
- package/tests/cli_box_scope.mjs +40 -0
- package/tests/cloud_bongos_pack.mjs +34 -4
- package/tests/conductor.mjs +2 -1
- package/tests/criterion_authoring_gate.mjs +28 -5
- package/tests/currency_label.mjs +10 -1
- package/tests/deploy_instance.mjs +2 -0
- package/tests/devbox_downloads.mjs +2 -1
- package/tests/display_name.mjs +95 -6
- package/tests/eviction_policy.mjs +2 -1
- package/tests/file_map.mjs +10 -0
- package/tests/first_admin_bootstrap.mjs +10 -2
- package/tests/first_run_engine_check.mjs +2 -1
- package/tests/fitness.mjs +26 -6
- package/tests/gate_approvals.mjs +15 -2
- package/tests/github_push_land_proof.mjs +50 -4
- package/tests/github_repos_helpers.mjs +30 -5
- package/tests/github_token_store.mjs +23 -0
- package/tests/goal_abuse_matrix.mjs +13 -3
- package/tests/goal_cli.mjs +89 -0
- package/tests/governance_abuse_matrix.mjs +386 -0
- package/tests/governance_fold.mjs +156 -0
- package/tests/governance_fold_bench.mjs +50 -0
- package/tests/governance_live_proof.mjs +201 -0
- package/tests/governance_page_gates.mjs +21 -9
- package/tests/governance_parity.mjs +11 -2
- package/tests/governance_require_permission.mjs +125 -1
- package/tests/governance_routes.mjs +334 -0
- package/tests/grader.mjs +7 -3
- package/tests/hall_nav.mjs +14 -4
- package/tests/helpers.mjs +73 -0
- package/tests/hook_core_resolve.mjs +2 -1
- package/tests/host_topology_skips.mjs +97 -0
- package/tests/infra_exec_paths.mjs +14 -4
- package/tests/init.mjs +147 -0
- package/tests/known_failing_ratchet.mjs +89 -0
- package/tests/lifecycle-card.mjs +2 -1
- package/tests/main_audit.mjs +72 -1
- package/tests/memory_isolation.mjs +56 -9
- package/tests/migrate_root_resolution.mjs +1 -1
- package/tests/mirror_redact.mjs +19 -0
- package/tests/module_api.mjs +3 -1
- package/tests/module_loader.mjs +4 -0
- package/tests/modules.mjs +35 -7
- package/tests/modules_route.mjs +29 -5
- package/tests/onboarding_observability.mjs +49 -11
- package/tests/onboarding_route_signals.mjs +1 -0
- package/tests/one_active_claim_per_session.mjs +80 -0
- package/tests/patch_gate_ordering.mjs +102 -0
- package/tests/pre_compact.mjs +2 -1
- package/tests/preview_server.mjs +2 -1
- package/tests/profile_route.mjs +1 -0
- package/tests/provision.mjs +170 -0
- package/tests/provisioning_onboard_mode.mjs +180 -0
- package/tests/publish_manifest.mjs +16 -3
- package/tests/publish_reconciler.mjs +181 -10
- package/tests/rank_tier_single_source.mjs +205 -0
- package/tests/recall_hints.mjs +2 -1
- package/tests/repo_map.mjs +4 -0
- package/tests/route_permission_check.mjs +14 -5
- package/tests/rubric_fixtures.mjs +3 -0
- package/tests/run_routine_two_root.mjs +2 -0
- package/tests/sandbox_stage.mjs +69 -7
- package/tests/search_ingest.mjs +7 -0
- package/tests/security_docs.mjs +28 -6
- package/tests/sequence.mjs +64 -0
- package/tests/session-cards.mjs +2 -1
- package/tests/session_start_freshness.mjs +2 -1
- package/tests/ship_broadcast_server.mjs +63 -1
- package/tests/ship_card.mjs +66 -0
- package/tests/ship_ci_deploy.mjs +66 -1
- package/tests/ship_smoke_gate.mjs +76 -0
- package/tests/versions_route.mjs +15 -0
- package/tests/workflow_exec_paths.mjs +16 -4
- package/tests/worktree_guard.mjs +2 -1
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# 0160 — The authoritative main audit gets a repo-verifiable caller
|
|
2
|
+
|
|
3
|
+
- **Status:** Accepted
|
|
4
|
+
- **Date:** 2026-08-08
|
|
5
|
+
- **Deciders:** jaxri (Archon), Claude
|
|
6
|
+
- **Track:** `internal` (build pipeline / governance)
|
|
7
|
+
- **Task:** [1002612](https://cloudbongos.com/builders#/task/1002612), under goal [1000024](https://cloudbongos.com/builders#/goal/1000024) (Build-pipeline integrity)
|
|
8
|
+
|
|
9
|
+
**Builds on:** [ADR 0043](<redacted>.md) (designates the post-push audit the authoritative layer — **unchanged**), [ADR 0159](<redacted>.md) (the merge-gate reconciliation this is the detective-lane companion to), [ADR 0158](<redacted>.md) (findings G-3, G-8, S-1).
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Context
|
|
14
|
+
|
|
15
|
+
`scripts/gds/main-audit.js` reads the real git history on `main` and the real builder ranks
|
|
16
|
+
and flags sub-Metic edits to permission-sensitive surfaces — the layer ADR 0043 calls
|
|
17
|
+
**authoritative**. Both of its declared invokers (`.claude/scheduled-tasks/main-audit/`,
|
|
18
|
+
`infra/deploy.sh`) have never existed in this repository (G-3). The honest limit S-1 stands:
|
|
19
|
+
the production droplet may run it from an untracked deploy script, which cannot be settled
|
|
20
|
+
from this checkout — so the remedy is a caller that **is** verifiable from the repo, not an
|
|
21
|
+
assumption about the droplet either way. Same shape, same pass (G-8):
|
|
22
|
+
`scripts/gds/audit-authorship.sh` — the no-hardcoded-Archon-identity enforcer named by
|
|
23
|
+
CLAUDE.md and canonical-permissions.md — also had no programmatic caller, and turned out to
|
|
24
|
+
be red with 340 pre-existing hits on untouched main (idea 1000653).
|
|
25
|
+
|
|
26
|
+
## Decision
|
|
27
|
+
|
|
28
|
+
1. **A `main-audit` workflow runs on every push to `main`** (plus `workflow_dispatch`),
|
|
29
|
+
auditing exactly the pushed range via `OTB_AUDIT_RANGE=before..after` from the push
|
|
30
|
+
event, falling back to the script's clamped first-parent window when `before` is a zero
|
|
31
|
+
or unknown SHA. It is a **detective lane, not a merge gate** — it must not join the
|
|
32
|
+
required PR contexts (`unit` / `secret-scan` / `gate-review`, ADR 0159).
|
|
33
|
+
|
|
34
|
+
2. **The roster comes from the public leaderboard when no session exists.**
|
|
35
|
+
`fetchRankMap` falls back to `GET /api/gds/public/leaderboard` — server-authoritative,
|
|
36
|
+
unauthenticated, and it carries exactly the two fields the audit keys on
|
|
37
|
+
(`github_login`, `rank` — login-only keying per the anti-aliasing rule). A builder
|
|
38
|
+
absent from the leaderboard resolves as *unresolved* ('review' finding), never as
|
|
39
|
+
falsely trusted.
|
|
40
|
+
|
|
41
|
+
3. **`--require-roster` makes an empty roster a loud DID-NOT-RUN (exit 2).** With no
|
|
42
|
+
ranks, every author is unresolved and a blocker can never fire — a green exit there is
|
|
43
|
+
a check that did not execute wearing the costume of a clean audit. The CI caller always
|
|
44
|
+
passes this flag; local best-effort reads keep the old warning behavior.
|
|
45
|
+
|
|
46
|
+
4. **The lane runs non-strict.** The script's own #863 calibration: a *resolved* sub-Metic
|
|
47
|
+
author on a protected path is the zero-false-positive blocker; an *unresolved* author
|
|
48
|
+
(the operator's display-name commits, deploy automation) is a review note. `--strict`
|
|
49
|
+
in CI would make the lane permanently red on routine operator commits — and a
|
|
50
|
+
permanently red detective lane rots into wallpaper.
|
|
51
|
+
|
|
52
|
+
5. **`audit-authorship.sh` gets its caller in the same workflow, as an advisory job**
|
|
53
|
+
(`continue-on-error: true`) — it is red on untouched main today, and enforcement
|
|
54
|
+
before the idea 1000653 triage would wedge the lane. Advisory makes the rot visible on
|
|
55
|
+
every push instead of nonexistent; flip it to enforcing when the triage lands.
|
|
56
|
+
|
|
57
|
+
## Consequences
|
|
58
|
+
|
|
59
|
+
- The authoritative layer now runs somewhere any repo reader can verify, on every push to
|
|
60
|
+
main. S-1 stays open exactly as written — this neither proves nor disproves a droplet
|
|
61
|
+
caller.
|
|
62
|
+
- The known-failing ratchet caught task 1002611's publish_manifest fix (the lane's first
|
|
63
|
+
red on main was `known_failing_ratchet` — the pairing working as designed): its entry is
|
|
64
|
+
removed and the ceiling ratchets 3 → 2. The two remaining entries now name task 1002617
|
|
65
|
+
as owner. Idea 1000542 (which owned the publish_manifest failure) is superseded — discard
|
|
66
|
+
at triage.
|
|
67
|
+
- A blocker finding on this lane is a *revert conversation*, not an automatic revert — the
|
|
68
|
+
ADR 0158 rule that a finding never executes its own remedy.
|
|
69
|
+
|
|
70
|
+
## Rejected
|
|
71
|
+
|
|
72
|
+
- **A GDS token secret for the authenticated roster route** — an owner dependency the
|
|
73
|
+
devcontainer lane already warned about ("half-wiring it would fail silently"); the public
|
|
74
|
+
surface carries the same two fields with no secret to rot.
|
|
75
|
+
- **`--strict` in CI** — see 4; permanent red is how a detective lane stops being read.
|
|
76
|
+
- **Wiring `audit-authorship.sh` as enforcing now** — 340 pre-existing hits would wedge
|
|
77
|
+
every push; visibility first, enforcement after triage.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# 0161 — Publish on merge: every merge to core `main` auto-publishes `@bongos/core`
|
|
2
|
+
|
|
3
|
+
- **Status:** Accepted
|
|
4
|
+
- **Date:** 2026-08-08
|
|
5
|
+
- **Deciders:** the owner (Archon), Claude. The owner chose this directly after reviewing the pipeline end-to-end: "any merge can publish, we can add in more complexity later."
|
|
6
|
+
- **Task:** task 1002620 (BONGOS-V1, goal 1000024 — build-pipeline integrity)
|
|
7
|
+
- **Supersedes:** [ADR 0137](<redacted>.md) (manual owner-gated publish)
|
|
8
|
+
- **Builds on:** [ADR 0134](<redacted>.md) (private-first npm), [ADR 0136](<redacted>.md) (channel policy), [ADR 0159](<redacted>.md) (the required `unit` check)
|
|
9
|
+
|
|
10
|
+
## Context
|
|
11
|
+
|
|
12
|
+
ADR 0137 kept publishing a manual, owner-gated step: no npm write token at rest, the owner runs `package-core.js --publish --live` when they decide to cut a release. Its own "When to revisit" clause said to re-evaluate when the manual step becomes a real bottleneck.
|
|
13
|
+
|
|
14
|
+
It became one twice in three weeks, measured:
|
|
15
|
+
|
|
16
|
+
- **171 commits / 10 days** unreleased (blocker 1000097) — an entire governance permission system sat on `main` while the live platform served the previous version and every pipeline layer reported success.
|
|
17
|
+
- **104 commits / 5 days** unreleased immediately after — including a `CORE_VERSION` bump (`1.19.0`) that was landed but never packaged, so the version number existed while no artifact carried it.
|
|
18
|
+
|
|
19
|
+
The consumption side (ADR 0136's subscription) was never the problem; supply was. The owner reviewed the full pipeline on 2026-08-08 and reversed 0137's trade-off explicitly.
|
|
20
|
+
|
|
21
|
+
## Decision
|
|
22
|
+
|
|
23
|
+
1. **Every merge to `main` publishes.** A `publish` workflow fires on the `unit` check succeeding on a main push (never on a red suite), builds via `package-core` — the fail-closed no-leak gate and `--self-verify` pin check run inside the build — publishes (restricted), and tags `core-v<version>`.
|
|
24
|
+
2. **CI bumps PATCH only.** When a merge lands without a human bump, `scripts/gds/bump-version.js` bumps the patch and writes the changelog line (shape-preserving; pinned by `tests/bump_version.mjs`). A **minor or major stays a deliberate in-task human edit** — it is a statement about the doorway surface, and it decides what patch-channel subscribers receive unattended (ADR 0136). CI is not allowed to make that call.
|
|
25
|
+
3. **Token custody reverses, knowingly.** A standing npm **write** Automation token (`NPM_TOKEN`) and a fine-grained **contents:write** PAT (`RELEASE_PUSH_TOKEN`, for the bump commit — the default `GITHUB_TOKEN` cannot push past the required `unit` check) live as GitHub Actions secrets. This is exactly the surface 0137 declined; the owner accepted it with the incidents as evidence. Mitigations: the lane is **default-inert** behind the repo variable `PUBLISH_ON_MERGE=1` (an owner kill-switch symmetrical to `gating.js`), packages publish `restricted`, and the no-leak gate structurally cannot upload a leaking artifact.
|
|
26
|
+
4. **Idempotent by version-compare.** The bump commit re-triggers `unit` → `publish`, which then finds HEAD's version already on npm and no-ops. npm's duplicate-version rejection is the backstop; concurrent merges queue behind a no-cancel concurrency group.
|
|
27
|
+
|
|
28
|
+
## Consequences
|
|
29
|
+
|
|
30
|
+
- A merged change is on npm within minutes, unattended. Combined with the subscription (ADR 0136), patch-channel instances take it on their next sweep — the full merge→live path has no human step for patches.
|
|
31
|
+
- The bump commit is authored by `github-actions[bot]` directly on `main` (admin-exempt push, `enforce_admins: false`). It re-runs `unit` as a safety net.
|
|
32
|
+
- `deploy-divergence.js`'s UNRELEASED gap should now hover near zero; a growing gap means the lane is disarmed or red — both loud.
|
|
33
|
+
- One-time owner arming step (filed as a blocker): create the two secrets, set `PUBLISH_ON_MERGE=1`.
|
|
34
|
+
- Revisit toward *more* ceremony (environments, provenance attestation, trusted publishing/OIDC to npm — which would retire the standing token) when the fleet grows; revisit toward *less* (auto-minor) never without a human surface-diff check.
|
package/docs/adr/README.md
CHANGED
|
@@ -224,5 +224,14 @@ This keeps the decision history honest and traceable.
|
|
|
224
224
|
| 0152 | [The landing gate is served by the **core app**, not by the front proxy — the cutover step of the landing migration ([task 1002411](https://example.com/builders#/task/1002411), L05 of goal 1000035). The reference instance's orb-gate front page was `file_server`'d by Caddy straight out of a checkout of an UNRELATED product repo (`root * <checkout>/brand/cloud-bongos`), so the landing had two sources of truth, no deploy path of its own, and a cross-product coupling the core could not express. [L01](https://example.com/builders#/task/1002407) had already ported the bundle into the core as `public-landing/` and [L02](https://example.com/builders#/task/1002408) had already taught `platform-server.js` to serve it (`/` -> 302 `/gate/`, `/gate/` serves the index raw, `express.static` covers the assets) — so by the time L05 came up, BOTH halves of its original plan ("give the landing (a) its own Caddy config and (b) its own deploy script") had dissolved. **Decision:** the app owns the landing end to end; the proxy drops `root` + `file_server` and keeps exactly three jobs on that surface — TLS, an optional pre-launch `basic_auth` lock, and the `@hidden` guard that keeps `gate/README.md` unreachable. No separate Caddy config to write (the resulting block IS the generic pure-proxy shape `provision.js`'s `caddyBlock()` already emits per instance, [ADR 0111](<redacted>.md) §4; host-specific hostnames/certs stay on the host per [ADR 0062](<redacted>.md) §7) and no separate deploy script to write (the landing ships INSIDE the pinned core package, so it rides the instance's existing pull-deploy — one artifact, one version, one path). Keeps `redir / /gate/ 302` because Caddy orders `redir` before `basic_auth`, so "/" behaves identically before and after, and the app issues the same 302 once the lock is lifted. Cost accepted: the landing now sits in the app's request path (a dead app = a dead front page — but the gate's whole purpose is to reach the app), and a landing tweak now needs a core release. Verified on the live instance: identical status codes across the apex and both vanity doors before/after, relative redirects (no origin leak), and a **severance test** — with the foreign repo's landing folder moved aside entirely the site still served the byte-identical gate, proving the dependency is cut rather than merely unused. Retiring the foreign copy is L06 ([task 1002412](https://example.com/builders#/task/1002412)).](<redacted>.md) | platform serving / instance infra |
|
|
225
225
|
| 0152 | [**Metic gains task abandonment, paired with an un-abandon at the same rank** (owner directive 2026-07-27: "Metics should also be able to abandon tasks"; [task 1002476](https://cloudbongos.com/builders#/task/1002476)). [ADR 0090](<redacted>.md) moved task authoring (create/edit/promote/deps/criteria) down to the trusted working rank but kept `POST /tasks/:id/abandon` Archon-only as "terminal scope removal" — so the rank that runs idea-triage, seeds the tasks, and shapes them still had to hand every duplicate/moot/superseded chore back to the owner to retire. That hand-back is janitorial, not adjudication. The real hazard was never the grant: abandon was **one-way through the API** (`/promote` took only backlog/blocked, `PATCH` refuses `status`), so a mis-retire needed hand-SQL on prod, and an abandoned task is invisible in every claimable list and every version rollup (migration 017 excludes it from `version_progress`) — nobody notices until the work silently doesn't happen. So the gate moves to `requireRank('metic','archon')` **and** `/promote` gains a third source state, `abandoned → backlog` (never straight to ready — a retired task re-enters un-workable and takes a second deliberate promote), backed by `db.restoreTask`, the mirror of `abandonTask`, which clears the `'Abandoned: <reason>'` stamp and only that. Unchanged: the shipped-task and active-claim refusals, idempotency, and the `audit_log` record of who retired what and who brought it back. The `EXPECTED_RANKS` lifecycle pin moves in lockstep (a *further* downgrade stays a hard CI fail); under [ADR 0151](<redacted>.md) the `task.abandon` floor moves archon→metic, landing as `governance_003` because the compat seed is run-once — purely additive, and the drift guard now compares the **union** of grant migrations to the catalog and fails loudly on a future revocation.](<redacted>.md) | GDS / permissions |
|
|
226
226
|
| 0153 | [**Sequential chain execution — one kickoff walks a dependency chain** ([task 1002484](https://cloudbongos.com/builders#/task/1002484)). [ADR 0015](<redacted>.md) made `dependencies[]` load-bearing and auto-promotes a task's dependents `backlog`→`ready` on ship — but nothing *picks the unblocked task up*, so on the live instance **146 of 303 open tasks sit behind a predecessor** and a 24-task planning seed needed 24 separate human kickoffs. The only "sequential" affordance was a clipboard prompt on the Tasks board (`<redacted>`), which is text rather than execution and cannot even select the gated successors, because they are still `backlog`. Requested independently by two builders (ideas 1000461, 1000398). **Decision:** a chain runner with **no schema change** (the polymorphic `dependencies` table + `task_is_fully_unblocked` + the promote-on-ship trigger already encode the order; a `chain_id`/queue column would be a second, drift-prone source of truth) and **no new claim guard** (one-active-claim-per-session is keyed on the *working tree*, so ship-before-next-claim is already the enforced shape — and batch-claiming a chain is impossible anyway, since successors fail `DEPS_NOT_SHIPPED` until their predecessor ships; the ship IS what unblocks the next step). Deterministic plumbing (`scripts/gds/sequence.js` — scope, topological order, halt matrix, all read off the task row) is split from judgement (`.claude/skills/builder-sequence/`, which defers to `/builder-claim` + `/dev` + `/builder-ship`). **Halt, do not skip** (owner decision): on `needs_migration`, `security_sensitive`, `protected_path`, `rank_floor`, `thin_spec`, `judgement_kind`, `not_claimable`, `deps_unmet`, `in_flight`, or `cycle`, the runner stops and reports with the task still claimed — because in a dependency graph a skipped task is a *predecessor*, so skipping strands everything behind it while the run keeps posting apparent progress. Not built: chains as a priced claimable unit on the board (idea 1000398), which is additive.](<redacted>.md) | GDS / methodology |
|
|
227
|
+
| 0155 | [**Adopting a private repo: widen the onboarding OAuth scope to `repo`** ([task 1002561](https://example.com/builders#/task/1002561)) — amends [ADR 0143](<redacted>.md) §1 by taking the exit 0143 itself named (“revisit to `repo` only if private support is needed”). Standing up a project on an EXISTING PRIVATE repo died at the provisioner’s scaffold push with GitHub `403 Write access to repository not granted`: `scopeForWebFlow` requested `public_repo`, which grants write to **public** repos only. Confirmed as scope and not credentials three ways — the live `github_oauth_tokens` row was `public_repo,read:user` and still VALID during the failure (a dead token 401s; this 403 text is GitHub’s canonical scope-insufficient reply); every greenfield project worked only because `createUserRepo` hardcodes `private:false`, so the platform had only ever pushed to repos it had just made public; and the picker already rendered a **“Private” badge** for a case `public_repo` made unreachable. Owner chose (B) widen-and-keep-pushing over (A) never-touch-the-user’s-repo (user runs `bongos init --adopt` + pushes; needs a deploy key for the instance to *run*) and (C) public-only, accepting the cost this reverses: the persisted token can now write to **every repo the user owns**. Containment from 0143 is unchanged and is what makes it tolerable — encrypted (secret-box), **1h TTL**, lazily swept, requested ONLY on the wizard’s `?repos=1` path (hall + CLI stay `read:user`), never stored when secret-box is off. Three guards ride along: (1) widening the *request* does not upgrade *stored* tokens, so new `grantedScopeCoversRepos()` gates `resolveRepoToken` and a surviving `public_repo` row takes the existing `repo_scope_required` (403) reconnect path instead of 200-ing while **silently omitting the user’s private repos** — it PARSES GitHub’s comma-separated grant rather than substring-matching, since `public_repo` *contains* “repo” and a naive match accepts exactly the stale token being guarded against; (2) `createUserRepo` keeps `private:false` — now a **product** choice (instances are open-source/capture-resistant by design), deliberately not a parameter, test-pinned so the widen can’t change what we create; (3) consent copy states the breadth in our own words first, since GitHub words `repo` as full control of all repositories. A central **GitHub App** (fine-grained `Contents:write` on only the selected repo) remains the principled fix and this makes its case stronger — a future ADR adopting it supersedes this. **This alone does not make adopt work:** provisioning is independently greenfield-only (`git init` a fresh tree + push to `main`, which an existing repo rejects as unrelated history) — [task 1002562](https://example.com/builders#/task/1002562) fixes that and, because the wider scope makes a mistaken `--force` a real data-loss route on a user’s repo, carries a test asserting the adopt push never forces; [1002563](https://example.com/builders#/task/1002563) verifies live.](<redacted>.md) | onboarding / auth / provisioning |
|
|
228
|
+
| 0156 | [**A builder's own display name wins, always** ([task 1002568](https://cloudbongos.com/builders#/task/1002568)). A builder renamed themselves in hall Settings, the save worked, and the name reverted to their GitHub account name at the next sign-in. `upsertBuilder` (`src/bongos/db-kernel.js`) is named for account creation but runs on **every authentication**, and its `ON CONFLICT (github_id) DO UPDATE` re-set `display_name = EXCLUDED.display_name` unconditionally — where `EXCLUDED` carries whatever the caller just read off GitHub. All four login paths feed it (`pollDeviceFlow`, `completeWebFlow`, `completeIdpFlow`, `completeDeviceExchange`), so CLI re-auth alone was enough to undo the save the same day. **Decision:** the row records *who last set the name*. A new core column `builders.display_name_source` (`'github' | 'user'`, migration `core_197`) is stamped `'user'` by `setBuilderDisplayName` — the only self-rename path — and the upsert's conflict branch guards the assignment with `CASE WHEN builders.display_name_source = 'user' THEN builders.display_name ELSE EXCLUDED.display_name END`. GitHub keeps seeding and re-syncing the name for everyone who never renamed; it never overwrites one the builder chose. `github_login`/`avatar_url` re-sync unchanged. **Rejected:** the one-line fix of deleting the assignment entirely — it freezes `display_name` at signup for *everyone*, so a GitHub rename (or a bare login seeded because the account had no GitHub display name) would never propagate again; that trades a visible bug affecting the few who renamed for a silent one affecting the many who never opened Settings. Not surfaced in `GET /me/display-name` or the OpenAPI spec (internal persistence state, no UI consumer). The federated hub's `platform_identity_accounts` needs no matching guard — the `CASE` runs regardless of what `EXCLUDED` carries, and that table is identity-only with no self-service editor. `tests/display_name.mjs` previously covered only the pure validator, which is why this shipped; it now reads the real SQL and asserts both directions.](<redacted>.md) | GDS / builder experience |
|
|
229
|
+
| 0157 | [**Archon is rank and identity only; the operational block delegates to Metic** ([task 1002584](https://cloudbongos.com/builders#/task/1002584), owner decision 2026-08-05). Archon had accumulated **50 route gates**, almost none about *authority* — reading the roster, listing dev boxes, viewing the audit log, adjudicating a vuln report, tearing down a droplet. Each arrived Archon-gated by [ADR 0016](<redacted>.md)'s fail-closed default for new privileged routes; nothing came back to lower them, so “fail closed” became “the owner is the only operator”. Generalises the one-power delegations of [ADR 0090](<redacted>.md) and [ADR 0152](<redacted>.md) instead of relitigating route by route. **20 permissions move archon→metic** — the governance pages (`/watch`, `/harbor`, `/gate`), session search, the dev-box + provisioning fleets, security adjudication, the audit log, roster reads, cross-builder memory reads, project curation, budgets, idea ratification, override decisions, release-on-behalf, criterion unsatisfy, goal reorder, version create, newcomer restock, peer-vote tally, Discord channel ops, autonomy precheck. **Only possible as a 1-file change** because BV1.R104/R105 had just migrated the gates to `requirePermission`, so the floor is declared once in `catalog.js` — the same decision was a 41-call-site diff a day earlier, and that is the concrete [ADR 0151](<redacted>.md) payoff. **13 stay Archon:** rank (`builder.rank.set`), identity (status/admission/session-revoke), and — refusing the literal reading of the directive — **four escalation keys** (`task.confirm.grade_bypass`, `gate_approval.decide`, `goal.scope.manage`, `governance.manage`) that form a chain to self-promotion: scope a goal into the permission core → claim a task there (protected paths already floor at *metic* per [ADR 0043](<redacted>.md)) → confirm past the failed grade → approve your own red CI gate → it lands on `main`. Moving all 20 would have made the delegation **self-reversible**, so keeping rank Archon-only depends on keeping those four Archon-only; any future delegation must re-run that check. Also held back: `version.close` (paired with rank as the powers that never delegate) and `dependency.cross_tier.manage` (`system: true` — clearing that flag to move it would widen what any CUSTOM role can hold, a second-order change nobody asked for). Mints **`gate_approval.read`** so the Gate page opens at Metic while approving stays Archon, and finishes the three reads R104/R105 skipped — otherwise the read would be **stricter than the write** (a Metic able to confirm a vuln report but not list one). Route pins move from ranks to `perm:` atoms so a floor change needs no pin edit. **Two flagged consequences:** `/security/docs` (attacker-usable exploit detail) is now Metic-readable, since it shares `security.report.adjudicate` — the one delegation widening who may *read* rather than *act*; and [ADR 0154](<redacted>.md)'s “the backward ratchet stays Archon” carve-out is superseded (satisfy/unsatisfy stay separate atoms, so confirming still never confers un-confirming). ADR 0016 is untouched end to end — floors move *inside* the boundary, never the enforcement point.](<redacted>.md) | governance / permissions |
|
|
230
|
+
| 0158 | [**The choke-point verdict taxonomy, and why a verdict never executes itself** ([task 1002598](https://cloudbongos.com/builders#/task/1002598)). [ADR 0157](<redacted>.md) delegated 20 permissions on one observation — each had been Archon-gated by [ADR 0016](<redacted>.md)'s fail-closed default, *never by a decision* — but applied that reasoning once, to a known backlog, without recording it as a **method**. Two things now make the question tractable: a **second Archon exists** (until 2026-08-06 "needs an Archon" and "needs Lars" were the same sentence, and a large share of past escalations reclassify on that distinction alone), and post-[ADR 0151](<redacted>.md) a floor is declared once, so classifying exhaustively is cheap. **Decision:** six ordered verdicts, first match wins — GAP · UNINTENDED-MISSING-SURFACE · DRIFT · STRUCTURAL · INTENDED · UNINTENDED-OVERTIGHT. Order is load-bearing: GAP leads because arguing a wall's rank while nothing enforces it is the costlier mistake, and UNINTENDED-OVERTIGHT is last because its remedy is the only one that *weakens* a boundary. DRIFT is never terminal — a DRIFT row must name what it collapses into. **The load-bearing rule: a verdict is advisory and never self-executing.** Recording UNINTENDED-OVERTIGHT is not authorization to lower a floor; that still needs an owner decision + `catalog.js` + a migration (the `governance_002` seed is run-once, so an edited `floor:` never reaches a migrated DB) + an ADR. A document that could move a floor by asserting a verdict would be privilege escalation through markdown — the audit describes, the database enforces. Every row carries a rigor marker (`obs` / `read` / **`absent`** / **`unver`**); the last two earn their own names because the two highest-severity findings in the first map are *absences* (a pre-push hook never once in git history; an "authoritative" audit script with no caller) and the sharpest structural one is an `unver` — the layer [ADR 0043](<redacted>.md) designates authoritative lives entirely outside the repository that documents it, so the trust model cannot be audited from the artifact that states it. Two methodological constraints, both learned the expensive way: **an Archon cannot audit the ownership walls** (`gateTaskOwnership` short-circuits on `rank === 'archon'` before the ownership lookup, so an Archon probe passes all 7 routes and observes nothing — which is why the single-Archon era *hid* a class of wall rather than merely queueing it), and **send two bodies per write** (16 of 29 in-handler-gated routes return 400/422 on `{}` before the authorization check, so a `{}`-only sweep concludes there are no in-handler walls). Produces [`docs/governance/<redacted>.md`](../governance/<redacted>.md). ADR 0016 and 0043 untouched — this adds vocabulary for *describing* the boundary; it moves no floor and changes no enforcement. **Rejected:** generating the map from the route census (a census answers "where is the gate", never "should it be there", and generating it would imply otherwise); folding verdicts into `canonical-permissions.md` (that file mirrors the enforced model — mixing judgments *about* it into the description *of* it is how a doc starts reading as authority); auto-filing a task on UNINTENDED-OVERTIGHT (a queued privilege change nobody decided); and collapsing to three verdicts (it merges GAP into UNINTENDED-OVERTIGHT, inverting the remedy — an unenforced wall needs a gate *added*, an over-tight one needs a floor *lowered*).](<redacted>.md) | governance / methodology |
|
|
231
|
+
|
|
232
|
+
| 0159 | [**Merge-gate reconciliation: required checks match reality, CODEOWNERS becomes real, protection stays the owner's switch** ([task 1002611](https://cloudbongos.com/builders#/task/1002611)). Findings D-12 + G-5 from the choke-point map: `gating.js` hardcoded three required status checks (`unit`, `trufflehog`, `gate-review`) of which two have never had a workflow — running `gating.js on` would have required contexts nothing can report, blocking every merge indefinitely instead of gating them — and CODEOWNERS was described as a live control by ADR 0042, `protected-surfaces.json`, `publish-manifest.js` and gating.js itself while not existing anywhere in the tree. Now that the `unit` lane exists (task 1002610), `DEFAULT_PROTECTION` requires ONLY `[unit]`; the future contexts are fixed as `secret-scan` + `gate-review` (the `CORE_EXPECTED_CHECKS` names — a context is named for what it asserts, not the tool asserting it) and return when their ADR 0058 workflows ship; CODEOWNERS becomes a real root file scoped to `gate-review.js`'s `HARD_FLOOR_GLOBS` + gating.js (inert until protection is on); branch protection itself stays OFF — flipping it remains the owner's explicit act, this only makes the switch safe. Rider: the unit lane is hardened so `unit` is actually requirable — `fetch-depth: 0` (depth-1 broke `tests/main_audit.mjs` on the lane's first run), two clean-env-red tests parked in `KNOWN_FAILING` with diagnoses + exit tracked in [task 1002617](https://cloudbongos.com/builders#/task/1002617), and `publish_manifest` (the public-mirror boundary test) fixed in-claim rather than parked — its ≥7-host-tests non-vacuity floor went stale when ADR 0107 moved host tests into `modules/<key>/tests/`, replaced by a regex specimen self-test. Rejected: deleting `GATE_WORKFLOWS`' forward-looking names (the switch handles absence gracefully; deleting them un-covers the workflows the moment they ship) and watering down the four CODEOWNERS descriptions instead of creating the one file.](<redacted>.md) | governance / build pipeline |
|
|
233
|
+
|
|
234
|
+
| 0160 | [**The authoritative main audit gets a repo-verifiable caller** ([task 1002612](https://cloudbongos.com/builders#/task/1002612)). Findings G-3 + G-8, honest limit S-1: `main-audit.js` — the post-push layer [ADR 0043](<redacted>.md) designates authoritative — had two declared invokers that never existed in this git history, and `audit-authorship.sh` (the no-hardcoded-Archon-identity enforcer) had no caller either and turned out red with 340 pre-existing hits on untouched main (idea 1000653). Now a `main-audit` workflow audits every push to `main` over exactly the pushed `before..after` range (clamped-window fallback); the roster comes from the public leaderboard when no session exists (server-authoritative, login-only keying, an absent builder resolves as unresolved — never falsely trusted); new `--require-roster` makes an empty roster a loud DID-NOT-RUN exit 2 (an audit that cannot fire a blocker must not exit green); the lane runs non-strict per the audit's own zero-false-positive calibration; and `audit-authorship.sh` rides as an advisory job until the 1000653 triage. Detective lane, not a merge gate — deliberately outside the required PR contexts. Rider: the known-failing ratchet caught task 1002611's publish_manifest fix exactly as designed — entry removed, ceiling ratcheted 3 → 2, remaining entries re-owned to [task 1002617](https://cloudbongos.com/builders#/task/1002617), idea 1000542 superseded. Rejected: a GDS token secret (silent-fail dependency the devcontainer lane warned about), `--strict` in CI (permanent red rots into wallpaper), enforcing authorship before triage.](<redacted>.md) | governance / build pipeline |
|
|
235
|
+
| 0161 | [**Publish on merge: every merge to core `main` auto-publishes `@bongos/core`** (task 1002620). Supersedes ADR 0137's manual owner-gated publish after its own "when to revisit" clause fired twice in three weeks: 171 commits/10 days, then 104 commits/5 days, sat on `main` reachable by no pin while every layer reported success. A `publish` workflow rides behind the required `unit` check (`workflow_run`, success-gated): when HEAD's `CORE_VERSION` is already on npm, CI bumps a PATCH via the shape-preserving `bump-version.js` (+ changelog line; pinned by `tests/bump_version.mjs`) and pushes the carrier commit; `package-core --self-verify --publish --live` builds through the fail-closed no-leak gate; the release is tagged `core-v<v>`. A MINOR/MAJOR stays a human in-task edit — it decides what patch-channel subscribers receive unattended (ADR 0136), a call CI must not make. Token custody knowingly reverses (owner-accepted): `NPM_TOKEN` write + `RELEASE_PUSH_TOKEN` PAT as Actions secrets, mitigated by the lane shipping INERT behind the `PUBLISH_ON_MERGE=1` repo variable — an owner kill-switch symmetrical to `gating.js`. Idempotent by version-compare; npm duplicate rejection is the backstop; queued no-cancel concurrency collapses merge races.](<redacted>.md) | build pipeline / distribution |
|
|
227
236
|
|
|
228
237
|
> ⚠️ **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`.)
|