@bongos/core 1.19.438 → 1.19.440

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.
@@ -256,3 +256,23 @@ Three mastheads, rendered dark and light at 1440 / 390 / 320 (ALL CLEAN) and mea
256
256
  **The kit.** The stub remembers a saved planet for the run (a `PLANETS` map, the teardown-ask precedent) and answers the route's own receipt shapes, so the page's re-read finds its choice; both featured fixtures carry the keys on every row and Demo's owner has chosen `pair-obsidian-tint` on sea (the feed path — kept the pair's box so the sky's composition, and a signed-out Shift probe's blank-spot click, stand); Harbor's row carries `blob-frost-tint` on sun-lit (the row path — the list draws it with no catalog row). A state, `in-manage-planet`, renders the section on Demo; three probes save a pick and read the receipt, the head and the ledger row back, hand the pick back to the platform, and save through the pills at 390. `render.js --page /projects` ALL CLEAN (67 states), the empty and floor siblings ALL CLEAN, probes 44/44.
257
257
 
258
258
  **Retargeted.** `tests/projects_hub.mjs`: the mine-row and walk pins name the owner's choice first, the field-path pin reads Demo's choice over the curated template, and five new pins hold the vocabulary lockstep (client ↔ provisioning ↔ platform-identity), the section's markup and fold, the script (the preview, the radiogroups, the tick and late-catalog rules, the PATCH body, no open-intent re-read), the sheet by scope with the 900px pills, the kit's state/probes/fixtures/stub, and the seam. `tests/provisioning_settings.mjs` (the planet: saved, echoed, audited, no push; null clears; no change; no re-kick; a mixed save; off-vocabulary → 400), `modules/provisioning/tests/provisioning.mjs` (the mirror, `planetChoice`, `publicInstance`), `tests/provisioning_settings_env.mjs` (never in the env). The API docs regenerated; the copy registry regenerated.
259
+
260
+ ## 17. Your projects: two doors a row, and every control on the project's own page (task 1003355)
261
+
262
+ **Date:** 2026-08-30 · the owner, on the shipped Your-projects list (§14.1): "for the buttons on the your projects page, I think we should consolidate to one or two buttons which would be 'view' or 'view' and 'manage' and move the other buttons inside the project page."
263
+
264
+ **No composition round.** The grammar the round already settled (§14.1: the doors as hairline pills, the accent only on the one that acts) answers a two-door row without a new sheet, and the round's method reserves a sheet for a reading the page cannot already draw. What changed is *which* controls a row holds, not how a door looks — so this is a build against the existing pick, recorded here.
265
+
266
+ **The row.** `renderCard` renders one `.actions` strip and nothing else: **View**, a plain link to the project's site, only where it is `active` and has an address; **Manage**, a real link to `?view=manage&id=N`, on every row. Neither acts, so neither takes the accent. Gone from the row: try again, bring it back, restart it, the two-press ender, and the bring-your-own-domain fold. What stays is everything that *says* rather than does — the planet, the name and its chip, the facts, the lifecycle rail, the honest snag paragraph, the torn-down note and the live region the watch writes into. The row's own `id="act-…"`, its confirm prompt (`cardAsking`/`askTeardown`/`unAskTeardown`), its four senders (`doTeardown`, `reProvision`, `doRestart`, `doAttach`), `quietActions`, `watchOnce` and `canTeardown` went with them; the delegated list handler is down to the one Manage anchor it upgrades. The focus-restore across the heartbeat re-render stays, shrunk to the two doors.
267
+
268
+ **The manage page gains "its address".** The fold's field is now a settings section of the project's own page (`#mAddress`, between the ledger and repository visibility), in the `.mSec` grammar the three sections below it wear: the title and its fold on the left, the control on the right, the field as one hairline, the receipt as the section's own status line. The section's heading is the disclosure, so the field needs no `<details>` of its own and `.attachFold` left the sheet with it. Every server truth came across unchanged — `canAttachDomain` mirrors `DOMAIN_ATTACH_FROM`, the section hides itself where there is nothing to point an address at (a snagged or torn-down project), no second control renders while one is wiring, and the re-kick (F19) and correction (task 1003237) doors keep their pre-filled fields. What the fold said by *opening itself*, the section says in a sentence above the field. `renderAddress` is fetch-free like its neighbours, so the minute tick repaints it; the half-typed domain, the caret and the receipt all survive that repaint, the receipt keyed by project so a different one never wears the last one's.
269
+
270
+ **Copy that pointed at the row, corrected.** Three sentences named a control the row no longer has, and each would now have been a dead end. `addressRow` takes a second argument for the surface reading it: on the manage page the unreachable line still says "or restart it yourself below" and the no-address line says "give it an address below"; on a row they name the project's own page instead, the second as a `data-manage` link the list opens in place. The ender's torn-down state pointed at "your projects" for the revive door that now sits at the top of the same page, and says so — dropping the clause where `canRevive` renders no button. The create flow's done panel named the list five times for controls that now live on the project's page — three "attach an address", one "retry it", one "bring it back" — and all five go through `projectPageLink`, which names the project by id whenever the flow has one. Its two remaining pointers at the list ("watch it there", "follow it there") stay: the list does still show the project.
271
+
272
+ **Carried, not lost.** `teardownFailure` gives the ender the refusal vocabulary the row's sender held (`intent_conflict`, `not_teardownable` — the tasks 1002691/1002692 rule), which the truthful-refusal pin in `tests/<redacted>.mjs` caught the moment the row's copy went. `canTeardown` did not survive: `renderDelete` already carried each of its three exclusions as its own honest state, so with the row's button gone it mirrored nothing — the gate pin moved onto `renderDelete` itself.
273
+
274
+ **The kit.** One new state, `in-manage-address`; `in-manage` now expects the section, `in-manage-snag` and `in-manage-gone` expect it hidden; `in-mine` counts the doors (seven anchors over five rows, zero buttons). Six row probes became five page ones: attach, restart, revive and retry drive the stub from `?view=manage&id=N`, the two row-teardown presses fold into the ender probe that already drove the same flow there, and a new probe holds the row itself to its two doors. `render.js --page /projects` ALL CLEAN (68 states), the empty and floor siblings ALL CLEAN, probes 43/43.
275
+
276
+ **Retargeted.** `tests/projects_hub.mjs` (`renderManage` reads `addressRow(inst, true)`; the delete gate reads off `renderDelete`) and `tests/projects_hub_pre_uat.mjs` (the restart door's one home, the restart sender, the one remaining confirm, the field's move and its section, the F19 and correction doors, the minute tick, the manifest snag's link, the announcements, the no-address door). The copy registry regenerated.
277
+
278
+ **Flagged to the copy desk, not changed here.** The manage page's own site door still reads "Open site →" while the row now reads "View" — each reads naturally in place (the row pairs two doors, the page sits among verbs), so neither was churned. `stripMarkup`'s queued-flow notes still say "this card updates when it starts" on a page that is not a card. And a prose pointer inside a row's address line inherits the mono face meant for the address itself — true before this build too, and left alone rather than churned.
@@ -1313,5 +1313,9 @@ is load-bearing: the script throws rather than guess if it is missing, and
1313
1313
  landed since 1.19.436 with no explicit bump. run 33289560561. (task 1002620)
1314
1314
  1.19.438 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
1315
1315
  landed since 1.19.437 with no explicit bump. run 33290212472. (task 1002620)
1316
+ 1.19.439 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
1317
+ landed since 1.19.438 with no explicit bump. run 33290633434. (task 1002620)
1318
+ 1.19.440 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
1319
+ landed since 1.19.439 with no explicit bump. run 33321131006. (task 1002620)
1316
1320
  ---------------------------------------------------------------------------
1317
1321
  ```
@@ -67,13 +67,22 @@ function normalizeShipAssurance(a) {
67
67
  //
68
68
  // `deps` is injected so this is unit-testable with no network and no DB.
69
69
  async function deriveShipAssurance({ taskId, body = {}, db, githubPush, onProbeError }) {
70
+ const report = (e) => { if (onProbeError) onProbeError(e); };
71
+ // The tip is the durable proof (task 1547); the branch/PR status is only a
72
+ // WITNESS for the out-of-band fallback (task 1002615). A claim with no branch
73
+ // makes getPublishStatus throw BAD_BRANCH — that used to abort the whole probe
74
+ // before landProvenForTask ever saw a recorded tip, so a commit provably on main
75
+ // was refused as "not proven" (strands 1003285/1003286, task 1003434). Each step
76
+ // now fails on its own: a status miss degrades to status=null, never to no-proof.
77
+ let publishedSha = null;
78
+ try { publishedSha = await db.getClaimPublishedSha(taskId); } catch (e) { report(e); }
79
+ let status = null;
80
+ try { status = await githubPush.getPublishStatus({ taskId, publishedSha }); } catch (e) { report(e); }
70
81
  try {
71
- const publishedSha = await db.getClaimPublishedSha(taskId);
72
- const status = await githubPush.getPublishStatus({ taskId, publishedSha });
73
82
  const proof = await githubPush.landProvenForTask({ taskId, publishedSha, status });
74
83
  if (proof && proof.proven) return { assurance: { kind: 'proof', reason: proof.reason } };
75
84
  } catch (e) {
76
- if (onProbeError) onProbeError(e);
85
+ report(e);
77
86
  }
78
87
 
79
88
  if (body.no_artifact === true) {
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.438",
3
+ "version": "1.19.440",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.19.438",
9
+ "version": "1.19.440",
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.438",
3
+ "version": "1.19.440",
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",
@@ -407,12 +407,9 @@ h1{font-family:var(--font-display);font-weight:700;font-size:clamp(24px,3.4vw,32
407
407
  .attach input[type=text]{flex:1;min-width:220px;font-family:var(--font-body);font-size:15px;font-weight:600;color:var(--ink);background:var(--bg-card);border:2px solid var(--ctl-line);border-radius:12px;padding:9px 14px;outline:none;transition:border-color .15s ease, box-shadow .15s ease;}
408
408
  .attach input[type=text]::placeholder{color:var(--ink-faint);font-weight:500;}
409
409
  .attach input[type=text]:focus{border-color:var(--accent);box-shadow:0 0 0 4px color-mix(in srgb,var(--accent) 13%,transparent);}
410
- /* the bring-your-own-domain fold (owner decision 2, 2026-08-24): the wizard's
411
- address-step disclosure, closed by default and after the card's doors — a
412
- domain the founder can't buy here must not be the card's loudest control */
413
- .attachFold{margin-top:12px;}
414
- .attachFold summary{cursor:pointer;width:fit-content;font-size:13px;font-weight:700;color:var(--ink-faint);}
415
- .attachFold summary:hover,.attachFold[open] summary{color:var(--ink-soft);}
410
+ /* the bring-your-own-domain field. It sat behind a fold on the list card until
411
+ task 1003355 moved it to the project's own page, where the section's heading
412
+ is the disclosure and the row it left carries only its two doors. */
416
413
  .attachNote{margin:8px 0 0;font-size:13px;line-height:1.45;color:var(--ink-faint);}
417
414
  .attachNote code{font-family:var(--font-mono);}
418
415
  .projMsg{font-size:13.5px;font-weight:600;margin-top:10px;min-height:18px;color:var(--ink-soft);line-height:1.5;}
@@ -1222,14 +1219,12 @@ p.sec-p{font-size:var(--fs-lede);font-weight:500;color:var(--ink-soft);line-heig
1222
1219
  #view-mine .addr{grid-area:addr;align-self:start;}
1223
1220
  #view-mine .strip{grid-area:rail;}
1224
1221
  #view-mine .actions{grid-area:doors;}
1225
- /* everything else on a card (a snag, a status line, the torn-down note, the
1226
- address fold) is a full row under the ledger line */
1227
- #view-mine .projBody>.projMsg,#view-mine .projBody>.attachFold{grid-column:1/-1;}
1222
+ /* everything else on a row (a snag, a status line, the torn-down note) is a
1223
+ full row under the ledger line */
1224
+ #view-mine .projBody>.projMsg{grid-column:1/-1;}
1228
1225
  #view-mine .projMsg{min-height:0;margin:0;font-weight:400;}
1229
1226
  #view-mine .projMsg:not(:empty){margin-top:10px;}
1230
1227
  #view-mine .projMsg.err{margin-top:12px;}
1231
- #view-mine .attachFold{margin-top:10px;}
1232
- #view-mine .actions:has(.confirmRow){grid-area:auto;grid-column:1/-1;justify-content:flex-start;margin-top:12px;}
1233
1228
  /* the name in the body face; the chip beneath it, allowed to wrap */
1234
1229
  #view-mine .projName{font-family:var(--font-body);font-weight:500;font-size:17px;letter-spacing:-.015em;color:var(--ink);}
1235
1230
  #view-mine .proj.gone .projName{color:var(--ink-soft);}
@@ -1245,14 +1240,12 @@ p.sec-p{font-size:var(--fs-lede);font-weight:500;color:var(--ink-soft);line-heig
1245
1240
  box; the address clause's mono link may run long and must wrap inside the
1246
1241
  prose, so it stays inline and takes the floor as vertical padding (an inline's
1247
1242
  rect is its content box plus padding, never the line box) */
1248
- #view-mine .projMsg a,#view-mine .attachNote a,#view-manage .ledger a,#view-manage .backRow a,#view-manage .mSec a{display:inline-block;padding:3px 0;min-height:24px;line-height:18px;font-weight:400;text-decoration:none;}
1243
+ #view-mine .projMsg a,#view-manage .ledger a,#view-manage .backRow a,#view-manage .mSec a{display:inline-block;padding:3px 0;min-height:24px;line-height:18px;font-weight:400;text-decoration:none;}
1249
1244
  #view-mine .addr{line-height:1.6;}
1250
1245
  #view-mine .addr a{display:inline;padding:4px 0;font-weight:400;text-decoration:none;}
1251
1246
  #view-mine .addr a,#view-manage .ledger a{font-family:var(--font-mono);font-size:12.5px;color:var(--ink-soft);}
1252
1247
  #view-mine .addr a:hover,#view-manage .ledger a:hover{color:var(--ink);text-decoration:underline;}
1253
1248
  #view-mine .projMsg a,#view-manage .mSec a{color:var(--ink);text-decoration:underline;}
1254
- #view-mine .attachFold summary{display:inline-flex;align-items:center;min-height:24px;font-weight:400;font-size:13.5px;color:var(--ink-soft);}
1255
- #view-mine .attachFold summary:hover,#view-mine .attachFold[open] summary{color:var(--ink);}
1256
1249
 
1257
1250
  /* ── the lifecycle rail (DESIGN.md): stripMarkup's markup, drawn as three
1258
1251
  hairlines with a 7px dot and one lit step — no plate, no connector, no
@@ -1294,13 +1287,15 @@ p.sec-p{font-size:var(--fs-lede);font-weight:500;color:var(--ink-soft);line-heig
1294
1287
  #view-mine .btn.small.danger,#view-manage .btn.small.danger{border-color:color-mix(in srgb,var(--err) 45%,transparent);color:var(--err);}
1295
1288
  #view-mine .btn.small.danger:hover,#view-manage .btn.small.danger:hover{background:none;border-color:var(--err);color:var(--err);}
1296
1289
  #view-mine .btn.small:disabled,#view-manage .btn.small:disabled{background:none;border-color:var(--rule-soft);color:var(--ink-faint);}
1297
- /* the fold's field and the ender's typed-back name: a hairline field */
1298
- #view-mine .attach,#view-manage .attach{gap:10px 14px;margin-top:12px;align-items:center;}
1299
- #view-mine .attach input[type=text],#view-manage .attach input[type=text]{min-width:220px;min-height:40px;font-family:var(--font-body);font-size:15.5px;font-weight:400;color:var(--ink);background:none;border:0;border-bottom:1px solid var(--rule);border-radius:0;padding:8px 0;}
1300
- #view-mine .attach input[type=text]::placeholder,#view-manage .attach input[type=text]::placeholder{font-weight:400;}
1301
- #view-mine .attach input[type=text]:focus,#view-manage .attach input[type=text]:focus{border-bottom-color:var(--ink);box-shadow:none;}
1302
- #view-mine .confirmRow,#view-manage .confirmRow{font-weight:400;}
1303
- #view-mine .confirmRow .plain,#view-manage .confirmRow .plain{font-weight:400;font-size:14.5px;line-height:1.5;}
1290
+ /* the address field and the ender's typed-back name: a hairline field. Both
1291
+ live on the project's own page now (task 1003355), so the scope is one. */
1292
+ #view-manage .attach{gap:10px 14px;margin-top:12px;align-items:center;}
1293
+ #view-manage .attach input[type=text]{min-width:220px;min-height:40px;font-family:var(--font-body);font-size:15.5px;font-weight:400;color:var(--ink);background:none;border:0;border-bottom:1px solid var(--rule);border-radius:0;padding:8px 0;}
1294
+ #view-manage .attach input[type=text]::placeholder{font-weight:400;}
1295
+ #view-manage .attach input[type=text]:focus{border-bottom-color:var(--ink);box-shadow:none;}
1296
+ #view-manage .attachNote{margin:0;font-size:13.5px;line-height:1.5;}
1297
+ #view-manage .confirmRow{font-weight:400;}
1298
+ #view-manage .confirmRow .plain{font-weight:400;font-size:14.5px;line-height:1.5;}
1304
1299
 
1305
1300
  /* ── the empty state: a band of the Projects band's grammar, one door ── */
1306
1301
  #view-mine .empty{display:grid;gap:14px;justify-items:start;text-align:left;background:var(--bg-card);border:0;border-top:1px solid var(--rule);border-bottom:1px solid var(--rule);border-radius:0;padding:58px var(--gutter) 62px;}
@@ -1392,7 +1387,7 @@ p.sec-p{font-size:var(--fs-lede);font-weight:500;color:var(--ink-soft);line-heig
1392
1387
  #view-mine .proj .worldOrb{--orb-scale:.875;grid-column:1;grid-row:1;}
1393
1388
  #view-mine .projBody{display:contents;}
1394
1389
  #view-mine .projHead{grid-area:auto;grid-column:2;grid-row:1;}
1395
- #view-mine .projMeta,#view-mine .addr,#view-mine .strip,#view-mine .actions,#view-mine .projBody>.projMsg,#view-mine .projBody>.attachFold{grid-area:auto;grid-column:1/-1;}
1390
+ #view-mine .projMeta,#view-mine .addr,#view-mine .strip,#view-mine .actions,#view-mine .projBody>.projMsg{grid-area:auto;grid-column:1/-1;}
1396
1391
  #view-mine .projMeta{margin-top:14px;}
1397
1392
  #view-mine .strip{margin-top:16px;}
1398
1393
  #view-mine .actions{margin-top:16px;justify-content:flex-start;flex-direction:row;align-items:center;}