@bongos/core 1.19.271 → 1.19.273

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.
@@ -101,8 +101,8 @@
101
101
  "at": [
102
102
  "modules/hall-ui/public/goals-page.js:674",
103
103
  "modules/hall-ui/public/goals-page.js:926",
104
- "modules/hall-ui/public/work.js:747",
105
- "modules/hall-ui/public/work.js:812"
104
+ "modules/hall-ui/public/work.js:751",
105
+ "modules/hall-ui/public/work.js:821"
106
106
  ]
107
107
  },
108
108
  {
@@ -134,8 +134,8 @@
134
134
  "text": "Copy prompt",
135
135
  "occurrences": 3,
136
136
  "at": [
137
- "modules/hall-ui/public/task.js:252",
138
- "modules/hall-ui/public/task.js:269",
137
+ "modules/hall-ui/public/task.js:258",
138
+ "modules/hall-ui/public/task.js:275",
139
139
  "modules/hall-ui/public/work.js:446"
140
140
  ]
141
141
  },
@@ -179,8 +179,8 @@
179
179
  "occurrences": 3,
180
180
  "at": [
181
181
  "modules/hall-ui/public/goals-page.js:949",
182
- "modules/hall-ui/public/work.js:783",
183
- "modules/hall-ui/public/work.js:836"
182
+ "modules/hall-ui/public/work.js:792",
183
+ "modules/hall-ui/public/work.js:845"
184
184
  ]
185
185
  },
186
186
  {
@@ -385,7 +385,7 @@
385
385
  "occurrences": 2,
386
386
  "at": [
387
387
  "modules/hall-ui/public/goals-page.js:677",
388
- "modules/hall-ui/public/work.js:750"
388
+ "modules/hall-ui/public/work.js:754"
389
389
  ]
390
390
  },
391
391
  {
@@ -775,7 +775,7 @@
775
775
  "occurrences": 2,
776
776
  "at": [
777
777
  "modules/hall-ui/public/profile.js:144",
778
- "modules/hall-ui/public/work.js:905"
778
+ "modules/hall-ui/public/work.js:914"
779
779
  ]
780
780
  },
781
781
  {
@@ -795,7 +795,7 @@
795
795
  "occurrences": 2,
796
796
  "at": [
797
797
  "modules/hall-ui/public/goals-page.js:702",
798
- "modules/hall-ui/public/work.js:954"
798
+ "modules/hall-ui/public/work.js:963"
799
799
  ]
800
800
  },
801
801
  {
@@ -915,7 +915,7 @@
915
915
  "occurrences": 2,
916
916
  "at": [
917
917
  "modules/hall-ui/public/goals-page.js:944",
918
- "modules/hall-ui/public/work.js:828"
918
+ "modules/hall-ui/public/work.js:837"
919
919
  ]
920
920
  },
921
921
  {
@@ -1519,7 +1519,7 @@
1519
1519
  "surface": "builders-hall",
1520
1520
  "text": ", follow its acceptance criteria, stay within touches[], /builder-ship",
1521
1521
  "file": "modules/hall-ui/public/work.js",
1522
- "line": 735,
1522
+ "line": 739,
1523
1523
  "origin": "js-markup",
1524
1524
  "confidence": "certain"
1525
1525
  },
@@ -2032,7 +2032,7 @@
2032
2032
  "surface": "builders-hall",
2033
2033
  "text": "Awaiting the grader / a confirmation before it can ship.",
2034
2034
  "file": "modules/hall-ui/public/task.js",
2035
- "line": 247,
2035
+ "line": 253,
2036
2036
  "origin": "js-markup",
2037
2037
  "confidence": "certain"
2038
2038
  },
@@ -2311,7 +2311,7 @@
2311
2311
  "surface": "builders-hall",
2312
2312
  "text": "Checking dependency order…",
2313
2313
  "file": "modules/hall-ui/public/work.js",
2314
- "line": 696,
2314
+ "line": 700,
2315
2315
  "origin": "js-text-assign",
2316
2316
  "confidence": "certain"
2317
2317
  },
@@ -2320,7 +2320,7 @@
2320
2320
  "surface": "builders-hall",
2321
2321
  "text": "Checking for conflicts…",
2322
2322
  "file": "modules/hall-ui/public/work.js",
2323
- "line": 675,
2323
+ "line": 679,
2324
2324
  "origin": "js-text-assign",
2325
2325
  "confidence": "certain"
2326
2326
  },
@@ -2401,7 +2401,7 @@
2401
2401
  "surface": "builders-hall",
2402
2402
  "text": "Claimed {…} tasks. Open a terminal to start work.",
2403
2403
  "file": "modules/hall-ui/public/work.js",
2404
- "line": 750,
2404
+ "line": 754,
2405
2405
  "origin": "js-notice",
2406
2406
  "confidence": "certain"
2407
2407
  },
@@ -2608,7 +2608,7 @@
2608
2608
  "surface": "builders-hall",
2609
2609
  "text": "Confirm that verification for #{…} actually passed?",
2610
2610
  "file": "modules/hall-ui/public/task.js",
2611
- "line": 284,
2611
+ "line": 290,
2612
2612
  "origin": "js-notice",
2613
2613
  "confidence": "certain"
2614
2614
  },
@@ -2743,7 +2743,7 @@
2743
2743
  "surface": "builders-hall",
2744
2744
  "text": "Copy prompt",
2745
2745
  "file": "modules/hall-ui/public/task.js",
2746
- "line": 252,
2746
+ "line": 258,
2747
2747
  "origin": "js-markup",
2748
2748
  "confidence": "certain"
2749
2749
  },
@@ -2752,7 +2752,7 @@
2752
2752
  "surface": "builders-hall",
2753
2753
  "text": "Copy prompt",
2754
2754
  "file": "modules/hall-ui/public/task.js",
2755
- "line": 269,
2755
+ "line": 275,
2756
2756
  "origin": "js-text-assign",
2757
2757
  "confidence": "certain"
2758
2758
  },
@@ -2950,7 +2950,7 @@
2950
2950
  "surface": "builders-hall",
2951
2951
  "text": "Could not load #{…}",
2952
2952
  "file": "modules/hall-ui/public/task.js",
2953
- "line": 303,
2953
+ "line": 309,
2954
2954
  "origin": "js-markup",
2955
2955
  "confidence": "certain"
2956
2956
  },
@@ -4147,7 +4147,7 @@
4147
4147
  "surface": "builders-hall",
4148
4148
  "text": "Goal #{…}",
4149
4149
  "file": "modules/hall-ui/public/task.js",
4150
- "line": 196,
4150
+ "line": 202,
4151
4151
  "origin": "js-markup",
4152
4152
  "confidence": "certain"
4153
4153
  },
@@ -4723,7 +4723,7 @@
4723
4723
  "surface": "builders-hall",
4724
4724
  "text": "Last claimed by",
4725
4725
  "file": "modules/hall-ui/public/task.js",
4726
- "line": 207,
4726
+ "line": 213,
4727
4727
  "origin": "js-markup",
4728
4728
  "confidence": "certain"
4729
4729
  },
@@ -5560,7 +5560,7 @@
5560
5560
  "surface": "builders-hall",
5561
5561
  "text": "Not found",
5562
5562
  "file": "modules/hall-ui/public/task.js",
5563
- "line": 298,
5563
+ "line": 304,
5564
5564
  "origin": "js-text-assign",
5565
5565
  "confidence": "certain"
5566
5566
  },
@@ -5632,7 +5632,7 @@
5632
5632
  "surface": "builders-hall",
5633
5633
  "text": "Nothing in the backlog right now.",
5634
5634
  "file": "modules/hall-ui/public/work.js",
5635
- "line": 944,
5635
+ "line": 953,
5636
5636
  "origin": "js-markup",
5637
5637
  "confidence": "certain"
5638
5638
  },
@@ -5659,7 +5659,7 @@
5659
5659
  "surface": "builders-hall",
5660
5660
  "text": "Nothing shipped yet.",
5661
5661
  "file": "modules/hall-ui/public/work.js",
5662
- "line": 905,
5662
+ "line": 914,
5663
5663
  "origin": "js-markup",
5664
5664
  "confidence": "certain"
5665
5665
  },
@@ -5794,7 +5794,7 @@
5794
5794
  "surface": "builders-hall",
5795
5795
  "text": "Open task #{…}",
5796
5796
  "file": "modules/hall-ui/public/work.js",
5797
- "line": 954,
5797
+ "line": 963,
5798
5798
  "origin": "js-markup",
5799
5799
  "confidence": "certain"
5800
5800
  },
@@ -5839,7 +5839,7 @@
5839
5839
  "surface": "builders-hall",
5840
5840
  "text": "Open the Work Board",
5841
5841
  "file": "modules/hall-ui/public/task.js",
5842
- "line": 252,
5842
+ "line": 258,
5843
5843
  "origin": "js-markup",
5844
5844
  "confidence": "certain"
5845
5845
  },
@@ -6352,7 +6352,7 @@
6352
6352
  "surface": "builders-hall",
6353
6353
  "text": "Recent history could not be loaded right now.",
6354
6354
  "file": "modules/hall-ui/public/work.js",
6355
- "line": 1043,
6355
+ "line": 1052,
6356
6356
  "origin": "js-markup",
6357
6357
  "confidence": "certain"
6358
6358
  },
@@ -6433,7 +6433,7 @@
6433
6433
  "surface": "builders-hall",
6434
6434
  "text": "Release your claim on #{…}? It returns to the queue and no {…} are earned.",
6435
6435
  "file": "modules/hall-ui/public/work.js",
6436
- "line": 828,
6436
+ "line": 837,
6437
6437
  "origin": "js-notice",
6438
6438
  "confidence": "certain"
6439
6439
  },
@@ -6442,7 +6442,7 @@
6442
6442
  "surface": "builders-hall",
6443
6443
  "text": "Release {…}? {…} to the queue and no {…} are earned.",
6444
6444
  "file": "modules/hall-ui/public/work.js",
6445
- "line": 777,
6445
+ "line": 786,
6446
6446
  "origin": "js-notice",
6447
6447
  "confidence": "certain"
6448
6448
  },
@@ -6460,7 +6460,7 @@
6460
6460
  "surface": "builders-hall",
6461
6461
  "text": "Released #{…}. It returns to the queue.",
6462
6462
  "file": "modules/hall-ui/public/work.js",
6463
- "line": 783,
6463
+ "line": 792,
6464
6464
  "origin": "js-notice",
6465
6465
  "confidence": "certain"
6466
6466
  },
@@ -6469,7 +6469,7 @@
6469
6469
  "surface": "builders-hall",
6470
6470
  "text": "Released #{…}. It returns to the queue.",
6471
6471
  "file": "modules/hall-ui/public/work.js",
6472
- "line": 836,
6472
+ "line": 845,
6473
6473
  "origin": "js-notice",
6474
6474
  "confidence": "certain"
6475
6475
  },
@@ -6937,7 +6937,7 @@
6937
6937
  "surface": "builders-hall",
6938
6938
  "text": "Select at least 2 waiting tasks to copy a parallel-session prompt.",
6939
6939
  "file": "modules/hall-ui/public/work.js",
6940
- "line": 660,
6940
+ "line": 664,
6941
6941
  "origin": "js-text-assign",
6942
6942
  "confidence": "certain"
6943
6943
  },
@@ -6946,7 +6946,7 @@
6946
6946
  "surface": "builders-hall",
6947
6947
  "text": "Select at least 2 waiting tasks to copy a sequential prompt.",
6948
6948
  "file": "modules/hall-ui/public/work.js",
6949
- "line": 685,
6949
+ "line": 689,
6950
6950
  "origin": "js-text-assign",
6951
6951
  "confidence": "certain"
6952
6952
  },
@@ -7090,7 +7090,7 @@
7090
7090
  "surface": "builders-hall",
7091
7091
  "text": "Ship it",
7092
7092
  "file": "modules/hall-ui/public/task.js",
7093
- "line": 243,
7093
+ "line": 249,
7094
7094
  "origin": "js-markup",
7095
7095
  "confidence": "certain"
7096
7096
  },
@@ -7099,7 +7099,7 @@
7099
7099
  "surface": "builders-hall",
7100
7100
  "text": "Shipped {…}{…}.",
7101
7101
  "file": "modules/hall-ui/public/task.js",
7102
- "line": 228,
7102
+ "line": 234,
7103
7103
  "origin": "js-markup",
7104
7104
  "confidence": "certain"
7105
7105
  },
@@ -7378,7 +7378,7 @@
7378
7378
  "surface": "builders-hall",
7379
7379
  "text": "Task #{…}",
7380
7380
  "file": "modules/hall-ui/public/task.js",
7381
- "line": 170,
7381
+ "line": 176,
7382
7382
  "origin": "js-text-assign",
7383
7383
  "confidence": "certain"
7384
7384
  },
@@ -7441,7 +7441,7 @@
7441
7441
  "surface": "builders-hall",
7442
7442
  "text": "Tasks are numbered separately from GitHub pull requests, so this may be a PR rather than a GDS task.",
7443
7443
  "file": "modules/hall-ui/public/task.js",
7444
- "line": 293,
7444
+ "line": 299,
7445
7445
  "origin": "js-markup",
7446
7446
  "confidence": "certain"
7447
7447
  },
@@ -7810,7 +7810,7 @@
7810
7810
  "surface": "builders-hall",
7811
7811
  "text": "The task list could not be loaded right now.",
7812
7812
  "file": "modules/hall-ui/public/work.js",
7813
- "line": 1097,
7813
+ "line": 1106,
7814
7814
  "origin": "js-markup",
7815
7815
  "confidence": "certain"
7816
7816
  },
@@ -7828,7 +7828,7 @@
7828
7828
  "surface": "builders-hall",
7829
7829
  "text": "The work board failed to load. Reload to try again.",
7830
7830
  "file": "modules/hall-ui/public/work.js",
7831
- "line": 1266,
7831
+ "line": 1275,
7832
7832
  "origin": "js-notice",
7833
7833
  "confidence": "certain"
7834
7834
  },
@@ -8089,7 +8089,7 @@
8089
8089
  "surface": "builders-hall",
8090
8090
  "text": "Try reloading in a moment.",
8091
8091
  "file": "modules/hall-ui/public/task.js",
8092
- "line": 303,
8092
+ "line": 309,
8093
8093
  "origin": "js-markup",
8094
8094
  "confidence": "certain"
8095
8095
  },
@@ -8269,7 +8269,7 @@
8269
8269
  "surface": "builders-hall",
8270
8270
  "text": "Welcome, {…}. Claim and release tasks and follow work in progress — no terminal needed.",
8271
8271
  "file": "modules/hall-ui/public/work.js",
8272
- "line": 1034,
8272
+ "line": 1043,
8273
8273
  "origin": "js-text-assign",
8274
8274
  "confidence": "certain"
8275
8275
  },
@@ -8566,7 +8566,7 @@
8566
8566
  "surface": "builders-hall",
8567
8567
  "text": "You claimed #{…}. Open a terminal to start work.",
8568
8568
  "file": "modules/hall-ui/public/work.js",
8569
- "line": 747,
8569
+ "line": 751,
8570
8570
  "origin": "js-notice",
8571
8571
  "confidence": "certain"
8572
8572
  },
@@ -8575,7 +8575,7 @@
8575
8575
  "surface": "builders-hall",
8576
8576
  "text": "You claimed #{…}. Open a terminal to start work.",
8577
8577
  "file": "modules/hall-ui/public/work.js",
8578
- "line": 812,
8578
+ "line": 821,
8579
8579
  "origin": "js-notice",
8580
8580
  "confidence": "certain"
8581
8581
  },
@@ -230,8 +230,48 @@
230
230
  return { label: label || stripMd(raw).slice(0, 80), detail };
231
231
  }
232
232
 
233
+
234
+ // ---- ADR 0116 error envelope (task 1002462) -------------------------------
235
+ //
236
+ // The server returns `{ error: { code, message, details } }` via res.fail().
237
+ // The code is NESTED, so a bare `data.error === 'CODE'` test compares a string
238
+ // to an OBJECT and silently never matches: every switch falls through to its
239
+ // generic default. That degrades into a wrong-but-plausible toast rather than a
240
+ // visible break, so no smoke test catches it — which is how the same defect
241
+ // survived independently across four hall surfaces (work.js, task.js, and
242
+ // hand-rolled copies in goals-page.js and task-detail.js).
243
+ //
244
+ // These live here, in the shared toolkit every hall page already loads first,
245
+ // so a fifth copy is never the easiest option. They take the RESPONSE BODY —
246
+ // callers pass `err.data` — and each accepts BOTH the envelope and the
247
+ // pre-envelope flat shape `{ error: 'CODE', ...fields }`, so an older server
248
+ // still maps. Pure: no DOM, no network, no page-specific behaviour (unlike the
249
+ // network helpers, which are deliberately NOT in this file).
250
+ function errCode(data) {
251
+ const e = data && data.error;
252
+ if (e && typeof e === 'object') return e.code || '';
253
+ if (typeof e === 'string') return e;
254
+ return (data && data.code) || '';
255
+ }
256
+ function errMessage(data) {
257
+ const e = data && data.error;
258
+ if (e && typeof e === 'object' && e.message) return e.message;
259
+ return (data && data.message) || '';
260
+ }
261
+ // Structured payload. Falls back to the BODY itself on the flat shape, where
262
+ // the extra fields (conflicts, failures, what_to_do) sat at the top level.
263
+ function errDetails(data) {
264
+ const e = data && data.error;
265
+ if (e && typeof e === 'object' && e.details && typeof e.details === 'object') return e.details;
266
+ // ALWAYS an object, so every caller can read `det.conflicts` with no type
267
+ // guard. A non-object body (a string, a number) would otherwise leak through
268
+ // and turn a detail read into undefined-or-worse at the call site.
269
+ return (data && typeof data === 'object') ? data : {};
270
+ }
271
+
233
272
  window.OTB = {
234
273
  escapeHtml, $, fmtNum, num, fmtInt, fmtCompact, fmtDate, rankLabel, toast, moduleOn,
274
+ errCode, errMessage, errDetails, // task 1002462 — ADR 0116 envelope readers
235
275
  contributeSettingsPanel, settingsPanels,
236
276
  contributeHallWidget, hallWidgets, hallWidgetIds,
237
277
  splitCriterion,
@@ -21,7 +21,7 @@
21
21
  // builds through unchanged; result-mode ({ status, ok, data }) preserves control flow 1:1.
22
22
  const api = window.BongosClient.createClient({ baseUrl: '', credentials: 'same-origin', throwOnError: false });
23
23
  const AUTH_NEEDED = 'auth-needed';
24
- const { escapeHtml, $, fmtDate } = window.OTB;
24
+ const { escapeHtml, $, fmtDate, errCode, errMessage } = window.OTB; // task 1002462: envelope readers
25
25
  const toast = (msg) => window.OTB.toast(msg, { duration: 2600 });
26
26
  const curLabel = () => (window.__BRANDING__ && window.__BRANDING__.currency && window.__BRANDING__.currency.label) || 'credits';
27
27
 
@@ -70,13 +70,19 @@
70
70
  // exactly those POST /tasks/:id/ship + /confirm can return. The server is the
71
71
  // authority (ADR 0016); the UI only surfaces the refusal.
72
72
  function friendlyActionError(status, data) {
73
- switch (data && data.error) {
73
+ // task 1002462: read the ADR 0116 envelope. `data.error` is an OBJECT here,
74
+ // so every case fell through to the generic default and a precise lifecycle
75
+ // refusal ("not confirmed yet", "attestation required") rendered as
76
+ // "Could not complete that (409)".
77
+ switch (errCode(data)) {
74
78
  case 'task_not_confirmed':
75
79
  return 'That task can only be shipped once it is confirmed (its grade has landed).';
76
80
  case 'task_not_completed':
77
81
  return 'That task is not marked complete yet.';
78
82
  case 'verify_attestation_required':
79
- return (data && data.message) || 'Confirm a verification task only after the verify actually passed.';
83
+ // The server's own sentence is the useful one — it names the task and the
84
+ // flag. It sits at error.message under the envelope, not data.message.
85
+ return errMessage(data) || 'Confirm a verification task only after the verify actually passed.';
80
86
  case 'rank_too_low_for_task':
81
87
  case 'INSUFFICIENT_RANK':
82
88
  return 'Your rank is not high enough for that action.';
@@ -35,7 +35,7 @@
35
35
  // window.OTB toolkit (dom-utils.js, loaded first). Thin wrappers keep this
36
36
  // file's exact variants (date-only fmtDate; a 2200ms clearing toast).
37
37
  // fmtAgo / toAuth / getJSON / postJSON stay local below.
38
- const { escapeHtml, $, fmtNum } = window.OTB;
38
+ const { escapeHtml, $, fmtNum, errCode, errDetails } = window.OTB; // task 1002462: envelope readers
39
39
  // Shared task-domain helpers (task 1002463). These lived in two copies here and
40
40
  // in the other board and had already drifted — goals-page.js had silently lost
41
41
  // friendlyBatchReason's MODULE_CONFLICT case. Destructured so every call site
@@ -468,14 +468,18 @@
468
468
  // Map the server's typed error code to a builder-readable line. The codes are
469
469
  // exactly those POST /claims and POST /claims/:id/resolve can return.
470
470
  function friendlyActionError(status, data) {
471
- const code = data && data.error;
472
- switch (code) {
471
+ // task 1002462: read the ADR 0116 envelope. `data.error` is an OBJECT, so the
472
+ // old `const code = data && data.error` compared a string to an object and
473
+ // EVERY case below fell through to the generic default — a wrong-but-plausible
474
+ // toast on every claim/release refusal.
475
+ const det = errDetails(data);
476
+ switch (errCode(data)) {
473
477
  case 'ALREADY_CLAIMED':
474
478
  return 'Someone else claimed that task first. The board will refresh.';
475
479
  case 'TASK_NOT_READY':
476
480
  return 'That task is no longer ready to be claimed.';
477
481
  case 'TOUCHES_CONFLICT': {
478
- const titles = Array.isArray(data.conflicts) ? data.conflicts.map((c) => c.title).filter(Boolean) : [];
482
+ const titles = Array.isArray(det.conflicts) ? det.conflicts.map((c) => c.title).filter(Boolean) : [];
479
483
  return titles.length
480
484
  ? `That task overlaps an active claim: ${titles.join('; ')}. Wait for it to ship.`
481
485
  : 'That task overlaps another active claim. Wait for it to ship.';
@@ -487,7 +491,7 @@
487
491
  case 'INSUFFICIENT_RANK':
488
492
  return 'Your rank is not yet high enough for that task.';
489
493
  case 'newcomer_must_ship_first':
490
- return data.what_to_do || 'Ship your current claim before opening another.';
494
+ return det.what_to_do || 'Ship your current claim before opening another.';
491
495
  case 'NOT_YOUR_CLAIM':
492
496
  return 'That claim is not yours to release.';
493
497
  case 'ALREADY_RESOLVED':
@@ -753,8 +757,13 @@
753
757
  await refreshLive();
754
758
  } catch (err) {
755
759
  if (err && err.message === 'redirecting to auth') return;
756
- if (err.status === 409 && err.data && err.data.error === 'batch_failed') {
757
- const failures = Array.isArray(err.data.failures) ? err.data.failures : [];
760
+ // task 1002462: same envelope defect — this tested `err.data.error === 'batch_failed'`
761
+ // against an object, so an all-or-nothing batch refusal rendered as the generic toast
762
+ // and the per-task reasons were dropped on the floor.
763
+ if (err.status === 409 && errCode(err.data) === 'batch_failed') {
764
+ const bdet = errDetails(err.data);
765
+ const failures = Array.isArray(bdet.failures) ? bdet.failures
766
+ : (Array.isArray(err.data && err.data.failures) ? err.data.failures : []);
758
767
  const lines = failures.map((f) => `#${f.task_id} (${friendlyBatchReason(f)})`);
759
768
  toast(lines.length
760
769
  ? `The batch could not be claimed — ${lines.join('; ')}.`
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.271",
3
+ "version": "1.19.273",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.19.271",
9
+ "version": "1.19.273",
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.271",
3
+ "version": "1.19.273",
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",
@@ -25,6 +25,7 @@
25
25
  // and must NEVER throw or block a claim.
26
26
 
27
27
  const { execFileSync } = require('node:child_process');
28
+ const path = require('node:path');
28
29
 
29
30
  // The live validators. task-classifier is a pure module (no DB, no network),
30
31
  // so importing it from a CLI is safe — same precedent as next-number.js reading
@@ -61,14 +62,70 @@ function apiContract() {
61
62
 
62
63
  // Resolve the absolute worktree root. runGit throws → fall back to cwd (which is
63
64
  // still better than nothing; the builder at least sees the directory they're in).
65
+ //
66
+ // task 1002573: also resolve WHICH KIND of tree this is. The pack used to print
67
+ // the root and then assert "this is the session's tree, not the main checkout"
68
+ // unconditionally — so claiming from the main checkout produced a sentence that
69
+ // was flatly false, and the tooling told the builder to do the one thing that
70
+ // makes the ship unmergeable (ship.js's local auto-merge has nowhere to merge
71
+ // INTO when the receiving tree is the one holding the branch — task 1002572).
72
+ //
73
+ // The signal is the same one claim.js detectWorktreeName() already uses: in the
74
+ // main checkout `--git-dir` and `--git-common-dir` resolve to the same path; in a
75
+ // linked worktree they diverge. isMainCheckout is TRI-STATE — null means "could
76
+ // not tell", and the guidance hedges rather than guessing, because this is a UX
77
+ // surface that must never block a claim.
64
78
  function resolveWorktreeRoot({ runGit, cwd }) {
79
+ let root = null;
80
+ let degraded = false;
65
81
  try {
66
- const root = runGit(['rev-parse', '--show-toplevel']).trim();
67
- if (root) return { root, degraded: false };
82
+ root = runGit(['rev-parse', '--show-toplevel']).trim() || null;
68
83
  } catch {
69
84
  /* fall through */
70
85
  }
71
- return { root: cwd, degraded: true };
86
+ if (!root) {
87
+ root = cwd;
88
+ degraded = true;
89
+ }
90
+ let isMainCheckout = null;
91
+ try {
92
+ const gitDir = runGit(['rev-parse', '--git-dir']).trim();
93
+ const commonDir = runGit(['rev-parse', '--git-common-dir']).trim();
94
+ if (gitDir && commonDir) {
95
+ // Both can come back RELATIVE ('.git' in the main checkout), so resolve
96
+ // against the tree we are describing rather than the process cwd.
97
+ const base = degraded ? cwd : root;
98
+ isMainCheckout = path.resolve(base, gitDir) === path.resolve(base, commonDir);
99
+ }
100
+ } catch {
101
+ /* unknown — the guidance hedges */
102
+ }
103
+ return { root, degraded, isMainCheckout };
104
+ }
105
+
106
+ // task 1002573: the guidance line(s) for the resolved tree. Pure, and exported so
107
+ // the "these two must not read the same" property is unit-tested rather than
108
+ // eyeballed. Returns an array of lines (the warning needs more than one).
109
+ function worktreeGuidance(worktree) {
110
+ const isMain = worktree ? worktree.isMainCheckout : null;
111
+ if (isMain === true) {
112
+ return [
113
+ ' ⚠ THIS IS THE MAIN CHECKOUT — not a per-claim worktree.',
114
+ ' Working the claim here parks the main checkout off `main`, and the local',
115
+ ' auto-merge then has nowhere to merge INTO: the ship strands at `confirmed`',
116
+ ' until the server reconciler (or /merge-mode) catches it. Automation that',
117
+ ' resets this tree mid-session can also take your uncommitted work with it.',
118
+ ' Prefer a worktree: git worktree add .claude/worktrees/<name> -b <branch>',
119
+ ];
120
+ }
121
+ if (isMain === false) {
122
+ return [' → edit files + run git HERE. This is the session\'s tree, not the main checkout (the #1 wrong-path footgun).'];
123
+ }
124
+ return [
125
+ ' → edit files + run git HERE.',
126
+ ' ⚠ Could not tell whether this is the main checkout or a linked worktree. If it is',
127
+ ' the main checkout, prefer a per-claim worktree — see the warning in /builder-claim.',
128
+ ];
72
129
  }
73
130
 
74
131
  // OS toolchain facts the corpus showed sessions tripping over. `which` returns a
@@ -148,7 +205,7 @@ function formatContextPack(pack) {
148
205
  const lines = [];
149
206
  lines.push('🧭 Context pack (so this session starts knowing, not hunting):');
150
207
  lines.push(` Worktree root: ${worktree.root}`);
151
- lines.push(' → edit files + run git HERE. This is the session\'s tree, not the main checkout (the #1 wrong-path footgun).');
208
+ lines.push(...worktreeGuidance(worktree)); // task 1002573 — tells the TRUTH about which tree this is
152
209
  if (worktree.degraded) {
153
210
  lines.push(' ⚠ git toplevel unreadable — showing cwd; double-check before writing.');
154
211
  }
@@ -217,6 +274,7 @@ module.exports = {
217
274
  API_PREFIX,
218
275
  apiContract,
219
276
  resolveWorktreeRoot,
277
+ worktreeGuidance, // task 1002573
220
278
  osFacts,
221
279
  normalizeClaims,
222
280
  buildContextPack,
package/src/module-api.js CHANGED
@@ -969,8 +969,12 @@ const { validateOrRespond, LIMITS, parseId, asyncHandler, corsPublicGet, parsePa
969
969
  // landed since 1.19.269 with no explicit bump. run 32428659648. (task 1002620)
970
970
  // 1.19.271 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
971
971
  // landed since 1.19.270 with no explicit bump. run 32437463473. (task 1002620)
972
+ // 1.19.272 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
973
+ // landed since 1.19.271 with no explicit bump. run 32438140524. (task 1002620)
974
+ // 1.19.273 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
975
+ // landed since 1.19.272 with no explicit bump. run 32441024959. (task 1002620)
972
976
  // ---------------------------------------------------------------------------
973
- const CORE_VERSION = '1.19.271'; // CI auto-patch carrier (ADR 0161); see changelog above
977
+ const CORE_VERSION = '1.19.273'; // CI auto-patch carrier (ADR 0161); see changelog above
974
978
 
975
979
  // A namespaced logger so a module's log lines are attributable + consistent.
976
980
  // Usage: const log = api.logger('dev-box'); log.info('mounted');