@bongos/core 1.17.3 → 1.18.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 +212 -332
- package/.devcontainer/healthcheck.sh +0 -0
- package/.devcontainer/init-firewall.sh +0 -0
- package/.devcontainer/post-create.sh +0 -0
- package/GOVERNANCE.md +1 -1
- package/README.md +26 -22
- package/bin/bongos.js +0 -0
- package/config/branding.neutral.json +5 -1
- package/docker-entrypoint.sh +0 -0
- package/docs/adr/0142-project-context-is-prose-only.md +41 -0
- package/docs/adr/0143-onboarding-repo-picker-oauth-scope.md +35 -0
- package/docs/adr/README.md +6 -0
- package/docs/api/openapi.json +1630 -632
- package/docs/api-reference.md +50 -15
- package/docs/file-map.md +0 -18
- package/docs/onboarding/diagrams/05-versioning.mmd +4 -6
- package/docs/onboarding/diagrams/assertions.json +5 -9
- package/docs/recipes/packaging-the-core.md +13 -0
- package/docs/recipes/upgrading-the-core.md +5 -2
- package/migrations/039_newcomer_friendly_column.sql +5 -0
- package/migrations/102_remove_box_first_provision_approval.sql +4 -0
- package/migrations/core_192_github_oauth_tokens.sql +33 -0
- package/modules/hall-ui/public/builders.js +37 -0
- package/modules/hall-ui/public/goals-page.js +98 -176
- package/modules/hall-ui/public/goals.css +183 -0
- package/modules/hall-ui/public/goals.html +35 -261
- package/modules/hall-ui/public/goals.js +7 -2
- package/modules/hall-ui/public/hall-widgets.js +12 -4
- package/modules/hall-ui/public/my-projects.html +78 -0
- package/modules/hall-ui/public/my-projects.js +142 -0
- package/modules/hall-ui/public/scouting.html +45 -0
- package/modules/hall-ui/public/scouting.js +73 -0
- package/modules/hall-ui/public/settings.css +355 -0
- package/modules/hall-ui/public/settings.html +86 -414
- package/modules/hall-ui/public/settings.js +96 -35
- package/modules/hall-ui/public/style.css +31 -0
- package/modules/hall-ui/public/watch.css +184 -0
- package/modules/hall-ui/public/watch.html +111 -285
- package/modules/hall-ui/public/watch.js +59 -21
- package/modules/status-ui/public/explore.html +54 -0
- package/modules/status-ui/public/explore.js +67 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/public-landing/create.html +292 -19
- package/public-landing/index.html +11 -76
- package/scripts/cron/style_guide_audit.sh +0 -0
- package/scripts/gds/api.js +0 -0
- package/scripts/gds/architect-audit.js +0 -0
- package/scripts/gds/audit-authorship.sh +0 -0
- package/scripts/gds/audit-replay.sh +0 -0
- package/scripts/gds/box.js +0 -0
- package/scripts/gds/capture.js +0 -0
- package/scripts/gds/cli-lib.js +11 -5
- package/scripts/gds/conductor-dispatch.js +0 -0
- package/scripts/gds/coreB-carve-proof.sh +0 -0
- package/scripts/gds/db-backup-nightly.sh +0 -0
- package/scripts/gds/db-backup-offsite.sh +0 -0
- package/scripts/gds/doctor.js +0 -0
- package/scripts/gds/grade-smoke.js +0 -0
- package/scripts/gds/hooks/pre-push.js +0 -0
- package/scripts/gds/install-git-hooks.js +0 -0
- package/scripts/gds/lint-migrations.js +102 -0
- package/scripts/gds/login.js +42 -10
- package/scripts/gds/main-audit.js +0 -0
- package/scripts/gds/mirror-redact.js +5 -0
- package/scripts/gds/oauth-secret.js +0 -0
- package/scripts/gds/onboarding-analyze.js +0 -0
- package/scripts/gds/onboarding-ship.js +0 -0
- package/scripts/gds/package-core.js +263 -4
- package/scripts/gds/paste-token.js +0 -0
- package/scripts/gds/portability-smoke-art.sh +0 -0
- package/scripts/gds/portability-smoke-memory.sh +0 -0
- package/scripts/gds/provision.js +270 -11
- package/scripts/gds/publish-manifest.js +15 -0
- package/scripts/gds/push-main.js +0 -0
- package/scripts/gds/render-ideas.js +0 -0
- package/scripts/gds/run-unit-tests.js +38 -14
- package/scripts/gds/security-baseline-check.sh +0 -0
- package/scripts/gds/session.js +0 -0
- package/scripts/gds/setup.js +41 -0
- package/scripts/gds/ship.js +126 -32
- package/scripts/gds/smoke-batch-claim.sh +0 -0
- package/scripts/gds/smoke-batch-release.sh +0 -0
- package/scripts/gds/smoke-box.sh +0 -0
- package/scripts/gds/smoke-claim-consistency.sh +0 -0
- package/scripts/gds/smoke-dependencies.sh +0 -0
- package/scripts/gds/smoke-write.sh +0 -0
- package/scripts/gds/upgrade.js +147 -5
- package/scripts/hall-preview/server.js +18 -1
- package/scripts/migrate.sh +10 -0
- package/scripts/migrate_cost_ledger.sh +0 -0
- package/scripts/render-diagrams.sh +0 -0
- package/scripts/security/dep-audit.js +0 -0
- package/scripts/setup-builder.js +0 -0
- package/scripts/setup-builder.sh +0 -0
- package/scripts/snapshots/maybe-render-on-deploy.sh +0 -0
- package/src/bongos/auth.js +362 -5
- package/src/bongos/db.js +66 -0
- package/src/bongos/github-repos.js +93 -0
- package/src/bongos/routes/auth.js +93 -11
- package/src/bongos/routes/github.js +90 -0
- package/src/bongos/routes/instance.js +15 -3
- package/src/bongos/routes.js +2 -0
- package/src/branding.js +17 -2
- package/src/instance-config.js +16 -0
- package/src/module-api.js +48 -1
- package/tests/branding.mjs +29 -23
- package/tests/github_repos_helpers.mjs +91 -0
- package/tests/github_token_store.mjs +121 -0
- package/tests/idp_device_exchange.mjs +105 -0
- package/tests/idp_federation.mjs +100 -0
- package/tests/migrations_forward_safe.mjs +86 -0
- package/tests/module_api.mjs +1 -1
- package/tests/package_core.mjs +246 -1
- package/tests/provision.mjs +226 -0
- package/tests/pruned_lockfile_integrity.mjs +79 -0
- package/tests/ship_ci_deploy.mjs +60 -0
- package/tests/upgrade.mjs +254 -5
- package/.gitignore +0 -91
- package/scripts/hall-preview/fixtures/access-requests.json +0 -1
- package/scripts/hall-preview/fixtures/achievements.json +0 -76
- package/scripts/hall-preview/fixtures/analytics__builder.json +0 -251
- package/scripts/hall-preview/fixtures/audit-log.json +0 -1
- package/scripts/hall-preview/fixtures/boxes__cost-ledger.json +0 -1
- package/scripts/hall-preview/fixtures/builders__active-claims.json +0 -1
- package/scripts/hall-preview/fixtures/builders__directory.json +0 -81
- package/scripts/hall-preview/fixtures/builders__roster.json +0 -1
- package/scripts/hall-preview/fixtures/goals.json +0 -502
- package/scripts/hall-preview/fixtures/goals__25.json +0 -96
- package/scripts/hall-preview/fixtures/goals__26.json +0 -67
- package/scripts/hall-preview/fixtures/goals__3.json +0 -103
- package/scripts/hall-preview/fixtures/goals__35.json +0 -49
- package/scripts/hall-preview/fixtures/goals__conflicts.json +0 -154
- package/scripts/hall-preview/fixtures/goals__detail.json +0 -96
- package/scripts/hall-preview/fixtures/goals__inbox.json +0 -5
- package/scripts/hall-preview/fixtures/goals__requests.json +0 -3
- package/scripts/hall-preview/fixtures/grades__by-builder.json +0 -1
- package/scripts/hall-preview/fixtures/inbox.json +0 -330
- package/scripts/hall-preview/fixtures/instance.json +0 -124
- package/scripts/hall-preview/fixtures/leaderboard.json +0 -184
- package/scripts/hall-preview/fixtures/me.json +0 -476
- package/scripts/hall-preview/fixtures/me__recent-ships.json +0 -304
- package/scripts/hall-preview/fixtures/override-requests.json +0 -1
- package/scripts/hall-preview/fixtures/provisioning__fleet.json +0 -1
- package/scripts/hall-preview/fixtures/provisioning__fleet__cost-ledger.json +0 -1
- package/scripts/hall-preview/fixtures/provisioning__instances.json +0 -1
- package/scripts/hall-preview/fixtures/public__analytics__ecosystem.json +0 -516
- package/scripts/hall-preview/fixtures/public__bounty-table.json +0 -37
- package/scripts/hall-preview/fixtures/public__cost-summary.json +0 -742
- package/scripts/hall-preview/fixtures/public__estimation-drift.json +0 -41
- package/scripts/hall-preview/fixtures/public__grades.json +0 -50
- package/scripts/hall-preview/fixtures/public__progress.json +0 -124
- package/scripts/hall-preview/fixtures/public__recent-shipped.json +0 -426
- package/scripts/hall-preview/fixtures/public__repo-health.json +0 -160
- package/scripts/hall-preview/fixtures/public__repo-info.json +0 -5
- package/scripts/hall-preview/fixtures/security__docs.json +0 -1
- package/scripts/hall-preview/fixtures/security__reports.json +0 -1
- package/scripts/hall-preview/fixtures/sessions__search.json +0 -1
- package/scripts/hall-preview/fixtures/tasks.json +0 -2420
- package/scripts/hall-preview/fixtures/tasks__claimable.json +0 -2555
- package/scripts/hall-preview/fixtures/tasks__detail.json +0 -111
- package/scripts/hall-preview/fixtures/tasks__peer-votes__feed.json +0 -330
- package/scripts/hall-preview/fixtures/versions.json +0 -89
|
@@ -10,199 +10,10 @@
|
|
|
10
10
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
11
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
12
12
|
<link rel="stylesheet" href="/builders/style.css?v=2026-07-02-shell1">
|
|
13
|
-
<style>
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
display: grid;
|
|
18
|
-
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
|
19
|
-
gap: 12px;
|
|
20
|
-
margin-top: 6px;
|
|
21
|
-
}
|
|
22
|
-
.watch-stat {
|
|
23
|
-
background: var(--surface);
|
|
24
|
-
border: 1px solid var(--border);
|
|
25
|
-
border-radius: var(--radius-sm);
|
|
26
|
-
padding: 14px 16px;
|
|
27
|
-
text-align: center;
|
|
28
|
-
}
|
|
29
|
-
.watch-stat__num {
|
|
30
|
-
font-family: var(--font-display);
|
|
31
|
-
font-size: 1.6rem;
|
|
32
|
-
font-weight: 650;
|
|
33
|
-
color: var(--ink);
|
|
34
|
-
line-height: 1.2;
|
|
35
|
-
font-variant-numeric: tabular-nums;
|
|
36
|
-
}
|
|
37
|
-
.watch-stat__label {
|
|
38
|
-
font-size: 11px;
|
|
39
|
-
font-weight: 600;
|
|
40
|
-
color: var(--ink-faint);
|
|
41
|
-
text-transform: uppercase;
|
|
42
|
-
letter-spacing: 0.06em;
|
|
43
|
-
margin-top: 4px;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
.watch-table-wrap { overflow-x: auto; margin-top: 6px; }
|
|
47
|
-
table.watch {
|
|
48
|
-
width: 100%;
|
|
49
|
-
border-collapse: collapse;
|
|
50
|
-
font-size: 13.5px;
|
|
51
|
-
color: var(--ink);
|
|
52
|
-
}
|
|
53
|
-
table.watch th, table.watch td {
|
|
54
|
-
padding: 8px 10px;
|
|
55
|
-
text-align: left;
|
|
56
|
-
border-bottom: 1px solid var(--border);
|
|
57
|
-
vertical-align: top;
|
|
58
|
-
}
|
|
59
|
-
table.watch th {
|
|
60
|
-
font-size: 11px;
|
|
61
|
-
font-weight: 600;
|
|
62
|
-
text-transform: uppercase;
|
|
63
|
-
letter-spacing: 0.06em;
|
|
64
|
-
color: var(--ink-faint);
|
|
65
|
-
border-bottom: 1px solid var(--border-strong);
|
|
66
|
-
white-space: nowrap;
|
|
67
|
-
}
|
|
68
|
-
table.watch td.num { text-align: right; font-variant-numeric: tabular-nums; }
|
|
69
|
-
table.watch td.warn { color: var(--danger); font-weight: 600; }
|
|
70
|
-
table.watch tr:hover td { background: var(--surface-2); }
|
|
71
|
-
.watch-mono { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 0.84rem; color: var(--info); }
|
|
72
|
-
.watch-empty { color: var(--ink-faint); font-size: 13px; padding: 10px 0; }
|
|
73
|
-
.watch-note { color: var(--ink-faint); font-size: 12.5px; margin-top: 10px; }
|
|
74
|
-
.watch-rank { font-size: 12px; color: var(--ink-faint); }
|
|
75
|
-
.watch-doc {
|
|
76
|
-
white-space: pre-wrap;
|
|
77
|
-
word-break: break-word;
|
|
78
|
-
font-family: ui-monospace, "SF Mono", Menlo, monospace;
|
|
79
|
-
font-size: 0.8rem;
|
|
80
|
-
line-height: 1.5;
|
|
81
|
-
max-height: 60vh;
|
|
82
|
-
overflow-y: auto;
|
|
83
|
-
padding: 12px;
|
|
84
|
-
margin-top: 8px;
|
|
85
|
-
background: var(--surface-2);
|
|
86
|
-
border: 1px solid var(--border);
|
|
87
|
-
border-radius: var(--radius-sm);
|
|
88
|
-
}
|
|
89
|
-
.watch-sub-h, .watch-subh {
|
|
90
|
-
font-family: var(--font-display);
|
|
91
|
-
font-size: 14px;
|
|
92
|
-
font-weight: 600;
|
|
93
|
-
color: var(--ink);
|
|
94
|
-
margin: 18px 0 4px;
|
|
95
|
-
}
|
|
96
|
-
.watch-sub-h:first-of-type { margin-top: 8px; }
|
|
97
|
-
|
|
98
|
-
/* Severity / status badges. */
|
|
99
|
-
.badge {
|
|
100
|
-
display: inline-block;
|
|
101
|
-
font-size: 11px;
|
|
102
|
-
font-weight: 600;
|
|
103
|
-
letter-spacing: 0.04em;
|
|
104
|
-
text-transform: uppercase;
|
|
105
|
-
padding: 2px 8px;
|
|
106
|
-
border-radius: 999px;
|
|
107
|
-
border: 1px solid var(--border-strong);
|
|
108
|
-
color: var(--ink-soft);
|
|
109
|
-
white-space: nowrap;
|
|
110
|
-
}
|
|
111
|
-
.badge--sev-critical { background: var(--danger-weak); color: var(--danger); border-color: color-mix(in srgb, var(--danger) 35%, transparent); }
|
|
112
|
-
.badge--sev-high { background: var(--warn-weak); color: var(--warn); border-color: color-mix(in srgb, var(--warn) 35%, transparent); }
|
|
113
|
-
.badge--sev-medium { background: var(--info-weak); color: var(--info); border-color: color-mix(in srgb, var(--info) 30%, transparent); }
|
|
114
|
-
.badge--sev-low { background: var(--surface-2); color: var(--ink-soft); }
|
|
115
|
-
.badge--status { background: var(--surface-2); color: var(--ink-soft); }
|
|
116
|
-
|
|
117
|
-
/* Row action buttons + selects. */
|
|
118
|
-
.watch-actions { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
|
|
119
|
-
.watch-btn {
|
|
120
|
-
font-family: var(--font-body);
|
|
121
|
-
font-size: 12.5px;
|
|
122
|
-
font-weight: 500;
|
|
123
|
-
padding: 5px 12px;
|
|
124
|
-
border: 1px solid var(--border-strong);
|
|
125
|
-
background: var(--surface);
|
|
126
|
-
color: var(--ink-soft);
|
|
127
|
-
border-radius: var(--radius-sm);
|
|
128
|
-
cursor: pointer;
|
|
129
|
-
}
|
|
130
|
-
.watch-btn:hover:not(:disabled) { background: var(--surface-2); color: var(--ink); }
|
|
131
|
-
.watch-btn:disabled { opacity: 0.45; cursor: default; }
|
|
132
|
-
.watch-btn--danger { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 40%, var(--border-strong)); }
|
|
133
|
-
.watch-select {
|
|
134
|
-
font-family: var(--font-body);
|
|
135
|
-
font-size: 13px;
|
|
136
|
-
padding: 4px 6px;
|
|
137
|
-
border: 1px solid var(--border-strong);
|
|
138
|
-
background: var(--surface);
|
|
139
|
-
color: var(--ink);
|
|
140
|
-
border-radius: var(--radius-sm);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
.watch-req {
|
|
144
|
-
border-bottom: 1px solid var(--border);
|
|
145
|
-
padding: 12px 0;
|
|
146
|
-
display: flex; gap: 14px; flex-wrap: wrap;
|
|
147
|
-
align-items: flex-start; justify-content: space-between;
|
|
148
|
-
}
|
|
149
|
-
.watch-req__who { font-weight: 600; color: var(--ink); }
|
|
150
|
-
.watch-req__meta { color: var(--ink-faint); font-size: 12.5px; margin-top: 2px; }
|
|
151
|
-
.watch-req__note { color: var(--ink); font-size: 13.5px; margin-top: 6px; max-width: 56ch; }
|
|
152
|
-
|
|
153
|
-
.watch-unavailable { color: var(--ink-faint); font-size: 13px; padding: 8px 0; }
|
|
154
|
-
|
|
155
|
-
.watch-trend { display: flex; flex-direction: column; gap: 4px; margin-top: 8px; }
|
|
156
|
-
.watch-trend__row {
|
|
157
|
-
display: grid; grid-template-columns: 84px 1fr 64px;
|
|
158
|
-
gap: 10px; align-items: center;
|
|
159
|
-
font-size: 13px; color: var(--ink);
|
|
160
|
-
}
|
|
161
|
-
.watch-trend__bar-track {
|
|
162
|
-
background: var(--surface-2); border-radius: 3px; height: 12px; overflow: hidden;
|
|
163
|
-
border: 1px solid var(--border);
|
|
164
|
-
}
|
|
165
|
-
.watch-trend__bar-fill { background: var(--accent); height: 100%; display: block; }
|
|
166
|
-
.watch-trend__val { text-align: right; font-variant-numeric: tabular-nums; color: var(--ink-soft); }
|
|
167
|
-
|
|
168
|
-
.watch-list { list-style: none; padding: 0; margin: 8px 0 0; }
|
|
169
|
-
.watch-list li {
|
|
170
|
-
display: flex; justify-content: space-between; gap: 12px;
|
|
171
|
-
padding: 5px 0; border-bottom: 1px solid var(--border);
|
|
172
|
-
font-size: 13.5px;
|
|
173
|
-
}
|
|
174
|
-
.watch-list li .k { color: var(--ink); }
|
|
175
|
-
.watch-list li .v { color: var(--ink-soft); font-variant-numeric: tabular-nums; }
|
|
176
|
-
|
|
177
|
-
.watch-foot-link {
|
|
178
|
-
display: inline-block; margin-top: 12px;
|
|
179
|
-
font-size: 13px; font-weight: 500;
|
|
180
|
-
color: var(--accent-text);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/* The in-page section rail: horizontal chip strip, sticky under the top bar
|
|
184
|
-
at every width (overrides .section-rail's desktop column layout). */
|
|
185
|
-
#watch-nav {
|
|
186
|
-
position: sticky;
|
|
187
|
-
top: var(--topbar-h);
|
|
188
|
-
z-index: 5;
|
|
189
|
-
flex-direction: row;
|
|
190
|
-
overflow-x: auto;
|
|
191
|
-
gap: 6px;
|
|
192
|
-
padding: 8px 0;
|
|
193
|
-
margin: 0 0 12px;
|
|
194
|
-
background: color-mix(in srgb, var(--bg) 92%, transparent);
|
|
195
|
-
backdrop-filter: blur(6px);
|
|
196
|
-
}
|
|
197
|
-
#watch-nav .rail-link {
|
|
198
|
-
white-space: nowrap;
|
|
199
|
-
border: 1px solid var(--border);
|
|
200
|
-
background: var(--surface);
|
|
201
|
-
border-radius: 999px;
|
|
202
|
-
padding: 4px 12px;
|
|
203
|
-
font-size: 12.5px;
|
|
204
|
-
}
|
|
205
|
-
</style>
|
|
13
|
+
<!-- Page-local styles (task 2173) — extracted from the old inline <style>
|
|
14
|
+
block per the hall placement rules; the attention tiles + tabs come from
|
|
15
|
+
style.css's shared .stat-row/.stat-tile + hall-kit rules. -->
|
|
16
|
+
<link rel="stylesheet" href="/builders/watch.css">
|
|
206
17
|
</head>
|
|
207
18
|
<body data-page="watch" data-page-title="Watch">
|
|
208
19
|
|
|
@@ -214,18 +25,6 @@
|
|
|
214
25
|
<div class="app-content">
|
|
215
26
|
<div class="page-head"><p class="page-head__sub" id="watch-sub">Loading…</p></div>
|
|
216
27
|
|
|
217
|
-
<nav class="section-rail" id="watch-nav" hidden aria-label="Watch sections">
|
|
218
|
-
<a class="rail-link" href="#gate-scroll">Access requests</a>
|
|
219
|
-
<a class="rail-link" href="#watch-scroll">Security</a>
|
|
220
|
-
<a class="rail-link" href="#roster-scroll">Roster</a>
|
|
221
|
-
<a class="rail-link" href="#box-costs-scroll">Box costs</a>
|
|
222
|
-
<a class="rail-link" href="#marks-scroll">Builder reviews</a>
|
|
223
|
-
<a class="rail-link" href="#mason-marks-scroll">Reviews</a>
|
|
224
|
-
<a class="rail-link" href="#surveyor-scroll">Estimates</a>
|
|
225
|
-
<a class="rail-link" href="#ledger-scroll">Repo health</a>
|
|
226
|
-
<a class="rail-link" href="#sessions-scroll">Sessions</a>
|
|
227
|
-
</nav>
|
|
228
|
-
|
|
229
28
|
<main>
|
|
230
29
|
<!-- Restricted notice — shown by watch.js when the viewer is not an Archon. -->
|
|
231
30
|
<section class="scroll" id="sealed-scroll" aria-labelledby="sealed-h" hidden>
|
|
@@ -233,85 +32,110 @@
|
|
|
233
32
|
<p class="scroll__lede" id="sealed-body">This page is available to Archons only.</p>
|
|
234
33
|
</section>
|
|
235
34
|
|
|
236
|
-
<!--
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
<
|
|
240
|
-
<
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
<
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
<
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
<
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
<
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
35
|
+
<!-- task 2173: "what needs me today" first — the attention row's tiles
|
|
36
|
+
carry live counts and each links to the tab that holds the detail. -->
|
|
37
|
+
<div class="stat-row watch-attention" id="watch-attention" hidden>
|
|
38
|
+
<a class="stat-tile" href="#people"><span class="stat-tile__label">Access requests</span><span class="stat-tile__num" id="att-access">—</span><span class="stat-tile__sub">pending — People tab</span></a>
|
|
39
|
+
<a class="stat-tile" href="#security"><span class="stat-tile__label">Security reports</span><span class="stat-tile__num" id="att-security">—</span><span class="stat-tile__sub">open — Security tab</span></a>
|
|
40
|
+
<a class="stat-tile" href="#people"><span class="stat-tile__label">Stale claims</span><span class="stat-tile__num" id="att-stale">—</span><span class="stat-tile__sub">builders — People tab</span></a>
|
|
41
|
+
<a class="stat-tile" href="#operations"><span class="stat-tile__label">Sessions</span><span class="stat-tile__num" id="att-sessions">—</span><span class="stat-tile__sub">recorded — Operations tab</span></a>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<!-- task 2173: the nine surfaces sit behind three OTBKit tabs, hash-synced
|
|
45
|
+
(/watch#security). Evidence behind tabs; the attention row stays above. -->
|
|
46
|
+
<nav id="watch-tabs" hidden aria-label="Watch sections"></nav>
|
|
47
|
+
|
|
48
|
+
<!-- ============ tab: People ============ -->
|
|
49
|
+
<div id="pane-people" role="tabpanel" aria-labelledby="tab-people">
|
|
50
|
+
|
|
51
|
+
<!-- 1. ACCESS REQUESTS -->
|
|
52
|
+
<section class="scroll" id="gate-scroll" aria-labelledby="gate-h" hidden>
|
|
53
|
+
<h2 id="gate-h" class="scroll__h">Access requests</h2>
|
|
54
|
+
<p class="scroll__lede">People asking to join. Approve or dismiss each request.</p>
|
|
55
|
+
<div id="gate-body"><span class="kit-skel"></span></div>
|
|
56
|
+
</section>
|
|
57
|
+
|
|
58
|
+
<!-- 2. ROSTER -->
|
|
59
|
+
<section class="scroll" id="roster-scroll" aria-labelledby="roster-h" hidden>
|
|
60
|
+
<h2 id="roster-h" class="scroll__h">Roster</h2>
|
|
61
|
+
<p class="scroll__lede">Every builder in {{worldName}} — rank, {{currency}}, karma, and active claims.</p>
|
|
62
|
+
<div id="roster-body"><span class="kit-skel"></span></div>
|
|
63
|
+
</section>
|
|
64
|
+
|
|
65
|
+
<!-- 3. REVIEWS BY BUILDER -->
|
|
66
|
+
<section class="scroll" id="marks-scroll" aria-labelledby="marks-h" hidden>
|
|
67
|
+
<h2 id="marks-h" class="scroll__h">Reviews by builder</h2>
|
|
68
|
+
<p class="scroll__lede">How each builder's shipped work has been graded over the past thirty days.</p>
|
|
69
|
+
<div id="marks-body"><span class="kit-skel"></span></div>
|
|
70
|
+
</section>
|
|
71
|
+
|
|
72
|
+
<!-- 4. REVIEW QUALITY -->
|
|
73
|
+
<section class="scroll" id="mason-marks-scroll" aria-labelledby="mason-marks-h" hidden>
|
|
74
|
+
<h2 id="mason-marks-h" class="scroll__h">Review quality</h2>
|
|
75
|
+
<p class="scroll__lede">Grades across all recent shipped work — a rolling aggregate.</p>
|
|
76
|
+
<div id="mason-marks-stats" class="watch-stats"></div>
|
|
77
|
+
<div id="mason-marks-trend"></div>
|
|
78
|
+
</section>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
<!-- ============ tab: Operations ============ -->
|
|
82
|
+
<div id="pane-operations" role="tabpanel" aria-labelledby="tab-operations" hidden>
|
|
83
|
+
|
|
84
|
+
<!-- 5. BOX COSTS (#602) — per-builder dev-box cost ledger + totals. -->
|
|
85
|
+
<section class="scroll" id="box-costs-scroll" aria-labelledby="box-costs-h" hidden>
|
|
86
|
+
<h2 id="box-costs-h" class="scroll__h">Dev-box costs</h2>
|
|
87
|
+
<p class="scroll__lede">What each builder's dev box has cost — spin-up, compute, and storage. Tracked for oversight; not charged in the early stage.</p>
|
|
88
|
+
<div id="box-costs-body"><span class="kit-skel"></span></div>
|
|
89
|
+
</section>
|
|
90
|
+
|
|
91
|
+
<!-- 6. SESSIONS -->
|
|
92
|
+
<section class="scroll" id="sessions-scroll" aria-labelledby="sessions-h" hidden>
|
|
93
|
+
<h2 id="sessions-h" class="scroll__h">Sessions</h2>
|
|
94
|
+
<p class="scroll__lede">A tally of recorded work sessions. The full record lives on the Sessions page.</p>
|
|
95
|
+
<div id="sessions-stats" class="watch-stats"></div>
|
|
96
|
+
<a class="watch-foot-link" href="/sessions">View all sessions →</a>
|
|
97
|
+
</section>
|
|
98
|
+
|
|
99
|
+
<!-- 7. REPO HEALTH -->
|
|
100
|
+
<section class="scroll" id="ledger-scroll" aria-labelledby="ledger-h" hidden>
|
|
101
|
+
<h2 id="ledger-h" class="scroll__h">Repo health</h2>
|
|
102
|
+
<p class="scroll__lede">The shape and health of the codebase.</p>
|
|
103
|
+
<div id="ledger-stats" class="watch-stats"></div>
|
|
104
|
+
<div id="ledger-loc"></div>
|
|
105
|
+
<div id="ledger-files"></div>
|
|
106
|
+
</section>
|
|
107
|
+
</div>
|
|
108
|
+
|
|
109
|
+
<!-- ============ tab: Security ============ -->
|
|
110
|
+
<div id="pane-security" role="tabpanel" aria-labelledby="tab-security" hidden>
|
|
111
|
+
|
|
112
|
+
<!-- 8. SECURITY -->
|
|
113
|
+
<section class="scroll" id="watch-scroll" aria-labelledby="watch-h" hidden>
|
|
114
|
+
<h2 id="watch-h" class="scroll__h">Security</h2>
|
|
115
|
+
<p class="scroll__lede">Vulnerability reports, engagement reports, override requests, and the audit log.</p>
|
|
116
|
+
|
|
117
|
+
<h3 class="watch-sub-h">Vulnerability reports</h3>
|
|
118
|
+
<div id="reports-body"><span class="kit-skel"></span></div>
|
|
119
|
+
|
|
120
|
+
<h3 class="watch-sub-h">Engagement reports</h3>
|
|
121
|
+
<p class="watch-note">Dated exploit-detail engagement reports — kept out of the repo (threat-model §6.3) and served only to Archons. Upload via POST /api/bongos/security/docs.</p>
|
|
122
|
+
<div id="engagement-docs-body"><span class="kit-skel"></span></div>
|
|
123
|
+
|
|
124
|
+
<h3 class="watch-sub-h">Override requests</h3>
|
|
125
|
+
<div id="overrides-body"><span class="kit-skel"></span></div>
|
|
126
|
+
|
|
127
|
+
<h3 class="watch-sub-h">Audit log</h3>
|
|
128
|
+
<div id="audit-body"><span class="kit-skel"></span></div>
|
|
129
|
+
</section>
|
|
130
|
+
|
|
131
|
+
<!-- 9. ESTIMATION ACCURACY -->
|
|
132
|
+
<section class="scroll" id="surveyor-scroll" aria-labelledby="surveyor-h" hidden>
|
|
133
|
+
<h2 id="surveyor-h" class="scroll__h">Estimation accuracy</h2>
|
|
134
|
+
<p class="scroll__lede">How task estimates compare with the time work actually took.</p>
|
|
135
|
+
<div id="surveyor-stats" class="watch-stats"></div>
|
|
136
|
+
<div id="surveyor-body"></div>
|
|
137
|
+
</section>
|
|
138
|
+
</div>
|
|
315
139
|
</main>
|
|
316
140
|
|
|
317
141
|
<footer class="app-foot" id="app-foot"></footer>
|
|
@@ -326,8 +150,10 @@
|
|
|
326
150
|
<script src="/builders/shell.js?v=2026-07-02-shell1"></script>
|
|
327
151
|
<!-- shared frontend toolkit (window.OTB) — loaded before watch.js, which pulls from it. -->
|
|
328
152
|
<script src="/builders/dom-utils.js?v=2026-06-14-domutils"></script>
|
|
153
|
+
<!-- shared component kit (window.OTBKit) — tabs, ledger, pager (task 2166). -->
|
|
154
|
+
<script src="/builders/hall-kit.js"></script>
|
|
329
155
|
<script src="/builders/task-detail.js?v=2026-07-03-taskdetail"></script>
|
|
330
156
|
<script src="/builders/brand-apply.js?v=2026-06-19-r56"></script>
|
|
331
|
-
<script src="/builders/watch.js?v=2026-
|
|
157
|
+
<script src="/builders/watch.js?v=2026-07-10-tabs"></script>
|
|
332
158
|
</body>
|
|
333
159
|
</html>
|
|
@@ -29,6 +29,9 @@
|
|
|
29
29
|
// wrappers keep this file's exact variants (date+time fmtDate; '' rankLabel
|
|
30
30
|
// empty; the 3200ms non-clearing toast). fmtDay / fmtDuration / fmtPct stay local.
|
|
31
31
|
const { escapeHtml, $, num, fmtInt, fmtCompact } = window.OTB;
|
|
32
|
+
// Shared component kit (hall-kit.js, task 2166): tabs, ledger, pager, empty
|
|
33
|
+
// states — adopted here by task 2173.
|
|
34
|
+
const { makeTabs, makeLedger, makePager, emptyStateHtml } = window.OTBKit;
|
|
32
35
|
const fmtDate = (iso) => window.OTB.fmtDate(iso, { time: true });
|
|
33
36
|
const rankLabel = (rank) => window.OTB.rankLabel(rank, { empty: '' });
|
|
34
37
|
const toast = (msg) => window.OTB.toast(msg);
|
|
@@ -90,6 +93,13 @@
|
|
|
90
93
|
target.innerHTML = `<p class="watch-unavailable">${escapeHtml(message)}</p>`;
|
|
91
94
|
}
|
|
92
95
|
|
|
96
|
+
// task 2173 — the attention row: each tile carries a live count fed by the
|
|
97
|
+
// section loader that owns the data, and links to the tab holding the detail.
|
|
98
|
+
function setAttention(id, n) {
|
|
99
|
+
const el = document.getElementById(id);
|
|
100
|
+
if (el) el.textContent = n == null ? '—' : fmtInt(n);
|
|
101
|
+
}
|
|
102
|
+
|
|
93
103
|
// ---- shared render skeletons (C10) ----------------------------------------
|
|
94
104
|
|
|
95
105
|
// section — the load→fetch→render→degrade skeleton every panel repeats. fetcher()
|
|
@@ -170,8 +180,9 @@
|
|
|
170
180
|
|
|
171
181
|
function renderGate(data, target) {
|
|
172
182
|
const requests = Array.isArray(data.requests) ? data.requests : [];
|
|
183
|
+
setAttention('att-access', requests.length); // tile count = table content
|
|
173
184
|
if (!requests.length) {
|
|
174
|
-
target.innerHTML = '
|
|
185
|
+
target.innerHTML = emptyStateHtml('No pending access requests.');
|
|
175
186
|
return;
|
|
176
187
|
}
|
|
177
188
|
target.innerHTML = requests
|
|
@@ -220,11 +231,15 @@
|
|
|
220
231
|
// =========================================================================
|
|
221
232
|
|
|
222
233
|
// 2a. Red-team / vulnerability reports.
|
|
234
|
+
// A report still needing Archon attention: not yet resolved (fixed/disputed).
|
|
235
|
+
const OPEN_REPORT = (r) => !['fixed', 'disputed', 'dismissed'].includes(String(r.status || '').toLowerCase());
|
|
236
|
+
|
|
223
237
|
function renderReports(data, target) {
|
|
224
238
|
const reports = Array.isArray(data.reports) ? data.reports : [];
|
|
225
239
|
const statuses = Array.isArray(data.statuses) ? data.statuses : [];
|
|
240
|
+
setAttention('att-security', reports.filter(OPEN_REPORT).length);
|
|
226
241
|
if (!reports.length) {
|
|
227
|
-
target.innerHTML = '
|
|
242
|
+
target.innerHTML = emptyStateHtml('No vulnerability reports filed.');
|
|
228
243
|
return;
|
|
229
244
|
}
|
|
230
245
|
const rows = reports
|
|
@@ -282,7 +297,7 @@
|
|
|
282
297
|
function renderEngagementDocs(data, target) {
|
|
283
298
|
const docs = Array.isArray(data.docs) ? data.docs : [];
|
|
284
299
|
if (!docs.length) {
|
|
285
|
-
target.innerHTML = '
|
|
300
|
+
target.innerHTML = emptyStateHtml('No engagement reports filed. Upload one via POST /api/bongos/security/docs.');
|
|
286
301
|
return;
|
|
287
302
|
}
|
|
288
303
|
const rows = docs
|
|
@@ -338,7 +353,7 @@
|
|
|
338
353
|
function renderOverrides(data, target) {
|
|
339
354
|
const requests = Array.isArray(data.requests) ? data.requests : [];
|
|
340
355
|
if (!requests.length) {
|
|
341
|
-
target.innerHTML = '
|
|
356
|
+
target.innerHTML = emptyStateHtml('No overrides sought.');
|
|
342
357
|
return;
|
|
343
358
|
}
|
|
344
359
|
const rows = requests
|
|
@@ -380,15 +395,19 @@
|
|
|
380
395
|
});
|
|
381
396
|
}
|
|
382
397
|
|
|
383
|
-
// 2c. Audit log (recent 50)
|
|
398
|
+
// 2c. Audit log (recent 50) — a read-only long table, so it adopts the kit
|
|
399
|
+
// ledger + pager (task 2173). Rebuilt per load; the pager pref persists.
|
|
384
400
|
function renderAudit(data, target) {
|
|
385
401
|
const rows = Array.isArray(data.rows) ? data.rows : [];
|
|
386
402
|
if (!rows.length) {
|
|
387
|
-
target.innerHTML = '
|
|
403
|
+
target.innerHTML = emptyStateHtml('No audit entries yet.');
|
|
388
404
|
return;
|
|
389
405
|
}
|
|
390
|
-
const
|
|
391
|
-
|
|
406
|
+
const pager = makePager('watch-audit', 'otb.watch.auditPerPage');
|
|
407
|
+
const ledger = makeLedger({
|
|
408
|
+
mount: target,
|
|
409
|
+
columns: ['When', 'Builder', 'Method', 'Route', { label: 'Status', class: 'num' }],
|
|
410
|
+
rowHtml: (r) => {
|
|
392
411
|
const status = num(r.response_status);
|
|
393
412
|
const warn = status >= 400 ? ' warn' : '';
|
|
394
413
|
return (
|
|
@@ -402,11 +421,11 @@
|
|
|
402
421
|
`<td class="num${warn}">${escapeHtml(r.response_status ?? '—')}</td>` +
|
|
403
422
|
'</tr>'
|
|
404
423
|
);
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
424
|
+
},
|
|
425
|
+
pager,
|
|
426
|
+
});
|
|
427
|
+
ledger.render(rows);
|
|
428
|
+
target.insertAdjacentHTML('beforeend', '<p class="watch-note">Newest first. The fifty most recent write operations.</p>');
|
|
410
429
|
}
|
|
411
430
|
|
|
412
431
|
function loadAudit() {
|
|
@@ -428,8 +447,9 @@
|
|
|
428
447
|
|
|
429
448
|
function renderRoster(data, target) {
|
|
430
449
|
const builders = Array.isArray(data.builders) ? data.builders : [];
|
|
450
|
+
setAttention('att-stale', builders.filter((b) => b.stale_claim).length);
|
|
431
451
|
if (!builders.length) {
|
|
432
|
-
target.innerHTML = '
|
|
452
|
+
target.innerHTML = emptyStateHtml('No builders on the roster.');
|
|
433
453
|
return;
|
|
434
454
|
}
|
|
435
455
|
const rows = builders
|
|
@@ -533,7 +553,7 @@
|
|
|
533
553
|
const ledger = Array.isArray(data.ledger) ? data.ledger : [];
|
|
534
554
|
const usd = (n) => `$${(Number(n) || 0).toFixed(2)}`;
|
|
535
555
|
if (!totals.length) {
|
|
536
|
-
target.innerHTML = '
|
|
556
|
+
target.innerHTML = emptyStateHtml('No dev-box costs accrued yet.');
|
|
537
557
|
return;
|
|
538
558
|
}
|
|
539
559
|
const totalRows = totals
|
|
@@ -576,7 +596,7 @@
|
|
|
576
596
|
const data = await fetchJson('/grades/by-builder?days=30');
|
|
577
597
|
const builders = Array.isArray(data.builders) ? data.builders : [];
|
|
578
598
|
if (!builders.length) {
|
|
579
|
-
target.innerHTML = '
|
|
599
|
+
target.innerHTML = emptyStateHtml('No reviews recorded in this window.');
|
|
580
600
|
return;
|
|
581
601
|
}
|
|
582
602
|
const sorted = builders.slice().sort((a, b) => num(b.n) - num(a.n));
|
|
@@ -606,7 +626,7 @@
|
|
|
606
626
|
if (err && err.kind === '403') { renderUnavailable(target, 'Archons only. Review data is not visible at your rank.'); return; }
|
|
607
627
|
// 404 / not-yet-built / any other failure → graceful empty state.
|
|
608
628
|
console.error('[watch] marks-by-builder failed', err);
|
|
609
|
-
target.innerHTML = '
|
|
629
|
+
target.innerHTML = emptyStateHtml('No reviews recorded in this window.');
|
|
610
630
|
}
|
|
611
631
|
}
|
|
612
632
|
|
|
@@ -628,7 +648,7 @@
|
|
|
628
648
|
|
|
629
649
|
const trend = Array.isArray(data.trend) ? data.trend.slice(-14) : [];
|
|
630
650
|
if (!trend.length) {
|
|
631
|
-
trendEl.innerHTML = '
|
|
651
|
+
trendEl.innerHTML = emptyStateHtml('No trend to show yet.');
|
|
632
652
|
return;
|
|
633
653
|
}
|
|
634
654
|
const maxN = Math.max(1, ...trend.map((t) => num(t.n)));
|
|
@@ -671,7 +691,7 @@
|
|
|
671
691
|
]);
|
|
672
692
|
const byVersion = Array.isArray(data.by_version) ? data.by_version : [];
|
|
673
693
|
if (!byVersion.length) {
|
|
674
|
-
body.innerHTML = '
|
|
694
|
+
body.innerHTML = emptyStateHtml('No drift recorded by version yet.');
|
|
675
695
|
return;
|
|
676
696
|
}
|
|
677
697
|
const rows = byVersion
|
|
@@ -778,6 +798,7 @@
|
|
|
778
798
|
|
|
779
799
|
function renderSessions(data, stats) {
|
|
780
800
|
const t = data.totals || {};
|
|
801
|
+
setAttention('att-sessions', t.total);
|
|
781
802
|
stats.innerHTML = statCards([
|
|
782
803
|
{ num: fmtInt(t.total), label: 'Sessions' },
|
|
783
804
|
{ num: fmtInt(t.builders), label: 'Builders' },
|
|
@@ -805,15 +826,32 @@
|
|
|
805
826
|
gate.hidden = false;
|
|
806
827
|
}
|
|
807
828
|
|
|
829
|
+
// task 2173 — the nine surfaces sit behind three hash-synced kit tabs
|
|
830
|
+
// (/watch#security deep-links; the "#/…" record-overlay namespace is left
|
|
831
|
+
// alone by makeTabs). Built only for a verified Archon in revealSections.
|
|
832
|
+
let watchTabs = null;
|
|
833
|
+
|
|
808
834
|
function revealSections() {
|
|
809
835
|
[
|
|
810
|
-
'watch-
|
|
811
|
-
'mason-marks-scroll', 'surveyor-scroll', 'ledger-scroll', 'sessions-scroll',
|
|
836
|
+
'watch-attention', 'watch-tabs', 'gate-scroll', 'watch-scroll', 'roster-scroll', 'box-costs-scroll',
|
|
837
|
+
'marks-scroll', 'mason-marks-scroll', 'surveyor-scroll', 'ledger-scroll', 'sessions-scroll',
|
|
812
838
|
].forEach((id) => {
|
|
813
839
|
const el = document.getElementById(id);
|
|
814
840
|
if (el) el.hidden = false;
|
|
815
841
|
});
|
|
816
842
|
$('#sealed-scroll').hidden = true;
|
|
843
|
+
if (!watchTabs) {
|
|
844
|
+
watchTabs = makeTabs({
|
|
845
|
+
mount: $('#watch-tabs'),
|
|
846
|
+
hash: true,
|
|
847
|
+
initial: 'people',
|
|
848
|
+
tabs: [
|
|
849
|
+
{ id: 'people', label: 'People', panel: 'pane-people' },
|
|
850
|
+
{ id: 'operations', label: 'Operations', panel: 'pane-operations' },
|
|
851
|
+
{ id: 'security', label: 'Security', panel: 'pane-security' },
|
|
852
|
+
],
|
|
853
|
+
});
|
|
854
|
+
}
|
|
817
855
|
}
|
|
818
856
|
|
|
819
857
|
async function load() {
|