@bongos/core 1.19.339 → 1.19.341

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/docs/file-map.md CHANGED
@@ -389,7 +389,7 @@ tests/
389
389
  <!-- BEGIN GENERATED FILE-MAP .claude/scheduled-tasks/ (scripts/gds/gen-file-map.js — do not hand-edit; notes live in docs/file-map.notes.json) -->
390
390
  ```
391
391
  .claude/scheduled-tasks/
392
- └── redteam-weekly/SKILL.md ← weekly deterministic red-team patrol (task 1003128): full-history gitleaks scan + dependency drift review (audit delta, cooldown, young pkgs, stale overrides) + action-pin check → files security reports (advisory, ADR 0162)
392
+ └── redteam-weekly/SKILL.md ← weekly deterministic red-team patrol (task 1003128): full-history gitleaks scan + dependency drift review (audit delta, cooldown, young pkgs, stale overrides) + action-pin check → files security reports (advisory, ADR 0162). FIRED BY .github/workflows/redteam-patrol.yml, Mondays 06:17 UTC — `cadence: weekly` here and that cron must agree or fitness Check 25 (scripts/gds/routine-schedule.js) fails the gate (task 1003209, ADR 0188)
393
393
  ```
394
394
  <!-- END GENERATED FILE-MAP .claude/scheduled-tasks/ -->
395
395
 
@@ -16,18 +16,69 @@ node scripts/gds/redteam-patrol.js --canary # self-test detection only
16
16
  node scripts/gds/redteam-patrol.js --canary --file # prove the full pipe (files + dispute-closes)
17
17
  ```
18
18
 
19
- The scheduled form lives at [`.claude/scheduled-tasks/redteam-weekly/`](../../.claude/scheduled-tasks/redteam-weekly/SKILL.md)
20
- (`mode: deterministic`, one step, sink `gds`). Install on a machine per the
21
- file-map convention: symlink the routine dir under `~/.claude/scheduled-tasks/`.
22
- Weekly is the cadence — the checks watch drift measured in days (release-age,
23
- new advisories), not minutes.
19
+ ## What actually fires it
20
+
21
+ **[`.github/workflows/redteam-patrol.yml`](../../.github/workflows/redteam-patrol.yml)
22
+ — Mondays 06:17 UTC** (task 1003209, ADR 0188). Before that lane the patrol was,
23
+ in the follow-up audit's words, a manual script: tracked, documented, wired into
24
+ the control manifest, and run zero times.
25
+
26
+ The routine itself lives at
27
+ [`.claude/scheduled-tasks/redteam-weekly/`](../../.claude/scheduled-tasks/redteam-weekly/SKILL.md)
28
+ (`mode: deterministic`, `cadence: weekly`, one step, sink `gds`) and the workflow
29
+ invokes it through `run-routine.js`, so the SKILL.md's `steps:` stay the single
30
+ source of truth for what a run does. Weekly is the cadence because the checks
31
+ watch drift measured in days (release-age, new advisories), not minutes.
32
+
33
+ **The cadence and the cron are checked against each other.** `cadence: weekly` in
34
+ the SKILL.md and `cron: '17 6 * * 1'` in the workflow must agree, or
35
+ `scripts/gds/routine-schedule.js` (fitness Check 25) fails the merge gate — as it
36
+ does if the workflow stops firing the routine, or fires one that no longer
37
+ exists. Change one and change the other in the same commit. The odd minute is
38
+ deliberate: GitHub queues scheduled workflows and top-of-hour is its worst
39
+ congestion window.
40
+
41
+ **Why CI and not the always-on server.** All three checks read things only the
42
+ *repo* has — full git history, `.github/workflows/`, an auditable lockfile. A
43
+ deployed instance runs a vendored core out of `node_modules/@bongos/core`, which
44
+ has none of them, so an in-process timer would have scanned nothing and reported
45
+ clean. ADR 0188 §2.1.
46
+
47
+ ### Filing from CI (optional)
48
+
49
+ A CI runner has no GDS session, so by default the scheduled run **reports but
50
+ cannot file**: findings go to the Actions job summary and the job exits 2. To let
51
+ it file, set the repo secret **`GDS_PATROL_SESSION`** to a GDS CLI session JSON
52
+ (`{"token":…,"api_base":…}`) for a builder holding `security.report.file`; the
53
+ workflow writes it to the session path `instance-config` resolves and the patrol
54
+ files normally. This is opt-in on purpose — the patrol must not *require* a
55
+ long-lived token to be useful.
56
+
57
+ **Red means a finding was LOST, not that a finding exists.** Findings are
58
+ advisory (ADR 0162), so a run that files three of them is a success:
59
+
60
+ | the run… | exit |
61
+ |---|---|
62
+ | found nothing | 0 |
63
+ | was a dry run | 0 |
64
+ | filed its findings | 0 |
65
+ | has findings it cannot file | **2** |
66
+
67
+ Expect a standing `history-secrets` hit until the staging credential in commit
68
+ `092e473` is scrubbed from history. That is the patrol working, not the lane
69
+ being broken.
24
70
 
25
71
  ## Prerequisites
26
72
 
27
73
  - **gitleaks** on PATH (`brew install gitleaks`) or `GITLEAKS_BIN=<path>`. The
28
74
  history scan degrades LOUDLY (a printed warning, no silent skip) when absent;
29
- the dependency + pin checks still run.
75
+ the dependency + pin checks still run. The scheduled lane installs it itself —
76
+ version-pinned and checksum-verified, the same binary and digest the unit gate
77
+ uses, rather than a mutable action tag (the tj-actions lesson).
30
78
  - A GDS session (the normal builder token) for `--file`; dry runs need nothing.
79
+ `--file` preflights it, so a sessionless run prints its findings and says it
80
+ could not file them — it never drops into the CLI's interactive re-auth wall,
81
+ which in a cron log is indistinguishable from a crash.
31
82
  - Network access to the npm registry for the dependency checks — registry
32
83
  failures print notes and skip that item (advisory layer: fail-open, loud).
33
84
 
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.339",
3
+ "version": "1.19.341",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.19.339",
9
+ "version": "1.19.341",
10
10
  "license": "AGPL-3.0-or-later",
11
11
  "dependencies": {
12
12
  "express": "^4.21.2",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.339",
3
+ "version": "1.19.341",
4
4
  "description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "main": "src/platform-server.js",
@@ -201,6 +201,10 @@
201
201
 
202
202
  *{box-sizing:border-box;margin:0;padding:0;}
203
203
  [hidden]{display:none !important;}
204
+ /* visually-hidden: said by a screen reader, never painted. The done panel's
205
+ progress strip needs it (its dots carry each stage's state for the eye only),
206
+ and the hub's map heading and skip link ride on it. */
207
+ .vh{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;}
204
208
  html{scroll-behavior:smooth;}
205
209
  body{font-family:var(--font-body);color:var(--ink);background:var(--page-bg);min-height:100vh;-webkit-font-smoothing:antialiased;overflow-x:hidden;}
206
210
 
@@ -283,14 +287,18 @@ h1{font-family:var(--font-display);font-weight:700;font-size:clamp(24px,3.4vw,32
283
287
  verification — warm when verified live, amber-dim when stale, ashen when
284
288
  it failed its check, ghosted when torn down. Born for the dark sky; on
285
289
  light cards the inset ring keeps it grounded. ── */
286
- .orb{flex:0 0 54px;width:54px;height:54px;border-radius:50%;position:relative;overflow:visible;cursor:pointer;border:none;padding:0;
290
+ .orb{flex:0 0 54px;width:54px;height:54px;border-radius:50%;position:relative;overflow:visible;border:none;padding:0;
287
291
  background:radial-gradient(120% 120% at 50% 50%, var(--acc,#fb923c), color-mix(in srgb, var(--acc,#fb923c) 55%, #1b2b52) 100%);
288
292
  box-shadow:0 0 0 1.5px rgba(255,255,255,.35) inset, 0 6px 18px rgba(20,16,40,.28), 0 0 26px var(--glow, rgba(251,146,60,.5));}
289
293
  .orb::after{content:'';position:absolute;inset:0;border-radius:50%;pointer-events:none;
290
294
  background:radial-gradient(38% 34% at 34% 28%, rgba(255,255,255,.9), rgba(255,255,255,0) 60%);}
291
295
  .orb.dim{filter:saturate(.55) brightness(.92);--glow:rgba(217,119,6,.35);}
292
296
  .orb.ashen{filter:saturate(.3) brightness(.78);--glow:rgba(220,38,38,.22);}
293
- .orb.ghost{opacity:.4;box-shadow:0 0 0 1.5px rgba(255,255,255,.25) inset;filter:saturate(.2);cursor:default;}
297
+ .orb.ghost{opacity:.4;box-shadow:0 0 0 1.5px rgba(255,255,255,.25) inset;filter:saturate(.2);}
298
+ /* only the LINKED orb is clickable: orbFor() emits a <span class="orb"> for
299
+ every non-navigable state, and index.html's .conItem .orb takes cursor:inherit
300
+ from the <a> it sits inside — so .orb.ghost's cursor reset is redundant. */
301
+ a.orb{cursor:pointer;}
294
302
 
295
303
  /* ── project cards ── */
296
304
  .projects{list-style:none;display:flex;flex-direction:column;gap:18px;}
@@ -622,6 +630,10 @@ p.sec-p{font-size:var(--fs-lede);font-weight:500;color:var(--ink-soft);line-heig
622
630
  .tbl th{text-align:left;font-family:var(--font-display);font-size:11.5px;font-weight:700;
623
631
  letter-spacing:.9px;text-transform:uppercase;color:var(--ink-faint);padding:15px 18px;
624
632
  border-bottom:2px solid var(--line);white-space:nowrap;}
633
+ /* the sort control is a real button so the keyboard can reach it; it must look
634
+ like the header it replaced, so it inherits everything the th declares. */
635
+ .tbl th button{all:unset;cursor:pointer;}
636
+ .tbl th button:focus-visible{outline:2px solid var(--accent);outline-offset:2px;}
625
637
  .tbl td{padding:15px 18px;border-bottom:1px solid var(--line);font-size:14px;font-weight:600;
626
638
  color:var(--ink-soft);vertical-align:middle;}
627
639
  .tbl tr:last-child td{border-bottom:none;}
@@ -631,7 +643,8 @@ p.sec-p{font-size:var(--fs-lede);font-weight:500;color:var(--ink-soft);line-heig
631
643
  .tbl .pname{display:flex;align-items:center;gap:11px;}
632
644
  .tbl .pdot{width:11px;height:11px;border-radius:50%;background:var(--acc);flex:0 0 auto;
633
645
  box-shadow:0 0 0 3px color-mix(in srgb,var(--acc) 22%,transparent);}
634
- .tbl .ptitle{font-family:var(--font-display);font-weight:700;font-size:15px;color:var(--ink);}
646
+ .tbl .ptitle{font-family:var(--font-display);font-weight:700;font-size:15px;color:var(--ink);text-decoration:none;}
647
+ .tbl a.ptitle:hover{text-decoration:underline;}
635
648
  .tbl .ptag{font-size:12.5px;color:var(--ink-faint);font-weight:600;}
636
649
  .tbl .num{font-family:var(--font-mono);font-weight:500;}
637
650
  .tbl .tags{display:flex;gap:6px;flex-wrap:wrap;}
@@ -753,6 +766,8 @@ p.sec-p{font-size:var(--fs-lede);font-weight:500;color:var(--ink-soft);line-heig
753
766
  .steps li.now .snum{border-color:var(--accent);color:var(--accent-deep);}
754
767
  .steps .slbl{font-size:12.5px;font-weight:700;color:var(--ink-faint);}
755
768
  .steps li.now .slbl,.steps li.done .slbl{color:var(--ink-soft);}
769
+ .steps li[role=button]{cursor:pointer;}
770
+ .steps li[role=button]:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:8px;}
756
771
  .createSplit{display:grid;grid-template-columns:1fr 300px;gap:var(--pad-md);align-items:center;}
757
772
  @media (max-width:840px){.createSplit{grid-template-columns:1fr;}.createSplit .bongoCell{display:none;}}
758
773