@bongos/core 1.19.791 → 1.19.792

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.
@@ -68,7 +68,7 @@
68
68
  "modules/hall-ui/public/settings.js:615",
69
69
  "modules/hall-ui/public/settings.js:714",
70
70
  "modules/hall-ui/public/settings.js:794",
71
- "modules/hall-ui/public/settings.js:1093"
71
+ "modules/hall-ui/public/settings.js:1096"
72
72
  ]
73
73
  },
74
74
  {
@@ -1520,7 +1520,7 @@
1520
1520
  "occurrences": 2,
1521
1521
  "at": [
1522
1522
  "modules/hall-ui/public/settings.js:788",
1523
- "modules/hall-ui/public/settings.js:1346"
1523
+ "modules/hall-ui/public/settings.js:1349"
1524
1524
  ]
1525
1525
  },
1526
1526
  {
@@ -3097,7 +3097,7 @@
3097
3097
  "surface": "builders-hall",
3098
3098
  "text": "Checking your key…",
3099
3099
  "file": "modules/hall-ui/public/settings.js",
3100
- "line": 1070,
3100
+ "line": 1073,
3101
3101
  "origin": "js-text-assign",
3102
3102
  "confidence": "certain"
3103
3103
  },
@@ -3691,7 +3691,7 @@
3691
3691
  "surface": "builders-hall",
3692
3692
  "text": "Could not copy automatically — select and copy manually. ({…})",
3693
3693
  "file": "modules/hall-ui/public/settings.js",
3694
- "line": 949,
3694
+ "line": 952,
3695
3695
  "origin": "js-notice",
3696
3696
  "confidence": "certain"
3697
3697
  },
@@ -3889,7 +3889,7 @@
3889
3889
  "surface": "builders-hall",
3890
3890
  "text": "Could not load your account. Reload the page to try again.",
3891
3891
  "file": "modules/hall-ui/public/settings.js",
3892
- "line": 1329,
3892
+ "line": 1332,
3893
3893
  "origin": "js-text-assign",
3894
3894
  "confidence": "certain"
3895
3895
  },
@@ -3916,7 +3916,7 @@
3916
3916
  "surface": "builders-hall",
3917
3917
  "text": "Could not load your settings.",
3918
3918
  "file": "modules/hall-ui/public/settings.js",
3919
- "line": 1332,
3919
+ "line": 1335,
3920
3920
  "origin": "js-notice",
3921
3921
  "confidence": "certain"
3922
3922
  },
@@ -3961,7 +3961,7 @@
3961
3961
  "surface": "builders-hall",
3962
3962
  "text": "Could not remove your key. Try again.",
3963
3963
  "file": "modules/hall-ui/public/settings.js",
3964
- "line": 1150,
3964
+ "line": 1153,
3965
3965
  "origin": "js-notice",
3966
3966
  "confidence": "certain"
3967
3967
  },
@@ -3970,7 +3970,7 @@
3970
3970
  "surface": "builders-hall",
3971
3971
  "text": "Could not remove. Try again.",
3972
3972
  "file": "modules/hall-ui/public/settings.js",
3973
- "line": 1149,
3973
+ "line": 1152,
3974
3974
  "origin": "js-text-assign",
3975
3975
  "confidence": "certain"
3976
3976
  },
@@ -4033,7 +4033,7 @@
4033
4033
  "surface": "builders-hall",
4034
4034
  "text": "Could not save your key. Try again.",
4035
4035
  "file": "modules/hall-ui/public/settings.js",
4036
- "line": 1094,
4036
+ "line": 1097,
4037
4037
  "origin": "js-notice",
4038
4038
  "confidence": "certain"
4039
4039
  },
@@ -4177,7 +4177,7 @@
4177
4177
  "surface": "builders-hall",
4178
4178
  "text": "Could not save. Try again.",
4179
4179
  "file": "modules/hall-ui/public/settings.js",
4180
- "line": 1093,
4180
+ "line": 1096,
4181
4181
  "origin": "js-text-assign",
4182
4182
  "confidence": "certain"
4183
4183
  },
@@ -4195,7 +4195,7 @@
4195
4195
  "surface": "builders-hall",
4196
4196
  "text": "Could not set up key storage. Try again.",
4197
4197
  "file": "modules/hall-ui/public/settings.js",
4198
- "line": 1130,
4198
+ "line": 1133,
4199
4199
  "origin": "js-notice",
4200
4200
  "confidence": "certain"
4201
4201
  },
@@ -4204,7 +4204,7 @@
4204
4204
  "surface": "builders-hall",
4205
4205
  "text": "Could not set up storage. Try again.",
4206
4206
  "file": "modules/hall-ui/public/settings.js",
4207
- "line": 1129,
4207
+ "line": 1132,
4208
4208
  "origin": "js-text-assign",
4209
4209
  "confidence": "certain"
4210
4210
  },
@@ -4883,15 +4883,6 @@
4883
4883
  "origin": "html-text",
4884
4884
  "confidence": "certain"
4885
4885
  },
4886
- {
4887
- "id": "d629e152f074",
4888
- "surface": "builders-hall",
4889
- "text": "Expires {…} · refreshes on use.",
4890
- "file": "modules/hall-ui/public/settings.js",
4891
- "line": 939,
4892
- "origin": "js-text-assign",
4893
- "confidence": "certain"
4894
- },
4895
4886
  {
4896
4887
  "id": "de62f4cc7d2e",
4897
4888
  "surface": "builders-hall",
@@ -5104,7 +5095,7 @@
5104
5095
  "surface": "builders-hall",
5105
5096
  "text": "Fresh CLI token issued. Paste it in your terminal:",
5106
5097
  "file": "modules/hall-ui/public/settings.js",
5107
- "line": 929,
5098
+ "line": 932,
5108
5099
  "origin": "js-text-assign",
5109
5100
  "confidence": "certain"
5110
5101
  },
@@ -5185,7 +5176,7 @@
5185
5176
  "surface": "builders-hall",
5186
5177
  "text": "Get a free key ↗",
5187
5178
  "file": "modules/hall-ui/public/settings.js",
5188
- "line": 973,
5179
+ "line": 976,
5189
5180
  "origin": "js-markup",
5190
5181
  "confidence": "certain"
5191
5182
  },
@@ -5734,7 +5725,7 @@
5734
5725
  "surface": "builders-hall",
5735
5726
  "text": "Image key removed.",
5736
5727
  "file": "modules/hall-ui/public/settings.js",
5737
- "line": 1146,
5728
+ "line": 1149,
5738
5729
  "origin": "js-notice",
5739
5730
  "confidence": "certain"
5740
5731
  },
@@ -5977,7 +5968,7 @@
5977
5968
  "surface": "builders-hall",
5978
5969
  "text": "Key removed.",
5979
5970
  "file": "modules/hall-ui/public/settings.js",
5980
- "line": 1145,
5971
+ "line": 1148,
5981
5972
  "origin": "js-text-assign",
5982
5973
  "confidence": "certain"
5983
5974
  },
@@ -5986,7 +5977,7 @@
5986
5977
  "surface": "builders-hall",
5987
5978
  "text": "Key storage is being set up by an Archon — check back shortly. {…}",
5988
5979
  "file": "modules/hall-ui/public/settings.js",
5989
- "line": 1024,
5980
+ "line": 1027,
5990
5981
  "origin": "js-markup",
5991
5982
  "confidence": "certain"
5992
5983
  },
@@ -5995,7 +5986,7 @@
5995
5986
  "surface": "builders-hall",
5996
5987
  "text": "Key storage isn't set up yet. As an Archon you can turn it on now — the server generates and safely stores the master key (no terminal needed).",
5997
5988
  "file": "modules/hall-ui/public/settings.js",
5998
- "line": 1020,
5989
+ "line": 1023,
5999
5990
  "origin": "js-markup",
6000
5991
  "confidence": "certain"
6001
5992
  },
@@ -6058,7 +6049,7 @@
6058
6049
  "surface": "builders-hall",
6059
6050
  "text": "Latest version: v{…}.",
6060
6051
  "file": "modules/hall-ui/public/settings.js",
6061
- "line": 1418,
6052
+ "line": 1421,
6062
6053
  "origin": "js-text-assign",
6063
6054
  "confidence": "certain"
6064
6055
  },
@@ -6733,7 +6724,7 @@
6733
6724
  "surface": "builders-hall",
6734
6725
  "text": "No builder account found for this sign-in.",
6735
6726
  "file": "modules/hall-ui/public/settings.js",
6736
- "line": 1337,
6727
+ "line": 1340,
6737
6728
  "origin": "js-text-assign",
6738
6729
  "confidence": "certain"
6739
6730
  },
@@ -7498,7 +7489,7 @@
7498
7489
  "surface": "builders-hall",
7499
7490
  "text": "Paste command copied.",
7500
7491
  "file": "modules/hall-ui/public/settings.js",
7501
- "line": 948,
7492
+ "line": 951,
7502
7493
  "origin": "js-notice",
7503
7494
  "confidence": "certain"
7504
7495
  },
@@ -7507,7 +7498,7 @@
7507
7498
  "surface": "builders-hall",
7508
7499
  "text": "Paste your key first.",
7509
7500
  "file": "modules/hall-ui/public/settings.js",
7510
- "line": 1069,
7501
+ "line": 1072,
7511
7502
  "origin": "js-notice",
7512
7503
  "confidence": "certain"
7513
7504
  },
@@ -7921,7 +7912,7 @@
7921
7912
  "surface": "builders-hall",
7922
7913
  "text": "Re-issue failed: {…}",
7923
7914
  "file": "modules/hall-ui/public/settings.js",
7924
- "line": 953,
7915
+ "line": 956,
7925
7916
  "origin": "js-notice",
7926
7917
  "confidence": "certain"
7927
7918
  },
@@ -8182,7 +8173,7 @@
8182
8173
  "surface": "builders-hall",
8183
8174
  "text": "Remove your image-generation key? Art generation will stop until you add one again.",
8184
8175
  "file": "modules/hall-ui/public/settings.js",
8185
- "line": 1137,
8176
+ "line": 1140,
8186
8177
  "origin": "js-notice",
8187
8178
  "confidence": "certain"
8188
8179
  },
@@ -8488,7 +8479,7 @@
8488
8479
  "surface": "builders-hall",
8489
8480
  "text": "Save key",
8490
8481
  "file": "modules/hall-ui/public/settings.js",
8491
- "line": 1005,
8482
+ "line": 1008,
8492
8483
  "origin": "js-markup",
8493
8484
  "confidence": "certain"
8494
8485
  },
@@ -8749,7 +8740,7 @@
8749
8740
  "surface": "builders-hall",
8750
8741
  "text": "Set up key storage",
8751
8742
  "file": "modules/hall-ui/public/settings.js",
8752
- "line": 1021,
8743
+ "line": 1024,
8753
8744
  "origin": "js-markup",
8754
8745
  "confidence": "certain"
8755
8746
  },
@@ -8767,7 +8758,7 @@
8767
8758
  "surface": "builders-hall",
8768
8759
  "text": "Setting up key storage…",
8769
8760
  "file": "modules/hall-ui/public/settings.js",
8770
- "line": 1105,
8761
+ "line": 1108,
8771
8762
  "origin": "js-text-assign",
8772
8763
  "confidence": "certain"
8773
8764
  },
@@ -11017,7 +11008,7 @@
11017
11008
  "surface": "builders-hall",
11018
11009
  "text": "Your image-generation key settings could not be loaded. Reload the page to try again.",
11019
11010
  "file": "modules/hall-ui/public/settings.js",
11020
- "line": 1172,
11011
+ "line": 1175,
11021
11012
  "origin": "js-markup",
11022
11013
  "confidence": "certain"
11023
11014
  },
@@ -11035,7 +11026,7 @@
11035
11026
  "surface": "builders-hall",
11036
11027
  "text": "Your key",
11037
11028
  "file": "modules/hall-ui/public/settings.js",
11038
- "line": 1001,
11029
+ "line": 1004,
11039
11030
  "origin": "js-markup",
11040
11031
  "confidence": "certain"
11041
11032
  },
@@ -11107,7 +11098,7 @@
11107
11098
  "surface": "builders-hall",
11108
11099
  "text": "Your preferences, {…}.",
11109
11100
  "file": "modules/hall-ui/public/settings.js",
11110
- "line": 1346,
11101
+ "line": 1349,
11111
11102
  "origin": "js-text-assign",
11112
11103
  "confidence": "certain"
11113
11104
  },
@@ -12196,7 +12187,7 @@
12196
12187
  "surface": "builders-hall",
12197
12188
  "text": "paste command",
12198
12189
  "file": "modules/hall-ui/public/settings.js",
12199
- "line": 931,
12190
+ "line": 934,
12200
12191
  "origin": "js-text-assign",
12201
12192
  "confidence": "certain"
12202
12193
  },
@@ -13078,7 +13069,7 @@
13078
13069
  "surface": "builders-hall",
13079
13070
  "text": "{…} · Stored encrypted; never shown again after saving.",
13080
13071
  "file": "modules/hall-ui/public/settings.js",
13081
- "line": 1007,
13072
+ "line": 1010,
13082
13073
  "origin": "js-markup",
13083
13074
  "confidence": "certain"
13084
13075
  },
@@ -13091,6 +13082,15 @@
13091
13082
  "origin": "js-markup",
13092
13083
  "confidence": "certain"
13093
13084
  },
13085
+ {
13086
+ "id": "a6e4ed98fbea",
13087
+ "surface": "builders-hall",
13088
+ "text": "{…} · revoke it any time under Active sessions.",
13089
+ "file": "modules/hall-ui/public/settings.js",
13090
+ "line": 942,
13091
+ "origin": "js-text-assign",
13092
+ "confidence": "certain"
13093
+ },
13094
13094
  {
13095
13095
  "id": "d73256fbc395",
13096
13096
  "surface": "builders-hall",
@@ -2056,5 +2056,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
2056
2056
  landed since 1.19.789 with no explicit bump. run 35163350575. (task 1002620)
2057
2057
  1.19.791 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2058
2058
  landed since 1.19.790 with no explicit bump. run 35165066743. (task 1002620)
2059
+ 1.19.792 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2060
+ landed since 1.19.791 with no explicit bump. run 35166486577. (task 1002620)
2059
2061
  ---------------------------------------------------------------------------
2060
2062
  ```
@@ -0,0 +1,58 @@
1
+ -- core_243 — CLI sessions lose their idle expiry (task 1003956, ADR 0294).
2
+ --
3
+ -- WHAT CHANGED IN CODE. db-kernel.js createSession now records NO expiry when a
4
+ -- caller names none (every such caller is source='cli'), and lookupSession's
5
+ -- refresh-on-use rolls expires_at forward only for a row that already has one.
6
+ -- Both halves are forward-looking: they govern sessions minted or used AFTER the
7
+ -- deploy. Neither touches the dated rows already sitting in the table.
8
+ --
9
+ -- WHY THAT NEEDS A MIGRATION. Without this, the code change would be nearly
10
+ -- invisible on the day it ships. Every live CLI session carries an expires_at
11
+ -- from migration 035's backfill and from every refresh since, so each one would
12
+ -- still lapse on its own 24h clock exactly as before — and each builder would eat
13
+ -- one final forced re-auth to get a row the new default applies to. That is the
14
+ -- precise annoyance the task set out to remove, delivered once more on the way
15
+ -- out. Clearing the column here is what makes the fix arrive for people who are
16
+ -- already signed in.
17
+ --
18
+ -- DIRECTION OF THE GRACE. Migration 035 faced the mirror of this and reasoned the
19
+ -- same way: it backfilled a 24h runway specifically so introducing a TTL would
20
+ -- not kill the session running the migration. This is that courtesy inverted —
21
+ -- 035 pushed expiries out so nobody was signed out by a new timer; this removes
22
+ -- them so nobody is signed out by a timer already gone from the code. In both
23
+ -- cases the migration exists to keep a policy change off the backs of the people
24
+ -- holding live sessions when it lands.
25
+ --
26
+ -- WHY source='cli' AND NOT A BLANKET UPDATE. builder_sessions holds both classes
27
+ -- and only the CLI's expiry was asked for. A web row's expires_at is an explicit
28
+ -- 30-day value its own flow chose (auth-idp.js / auth-github.js pass a real date,
29
+ -- so the new NULL default never reaches them); nulling it here would silently
30
+ -- hand browser cookies an immortality nobody decided on, and the code would not
31
+ -- re-establish it — lookupSession only rolls an expiry it can already see, so a
32
+ -- web row cleared by mistake stays cleared forever. The filter is the whole
33
+ -- safety property of this statement.
34
+ --
35
+ -- WHY revoked_at IS NULL. A revoked row is dead by revoked_at, which lookupSession
36
+ -- checks before it ever reads expires_at, so clearing its expiry could not revive
37
+ -- it. It is excluded anyway: revoked rows are the audit trail of sessions somebody
38
+ -- deliberately killed, and rewriting their columns muddies what that record says.
39
+ -- Touch only what the change is actually about.
40
+ --
41
+ -- WHAT THIS DOES NOT WEAKEN. Revocation is untouched and remains the real remedy
42
+ -- (ADR 0206): POST /me/sessions/revoke and "Sign out everywhere" kill a leaked
43
+ -- bearer immediately, setBuilderRank sweeps every session on demotion, and
44
+ -- requireBuilder refuses a deactivated builder on the hot path regardless of any
45
+ -- live token. None of those consult expires_at.
46
+ --
47
+ -- Idempotent: re-running matches no rows the second time (expires_at is already
48
+ -- NULL) and is a no-op.
49
+
50
+ BEGIN;
51
+
52
+ UPDATE builder_sessions
53
+ SET expires_at = NULL
54
+ WHERE source = 'cli'
55
+ AND revoked_at IS NULL
56
+ AND expires_at IS NOT NULL;
57
+
58
+ COMMIT;
@@ -913,7 +913,10 @@
913
913
  if (res.status === 401) { toAuth(); return; }
914
914
  const body = (res.data || {});
915
915
  if (!res.ok) throw new Error(body.message || `HTTP ${res.status}`);
916
- const expires = body.expires_at ? new Date(body.expires_at).toLocaleString() : 'unknown';
916
+ // No expires_at is the NORMAL case for a CLI bearer since ADR 0294 — say so
917
+ // plainly. 'unknown' read as a gap in the page's knowledge; the absence of a
918
+ // date is the fact, and the revoke is what replaced the timer.
919
+ const expires = body.expires_at ? `Expires ${new Date(body.expires_at).toLocaleString()}` : 'Never expires';
917
920
  const pasteCommand = body.paste_command || '';
918
921
  // The secret is QUOTED (settings.css `.quote`): a 64-character token cannot
919
922
  // be a line of prose, so it sits one tonal step down with its own foot. Same
@@ -936,7 +939,7 @@
936
939
  copyBtn.id = 'cli-reissue-copy';
937
940
  copyBtn.textContent = 'Copy';
938
941
  const hint = el('span', 'settings-card__hint');
939
- hint.textContent = `Expires ${expires} · refreshes on use.`;
942
+ hint.textContent = `${expires} · revoke it any time under Active sessions.`;
940
943
  const foot = el('div', 'quote__foot');
941
944
  foot.append(copyBtn, hint);
942
945
  const quote = el('div', 'quote');
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.791",
3
+ "version": "1.19.792",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.19.791",
9
+ "version": "1.19.792",
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.791",
3
+ "version": "1.19.792",
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",
@@ -93,7 +93,7 @@ async function probeMe(tokenInfo) {
93
93
  function printReauth({ boxScoped }) {
94
94
  const why = boxScoped
95
95
  ? 'This box holds the BOX-SCOPED bootstrap token (source=box, ADR 0053) — it can bootstrap the box but is refused (403) on claim / ship / publish.'
96
- : 'This session token is EXPIRED or revoked (CLI tokens carry a 24h idle TTL).';
96
+ : 'This session token is REVOKED or otherwise rejected (CLI tokens do not expire on their own — ADR 0294).';
97
97
  console.log('[otb] ── dev box: RE-AUTH BEFORE YOU WORK ──');
98
98
  console.log(`[otb] ${why}`);
99
99
  console.log('[otb] ⚠ FIRST STEP this session: get the builder onto a real CLI session BEFORE claiming or shipping —');
@@ -521,9 +521,9 @@ function printUnauthGuidanceAndExit() {
521
521
  }
522
522
  console.error('');
523
523
  console.error(' Possible causes:');
524
- console.error(' - Your session token expired (24h idle TTL, auto-refreshes on each request)');
525
- console.error(' - Your token was revoked by an Archon');
524
+ console.error(' - Your token was revoked — by you ("Sign out everywhere") or by an Archon');
526
525
  console.error(' - A recent deploy applied an auth-changing migration (see deploy banner)');
526
+ console.error(' - This instance is older than ADR 0294 and still expires idle CLI sessions');
527
527
  console.error('');
528
528
  console.error(' Once re-authed, re-run whichever command you were trying.');
529
529
  // `doctor` is checkout-only — it is not one of the public CLI's verbs (ADR 0258).
@@ -3,11 +3,13 @@
3
3
  //
4
4
  // The fast, UI-first path to refresh an expired/invalid GDS CLI session.
5
5
  //
6
- // Why this exists: CLI bearer tokens carry a 24h idle TTL (refresh-on-use) for
7
- // auth-token hygiene (GDS-V3 criterion C9) — a leaked or abandoned token in the
8
- // plaintext session file dies on its own instead of living forever. That's a
9
- // keeper. The friction it caused (re-auth via the slow Device Flow, terminal
10
- // codes, Gemini-key prompts) is NOT a keeper. This script is the fix:
6
+ // Why this exists: a CLI session can stop working — revoked from the hall's
7
+ // "Sign out everywhere", swept by a demotion, or invalidated by an auth-changing
8
+ // deploy. (It no longer stops working from mere disuse: ADR 0294 removed the idle
9
+ // expiry, because the timer only ever signed out the legitimate holder while
10
+ // refresh-on-use kept a thief's copy alive.) Whatever killed it, the friction of
11
+ // getting back in — the slow Device Flow, terminal codes, Gemini-key prompts — is
12
+ // not something to keep. This script is the fix:
11
13
  //
12
14
  // 1. Detect — is the current session still valid? (GET /api/gds/me)
13
15
  // valid → print who you are + exit 0. Nothing to do.
@@ -133,8 +135,8 @@ async function main() {
133
135
  const b = (res.data && res.data.builder) || {};
134
136
  console.log(`Your GDS CLI session is valid — no re-auth needed.`);
135
137
  console.log(` Signed in as ${b.github_login || '?'}${b.rank ? ` (rank: ${b.rank})` : ''}.`);
136
- console.log(' (Sessions carry a 24h idle TTL and refresh on every use, so an');
137
- console.log(' actively-used session stays alive.)');
138
+ console.log(' (CLI sessions do not expire — they last until revoked. Kill one from');
139
+ console.log(' Settings → Active sessions, or "Sign out everywhere".)');
138
140
  process.exit(0);
139
141
  }
140
142
 
@@ -145,6 +145,13 @@ const INTEGRATION = new Set([
145
145
  // prove the CHECK actually refuses a stored fourth state, that the backfill lands on a
146
146
  // pre-migration row, and that publishableSql and projectPublishability agree.
147
147
  'project_visibility_db',
148
+ // task 1003956 (ADR 0294): that CLI sessions really never expire. The DB-free
149
+ // sibling (auth_session_ttl) pins the constant, createSession's value against a
150
+ // stub pool, and the TEXT of the refresh statement — but a regex over source
151
+ // proves the characters are there, not that Postgres does what they mean. Only a
152
+ // real engine can show the CASE guard leaving a NULL alone on an actual use,
153
+ // which is exactly where the removed timeout would come back.
154
+ 'auth_session_expiry_db',
148
155
  'scouting_rollup_fanout', 'session_records',
149
156
  // task 1003217: the cost-row RAISE against real SQL. Every claim in it IS the
150
157
  // SQL — an ON CONFLICT DO UPDATE guarded to move a row only upward, and a
@@ -218,6 +218,8 @@ async function pollDeviceFlow(deviceCode, userAgent) {
218
218
  source: 'cli',
219
219
  userAgent: userAgent ?? null,
220
220
  // CLI tokens have no expiry (manually revocable). Web tokens expire.
221
+ // True again as of ADR 0294: migration 035 made this line a lie for two years
222
+ // by defaulting a null to a TTL, and removing that default restored it.
221
223
  expiresAt: null,
222
224
  });
223
225
  // V3.R75 (#294): tick the onboarding state machine. Best-effort — auth
@@ -262,16 +262,25 @@ async function accessStateByLogin(login) {
262
262
 
263
263
  // --- Auth sessions (kernel: the builder_sessions token store auth.js drives) ----
264
264
 
265
- // SESSION_TTL_MS — session TTL on create/refresh. Centralized so the migration's
266
- // grace formula, the tests, and the code agree on one number.
265
+ // SESSION_TTL_MS — the roll-forward window for a session that HAS an expiry.
266
+ // It is no longer a default: a caller that names no expiry gets none (ADR 0294).
267
+ // What still reads it is refresh-on-use below, which rolls an already-dated row
268
+ // (the web flow's) forward on each request. Centralized so the tests and the
269
+ // code agree on one number.
267
270
  const SESSION_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
268
271
 
269
- // createSession — mint a builder_sessions row. Defaults expiry to NOW()+TTL when
270
- // the caller passes null/undefined (refresh-on-use keeps active sessions alive).
272
+ // createSession — mint a builder_sessions row.
273
+ //
274
+ // A null/undefined expiresAt means NO EXPIRY (expires_at NULL), which
275
+ // lookupSession honours as never-expires. That is the CLI's contract (ADR 0294,
276
+ // restoring 003_pms.sql's original one): a `bongos` sign-in lasts until it is
277
+ // revoked, because an idle expiry only ever logged out the legitimate holder —
278
+ // the remedy for a leaked bearer is the own-scoped revoke of ADR 0206, which is
279
+ // immediate where a timer is not. Every caller that passes null is source='cli'.
280
+ //
281
+ // Web callers pass an explicit date (30 days) and are untouched by this default.
271
282
  async function createSession({ builderId, token, source, userAgent, expiresAt }) {
272
- const effectiveExpiresAt = expiresAt === undefined || expiresAt === null
273
- ? new Date(Date.now() + SESSION_TTL_MS)
274
- : expiresAt;
283
+ const effectiveExpiresAt = expiresAt ?? null;
275
284
  const { rows } = await pool.query(
276
285
  `INSERT INTO builder_sessions (builder_id, token, source, user_agent, expires_at)
277
286
  VALUES ($1, $2, $3, $4, $5)
@@ -282,9 +291,10 @@ async function createSession({ builderId, token, source, userAgent, expiresAt })
282
291
  }
283
292
 
284
293
  // lookupSession — resolve a live (unrevoked, unexpired) session token to its
285
- // builder identity, and refresh-on-use (bump last_used_at + roll expiry forward,
286
- // fire-and-forget). Returns null for missing/revoked/expired. Read fresh per
287
- // request, never cached (ADR 0016).
294
+ // builder identity, and refresh-on-use (bump last_used_at, and roll expiry
295
+ // forward for a row that has one, fire-and-forget). Returns null for
296
+ // missing/revoked/expired; a row with expires_at NULL never expires. Read fresh
297
+ // per request, never cached (ADR 0016).
288
298
  //
289
299
  // The governance FOLD (task 1002556): when the governance module is enabled, the
290
300
  // same round-trip also aggregates the builder's raw permission grant keys, so
@@ -335,11 +345,19 @@ async function lookupSession(token) {
335
345
  if (!row) return null;
336
346
  if (row.revoked_at) return null;
337
347
  if (row.expires_at && row.expires_at < new Date()) return null;
348
+ // Refresh-on-use. last_used_at always moves — the own-sessions list (ADR 0206)
349
+ // is how a person spots a session they don't recognise, and that reading is the
350
+ // whole remedy now that CLI rows never lapse. expires_at only rolls forward for
351
+ // a row that HAS one: the CASE is what stops a use from minting an expiry on a
352
+ // never-expires row and quietly reintroducing the timeout per ADR 0294.
338
353
  pool
339
354
  .query(
340
355
  `UPDATE builder_sessions
341
356
  SET last_used_at = now(),
342
- expires_at = now() + ($2::int * INTERVAL '1 millisecond')
357
+ expires_at = CASE
358
+ WHEN expires_at IS NULL THEN NULL
359
+ ELSE now() + ($2::int * INTERVAL '1 millisecond')
360
+ END
343
361
  WHERE id = $1`,
344
362
  [row.session_id, SESSION_TTL_MS]
345
363
  )