@bongos/core 1.19.906 → 1.19.909

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.bongos-core.json CHANGED
@@ -2,22 +2,22 @@
2
2
  "artifact": "bongos-core",
3
3
  "manifest_schema": 1,
4
4
  "generator": "scripts/gds/package-core.js",
5
- "core_version": "1.19.906",
6
- "core_contract": "1.19.906",
7
- "source_commit": "292f91e86ee9b852efe6c0e93158f5815ccdfa42",
5
+ "core_version": "1.19.909",
6
+ "core_contract": "1.19.909",
7
+ "source_commit": "a378172e3f20f9432a63ee723274cb46acd87e5d",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-09-20T13:41:10.148Z",
9
+ "built_at": "2026-09-20T14:45:23.165Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
- "docs_redacted": 502,
12
+ "docs_redacted": 503,
13
13
  "agent_docs_stubbed": 26,
14
14
  "functional_verbatim": 2283,
15
15
  "rules": 3,
16
16
  "gate_literals": 3,
17
17
  "gate": "passed"
18
18
  },
19
- "file_count": 2811,
20
- "tree_sha256": "160619c1eb4a21d556e0ed9151463e10b29b88a5aeb1249d213d371aaae5402a",
19
+ "file_count": 2812,
20
+ "tree_sha256": "8f49b63378d69ecb4c8d7d3d6b4ad472ba735ba1ca96922843be33ff8d475d89",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/ask-for-help/SKILL.md",
@@ -2059,10 +2059,15 @@
2059
2059
  "mode": "0000644",
2060
2060
  "sha256": "9b301cd17f96c3f0b49010f046b994e112a5e1f971797964b836bc578578dd70"
2061
2061
  },
2062
+ {
2063
+ "path": "docs/adr/0314-module-protection-is-per-path-not-per-module.md",
2064
+ "mode": "0000644",
2065
+ "sha256": "541a0ae0223982fe53fcf96e3c4a9509e94101d04db0a87395f39cc1bcd881e8"
2066
+ },
2062
2067
  {
2063
2068
  "path": "docs/adr/README.md",
2064
2069
  "mode": "0000644",
2065
- "sha256": "85bb537649c78b08e36e2de94dfde8449760ca163577a7fac63603da4074dd37"
2070
+ "sha256": "4bd65e814cacf8b886b542bf7741dff8f61e9aad3e101db1af2bd28e0eb1a49e"
2066
2071
  },
2067
2072
  {
2068
2073
  "path": "docs/api-reference.md",
@@ -2097,12 +2102,12 @@
2097
2102
  {
2098
2103
  "path": "docs/copy-inventory.md",
2099
2104
  "mode": "0000644",
2100
- "sha256": "3e657714f3647bfb041f4eda9e4982a2b60747c4aceec0d8d8cbf8ee0de6eb47"
2105
+ "sha256": "3a121e993f87d7379836af082bebb8c857427481eb265d477b4b55584cdd604b"
2101
2106
  },
2102
2107
  {
2103
2108
  "path": "docs/copy-registry.json",
2104
2109
  "mode": "0000644",
2105
- "sha256": "1ba7f556256ee4cbb637b9809698c69aff529c080131949b4055058f8fb4716b"
2110
+ "sha256": "77e94a0337636dd8e444bfca6d749c9a16a937ed8e98b372072c17f5b43cc3fe"
2106
2111
  },
2107
2112
  {
2108
2113
  "path": "docs/design/apex-pass-2-direction.md",
@@ -2632,7 +2637,7 @@
2632
2637
  {
2633
2638
  "path": "docs/module-api-changelog.md",
2634
2639
  "mode": "0000644",
2635
- "sha256": "d329f2a3999d8bc88ce4715be5ee51d9e7a60ba0e0f0a9e06163c12ff94d87ba"
2640
+ "sha256": "9acd2adf3d2f21d23fcc9cc626a26ca331972eb6980c5e0c9f8b883c9094b40f"
2636
2641
  },
2637
2642
  {
2638
2643
  "path": "docs/modules-contract.md",
@@ -4662,22 +4667,22 @@
4662
4667
  {
4663
4668
  "path": "modules/hall-ui/public/collab-lib.js",
4664
4669
  "mode": "0000644",
4665
- "sha256": "bfadae8700cc22ea13f8bc39a3e2a1876b58da6151032e9a973402bc9bd0aaa7"
4670
+ "sha256": "baa893e9f8bd207416ee271f429964a85f7d6e1d44235c98a0a9dc20c7998049"
4666
4671
  },
4667
4672
  {
4668
4673
  "path": "modules/hall-ui/public/collab.css",
4669
4674
  "mode": "0000644",
4670
- "sha256": "884118a3b38b0c1ed5e1ac9c90c0b5994714bbabde67959f67c49e7f49536983"
4675
+ "sha256": "ee8845701481932fd9c222b5bb1714aaa552c2c0967d97fc91eef166fe6ab712"
4671
4676
  },
4672
4677
  {
4673
4678
  "path": "modules/hall-ui/public/collab.html",
4674
4679
  "mode": "0000644",
4675
- "sha256": "186a0828e1c3e44388146b94c56f239ea6b2392bd599f143c7c73029da35da32"
4680
+ "sha256": "9876929d0ce989d12dadcdfa6da5cd93ca660e0b291a24a467a920632245dd65"
4676
4681
  },
4677
4682
  {
4678
4683
  "path": "modules/hall-ui/public/collab.js",
4679
4684
  "mode": "0000644",
4680
- "sha256": "91a0751cebcbc179f28ad1cac7a6c447f90369ae40f29e5f60c1bd934ac68f85"
4685
+ "sha256": "465198338e63c762a8f099df8a43e449e804097074c62285243f4876085f6dc5"
4681
4686
  },
4682
4687
  {
4683
4688
  "path": "modules/hall-ui/public/collab.states.json",
@@ -4912,17 +4917,17 @@
4912
4917
  {
4913
4918
  "path": "modules/hall-ui/public/ideas.css",
4914
4919
  "mode": "0000644",
4915
- "sha256": "4da2ff00354a825d32f2f55e3db5f1d18a112ddc9d1056220e73683766b952b3"
4920
+ "sha256": "80edba7f2ea1343a72b1885d13d7411c4b1f127e38a2ccffa85f50a4f3cc8dfd"
4916
4921
  },
4917
4922
  {
4918
4923
  "path": "modules/hall-ui/public/ideas.html",
4919
4924
  "mode": "0000644",
4920
- "sha256": "645ba0757c89e328b955565cca3be5c38acdd5412ba5b8726c210aa6486acd1a"
4925
+ "sha256": "05116249b8cc983297c126c1d1803cb94210d885841b06b2b1667a771cfe866a"
4921
4926
  },
4922
4927
  {
4923
4928
  "path": "modules/hall-ui/public/ideas.js",
4924
4929
  "mode": "0000644",
4925
- "sha256": "be562d9cac8180a42cd8b0d9bc0e0a0d369c2703b859eda235645a5bd56a6368"
4930
+ "sha256": "3496ae8afbf111bff89198146e1b079cb5e7da3f3bd425ab9972ec7b034fbd7d"
4926
4931
  },
4927
4932
  {
4928
4933
  "path": "modules/hall-ui/public/ideas.states.json",
@@ -7782,12 +7787,12 @@
7782
7787
  {
7783
7788
  "path": "package-lock.json",
7784
7789
  "mode": "0000644",
7785
- "sha256": "6a2f94c668864dc88fdc003473496102838182e8d18636930537c32bd67c7e47"
7790
+ "sha256": "97fdcfbc606ed913875732b87e7cfa0cf105349b9a25a8c1831fd9d59f5d0b76"
7786
7791
  },
7787
7792
  {
7788
7793
  "path": "package.json",
7789
7794
  "mode": "0000644",
7790
- "sha256": "1ddcd43de722cb5eff00c36a440b0df181f1c8168a8c8b3193fc3d9a586afdbd"
7795
+ "sha256": "f060d07f1520e822ce6bc8294d6970fa66f87ae4c23aa6bdf2e7f64197aeec60"
7791
7796
  },
7792
7797
  {
7793
7798
  "path": "public-docs/index.html",
@@ -9782,7 +9787,7 @@
9782
9787
  {
9783
9788
  "path": "src/module-api.js",
9784
9789
  "mode": "0000644",
9785
- "sha256": "4593c8749b7b52a5bb6116e0d3dbe6004dc24346bb79ca0a5757359e98dc259e"
9790
+ "sha256": "22cc35de1bea324e4016468dcd0c95e1fa859c2d467127fa3acef7dc18432dbd"
9786
9791
  },
9787
9792
  {
9788
9793
  "path": "src/module-loader/catalog.js",
@@ -10622,7 +10627,7 @@
10622
10627
  {
10623
10628
  "path": "tests/collab_page.mjs",
10624
10629
  "mode": "0000644",
10625
- "sha256": "b710669fabe9e747fe37abf429356e80c1f7a36cd63ac308dda2a933243e2e6d"
10630
+ "sha256": "3e6ae0773f3997f82764f51373dd2e12b965d05366f7615346ba4f504151be77"
10626
10631
  },
10627
10632
  {
10628
10633
  "path": "tests/compose_demo_credentials.mjs",
@@ -11607,7 +11612,7 @@
11607
11612
  {
11608
11613
  "path": "tests/hall_collab_world.mjs",
11609
11614
  "mode": "0000644",
11610
- "sha256": "d005de58e0eabd019f616ee6c77123c5880b67034ce33dc1b01d687a2b284b10"
11615
+ "sha256": "0374c15f7bf4cfdb4cccadb51f5c62e2331413e6970a69599cb1f51899d79b0a"
11611
11616
  },
11612
11617
  {
11613
11618
  "path": "tests/hall_error_envelope.mjs",
@@ -11877,7 +11882,7 @@
11877
11882
  {
11878
11883
  "path": "tests/idea_spark_hall.mjs",
11879
11884
  "mode": "0000644",
11880
- "sha256": "3c62df24b4fc184ac9669fcdc150f7fdde1d60eb007d888bfba502a7890a1e02"
11885
+ "sha256": "c7125e9c139999e48a778e7d149068e94da1e817ce737446f2312e75aaad4388"
11881
11886
  },
11882
11887
  {
11883
11888
  "path": "tests/idea_spark_mark.mjs",
@@ -12272,7 +12277,7 @@
12272
12277
  {
12273
12278
  "path": "tests/module-scope-map.mjs",
12274
12279
  "mode": "0000644",
12275
- "sha256": "d55b193ee9dcba85a9d51f108352de17f453dfb413b9b391028c9d8f7ff7fab0"
12280
+ "sha256": "b2609440d099b93b61c63c3cdaa4cf6e65c6dc107b8aa4d06d9cb81c9ec5e2c9"
12276
12281
  },
12277
12282
  {
12278
12283
  "path": "tests/module_api.mjs",
@@ -0,0 +1,133 @@
1
+ # ADR 0314 — A module owns a protected path without the whole module becoming protected
2
+
3
+ - **Status:** accepted (design only — the implementation is a follow-up, see *Not built here*)
4
+ - **Date:** 2026-09-20
5
+ - **Task:** [task 1004070](https://cloudbongos.com/builders#/task/1004070), goal 1000095 — BONGOS-V2
6
+ - **From:** idea 1000689; owner decision 2026-09-19 — *option 1, narrow what counts as protected*
7
+ - **Supersedes nothing.** Refines the derivation in [ADR 0086](0086-goal-scoped-work-hierarchy.md) §7.
8
+
9
+ ## The question
10
+
11
+ `protected` on a module is DERIVED — a module is protected iff any of its globs
12
+ overlaps `PROTECTED_GLOBS` ([ADR 0086](0086-goal-scoped-work-hierarchy.md) §7,
13
+ the SEC #863 "second list that drifts" rule). A protected module makes creating a
14
+ goal scoped to it Archon-only.
15
+
16
+ Three modules derive protected because of exactly one file that is not their
17
+ domain — a CLI they own that happens to sit on a protected path:
18
+
19
+ | Module | Protected solely by | of N globs |
20
+ |---|---|---|
21
+ | `onboarding` | `scripts/gds/setup.js` | 1 of 5 |
22
+ | `autonomy` | `scripts/gds/conductor-dispatch.js` | 1 of 6 |
23
+ | `copy-desk` | `scripts/gds/copy-inventory.js` | 1 of 4 |
24
+
25
+ `onboarding` is the case that raised it: a public goal was <redacted>
26
+ for a Metic because the module owns one CLI that installs the pre-push hook.
27
+
28
+ ## Two corrections to the numbers the task was written on
29
+
30
+ Re-measured on this tree (`isProtectedModule` over `moduleKeys()`, 2026-09-20):
31
+
32
+ - **12 of 26 modules derive protected, not 11.** The task's re-measurement of
33
+ 2026-09-19 was already one short.
34
+ - **`agents` is the twelfth**, protected by `modules/agents/` — which is itself a
35
+ `PROTECTED_GLOBS` entry. It is absent from the task's list of seven that "stay
36
+ protected", so a reader working from that list would have been surprised by it.
37
+
38
+ Both corrections argue for the same thing, below: **pin the set by name.**
39
+
40
+ `government` and `agents` are each protected by exactly one glob too — so "1 of N"
41
+ is not the discriminator. The real one is **whether the protecting glob is the
42
+ module's own territory**: `modules/government/` and `modules/agents/` *are* those
43
+ modules; `scripts/gds/setup.js` merely lives near `onboarding`.
44
+
45
+ ## The options, and why the obvious one is wrong
46
+
47
+ You cannot subtract. The glob format has no wildcards, so "onboarding minus
48
+ setup.js" is inexpressible. And you cannot delete the glob: `MODULE_GLOBS` is also
49
+ the territory deciding **who may author a task touching that path**, and the shared
50
+ floor is only `tests/` — so an unowned path is authorable by no goal at all.
51
+
52
+ That left **(a) reassign each incidental CLI to an already-protected module**. It
53
+ was measured rather than reasoned about, by applying the edit to the source and
54
+ re-requiring in a fresh process — `MODULE_SCOPE_MAP` is frozen and built from a
55
+ copy at load, so mutating `MODULE_GLOBS` in-process proves nothing.
56
+
57
+ With `copy-inventory.js` and `conductor-dispatch.js` moved to `devsecops`:
58
+
59
+ | Goal scoped to | Authoring | Before | After (a) |
60
+ |---|---|---|---|
61
+ | `copy-desk` | its own generator | authorable | **denied, out_of_scope** |
62
+ | `autonomy` | its own conductor | authorable | **denied, out_of_scope** |
63
+ | `devsecops` | the generator **and its two outputs** | — | **denied, out_of_scope** |
64
+
65
+ The third row is the one that decides it. `docs/copy-registry.json` and
66
+ `docs/copy-inventory.md` stay `copy-desk`'s, so the generator and the artifacts it
67
+ writes end up either side of a module boundary and **the routine "change a UI
68
+ string, regenerate the registry" becomes authorable by no single goal.** That is
69
+ not a hypothetical workflow: it is the ship-check freshness gate every UI task
70
+ hits, because every row in the registry carries a line number and any edit to a
71
+ scanned file shifts them.
72
+
73
+ So (a) does not relocate a cost. It converts a correct ownership statement into a
74
+ false one, damages the authoring wall for two of the three modules, and buys the
75
+ flip with a workflow the project runs daily. It is right for exactly one of the
76
+ three — `setup.js` → `devsecops`, which already owns `.husky/` and the hooks.
77
+
78
+ ## Decision
79
+
80
+ **Protection becomes per-path at the goal-scope wall, as it already is at the
81
+ other three walls.** A module may own a protected path; owning one no longer makes
82
+ the whole module Archon-only to scope a goal to.
83
+
84
+ The derivation is not weakened and no flag is hand-set — the rule stays computed
85
+ from `PROTECTED_GLOBS`, the single source. What changes is the *question* the
86
+ derivation answers: not "does this module touch the trust core" but "is the
87
+ territory this goal is being scoped to, itself protected".
88
+
89
+ Three reasons this is the honest shape rather than the convenient one:
90
+
91
+ - **Per-path is already the rule everywhere else.** `matchProtected` /
92
+ `checkPermissionPaths` decides task-authoring ([ADR 0086](0086-goal-scoped-work-hierarchy.md) wall 2),
93
+ the grader and gate decide ship, and the post-push main audit decides the
94
+ dishonest case. All three ask about the path. Only goal-creation asks about the
95
+ module, and that inconsistency is the whole defect.
96
+ - **The wall that matters does not move.** A Metic-floor path stays Metic-floor:
97
+ a sub-Metic builder touching `scripts/gds/setup.js` is refused exactly as
98
+ before, by the same check. What changes is who may *create a goal* whose
99
+ territory happens to include it — a question about scoping, not about writing.
100
+ - **It keeps a command with its domain** (design 02§1), which is why those three
101
+ globs are where they are.
102
+
103
+ ## Not built here
104
+
105
+ Per the task: an ADR first, implementation as a follow-up. This decision builds no
106
+ new derivation mechanism. Filed separately:
107
+
108
+ - The implementation of the per-path goal-scope wall.
109
+ - **`builder-settings`, deliberately out of scope.** Its overlap is
110
+ `src/bongos/routes/me.js` caught by the blanket `src/bongos/routes/` prefix, so
111
+ narrowing it means either finishing the strangler move of `me.js` into
112
+ `modules/builder-settings/` or narrowing a blanket protected glob — a security
113
+ change with its own blast radius.
114
+ - **Nine protected paths are owned by no module at all** — `gen-repo-map.js`,
115
+ `gen-file-map.js`, `gen-session-index.js`, `install-git-hooks.js`, `cli-lib.js`,
116
+ `run-unit-tests.js`, `git-merge-regen.js`, `scripts/gds/hooks/` and
117
+ `.gitattributes`. By the rule above, no goal can author a task on any of them.
118
+ Found while checking whether deletion was viable; it is a pre-existing hole,
119
+ not one this decision opens.
120
+
121
+ ## Shipped with this ADR
122
+
123
+ One thing is built, because it guards the decision rather than implementing it:
124
+ a test pinning the **full protected key set by name**. A count assertion passes on
125
+ the wrong twelve, and both corrections above are exactly the drift it catches — a
126
+ future glob edit that silently unprotects `kernel` or `lifecycle` now reds the
127
+ build.
128
+
129
+ ## Does not decide
130
+
131
+ The floor a protected path carries (unchanged, Metic, from the surface registry);
132
+ whether `scripts/gds/` should have a shared-floor entry the way `tests/` does;
133
+ or whether the nine unowned paths are assigned or given a home of their own.
@@ -405,3 +405,4 @@ This keeps the decision history honest and traceable.
405
405
  | 0311 | [**An idea is a permanent origin tag, and the payout follows its descent** ([task 1004076](https://cloudbongos.com/builders#/task/1004076), goal 1000095 — BONGOS-V2). An idea today is a CONTAINER for work: it leaves `idea_inbox` when it names a goal and lives on as a task, so the better-aimed the thought the faster it vanishes from whoever had it. Reported as a small confusion — a thought filed from the hall routed into a goal, the confirmation line cleared on the next keystroke, and five minutes later the owner could not find it. The idea becomes an **immutable origin tag** instead, the only thing that can answer where a piece of work came from, and **the ideator payout follows its whole descent** rather than stopping at the earliest lineage link (`awardIdeaTaskShipCredit`), decaying by depth — full at the direct task, halving each hop — so an infinite descent is worth at most twice the direct task. That is what gives the tag teeth: if it does not survive a fork, someone does not get paid. **Size and brightness are two channels, not one number**: size is the sum of those payouts and never falls, brightness is how much of that work is still alive, so a thought whose work the project tore out renders LARGE AND DEAD rather than looking like one that never mattered. **Karma was rejected as the basis** — `karma_log` carries no task key and no idea key, deliberately ([`migrations/040_builder_karma.sql`](../../migrations/040_builder_karma.sql)), so "the karma a thought caused" is not computable; credits already are idea-attributed. **The task hierarchy is NOT widened** to carry the descent — it is capped at one level and refuses cross-version parents because ship rollup and claim safety lean on it, and provenance is a different relation from work decomposition. **Nothing records that shipped work was later removed** (`shipped` is terminal, `merged_into_task_id` is CHECK-constrained to abandoned rows), so the first `cascade.js` rule PROPOSES a removal and a person confirms it — derived-only would dim for refactors and renames, declared-only would rot. A ratified **Full Idea becomes a goal or a criterion**, carrying a recommendation the board rules on, because scope is the thing you learn last; the five questions are replaced and VERSIONED so prior filings keep their own. Dropped three tasks this invalidated and amended a fourth whose title asserted the exact exclusivity it reverses. Does not decide: the decay rate beyond its default, what precisely counts as removed, how the edges are physically recorded, or how any of it is drawn.](0311-an-idea-is-a-permanent-origin-tag.md) | ideas / economy |
406
406
  | 0312 | [**Provenance is a SECOND ideas-owned edge table, written by the seams that already know** ([task 1004080](https://cloudbongos.com/builders#/task/1004080), goal 1000095 — BONGOS-V2). The spike [ADR 0311](0311-an-idea-is-a-permanent-origin-tag.md) deferred: how the descent edges are physically recorded. A descent (`idea → task → rewrite → split → removal`) is four levels deep and crosses a version boundary, and the task hierarchy refuses both — `attachParent` enforces `SELF_PARENT`, `VERSION_MISMATCH`, `PARENT_HAS_PARENT` and `TARGET_HAS_CHILDREN`, all load-bearing for ship rollup and claim safety. The spike was told to CONFIRM `ideas_task_lineage` rather than assume it, and confirmed one half while refuting the other: the table is right as the **idea→task anchor** (bipartite, no depth cap, no version predicate) but CANNOT carry the task→task edge, because a derivation is a property of the task PAIR and [ADR 0236](0236-many-ideas-one-task-the-lineage-key-is-the-pair.md) made co-source ideas both legal and common — a `derived_from_task_id` column would write the same derivation once per co-source idea and let two rows disagree about where a task came from, the same under-keying that silently lost attribution on prod once already. A merge also gives a task SEVERAL parents, so the relation is a **DAG, not a tree**. Decision: a new `ideas_task_descent` (`task_id`, `parent_task_id`, CHECK'd `relation`, PK on the pair, indexed both ways), with NO depth cap and NO version predicate, and **cycles refused at write time** because the payout walks this graph and a cycle is a non-terminating walk rather than a cosmetic error. On who writes it — the question the task actually set, since an edge depending on memory will have holes — **three seams already know and none is telling anyone**: `cascade.js` encodes the originating task id inside `source_ref` as a STRING nothing can join on, `tasks.merged_into_task_id` already records the fold, and `parent_task_id` already records the split. Only `rewrite` and cross-version `merge` stay manual, which is honest — they are editorial acts with no automatic signal, and their absence degrades the picture rather than corrupting it. What it fixes: `sourceIdeaForTask` and `awardIdeaTaskShipCredit` are both one-hop `LIMIT 1` point reads, so a DERIVED task resolves to `no_source_idea` and the origin is not paid at all. Does not decide: the decay rate beyond its default, what counts as removed ([ADR 0313](0313-a-removal-is-proposed-by-the-ship-and-confirmed-by-a-person.md)), or how any of it is drawn.](0312-provenance-is-a-second-ideas-owned-edge-table.md) | ideas / lifecycle |
407
407
  | 0313 | [**A removal is derived from the SERVER's own merge diff and confirmed by a person** ([task 1004081](https://cloudbongos.com/builders#/task/1004081), goal 1000095 — BONGOS-V2). The other half [ADR 0311](0311-an-idea-is-a-permanent-origin-tag.md) deferred: what counts as removed, so that brightness can fall at all. Nothing records it today — `shipped` is terminal (`rot.js` says so outright) and `merged_into_task_id` is CHECK'd to `abandoned` rows, describing only work cut BEFORE it landed. Owner decision 13 set the shape (system proposes, person confirms); this settles the detail, and corrects two premises the task was written on. **`cascade.js` is no longer empty** — it carries a production rule and [ADR 0242](0242-a-cascade-is-a-declaration-table-on-the-event-that-already-exists.md) fixed the contract (append an entry, never touch the runner), so there is a precedent to copy including its anti-recursion guard. **`netNegativeBonusAmount` cannot be the trigger** despite being the named nearest signal: it is an aggregate with NO TARGET (it says deletion happened, never what or whose), it is CLIENT-SUPPLIED via `signals.diff_stats`, and `grader-score.js` already documents the forgery it defends against — and brightness sits beside a payout, so a forgeable target-less counter cannot carry it. **Nothing durable records what any ship touched**: `committed_files` and `diff_stats` are client-supplied at grade time and never persisted, `touches[]` is advisory ([ADR 0049](0049-split-parallel-safety-contract.md)), so a removal cannot be reconstructed from history — only derived as a ship lands. Decision: derive it from the SERVER's own merge diff ([ADR 0055](0055-server-mediated-branch-publish.md) — the server holds the repo and does the merge, so it computes the diff rather than being told one), and attribute the deleted hunks through **`claims.published_head_sha`** (`migrations/171`), NOT by parsing `(task NNNN)` out of commit text — only 7 of `main`'s last 15 commits carry a task id, and a convention that holds most of the time cannot underwrite a payout. An UNATTRIBUTABLE deletion files nothing: a wrong proposal costs attention and dims a real star. A rename, a move and a rewrite-in-place are NOT removals, and a cold body is not a remnant — removal applies only below a task that actually shipped. The proposal is an appended `CASCADES` entry filing a QUESTION; confirmation is Metic+/`task.promote` on the existing awaiting-nod surface; an unanswered one rots on the normal clock. Only a CONFIRMED proposal dims a star. The derivation must be NON-BLOCKING — landing work matters more than dimming a star on time. Brightness can only fall forward from here, so historical sizes need a marker or the number lies.](0313-a-removal-is-proposed-by-the-ship-and-confirmed-by-a-person.md) | ideas / lifecycle |
408
+ | 0314 | [**A module owns a protected path without the whole module becoming protected** ([task 1004070](https://cloudbongos.com/builders#/task/1004070), goal 1000095 — BONGOS-V2). Three modules derive `protected` — and so are Archon-only to scope a goal to — because of ONE file that is not their domain: `onboarding` on `scripts/gds/setup.js`, `autonomy` on `scripts/gds/conductor-dispatch.js`, `copy-desk` on `scripts/gds/copy-inventory.js`. The owner chose *narrow what counts as protected*; the task set the fork and required the choice be justified before any glob moved. **Deleting the glob is out**: `MODULE_GLOBS` is also the territory deciding who may AUTHOR a task on a path, and the shared floor is only `tests/`, so an unowned path is authorable by no goal at all. That left reassigning each CLI to an already-protected module — **measured, not reasoned about**, by applying the edit to the source and re-requiring in a fresh process (`MODULE_SCOPE_MAP` is frozen and built from a COPY of `MODULE_GLOBS` at load, so an in-process mutation proves nothing and passes green). The measurement kills it: `copy-desk` and `autonomy` lose the ability to author on their own generator and their own conductor, and — the row that decides it — `devsecops` as the new owner **cannot author the generator together with the two artifacts it writes**, because `docs/copy-registry.json` and `docs/copy-inventory.md` stay `copy-desk`'s. So *change a UI string, regenerate the registry* becomes authorable by no single goal, and that is the ship-check freshness gate every UI task hits. Decision: **protection becomes per-path at the goal-scope wall, as it already is at the other three** — `matchProtected` decides task-authoring, the grader and gate decide ship, the post-push audit decides the dishonest case; only goal-creation asked about the MODULE, and that inconsistency is the whole defect. The derivation stays computed from `PROTECTED_GLOBS` and no flag is hand-set ([ADR 0086](0086-goal-scoped-work-hierarchy.md) §7 / SEC #863), and the Metic floor on those paths does not move. **Corrects the task's own numbers**: 12 of 26 modules derive protected, not 11, and `agents` (protected by `modules/agents/`, itself a protected glob) is absent from its list of seven — which is why the one thing this ADR SHIPS is a test pinning the full protected key set **by name**, a count assertion passing on the wrong twelve being exactly how that drifted. Implementation is deferred to task 1004109, per the task's own instruction to stop after the ADR. Also filed: `builder-settings` (task 1004110), whose overlap rides the blanket `src/bongos/routes/` prefix and so needs either the `me.js` strangler move or its own security ADR; and **nine protected paths owned by no module at all** (task 1004111) — the freshness generators, the merge-driver pair and `cli-lib.js` among them — found while checking whether deletion was viable, a pre-existing hole rather than one this opens. Does not decide: the floor a protected path carries, whether `scripts/gds/` deserves a shared-floor entry the way `tests/` has one, or how the nine unowned paths get a home.](0314-module-protection-is-per-path-not-per-module.md) | modules / permissions |