@bongos/core 1.19.92 → 1.19.94
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 +38 -88
- package/docs/design/mocks/projects-hub-mock.html +991 -0
- package/docs/design/mocks/projects-hub-variants.html +146 -0
- package/docs/design/projects-hub-direction.md +347 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/public-landing/assets/cosmos.css +240 -0
- package/public-landing/index.html +10 -4
- package/public-landing/projects.html +663 -44
- package/scripts/gds/run-unit-tests.js +0 -1
- package/src/bongos/module-scope-map.js +1 -1
- package/src/module-api.js +5 -1
- package/src/platform-server.js +24 -42
- package/tests/known_failing_ratchet.mjs +7 -8
- package/tests/landing_page.mjs +15 -2
- package/tests/projects_hub.mjs +205 -0
- package/public-landing/gate/README.md +0 -137
- package/public-landing/gate/dispmaps/bar.png +0 -0
- package/public-landing/gate/dispmaps/flat.png +0 -0
- package/public-landing/gate/dispmaps/key.png +0 -0
- package/public-landing/gate/index.html +0 -634
- package/public-landing/gate/previews/cloud-bongos.jpg +0 -0
- package/public-landing/gate/previews/off-the-boats.jpg +0 -0
- package/public-landing/gate/space.css +0 -809
- package/public-landing/gate/space.js +0 -1848
- package/public-landing/gate/sprites/enter.png +0 -0
- package/public-landing/gate/sprites/search.png +0 -0
- package/public-landing/gate/sprites/terminal-blank.png +0 -0
- package/public-landing/gate/sprites/tile.png +0 -0
- package/tests/gate_launch_metadata.mjs +0 -67
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>The hub's ground — three candidates (task 1002758)</title>
|
|
7
|
+
<link rel="stylesheet" href="../../../public-landing/assets/cosmos.css">
|
|
8
|
+
<link href="https://fonts.googleapis.com/css2?family=Baloo+2:wght@500;600;700&family=Quicksand:wght@400;500;600;700&family=Fira+Code:wght@400;500&display=swap" rel="stylesheet">
|
|
9
|
+
<style>
|
|
10
|
+
/* Contact sheet — the same pattern landing-palettes.html used for the palette
|
|
11
|
+
choice. Each tile is the REAL mock at ?rail=0, scaled, so nothing is drawn
|
|
12
|
+
twice and the comparison cannot drift from the thing being approved. */
|
|
13
|
+
body{background:var(--page-bg);padding:clamp(18px,3vw,36px);}
|
|
14
|
+
.head{max-width:1180px;margin:0 auto 26px;}
|
|
15
|
+
.head h1{font-family:var(--font-display);font-size:var(--fs-h2);letter-spacing:-.5px;margin-bottom:8px;}
|
|
16
|
+
.head p{font-size:var(--fs-lede);color:var(--ink-soft);font-weight:500;line-height:1.6;max-width:74ch;}
|
|
17
|
+
.head p + p{margin-top:10px;}
|
|
18
|
+
.head b{color:var(--ink);}
|
|
19
|
+
.sheet{max-width:1180px;margin:0 auto;display:grid;gap:var(--pad-md);grid-template-columns:repeat(2,1fr);}
|
|
20
|
+
@media (max-width:920px){.sheet{grid-template-columns:1fr;}}
|
|
21
|
+
.tile{background:var(--bg-card);border:2px solid var(--line);border-radius:20px;overflow:hidden;
|
|
22
|
+
box-shadow:var(--shadow-card);}
|
|
23
|
+
.tile h2{font-family:var(--font-display);font-size:16px;padding:14px 18px 4px;display:flex;
|
|
24
|
+
align-items:center;gap:10px;flex-wrap:wrap;}
|
|
25
|
+
.tile h2 .tag{font-family:var(--font-mono);font-size:11px;font-weight:500;padding:2px 9px;
|
|
26
|
+
border-radius:999px;background:var(--accent-soft);color:var(--accent-deep);}
|
|
27
|
+
.tile h2 .rec{background:var(--ok-soft);color:var(--ok);}
|
|
28
|
+
.tile p{font-size:13.5px;color:var(--ink-soft);font-weight:500;line-height:1.55;padding:0 18px 12px;}
|
|
29
|
+
.tile p .risk{color:var(--err);font-weight:700;}
|
|
30
|
+
.frame{position:relative;height:430px;border-top:2px solid var(--line);background:var(--bg-deep);overflow:hidden;}
|
|
31
|
+
.frame iframe{position:absolute;top:0;left:0;width:1440px;height:900px;border:0;
|
|
32
|
+
transform:scale(.4097);transform-origin:0 0;}
|
|
33
|
+
.pair{display:grid;grid-template-columns:1fr 1fr;}
|
|
34
|
+
.pair .frame{height:300px;}
|
|
35
|
+
.pair .frame iframe{transform:scale(.2861);}
|
|
36
|
+
.pair .lbl{position:absolute;left:9px;top:9px;z-index:2;font-family:var(--font-mono);font-size:10.5px;
|
|
37
|
+
background:rgba(0,0,0,.62);color:#fff;padding:2px 8px;border-radius:999px;}
|
|
38
|
+
.pair .frame + .frame{border-left:2px solid var(--line);}
|
|
39
|
+
.foot{max-width:1180px;margin:26px auto 0;font-size:13.5px;color:var(--ink-soft);font-weight:500;line-height:1.6;}
|
|
40
|
+
.foot a{color:var(--accent-deep);font-weight:700;}
|
|
41
|
+
</style>
|
|
42
|
+
</head>
|
|
43
|
+
<body>
|
|
44
|
+
|
|
45
|
+
<div class="head">
|
|
46
|
+
<h1>The hub’s ground — three candidates</h1>
|
|
47
|
+
<p>Task 1002758 · goal 1000061. <b>Structure is already settled</b> — <code>/projects</code> is the one hub
|
|
48
|
+
holding the map, your projects, and create. What is open is the <b>ground</b>: today the sky is a dark
|
|
49
|
+
full-bleed canvas while <code>/projects</code> and <code>/create</code> are light marigold document pages, and
|
|
50
|
+
one hub has to reconcile them.</p>
|
|
51
|
+
<p>Each tile below is the <b>real mock</b> (<code>projects-hub-mock.html</code>) running at that ground, in
|
|
52
|
+
light and dark. Open any of them full size to walk it. The status quo is included as a labelled option —
|
|
53
|
+
<b>C</b> is what the gate ships today.</p>
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
<div class="sheet">
|
|
57
|
+
|
|
58
|
+
<div class="tile">
|
|
59
|
+
<h2>B · dual-mode full-bleed <span class="tag rec">recommended</span> <span class="tag">default</span></h2>
|
|
60
|
+
<p>The sky is the page, and it follows light/dark like everything else: marigold daylight in light, warm-umber
|
|
61
|
+
space in dark. <b>cosmos.css already encodes this</b> — <code>--sky-bg</code> is <code>#f9d9a8</code>/<code>#150c06</code>
|
|
62
|
+
and <code>--star-display</code> flips <code>none</code>/<code>block</code> (:61-62, :99-100), so no new decision
|
|
63
|
+
is needed and the mode toggle keeps meaning something in every view.
|
|
64
|
+
<span class="risk">Its risk:</span> light mode loses the starfield drama entirely — the map becomes a calm
|
|
65
|
+
diagram rather than a place.</p>
|
|
66
|
+
<div class="pair">
|
|
67
|
+
<div class="frame"><span class="lbl">light</span>
|
|
68
|
+
<iframe src="projects-hub-mock.html?view=map&rail=0#b-light" data-g="b" data-m="light" loading="lazy"></iframe></div>
|
|
69
|
+
<div class="frame"><span class="lbl">dark</span>
|
|
70
|
+
<iframe src="projects-hub-mock.html?view=map&rail=0#b-dark" data-g="b" data-m="dark" loading="lazy"></iframe></div>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<div class="tile">
|
|
75
|
+
<h2>A · framed window <span class="tag">document-first</span></h2>
|
|
76
|
+
<p>The hub is a marigold document page in both modes and the sky lives inside a bounded, rounded panel —
|
|
77
|
+
a component rather than the environment. The chrome never changes character between views, and the map
|
|
78
|
+
stops competing with the page it sits on.
|
|
79
|
+
<span class="risk">Its risk:</span> a 540px window onto a gravity field reads as a widget; the sky’s whole
|
|
80
|
+
appeal is that it feels like somewhere you are, and a panel makes it somewhere you are looking at.</p>
|
|
81
|
+
<div class="pair">
|
|
82
|
+
<div class="frame"><span class="lbl">light</span>
|
|
83
|
+
<iframe src="projects-hub-mock.html?view=map&rail=0#a-light" data-g="a" data-m="light" loading="lazy"></iframe></div>
|
|
84
|
+
<div class="frame"><span class="lbl">dark</span>
|
|
85
|
+
<iframe src="projects-hub-mock.html?view=map&rail=0#a-dark" data-g="a" data-m="dark" loading="lazy"></iframe></div>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<div class="tile">
|
|
90
|
+
<h2>C · locked deep space <span class="tag">the status quo</span></h2>
|
|
91
|
+
<p>What the gate ships today: the blue-violet starfield, full-bleed, in <b>both</b> modes — the locked
|
|
92
|
+
<code>--space-deep/mid/high</code> palette (cosmos.css:47-49) that no branding pack can re-theme. Keeps the
|
|
93
|
+
sky exactly as designed.
|
|
94
|
+
<span class="risk">Its risk:</span> the light/dark toggle silently does nothing on the hub’s main view, and
|
|
95
|
+
the hub reads as a different product from the marigold landing page a visitor just came through.</p>
|
|
96
|
+
<div class="pair">
|
|
97
|
+
<div class="frame"><span class="lbl">light</span>
|
|
98
|
+
<iframe src="projects-hub-mock.html?view=map&rail=0#c-light" data-g="c" data-m="light" loading="lazy"></iframe></div>
|
|
99
|
+
<div class="frame"><span class="lbl">dark</span>
|
|
100
|
+
<iframe src="projects-hub-mock.html?view=map&rail=0#c-dark" data-g="c" data-m="dark" loading="lazy"></iframe></div>
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
<div class="tile">
|
|
105
|
+
<h2>The other two views <span class="tag">ground-independent</span></h2>
|
|
106
|
+
<p>Your projects and New project are document views in every candidate — they carry controls a canvas cannot.
|
|
107
|
+
Shown here in light and dark so the card vocabulary, the verification chips, and the dropped-buddha create
|
|
108
|
+
step can be judged alongside the map.</p>
|
|
109
|
+
<div class="pair">
|
|
110
|
+
<div class="frame"><span class="lbl">your projects</span>
|
|
111
|
+
<iframe src="projects-hub-mock.html?view=mine&rail=0" loading="lazy"></iframe></div>
|
|
112
|
+
<div class="frame"><span class="lbl">new project</span>
|
|
113
|
+
<iframe src="projects-hub-mock.html?view=new&rail=0" loading="lazy"></iframe></div>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<p class="foot">
|
|
120
|
+
Walk the real thing: <a href="projects-hub-mock.html">projects-hub-mock.html</a> — the rail at the bottom
|
|
121
|
+
switches ground, view, mode and signed-in state; <code>S</code> outlines apex-only blocks and <code>C</code>
|
|
122
|
+
previews the child-instance shape. Serve over HTTP (<code>python -m http.server 8899</code>), not
|
|
123
|
+
<code>file://</code>.
|
|
124
|
+
</p>
|
|
125
|
+
|
|
126
|
+
<script>
|
|
127
|
+
/* Each tile drives its own iframe to a ground/mode after load. The iframes share
|
|
128
|
+
a localStorage key, so the attribute is written directly into the frame's
|
|
129
|
+
document instead of relying on the mock's own persistence. */
|
|
130
|
+
document.querySelectorAll('iframe[data-g]').forEach(function (f) {
|
|
131
|
+
f.addEventListener('load', function () {
|
|
132
|
+
try {
|
|
133
|
+
var d = f.contentDocument.documentElement;
|
|
134
|
+
d.setAttribute('data-ground', f.dataset.g);
|
|
135
|
+
d.setAttribute('data-mode', f.dataset.m);
|
|
136
|
+
} catch (e) {}
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
document.querySelectorAll('iframe:not([data-g])').forEach(function (f, i) {
|
|
140
|
+
f.addEventListener('load', function () {
|
|
141
|
+
try { f.contentDocument.documentElement.setAttribute('data-mode', i === 0 ? 'light' : 'dark'); } catch (e) {}
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
</script>
|
|
145
|
+
</body>
|
|
146
|
+
</html>
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
# The /projects Hub — Direction
|
|
2
|
+
|
|
3
|
+
> **Task 1002758** (goal 1000061 "Apex UI pass") · decided with the owner 2026-08-13.
|
|
4
|
+
> The mock this approves: [`mocks/projects-hub-mock.html`](mocks/projects-hub-mock.html).
|
|
5
|
+
> Ground comparison sheet: [`mocks/projects-hub-variants.html`](mocks/projects-hub-variants.html).
|
|
6
|
+
|
|
7
|
+
Scope: the **look and view model** of `/projects` once it becomes the project hub. Structure was already
|
|
8
|
+
settled by [`front-door-and-hub-direction.md`](front-door-and-hub-direction.md) §1–2, whose §7 deferred the
|
|
9
|
+
visual design to this pass and told it to take the structure as given. This document does not reopen which
|
|
10
|
+
URL serves what, what the hub contains, or what redirects where.
|
|
11
|
+
|
|
12
|
+
It also does **not** cover *how the sky moves* — panning, zoom, the Shift-search spotlight, the hover-card
|
|
13
|
+
lifecycle, the ghost orb, the minimap and the whale are goal 1000031. The line: **if it changes where a
|
|
14
|
+
person can go it is this pass; if it changes how the sky moves it is not.**
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 0. Starting point — what exists today
|
|
19
|
+
|
|
20
|
+
Verified live on core 1.19.91 and read from `origin/main` at `3458c70`, 2026-08-13.
|
|
21
|
+
|
|
22
|
+
**Three surfaces that do not know about each other.**
|
|
23
|
+
|
|
24
|
+
| Path | What it is | Nav out |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| `/gate/` | the orb sky, behind the pre-launch `basic_auth` (401) | a corner `.space-projects` pill — **and it is hidden in the table view** |
|
|
27
|
+
| `/projects` | a hero + a sign-in card. Signed out, that is the entire page | wordmark, "+ New project" |
|
|
28
|
+
| `/create` | the buddha, a 4-step rail, a sign-in card | "Exit `esc`" |
|
|
29
|
+
|
|
30
|
+
**Four defects this pass found on shipped files**, recorded here because the build inherits them:
|
|
31
|
+
|
|
32
|
+
1. **`/projects` promises a sky it does not have.** Its lede reads *"The same sky as the front door — every
|
|
33
|
+
project you own is an orb here"*, and the page renders a flat marigold ground with one card. The copy
|
|
34
|
+
describes the gate, which a visitor to `/projects` never sees.
|
|
35
|
+
2. **`?view=` is inert.** `public-landing/index.html:240` and `:430` — both "Start a project" CTAs on the
|
|
36
|
+
landing page shipped in `d53f51b` — link `/projects?view=new`, and `projects.html` reads **no query
|
|
37
|
+
string at all** (`grep -c "searchParams\|location.search" ` → 0). Both land on the plain list. This is a
|
|
38
|
+
live navigation bug on the front door, and §1.5 fixes it here because the hub is the surface that owns it.
|
|
39
|
+
3. **The table view has no verification overlay and no way back.** The gate's table shows Project / Builders
|
|
40
|
+
/ Type / Tags and no liveness chip, and its `body:not(.view-space)` rule hides the only projects door —
|
|
41
|
+
so the one view where a person is scanning for their own project is the view that cannot say whether it
|
|
42
|
+
is up, or get them to it.
|
|
43
|
+
4. **The landing hero's shadow inverts in dark mode.** `public-landing/index.html:276` fills the drums'
|
|
44
|
+
ground shadow with `var(--ink)`, which is `#fdeedd` in dark — a glowing cream puddle rather than a
|
|
45
|
+
shadow. Filed as its own task (§8) because it is a fault on the *landing* page, not a hub decision.
|
|
46
|
+
|
|
47
|
+
`projects.html` also bakes two platform claims into a file that ships to every instance — `<title>Your
|
|
48
|
+
projects — Cloud Bongos</title>` (`:6`) and the commons footer (`:93`) — and contains **zero** apex-only
|
|
49
|
+
sentinels. §7 C5 and the mock's `C` preview settle which side of the line each block sits on.
|
|
50
|
+
|
|
51
|
+
## 1. Decisions (owner, 2026-08-13)
|
|
52
|
+
|
|
53
|
+
1. **The map is what you land on.** Signed in or out, `/projects` opens on the map.
|
|
54
|
+
2. **An "only mine" filter lives in the map *and* the table.** The catalog is four projects and not all of
|
|
55
|
+
them are the viewer's; one control filters both browse views in place.
|
|
56
|
+
3. **The ground is `B` — dual-mode full-bleed.** The sky is the page and follows light/dark.
|
|
57
|
+
4. **`/gate/` retires at the apex flip.** The landing page already replaces it as the front door.
|
|
58
|
+
5. **The buddha is dropped.** The bongo pair is the mark on every surface.
|
|
59
|
+
6. **"Your projects" stays a distinct view, not a filtered map** (§3).
|
|
60
|
+
7. **`?view=map|mine|new` is the hub's deep-link contract** (§4), which fixes defect 2 above.
|
|
61
|
+
|
|
62
|
+
## 2. The ground — why dual-mode beat a framed panel
|
|
63
|
+
|
|
64
|
+
Three grounds were built as the *same mock* under a switch and compared as rendered pages; all three are
|
|
65
|
+
preserved in `projects-hub-mock.html` behind `html[data-ground]`, and the contact sheet is the record.
|
|
66
|
+
|
|
67
|
+
**B · dual-mode full-bleed won because cosmos.css had already decided it.** `--sky-bg` is
|
|
68
|
+
`#f9d9a8` in light and `#150c06` in dark, and `--star-display` flips `none`/`block` (`cosmos.css:61-62`,
|
|
69
|
+
`:99-100`). The shared stylesheet was built expecting a sky that changes with the mode; a hub that ignored
|
|
70
|
+
that would have been the only surface where the persistent ☾/☀ toggle does nothing.
|
|
71
|
+
|
|
72
|
+
- **A · framed window** — the sky as a bounded panel on a document page — was rejected because a ~540px
|
|
73
|
+
window onto a gravity field reads as a widget. The sky's whole appeal is that it is somewhere you *are*.
|
|
74
|
+
- **C · locked deep space** — the status quo, blue-violet in both modes — was rejected on two counts: the
|
|
75
|
+
mode toggle would silently do nothing on the hub's main view, and the hub would read as a different
|
|
76
|
+
product from the marigold landing page a visitor just came through.
|
|
77
|
+
|
|
78
|
+
**Dark mode is warm, not blue.** The map's dark ground is `--sky-bg` `#150c06` (warm umber), **not** the
|
|
79
|
+
gate's `--space-deep` `#05060f`. The locked space palette (`cosmos.css:47-49`) stays available and
|
|
80
|
+
platform-fixed, but the hub does not reintroduce the blue-violet the marigold pass moved away from.
|
|
81
|
+
|
|
82
|
+
> **Its risk, recorded so the build can watch for it:** light mode loses the starfield entirely
|
|
83
|
+
> (`--star-display:none`), so the map becomes a calm diagram rather than a place. If light mode ends up
|
|
84
|
+
> feeling inert, the fix is *not* to force stars onto a marigold ground — it is to give the light sky its
|
|
85
|
+
> own depth cue (the gravity grid carries most of it already; a soft vignette or warm haze layer is the
|
|
86
|
+
> next lever).
|
|
87
|
+
|
|
88
|
+
## 2b. What "mine" means — and the fact that nothing is
|
|
89
|
+
|
|
90
|
+
The owner's "only mine" toggle sounds like one predicate. It is not, and the platform had already decided
|
|
91
|
+
the vocabulary before this pass asked the question.
|
|
92
|
+
|
|
93
|
+
**Authority is the memberships table, not the catalog's owner column.**
|
|
94
|
+
`<redacted>` (ADR 0141 §3) carries `role IN ('owner','builder','visitor','pending')`,
|
|
95
|
+
and `GET /my-projects` already returns the split — `{ owned, building }`, with `pending` excluded
|
|
96
|
+
(`modules/platform-identity/routes/my-projects.js:25-38`). Meanwhile
|
|
97
|
+
`platform_identity_projects.owner_github_id` describes itself in its own migration as *"advisory attribution
|
|
98
|
+
(not an authority)"*. **The build must read memberships. It must not read `owner_github_id`.**
|
|
99
|
+
|
|
100
|
+
So the filter keeps `owner` **and** `builder`, and the map says the two differently — a solid accent ring
|
|
101
|
+
and a filled **yours** badge for owned; a softer ring and an outlined **you build here** badge for building.
|
|
102
|
+
Claiming ownership the membership row does not assert would be the same class of lie as the verification
|
|
103
|
+
overlay's (C6).
|
|
104
|
+
|
|
105
|
+
**And today the honest answer is that nothing is anyone's.** Verified 2026-08-13 as the platform's own
|
|
106
|
+
archon: `GET /my-projects` → `{"owned":[],"building":[]}`. Of the three catalog rows, `Demo` is owned by
|
|
107
|
+
another GitHub id and `Emersonian Circles` and `Example` have `owner_github_id` **NULL**. The
|
|
108
|
+
memberships directory is written only by the server-to-server check-in a *federated* instance posts on
|
|
109
|
+
sign-in — and the apex is not a federated client of itself.
|
|
110
|
+
|
|
111
|
+
That makes the empty state the **day-one** state, not an edge case, so the mock designs it: `0 projects`,
|
|
112
|
+
"You don't own or build on anything here yet", and a way out (turn the filter off, or start one). The
|
|
113
|
+
mock's rail carries a **real memberships** switch that reproduces it exactly, so the build cannot forget.
|
|
114
|
+
The data gap itself is **task 1002760** (§8), which now blocks carrier 1002744.
|
|
115
|
+
|
|
116
|
+
> **Its risk, recorded so the build can watch for it:** the sample data in the mock is *illustrative* —
|
|
117
|
+
> it marks one project owned and two built-on so the feature can be judged. Do not read it as a fixture.
|
|
118
|
+
> The switch, not the default, shows the truth.
|
|
119
|
+
|
|
120
|
+
## 3. Why "your projects" is a view and not a filter
|
|
121
|
+
|
|
122
|
+
The owner's "only mine" toggle could have replaced the manage view outright. It does not, because the two
|
|
123
|
+
answer different questions and only one of them fits on an orb.
|
|
124
|
+
|
|
125
|
+
The manage card is **contractual**, and its order is fixed by
|
|
126
|
+
[`projects-surfaces-redesign-direction.md`](projects-surfaces-redesign-direction.md) §8: orb → name +
|
|
127
|
+
status chip → meta row → address row → optional attach-domain input → optional error paragraph → progress
|
|
128
|
+
strip → last-action message → actions. Behind it sit **eight** chip outcomes, **four** progress flows
|
|
129
|
+
(standup / revive / teardown / address) × three stages, a teardown confirm that swaps the actions row, and
|
|
130
|
+
**eleven** named refusal messages. None of that survives being drawn as a dot in a starfield.
|
|
131
|
+
|
|
132
|
+
So: the map answers *what exists and is any of it mine*, and the toggle makes that fast. "Your projects"
|
|
133
|
+
answers *what do I do about it*. The filter is a lens on the browse surface; the view is where the controls
|
|
134
|
+
live.
|
|
135
|
+
|
|
136
|
+
## 3b. Search and filtering in the manage view
|
|
137
|
+
|
|
138
|
+
Added on the owner's ask, 2026-08-13: *"we should probably have some sort of search and filtering on the
|
|
139
|
+
Your Projects tab."* It is the one view that grows without bound — a builder with twenty projects has no
|
|
140
|
+
way to find one — and it was the only browse surface with no way to narrow.
|
|
141
|
+
|
|
142
|
+
**Search** matches name, repo slug and address, so `example-owner/spike` finds Spike Harbor and
|
|
143
|
+
`emersonian.cloudbongos.com` finds Emersonian Circles. Same predicate for all three fields; substring, not
|
|
144
|
+
fuzzy.
|
|
145
|
+
|
|
146
|
+
**The filter groups the chip outcomes; it never relabels them.** Five pills, each carrying a live count:
|
|
147
|
+
|
|
148
|
+
| Pill | Holds | Why |
|
|
149
|
+
|---|---|---|
|
|
150
|
+
| **All** | everything | |
|
|
151
|
+
| **Live** | `live` **and** `live?` | neither is known-down |
|
|
152
|
+
| **Needs you** | `unreachable`, `snagged` | the two that will not resolve on their own |
|
|
153
|
+
| **Working** | `queued`, `standing up`, `tearing down` | the platform is mid-flight; wait |
|
|
154
|
+
| **Torn down** | `torn down` | |
|
|
155
|
+
|
|
156
|
+
**This does not collapse the three active outcomes (C6).** Grouping `live` with `live?` under one *filter*
|
|
157
|
+
is not the same as printing one *label*: every card still says which it is, with its own recency. The rule
|
|
158
|
+
forbids a badge that claims more than the probe knows — it does not forbid a filter whose question is "is
|
|
159
|
+
this known to be down". A pill named "Up" would break it; "Live" holding both, with the cards unchanged
|
|
160
|
+
underneath, does not.
|
|
161
|
+
|
|
162
|
+
**Counts recompute against the search**, so typing a query and seeing `Needs you 0` is a real answer rather
|
|
163
|
+
than a stale one. An empty result says so and offers to clear.
|
|
164
|
+
|
|
165
|
+
## 4. Navigation — one shell, three destinations, and a real URL
|
|
166
|
+
|
|
167
|
+
The persistent header is fixed in form by [`gate-navigation-direction.md`](gate-navigation-direction.md) §4:
|
|
168
|
+
a header belonging to the **page shell**, not the orb field, so it does not drift, scale or pan with the
|
|
169
|
+
sky. It replaces `.space-projects`, and the `body:not(.view-space)` hide rule is deleted rather than
|
|
170
|
+
extended — which is what closes defect 3.
|
|
171
|
+
|
|
172
|
+
`?view=` carries `map` (default) / `mine` / `new`, pushed with `history.replaceState` so a view is
|
|
173
|
+
linkable and back-button-able. `/create` redirects to `?view=new`, and the landing page's two existing
|
|
174
|
+
`/projects?view=new` links start working the day this ships.
|
|
175
|
+
|
|
176
|
+
**The nav carries a `Home` item, and it is not a view.** The first draft had only the three hub views, on
|
|
177
|
+
the assumption that the wordmark's link to `/` was door enough. Owner review killed that: *"I dont see
|
|
178
|
+
exactly how a landing page is going to fit in here. Theres no 'home' page at the top tabs."* A wordmark that
|
|
179
|
+
happens to be a link announces nothing, and after the apex flip `/` is a real destination with real content.
|
|
180
|
+
|
|
181
|
+
So the nav reads `Home │ Map · Your projects · New project`, with a hairline after Home. The two kinds of
|
|
182
|
+
destination are deliberately not levelled: **Home is a page**, so it navigates and never takes the
|
|
183
|
+
current-view pill; the other three are **views of this page**, so they swap in place and one of them is
|
|
184
|
+
always current. The relationship between the two surfaces is one-way by design — the landing page is the
|
|
185
|
+
stranger's front door and sends people *into* the hub (its "Start a project" and "See what's building" CTAs
|
|
186
|
+
both point here); the hub is where they stay. `Home` is the way back out, not a tab someone is expected to
|
|
187
|
+
live on.
|
|
188
|
+
|
|
189
|
+
> **A trap the build must not walk into, found while mocking:** the wordmark **types**, so its width changes
|
|
190
|
+
> every ~190ms. With the nav as the middle child of a `space-between` row, the tabs visibly slide left and
|
|
191
|
+
> right while the logo animates. Both flanks take `flex:1 1 0` so they compute to equal width and the nav is
|
|
192
|
+
> pinned dead centre regardless of what the mark is currently spelling. Measured: 0px drift across seven
|
|
193
|
+
> typed states. Below 820px the three groups stack and the nav takes its own centred row.
|
|
194
|
+
|
|
195
|
+
## 5. The content spine
|
|
196
|
+
|
|
197
|
+
Ordered. **Portable** = true on every instance; **apex-only** = true of Cloud Bongos the platform.
|
|
198
|
+
Press `S` in the mock to outline the apex-only blocks, `C` to see the child-instance shape.
|
|
199
|
+
|
|
200
|
+
| | Section | Portable? |
|
|
201
|
+
|---|---|---|
|
|
202
|
+
| S0 | Head metadata — title + description from `{{productName}}`/`{{tagline}}` | server-stamped |
|
|
203
|
+
| S1 | Shell — self-typing wordmark, **Home │ Map · Your projects · New project**, hall link, mode toggle, identity chip | portable (hall link apex-only) |
|
|
204
|
+
| S2 | Toolbar — Sky \| Table, **only mine**, search + count | portable |
|
|
205
|
+
| S3 | Map · sky — orb field, owned marking, verification chip on owned orbs, hint rail | **catalog apex-only** |
|
|
206
|
+
| S4 | Map · table — Project / Builders / Type / Tags / **Status** / open | **catalog apex-only** |
|
|
207
|
+
| S5 | Your projects — **search + state filter**, then the manage cards (§3) | portable |
|
|
208
|
+
| S6 | New project — 4-step rail, the bongo pair, AGPL fine print | portable |
|
|
209
|
+
| S7 | Footer | split — commons claim apex-only |
|
|
210
|
+
|
|
211
|
+
Copy notes:
|
|
212
|
+
- The create pitch is verbatim from `create.html`, and the AGPL sentence from `create.html:391` — both
|
|
213
|
+
already public-facing and owner-approved. **Not newly invented.**
|
|
214
|
+
- **`/projects`' current lede is retired**, not reworded: "The same sky as the front door" described a page
|
|
215
|
+
the visitor never reached, and after the apex flip there is no separate front-door sky to be the same as.
|
|
216
|
+
- The self-typing wordmark **stays** — it is the sole carrier of the "type `bongos` in any AI" metaphor and
|
|
217
|
+
the one gate flourish that survives the ritual's removal (owner disposition, gate-navigation §4).
|
|
218
|
+
- **The entry ritual's copy dies with it**, including the table footer's "`esc` back to entry".
|
|
219
|
+
|
|
220
|
+
## 6. The design system
|
|
221
|
+
|
|
222
|
+
The mock **links `cosmos.css`** and adds a page-local sheet. It does not fork it. The chips are literally
|
|
223
|
+
the `.chip .live/.maybe/.down/.bad/.busy/.calm` vocabulary the manage list already ships, the manage cards
|
|
224
|
+
are `.proj`/`.projHead`/`.addr`/`.strip`, and the buttons are `.btn`/`.btn-space` — the map and the
|
|
225
|
+
management page share components rather than resembling each other.
|
|
226
|
+
|
|
227
|
+
**These are authored page-locally in the mock and must GRADUATE into `cosmos.css` in the build**, not be
|
|
228
|
+
copied into the page (each is marked ★ in the mock's stylesheet):
|
|
229
|
+
|
|
230
|
+
| Component | What it is |
|
|
231
|
+
|---|---|
|
|
232
|
+
| `.shell` / `.navrow` | the persistent hub header + its three-destination nav, incl. the equal-flanks rule (§4) |
|
|
233
|
+
| `.toolbar` / `.seg` | the per-view control strip and the segmented Sky \| Table control |
|
|
234
|
+
| `.switch` | the two-state "only mine" filter |
|
|
235
|
+
| `.search` | the glass search field + result count — used by the map toolbar **and** the manage bar |
|
|
236
|
+
| `.mineBar` / `.filters` | the manage view's search + state-filter pills with live counts (§3b) |
|
|
237
|
+
| `.field` / `.worldOrb` | the orb field and a project rendered as an orb, incl. `.badge` and the owned ring |
|
|
238
|
+
| `.tbl` | the directory table |
|
|
239
|
+
| `.steps` | the 4-step create rail |
|
|
240
|
+
| `.fieldNote` | the honest empty / not-available-here state |
|
|
241
|
+
|
|
242
|
+
**Orb colour must be tokenized.** `projects.html:221-231` hashes five hardcoded hexes and five rgba glows
|
|
243
|
+
off the instance slug; two happen to equal `--sun-lit`/`--gold-soft`, three are orphans, and none follow a
|
|
244
|
+
re-theme. Keep the per-project variety — it is what makes a sky legible — but re-express the five as
|
|
245
|
+
`color-mix()` derivations off `--accent`, `--sea`, `--terracotta` and the locked `--sun-lit`/`--gold`, so
|
|
246
|
+
every orb accent lands inside the contrast test.
|
|
247
|
+
|
|
248
|
+
## 7. Constraints the build must respect
|
|
249
|
+
|
|
250
|
+
- **C1 · One `:root`.** `injectBrandingGlobal()` splices the pack's `:root` at the **end of `<head>`, after
|
|
251
|
+
the stylesheet link** (`src/bongos/serve-internal.js:138-146`) — equal specificity, later in order, so the
|
|
252
|
+
pack wins. A page-local `:root` silently outranks it and defeats re-branding. Page-local custom properties
|
|
253
|
+
stay scoped to their component. The mock has **no** `:root` block; follow that.
|
|
254
|
+
- **C2 · Dark changes are made twice.** `:root[data-mode="dark"]` and the `prefers-color-scheme` twin are
|
|
255
|
+
byte-identical duplicates in `cosmos.css`. Both, every time — a `deepEqual` lockstep test compares them.
|
|
256
|
+
- **C3 · The page must ship a `.sky` element.** `themeMarkup()` emits `body{background:#f9d9a8}` after
|
|
257
|
+
cosmos.css in **both** modes and not mode-aware (`serve-internal.js:119`); `.sky` is the only mode-aware
|
|
258
|
+
full-page paint. Never ground the hub on `body`.
|
|
259
|
+
- **C4 · Never pin `--accent`, `--accent-deep`, `--sea`, `--terracotta` to a literal hex in a dark block**
|
|
260
|
+
(dark blocks are (0,2,0) and would outrank the pack permanently), and add every new fg/bg pair to
|
|
261
|
+
`tests/cosmos_token_contrast.mjs`'s `PAIRS` array — 32 pairs at 4.5:1 in **both** modes, CI-enforced.
|
|
262
|
+
- **C5 · Instance portability.** `public-landing/` ships wholesale to every instance. The catalog of other
|
|
263
|
+
instances, the "this platform" self-badge and the commons footer line are **apex-only** and go inside
|
|
264
|
+
`<!--apex-only:start--> … <!--apex-only:end-->` (server-stripped by `stripApexOnly()`,
|
|
265
|
+
`src/platform-server.js:75-97`) — removal, not CSS-hiding. The `<title>` becomes
|
|
266
|
+
`{{productName}}`/`{{tagline}}`. On a child, provisioning is `"default": false`, so the hub renders the
|
|
267
|
+
plain "projects aren't managed from this instance" state rather than falling into the generic alert.
|
|
268
|
+
- **C6 · Verification truth is load-bearing.** Three active outcomes stay three — `null` = never probed →
|
|
269
|
+
"live?", `false` = probed and down → "unreachable" (`modules/provisioning/provisioning.js:151`: *"Never
|
|
270
|
+
collapse the two."*). Liveness is an **overlay, never a lifecycle state**; an unreachable instance is
|
|
271
|
+
still `active` and still teardownable. Every liveness claim carries recency, and "live" only appears
|
|
272
|
+
inside `FRESH_MS` (12 min). **Map and list are two views of one truth** — never alive on one and
|
|
273
|
+
unreachable in the other.
|
|
274
|
+
- **C7 · Real markup, not JS-built.** The hub must read correctly to a crawler and with JavaScript off —
|
|
275
|
+
the exact failure task 1002746 had to repair on the gate.
|
|
276
|
+
- **C8 · The map must not run when it is not visible.** The gate's `requestAnimationFrame(tick)` at
|
|
277
|
+
`space.js:1847` writes a transform to every orb node with **no view guard** (`:631-654`), and `space.js`
|
|
278
|
+
assigns `document.body.className` **wholesale in 10 places** (`904, 961, 974, 979, 1241, 1248, 1374, 1394,
|
|
279
|
+
1406, 1827`), which would destroy any hub-level body class on every view change. Those become `classList`
|
|
280
|
+
operations, `render()` gets a view guard, and the design does not rely on a persistent `body` class —
|
|
281
|
+
`data-mode` lives on `<html>`.
|
|
282
|
+
- **C9 · Motion respects `prefers-reduced-motion`.** The gate honors it throughout (`space.css:802-809`);
|
|
283
|
+
the typing wordmark, the chip pulse and any orb drift must too.
|
|
284
|
+
|
|
285
|
+
## 8. Follow-on tasks this direction produced
|
|
286
|
+
|
|
287
|
+
| Task | Goal | What it does |
|
|
288
|
+
|---|---|---|
|
|
289
|
+
| **task 1002743** | 1000061 | **Build carrier 1 — the shell.** Retires the entry ritual, builds the persistent header + `?view=` contract across every view including the table, and carries the apex flip (part 3) with `platform_boot` unparked in the same change. Now **depends on 1002758**. |
|
|
290
|
+
| **task 1002744** | 1000061 | **Build carrier 2 — the map.** Owner-scoped feed, owned-orb identity with click-to-manage, and the verification chip on owned orbs. Now **depends on 1002758**. |
|
|
291
|
+
| **task 1002759** | 1000059 | **The dark-mode hero shadow** found in §0.4. Filed separately because it is a live fault on the shipped *landing* page and should not be buried inside a hub commit — the same reasoning that split task 1002749 out of task 1002747. |
|
|
292
|
+
| **task 1002760** | 1000061 | **The membership data gap** found in §2b — `GET /my-projects` is empty for the platform's own archon, and two of three catalog rows have a NULL owner, so "only mine" and owned-orb identity have nothing to render on the apex. **Blocks 1002744**, which is why it is a dependency rather than a note. |
|
|
293
|
+
| **task 1002761** | — | **`docs-entropy.js` is a silent no-op on Windows.** Found running it as a pre-ship check here: `git ls-files '*.md'` keeps its quotes through the shell Node uses on Windows, so git matches 0 of 339 tracked files and the tool reports a clean run. Unrelated to the hub, filed on its own. |
|
|
294
|
+
|
|
295
|
+
This document plus the approved mock are the contract for 1002743 and 1002744: **build what the mock shows;
|
|
296
|
+
do not redesign it.**
|
|
297
|
+
|
|
298
|
+
Also settled by this pass, for the carrier that lands it: **criterion 1000253 previously had no design
|
|
299
|
+
task.** Its only linked tasks were the two build carriers, both with empty `dependencies`, so nothing gated
|
|
300
|
+
the hub build on an approved mock and the criterion was unsatisfiable as written. Task 1002758 now carries
|
|
301
|
+
the criterion link and both carriers depend on it.
|
|
302
|
+
|
|
303
|
+
## 9. What is deliberately still open
|
|
304
|
+
|
|
305
|
+
- **How the sky moves.** Pan, zoom, spotlight search, hover cards, the ghost orb, the minimap and the whale
|
|
306
|
+
are goal 1000031. The mock places orbs statically on purpose.
|
|
307
|
+
- **`view-detail` and `view-download`.** The gate has five views; the hub names three. The recommendation on
|
|
308
|
+
the table — not yet an owner decision — is to delete `view-download` (a 2.75s descent cinematic, a temple
|
|
309
|
+
`.stage` with non-functional tiles, a 44-frame buddha loop and a 190-line drag IIFE at
|
|
310
|
+
`gate/index.html:378-630`) and make the self-orb open the **same** detail card every other orb opens, kept
|
|
311
|
+
as an overlay *inside* the map rather than a fourth destination. That is ~380 lines and two sprite files.
|
|
312
|
+
- **Whether light mode needs a depth cue** beyond the gravity grid (§2's recorded risk).
|
|
313
|
+
- **What the light sky does at 40 projects.** Four orbs sit comfortably; the mock does not prove a crowd.
|
|
314
|
+
|
|
315
|
+
## 10. Sign-off dispositions (owner, 2026-08-13)
|
|
316
|
+
|
|
317
|
+
1. **Map first**, for signed-in owners too — asked as a two-option question, answered with a correction
|
|
318
|
+
worth keeping: *"The map shows 4 total projects, not all of which the user is a part of."* The four are
|
|
319
|
+
the platform's own orb plus `Demo`, `Emersonian Circles` and `Example` (verified via
|
|
320
|
+
`GET /projects`). The premise of the question — that the catalog held one project — **was wrong**, and
|
|
321
|
+
the "only mine" toggle exists because the owner corrected it.
|
|
322
|
+
2. **The "only mine" toggle appears in the table too**, not just the sky — stated explicitly.
|
|
323
|
+
3. **`/gate/` retires at the apex flip** rather than surviving as a redirect or an easter egg, *"since we
|
|
324
|
+
have already designed a landing page."*
|
|
325
|
+
4. **The buddha is dropped** in favour of the bongo pair everywhere — chosen against the recommendation to
|
|
326
|
+
keep it in the create view.
|
|
327
|
+
5. **The ground was not decided in the abstract.** The owner declined to pick from a description —
|
|
328
|
+
*"we should run through these where you publish versions and I approve"* — so all three were built and
|
|
329
|
+
rendered, and **B** was approved from the walked mock.
|
|
330
|
+
6. **The nav-drift bug was caught by the owner in review**, not by the mock's author: *"the top tabs move
|
|
331
|
+
with the cloud ____ typing."* Fixed in §4 and pinned as a build constraint.
|
|
332
|
+
7. **The invented ownership was caught by the owner in review**, and it turned out to be the biggest finding
|
|
333
|
+
of the pass: *"example and emersonian circles arent owned by me and i am not apart of them yet they
|
|
334
|
+
appear in only mine."* The mock had asserted ownership no row supports. Chasing it produced §2b — the
|
|
335
|
+
owner/builder vocabulary, the rule that `owner_github_id` is not the authority, the day-one empty state,
|
|
336
|
+
and **task 1002760**, which blocks carrier 1002744. The owner's second phrasing — *"not owned by me
|
|
337
|
+
**and** i am not a part of them"* — is exactly the `{ owned, building }` split the API already returns,
|
|
338
|
+
arrived at independently.
|
|
339
|
+
8. **A missing door home was caught by the owner in review** (§4): the nav offered no route back to the
|
|
340
|
+
landing page. `Home` added, and deliberately set apart from the three views.
|
|
341
|
+
9. **Malformed table controls were caught by the owner in review:** "Manage →" wrapped to two lines and the
|
|
342
|
+
status chip's recency dropped below its label, because nothing stopped the action and status cells
|
|
343
|
+
breaking. Both now claim their width and refuse to wrap; the name cell absorbs the slack (§6 `.tbl`).
|
|
344
|
+
10. **Search + filtering on the manage view was asked for by the owner** and is §3b. The mock gained a
|
|
345
|
+
fifth card (`Mercury`, standing up) so the "Working" filter has a real member — and, incidentally, so
|
|
346
|
+
the standup progress flow is shown somewhere, which no other card did.
|
|
347
|
+
11. **Approved to ship** on the owner's word, 2026-08-13, after four review rounds against the live mock.
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.94",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.19.
|
|
9
|
+
"version": "1.19.94",
|
|
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.
|
|
3
|
+
"version": "1.19.94",
|
|
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",
|