@wenathlan/cobaia 2.0.167 → 2.0.169

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/cobaia.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "cobaia"
3
- spec.version = ENV.fetch("COBAIA_VERSION", "2.0.167")
3
+ spec.version = ENV.fetch("COBAIA_VERSION", "2.0.169")
4
4
  spec.authors = ["wenathlan"]
5
5
  spec.email = ["support@users.noreply.github.com"]
6
6
  spec.summary = "The cobaia documentation and tests envelope (the monetization surface — the plans, the support rails and the honest advertisement slots)."
package/cobaia.java CHANGED
@@ -10,7 +10,7 @@ package com.wenathlan.cobaia;
10
10
  */
11
11
  final class Cobaia {
12
12
  /** The version of the cobaia envelope (the six-distribution completeness wave). */
13
- public static final String VERSION = "2.0.167";
13
+ public static final String VERSION = "2.0.169";
14
14
  private Cobaia() {
15
15
  }
16
16
  }
package/cobaia.rs ADDED
@@ -0,0 +1,8 @@
1
+ //! The cobaia version envelope carrier.
2
+ //!
3
+ //! The carrier answers the lowercase file name doctrine: the envelope
4
+ //! carries the version constant the metadata lockstep stamps, the cargo
5
+ //! lane packages it, the registry lanes never compile it locally.
6
+
7
+ /// The version of the cobaia envelope (the family tri-channel wave).
8
+ pub const VERSION: &str = "2.0.169";
package/db.ts CHANGED
@@ -8,6 +8,7 @@
8
8
  * tables over HTTPS (GET/POST /api/v1/onboarding, GET /api/v1/ui/content);
9
9
  * no server route lives here.
10
10
  */
11
+ import { createOnboardingStore } from "@wenathlan/vault/onboardingstore";
11
12
  import { openStorageLane } from "@wenathlan/vault/storage";
12
13
  import { CONTENTKINDS, type contentrow, seedAdsLabel, seedAdsEmpty, seedAdsSlots, seedPlans, seedPosts, seedRoster, seedSupportLinks } from "./content";
13
14
  import { LABEL_MANIFEST, LABEL_REVISION } from "./labels";
@@ -70,6 +71,12 @@ export type OnboardingStateRow = {
70
71
  /** the stage flags the entry flow consults, as booleans. */
71
72
  export type OnboardingFlags = { introseen: boolean; onboardingseen: boolean };
72
73
 
74
+ /** the onboarding store of the site: the vault factory over the site's own
75
+ * storage lane (the seen-flags table rides the app schema, the read and the
76
+ * seen-wins upsert ride the shared mechanism — never duplicated inside the
77
+ * app; the storage lane law of the family, the labelstore precedent). */
78
+ const onboardingstore = createOnboardingStore(lane);
79
+
73
80
  /**
74
81
  * Reads the onboarding stage flags of one visitor (parameterized; undefined
75
82
  * before the first write). The browser accessor serves the same flags over
@@ -79,17 +86,13 @@ export type OnboardingFlags = { introseen: boolean; onboardingseen: boolean };
79
86
  * @returns the flags, or undefined when the visitor never wrote.
80
87
  */
81
88
  export function getOnboardingState(visitor: string): OnboardingFlags | undefined {
82
- const row = queryOne<Pick<OnboardingStateRow, "introseen" | "onboardingseen">>(
83
- "SELECT introseen, onboardingseen FROM onboarding_states WHERE visitor = ?",
84
- [visitor],
85
- );
86
- if (!row) return undefined;
87
- return { introseen: row.introseen === 1, onboardingseen: row.onboardingseen === 1 };
89
+ return onboardingstore.getOnboardingState(visitor);
88
90
  }
89
91
 
90
92
  /**
91
- * Marks one onboarding stage seen for a visitor — idempotent seen-wins
92
- * upsert (a stage seen anywhere stays seen), prepared and parameterized,
93
+ * Marks one onboarding stage seen for a visitor — the idempotent seen-wins
94
+ * upsert of the vault store (a stage seen anywhere stays seen; the later
95
+ * stage implies the earlier — the flow order), prepared and parameterized,
93
96
  * never concatenated SQL.
94
97
  *
95
98
  * @param visitor the visitor key of the row.
@@ -97,15 +100,7 @@ export function getOnboardingState(visitor: string): OnboardingFlags | undefined
97
100
  * @returns the flags after the write.
98
101
  */
99
102
  export function setOnboardingStage(visitor: string, stage: "intro" | "onboarding"): OnboardingFlags {
100
- execute(
101
- `INSERT INTO onboarding_states (visitor, introseen, onboardingseen, updatedAt)
102
- VALUES (?, ?, ?, datetime('now'))
103
- ON CONFLICT(visitor) DO UPDATE SET
104
- introseen = MAX(introseen, excluded.introseen),
105
- onboardingseen = MAX(onboardingseen, excluded.onboardingseen),
106
- updatedAt = datetime('now')`,
107
- [visitor, stage === "intro" ? 1 : 0, stage === "onboarding" ? 1 : 0],
108
- );
103
+ onboardingstore.setOnboardingStage(visitor, stage);
109
104
  return getOnboardingState(visitor) ?? { introseen: false, onboardingseen: false };
110
105
  }
111
106
 
@@ -29,7 +29,7 @@
29
29
 
30
30
  services:
31
31
  cobaia-engine:
32
- image: "ghcr.io/wenathlan/cobaia:${COBAIA_VERSION:-2.0.166}"
32
+ image: "ghcr.io/wenathlan/cobaia:${COBAIA_VERSION:-2.0.167}"
33
33
  # the engine never publishes a port by default: the face proxies it on
34
34
  # the private compose network (the vault precedent). uncomment to serve
35
35
  # the engine lane directly behind your own door:
@@ -41,7 +41,7 @@ services:
41
41
  restart: unless-stopped
42
42
 
43
43
  cobaia-face:
44
- image: "ghcr.io/wenathlan/cobaia:${COBAIA_VERSION:-2.0.166}"
44
+ image: "ghcr.io/wenathlan/cobaia:${COBAIA_VERSION:-2.0.167}"
45
45
  volumes:
46
46
  # the family conf over the default site conf: the resolver law, the
47
47
  # security headers, the gzip and cache law, the /api proxy lane.
package/docker.config CHANGED
@@ -2,7 +2,7 @@
2
2
  "meta": {
3
3
  "name": "docker.config",
4
4
  "title": "cobaia - the container configuration of the monetization site (the compose pair, the nginx face, the site container)",
5
- "version": "2.0.167",
5
+ "version": "2.0.169",
6
6
  "date": "2026-11-06",
7
7
  "language": "en",
8
8
  "sources": [
@@ -45,7 +45,7 @@
45
45
  },
46
46
  "face": {
47
47
  "service": "cobaia-face",
48
- "image": "ghcr.io/wenathlan/cobaia:2.0.167",
48
+ "image": "ghcr.io/wenathlan/cobaia:2.0.169",
49
49
  "surface": "the nginx face: the family conf (nginx.conf) mounted over the default site conf of the same cobaia image — resolver 127.0.0.11, the _headers security law, gzip, the hashed-asset cache, the ^~ /api proxy lane, the faun and root-emit seals, the try_files spa rewrite",
50
50
  "listen": 8080,
51
51
  "seals": [
package/homebrew.rb ADDED
@@ -0,0 +1,25 @@
1
+ # wenathlan-cobaia — the homebrew formula of the family (the homebrew channel).
2
+ # The lane stamps the version and sha256 at push time (the sums derive from
3
+ # the release tarball assets the release lane builds, never hardcoded).
4
+ class WenathlanCobaia < Formula
5
+ desc "The monetization surface — the plans, the support rails and the honest advertisement slots"
6
+ homepage "https://github.com/wenathlan/devthink"
7
+ url "https://github.com/wenathlan/devthink/releases/download/v2.0.167/wenathlan-cobaia-2.0.167.tgz"
8
+ version "2.0.167"
9
+ # sha256 stamped by the lane from the release asset (never hardcoded)
10
+ sha256 "0000000000000000000000000000000000000000000000000000000000000000"
11
+
12
+ depends_on "node"
13
+
14
+ def install
15
+ libexec.install Dir["*"]
16
+ (bin/"wenathlan-cobaia").write <<~SH
17
+ #!/bin/bash
18
+ exec "#{libexec}/cli.js" "$@"
19
+ SH
20
+ end
21
+
22
+ test do
23
+ assert_match "2.0.167", shell_output("#{bin}/wenathlan-cobaia --version")
24
+ end
25
+ end
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wenathlan/cobaia",
3
- "version": "2.0.167",
3
+ "version": "2.0.169",
4
4
  "private": false,
5
5
  "description": "cobaia is the monetization surface of the wenathlan family: the content site that carries the plans, the support rails and the honest advertisement slots while the family apps stay clean; the name is provisional until the owner picks the official one",
6
6
  "license": "GPL-3.0-only",
@@ -14,9 +14,9 @@
14
14
  "test": "vitest run"
15
15
  },
16
16
  "dependencies": {
17
- "@ai-sdk/openai": "^4.0.110",
18
- "@ai-sdk/openai-compatible": "^3.0.86",
19
- "@ai-sdk/provider-utils": "^5.0.75",
17
+ "@ai-sdk/openai": "^4.0.111",
18
+ "@ai-sdk/openai-compatible": "^3.0.87",
19
+ "@ai-sdk/provider-utils": "^5.0.76",
20
20
  "@anthropic-ai/sdk": "^1.6.0",
21
21
  "@biomejs/biome": "^2.6.6",
22
22
  "@capacitor/android": "^8.6.0",
@@ -86,15 +86,15 @@
86
86
  "@types/react-dom": "^19.3.0",
87
87
  "@types/three": "^0.187.0",
88
88
  "@vitejs/plugin-react": "^6.2.1",
89
- "@wenathlan/argan": "~2.0.166",
90
- "@wenathlan/cadria": "~2.0.166",
91
- "@wenathlan/debonair": "~2.0.166",
92
- "@wenathlan/devthink": "~2.0.166",
93
- "@wenathlan/getry": "~2.0.166",
94
- "@wenathlan/saddle": "~2.0.166",
95
- "@wenathlan/vault": "~2.0.166",
89
+ "@wenathlan/argan": "~2.0.168",
90
+ "@wenathlan/cadria": "~2.0.168",
91
+ "@wenathlan/debonair": "~2.0.168",
92
+ "@wenathlan/devthink": "~2.0.168",
93
+ "@wenathlan/getry": "~2.0.168",
94
+ "@wenathlan/saddle": "~2.0.168",
95
+ "@wenathlan/vault": "~2.0.168",
96
96
  "add": "^2.0.9",
97
- "ai": "^7.0.164",
97
+ "ai": "^7.0.165",
98
98
  "autoprefixer": "^10.6.2",
99
99
  "axios": "^1.21.0",
100
100
  "baseline-browser-mapping": "^2.11.35",
@@ -105,7 +105,7 @@
105
105
  "class-variance-authority": "^0.7.1",
106
106
  "clsx": "^2.1.1",
107
107
  "cmdk": "^1.1.1",
108
- "commander": "^15.0.0",
108
+ "commander": "^15.1.0",
109
109
  "date-fns": "^4.4.0",
110
110
  "deepmerge-ts": "^8.0.2",
111
111
  "dockerode": "^5.0.1",
@@ -119,17 +119,16 @@
119
119
  "express": "^5.3.0",
120
120
  "fast-check": "^4.10.2",
121
121
  "fast-uri": "^4.2.3",
122
- "follow-redirects": "^1.16.2",
122
+ "follow-redirects": "^1.16.3",
123
123
  "framer-motion": "^14.10.1",
124
124
  "glob": "^14.0.4",
125
125
  "gsap": "^3.15.1",
126
- "hono": "^4.13.16",
126
+ "hono": "^4.13.17",
127
127
  "ink": "^8.0.0",
128
128
  "input-otp": "^1.5.0",
129
129
  "js-yaml": "^5.5.0",
130
130
  "jsdom": "^31.0.0",
131
131
  "katex": "^0.19.1",
132
- "lucide-react": "^1.70.0",
133
132
  "minimatch": "^11.0.5",
134
133
  "motion": "^14.10.1",
135
134
  "mysql2": "^3.24.6",
@@ -144,7 +143,7 @@
144
143
  "playwright": "^1.65.0",
145
144
  "pnpm": "^12.18.0",
146
145
  "postcss": "^8.5.32",
147
- "postcss-selector-parser": "^7.1.7",
146
+ "postcss-selector-parser": "^7.1.8",
148
147
  "prettier": "^3.9.10",
149
148
  "prisma": "^7.10.1",
150
149
  "proxy-addr": "^2.0.8",
@@ -154,7 +153,7 @@
154
153
  "react-dom": "^19.3.1",
155
154
  "react-hook-form": "^7.91.0",
156
155
  "react-markdown": "^10.1.0",
157
- "react-resizable-panels": "^4.19.1",
156
+ "react-resizable-panels": "^4.20.0",
158
157
  "react-syntax-highlighter": "^16.1.2",
159
158
  "recharts": "^3.10.1",
160
159
  "request-ip": "^3.3.0",
@@ -188,9 +187,9 @@
188
187
  "zustand": "^5.1.0"
189
188
  },
190
189
  "devDependencies": {
191
- "@ai-sdk/openai": "^4.0.110",
192
- "@ai-sdk/openai-compatible": "^3.0.86",
193
- "@ai-sdk/provider-utils": "^5.0.75",
190
+ "@ai-sdk/openai": "^4.0.111",
191
+ "@ai-sdk/openai-compatible": "^3.0.87",
192
+ "@ai-sdk/provider-utils": "^5.0.76",
194
193
  "@anthropic-ai/sdk": "^1.6.0",
195
194
  "@biomejs/biome": "^2.6.6",
196
195
  "@capacitor/android": "^8.6.0",
@@ -260,15 +259,15 @@
260
259
  "@types/react-dom": "^19.3.0",
261
260
  "@types/three": "^0.187.0",
262
261
  "@vitejs/plugin-react": "^6.2.1",
263
- "@wenathlan/argan": "~2.0.166",
264
- "@wenathlan/cadria": "~2.0.166",
265
- "@wenathlan/debonair": "~2.0.166",
266
- "@wenathlan/devthink": "~2.0.166",
267
- "@wenathlan/getry": "~2.0.166",
268
- "@wenathlan/saddle": "~2.0.166",
269
- "@wenathlan/vault": "~2.0.166",
262
+ "@wenathlan/argan": "~2.0.168",
263
+ "@wenathlan/cadria": "~2.0.168",
264
+ "@wenathlan/debonair": "~2.0.168",
265
+ "@wenathlan/devthink": "~2.0.168",
266
+ "@wenathlan/getry": "~2.0.168",
267
+ "@wenathlan/saddle": "~2.0.168",
268
+ "@wenathlan/vault": "~2.0.168",
270
269
  "add": "^2.0.9",
271
- "ai": "^7.0.164",
270
+ "ai": "^7.0.165",
272
271
  "autoprefixer": "^10.6.2",
273
272
  "axios": "^1.21.0",
274
273
  "baseline-browser-mapping": "^2.11.35",
@@ -279,7 +278,7 @@
279
278
  "class-variance-authority": "^0.7.1",
280
279
  "clsx": "^2.1.1",
281
280
  "cmdk": "^1.1.1",
282
- "commander": "^15.0.0",
281
+ "commander": "^15.1.0",
283
282
  "date-fns": "^4.4.0",
284
283
  "deepmerge-ts": "^8.0.2",
285
284
  "dockerode": "^5.0.1",
@@ -293,17 +292,16 @@
293
292
  "express": "^5.3.0",
294
293
  "fast-check": "^4.10.2",
295
294
  "fast-uri": "^4.2.3",
296
- "follow-redirects": "^1.16.2",
295
+ "follow-redirects": "^1.16.3",
297
296
  "framer-motion": "^14.10.1",
298
297
  "glob": "^14.0.4",
299
298
  "gsap": "^3.15.1",
300
- "hono": "^4.13.16",
299
+ "hono": "^4.13.17",
301
300
  "ink": "^8.0.0",
302
301
  "input-otp": "^1.5.0",
303
302
  "js-yaml": "^5.5.0",
304
303
  "jsdom": "^31.0.0",
305
304
  "katex": "^0.19.1",
306
- "lucide-react": "^1.70.0",
307
305
  "minimatch": "^11.0.5",
308
306
  "motion": "^14.10.1",
309
307
  "mysql2": "^3.24.6",
@@ -318,7 +316,7 @@
318
316
  "playwright": "^1.65.0",
319
317
  "pnpm": "^12.18.0",
320
318
  "postcss": "^8.5.32",
321
- "postcss-selector-parser": "^7.1.7",
319
+ "postcss-selector-parser": "^7.1.8",
322
320
  "prettier": "^3.9.10",
323
321
  "prisma": "^7.10.1",
324
322
  "proxy-addr": "^2.0.8",
@@ -328,7 +326,7 @@
328
326
  "react-dom": "^19.3.1",
329
327
  "react-hook-form": "^7.91.0",
330
328
  "react-markdown": "^10.1.0",
331
- "react-resizable-panels": "^4.19.1",
329
+ "react-resizable-panels": "^4.20.0",
332
330
  "react-syntax-highlighter": "^16.1.2",
333
331
  "recharts": "^3.10.1",
334
332
  "request-ip": "^3.3.0",
@@ -362,9 +360,9 @@
362
360
  "zustand": "^5.1.0"
363
361
  },
364
362
  "overrides": {
365
- "@ai-sdk/openai": "^4.0.110",
366
- "@ai-sdk/openai-compatible": "^3.0.86",
367
- "@ai-sdk/provider-utils": "^5.0.75",
363
+ "@ai-sdk/openai": "^4.0.111",
364
+ "@ai-sdk/openai-compatible": "^3.0.87",
365
+ "@ai-sdk/provider-utils": "^5.0.76",
368
366
  "@anthropic-ai/sdk": "^1.6.0",
369
367
  "@biomejs/biome": "^2.6.6",
370
368
  "@capacitor/android": "^8.6.0",
@@ -434,15 +432,15 @@
434
432
  "@types/react-dom": "^19.3.0",
435
433
  "@types/three": "^0.187.0",
436
434
  "@vitejs/plugin-react": "^6.2.1",
437
- "@wenathlan/argan": "~2.0.166",
438
- "@wenathlan/cadria": "~2.0.166",
439
- "@wenathlan/debonair": "~2.0.166",
440
- "@wenathlan/devthink": "~2.0.166",
441
- "@wenathlan/getry": "~2.0.166",
442
- "@wenathlan/saddle": "~2.0.166",
443
- "@wenathlan/vault": "~2.0.166",
435
+ "@wenathlan/argan": "~2.0.168",
436
+ "@wenathlan/cadria": "~2.0.168",
437
+ "@wenathlan/debonair": "~2.0.168",
438
+ "@wenathlan/devthink": "~2.0.168",
439
+ "@wenathlan/getry": "~2.0.168",
440
+ "@wenathlan/saddle": "~2.0.168",
441
+ "@wenathlan/vault": "~2.0.168",
444
442
  "add": "^2.0.9",
445
- "ai": "^7.0.164",
443
+ "ai": "^7.0.165",
446
444
  "autoprefixer": "^10.6.2",
447
445
  "axios": "^1.21.0",
448
446
  "baseline-browser-mapping": "^2.11.35",
@@ -453,7 +451,7 @@
453
451
  "class-variance-authority": "^0.7.1",
454
452
  "clsx": "^2.1.1",
455
453
  "cmdk": "^1.1.1",
456
- "commander": "^15.0.0",
454
+ "commander": "^15.1.0",
457
455
  "date-fns": "^4.4.0",
458
456
  "deepmerge-ts": "^8.0.2",
459
457
  "dockerode": "^5.0.1",
@@ -467,17 +465,16 @@
467
465
  "express": "^5.3.0",
468
466
  "fast-check": "^4.10.2",
469
467
  "fast-uri": "^4.2.3",
470
- "follow-redirects": "^1.16.2",
468
+ "follow-redirects": "^1.16.3",
471
469
  "framer-motion": "^14.10.1",
472
470
  "glob": "^14.0.4",
473
471
  "gsap": "^3.15.1",
474
- "hono": "^4.13.16",
472
+ "hono": "^4.13.17",
475
473
  "ink": "^8.0.0",
476
474
  "input-otp": "^1.5.0",
477
475
  "js-yaml": "^5.5.0",
478
476
  "jsdom": "^31.0.0",
479
477
  "katex": "^0.19.1",
480
- "lucide-react": "^1.70.0",
481
478
  "minimatch": "^11.0.5",
482
479
  "motion": "^14.10.1",
483
480
  "mysql2": "^3.24.6",
@@ -492,7 +489,7 @@
492
489
  "playwright": "^1.65.0",
493
490
  "pnpm": "^12.18.0",
494
491
  "postcss": "^8.5.32",
495
- "postcss-selector-parser": "^7.1.7",
492
+ "postcss-selector-parser": "^7.1.8",
496
493
  "prettier": "^3.9.10",
497
494
  "prisma": "^7.10.1",
498
495
  "proxy-addr": "^2.0.8",
@@ -502,7 +499,7 @@
502
499
  "react-dom": "^19.3.1",
503
500
  "react-hook-form": "^7.91.0",
504
501
  "react-markdown": "^10.1.0",
505
- "react-resizable-panels": "^4.19.1",
502
+ "react-resizable-panels": "^4.20.0",
506
503
  "react-syntax-highlighter": "^16.1.2",
507
504
  "recharts": "^3.10.1",
508
505
  "request-ip": "^3.3.0",
@@ -548,5 +545,6 @@
548
545
  "@swc/core",
549
546
  "pnpm",
550
547
  "protobufjs"
551
- ]
548
+ ],
549
+ "optionalDependencies": {}
552
550
  }
@@ -48,7 +48,6 @@ minimumReleaseAgeExclude:
48
48
  - '@opencode-ai/sdk@1.19.5'
49
49
  - react-resizable-panels@4.15.1 || 4.15.2 || 4.15.3 || 4.16.0 || 4.16.1 || 4.17.0 || 4.18.0 || 4.18.1 || 4.19.0 || 4.19.1
50
50
  - '@types/google.maps@3.66.9 || 3.66.10'
51
- - lucide-react@1.64.0 || 1.65.0 || 1.66.0 || 1.67.0 || 1.68.0 || 1.69.0 || 1.70.0
52
51
  - playwright@1.65.0
53
52
  - playwright-core@1.65.0
54
53
  - '@anthropic-ai/sdk@1.6.0'
@@ -56,13 +55,13 @@ minimumReleaseAgeExclude:
56
55
  - '@tanstack/query-core@5.106.1 || 5.107.1'
57
56
  - '@tanstack/react-query@5.106.1 || 5.107.1'
58
57
  - openai@7.52.0 || 7.53.0
59
- - '@wenathlan/argan@2.0.155 || 2.0.165 || 2.0.166'
60
- - '@wenathlan/cadria@2.0.154 || 2.0.155 || 2.0.156 || 2.0.165 || 2.0.166 || 2.1.8'
61
- - '@wenathlan/debonair@2.0.154 || 2.0.155 || 2.0.156 || 2.0.165 || 2.0.166 || 2.1.8'
62
- - '@wenathlan/devthink@2.0.154 || 2.0.155 || 2.0.156 || 2.0.165 || 2.0.166 || 2.1.7'
63
- - '@wenathlan/getry@2.0.154 || 2.0.155 || 2.0.156 || 2.0.165 || 2.0.166'
64
- - '@wenathlan/saddle@2.0.154 || 2.0.155 || 2.0.156 || 2.0.165 || 2.0.166 || 2.1.8'
65
- - '@wenathlan/vault@2.0.152 || 2.0.153 || 2.0.154 || 2.0.155 || 2.0.156 || 2.0.165 || 2.0.166 || 2.1.8'
58
+ - '@wenathlan/argan@2.0.155 || 2.0.165 || 2.0.166 || 2.0.167'
59
+ - '@wenathlan/cadria@2.0.154 || 2.0.155 || 2.0.156 || 2.0.165 || 2.0.166 || 2.1.8 || 2.0.167'
60
+ - '@wenathlan/debonair@2.0.154 || 2.0.155 || 2.0.156 || 2.0.165 || 2.0.166 || 2.1.8 || 2.0.167'
61
+ - '@wenathlan/devthink@2.0.154 || 2.0.155 || 2.0.156 || 2.0.165 || 2.0.166 || 2.1.7 || 2.0.167'
62
+ - '@wenathlan/getry@2.0.154 || 2.0.155 || 2.0.156 || 2.0.165 || 2.0.166 || 2.0.167'
63
+ - '@wenathlan/saddle@2.0.154 || 2.0.155 || 2.0.156 || 2.0.165 || 2.0.166 || 2.1.8 || 2.0.167'
64
+ - '@wenathlan/vault@2.0.152 || 2.0.153 || 2.0.154 || 2.0.155 || 2.0.156 || 2.0.165 || 2.0.166 || 2.1.8 || 2.0.167'
66
65
  - jsdom@31.0.0
67
66
  - pnpm@12.18.0
68
67
  - "@pnpm/exe.linux-x64@12.18.0"
@@ -90,10 +89,10 @@ minimumReleaseAgeExclude:
90
89
  - tailwindcss@4.3.4 || 4.3.5
91
90
  - vitest@5.1.0
92
91
  - gsap@3.15.1
93
- - '@wenathlan/cobaia@2.0.166'
94
- - '@wenathlan/forge@2.0.166'
95
- - '@wenathlan/foundry@2.0.166'
96
- - '@wenathlan/stealthhead@2.0.166'
92
+ - '@wenathlan/cobaia@2.0.166 || 2.0.167'
93
+ - '@wenathlan/forge@2.0.166 || 2.0.167'
94
+ - '@wenathlan/foundry@2.0.166 || 2.0.167'
95
+ - '@wenathlan/stealthhead@2.0.166 || 2.0.167'
97
96
  - framer-motion@14.10.1
98
97
  - motion-dom@14.10.1
99
98
  - motion@14.10.1
package/pom.xml CHANGED
@@ -12,7 +12,7 @@
12
12
  <scm><url>https://github.com/wenathlan/devthink</url><connection>scm:git:https://github.com/wenathlan/devthink.git</connection></scm>
13
13
  <distributionManagement><repository><id>github</id><name>GitHub Packages</name><url>https://maven.pkg.github.com/wenathlan/devthink</url></repository></distributionManagement>
14
14
  <properties>
15
- <revision>2.0.167</revision>
15
+ <revision>2.0.169</revision>
16
16
  </properties>
17
17
  <build>
18
18
  <resources>
package/pyproject.toml ADDED
@@ -0,0 +1,23 @@
1
+ # cobaia — the python documentation envelope of the family (the pypi channel).
2
+ # Ships the same envelope the gem face packs: README, docs and tests.
3
+ # Built by the publish lane with `python -m build` (PEP 517); the version
4
+ # rides the COBAIA_VERSION environment the metadata lockstep stamps — the
5
+ # pyproject table cannot fetch an environment the gemspec reads, so the
6
+ # static version below is the fallback the lane sed-stamps before building.
7
+ [build-system]
8
+ requires = ["setuptools>=75"]
9
+ build-backend = "setuptools.build_meta"
10
+
11
+ [project]
12
+ name = "wenathlan-cobaia"
13
+ version = "2.0.169"
14
+ authors = [{name = "wenathlan"}]
15
+ description = "The monetization surface — the plans, the support rails and the honest advertisement slots"
16
+ readme = "README.md"
17
+ license = {text = "GPL-3.0-only"}
18
+ requires-python = ">=3.11"
19
+
20
+ # The envelope carries no python code — the empty package list keeps the
21
+ # build honest while the MANIFEST.in packs the envelope files.
22
+ [tool.setuptools]
23
+ packages = []
@@ -20,28 +20,24 @@
20
20
  // this module never judges engine vocabulary, so the mirror cannot drift
21
21
  // when the registry grows). The module never spawns anything and resolves
22
22
  // no join: it names the lanes' truth; the platform resolves the sandbox.
23
- // Zero consumer data, zero imports.
23
+ // Zero consumer data; the one import below is the owner's lane seat
24
+ // factory and nothing else enters.
25
+ //
26
+ // The engine seat (wave W5, the dedup law): the seat resolver, the env
27
+ // reader and the lane lookup no longer live in this file — they ride the
28
+ // saddle factory (laneseating of ../saddle/workloadlaw.ts, the owner's
29
+ // workload law) bound once to this app's own data, re-exported under the
30
+ // same names the surface always spoke. The rows stay mirrored (the drift
31
+ // pin the battery wants), only the engine moved: zero behavior change,
32
+ // zero public-surface change.
33
+
34
+ import { type AppWorkloadLane, type LaneSeatResult, laneseating } from "../saddle/workloadlaw.ts";
24
35
 
25
36
  /** one mirrored workload lane row — the same five keys the engine law pins
26
- * (app, lane, role, demand, today). */
27
- export type AppWorkloadLane = {
28
- /** the official app slug every row carries. */
29
- readonly app: string;
30
- /** the lane id inside the app (kebab-case, the engine catalog id). */
31
- readonly lane: string;
32
- /** what the lane does, in one sentence (the engine row's sentence). */
33
- readonly role: string;
34
- /** the demand the lane puts on the sandbox (gpu, network, isolation,
35
- * boot budget — never a modality name: the nuclear law). */
36
- readonly demand: {
37
- readonly gpu: boolean;
38
- readonly network: boolean;
39
- readonly isolation: "process" | "namespace" | "vm" | "hardware";
40
- readonly bootbudget?: number;
41
- };
42
- /** where the heavy pass runs today — the honest truth the census reads. */
43
- readonly today: "engine-lane" | "app-lane";
44
- };
37
+ * (app, lane, role, demand, today); the shape itself rides the owner's
38
+ * law now (wave W5 — saddle/workloadlaw.ts answers the type once),
39
+ * re-exported under the historical surface name. */
40
+ export type { AppWorkloadLane };
45
41
 
46
42
  /** the app slug every mirrored row carries. */
47
43
  export const APPSLUG = "cobaia";
@@ -83,10 +79,13 @@ export const SANDBOXLANEENV = "COBAIA_SANDBOX_LANE";
83
79
  * modality id the deploy named (validated by the platform's join at
84
80
  * dispatch, never judged here). every answer is honest: an absent or
85
81
  * blank choice answers the declared default, never a silent switch. */
86
- export type LaneSeatResult =
87
- | { ok: true; seat: "local"; sandboxed: false }
88
- | { ok: true; seat: "join"; sandboxed: true; pinned: false }
89
- | { ok: true; seat: string; sandboxed: true; pinned: true };
82
+ export type { LaneSeatResult };
83
+
84
+ /** the lane seat engine of this app — the saddle factory bound once to
85
+ * this app's own data (the dedup law: the engine lives in the owner, the
86
+ * app keeps its data), the seats re-exported below under the names the
87
+ * surface always spoke. */
88
+ const seating = laneseating({ slug: APPSLUG, envvar: SANDBOXLANEENV, lanes: WORKLOADLANES });
90
89
 
91
90
  /**
92
91
  * Resolves the sandbox lane seat of this application — the deploy's
@@ -101,16 +100,7 @@ export type LaneSeatResult =
101
100
  * @param choice the deploy's choice (the env value or the config row).
102
101
  * @returns the seat declaration.
103
102
  */
104
- export function lanesandbox(choice: string | undefined): LaneSeatResult {
105
- const name = choice?.trim() ?? "";
106
- if (name.length === 0 || name === "local") {
107
- return { ok: true, seat: "local", sandboxed: false };
108
- }
109
- if (name === "join") {
110
- return { ok: true, seat: "join", sandboxed: true, pinned: false };
111
- }
112
- return { ok: true, seat: name, sandboxed: true, pinned: true };
113
- }
103
+ export const lanesandbox = seating.lanesandbox;
114
104
 
115
105
  /**
116
106
  * Reads the lane seat off one environment lookup — the deploy pins
@@ -121,9 +111,7 @@ export function lanesandbox(choice: string | undefined): LaneSeatResult {
121
111
  * @param lookup the environment lookup function (the env carrier).
122
112
  * @returns the seat declaration.
123
113
  */
124
- export function lanesandboxfromenv(lookup: (key: string) => string | undefined): LaneSeatResult {
125
- return lanesandbox(lookup(SANDBOXLANEENV));
126
- }
114
+ export const lanesandboxfromenv = seating.lanesandboxfromenv;
127
115
 
128
116
  /**
129
117
  * Answers one mirrored lane row by lane id — the lookup the app surfaces
@@ -133,6 +121,4 @@ export function lanesandboxfromenv(lookup: (key: string) => string | undefined):
133
121
  * @returns the mirrored row, or undefined when the app carries no such
134
122
  * lane.
135
123
  */
136
- export function laneof(lane: string): AppWorkloadLane | undefined {
137
- return WORKLOADLANES.find((row) => row.lane === lane);
138
- }
124
+ export const laneof = seating.laneof;
package/sol/Sol.tsx CHANGED
@@ -29,7 +29,7 @@ import OnboardingAnchor from "./onboarding/onboarding";
29
29
  import LegalAnchor from "./legal/legal";
30
30
  import NotFoundAnchor from "./notfound/notfound";
31
31
  import PricingAnchor from "./pricing/pricing";
32
- import { EntryGate } from "./wingets";
32
+ import { EntryGate } from "../wingets";
33
33
  import { Shell } from "./shell/Shell";
34
34
  import SupportAnchor from "./support/support";
35
35
 
package/sol/apps/apps.tsx CHANGED
@@ -17,7 +17,7 @@ import { useContent } from "../../content.ts";
17
17
  import { familyurl } from "../../familyurl";
18
18
  import { label, labelfill } from "../../labels";
19
19
  import { roster } from "../../monetization.ts";
20
- import { AdSlot } from "../wingets";
20
+ import { AdSlot } from "../../wingets";
21
21
 
22
22
  export function Apps() {
23
23
  useContent();
package/sol/blog/blog.tsx CHANGED
@@ -17,7 +17,7 @@ import type { CSSProperties } from "react";
17
17
  import { useContent } from "../../content.ts";
18
18
  import { label, labelfill } from "../../labels";
19
19
  import { type blogpost, postindex, postwords } from "../../monetization";
20
- import { AdSlot } from "../wingets";
20
+ import { AdSlot } from "../../wingets";
21
21
 
22
22
  /** the meta line of one post: the date and the honest word count. */
23
23
  function PostMeta({ post }: { post: blogpost }) {
package/sol/home/home.tsx CHANGED
@@ -22,7 +22,7 @@ import { useContent } from "../../content.ts";
22
22
  import { familyurl } from "../../familyurl";
23
23
  import { type LabelKey, label, labelfill } from "../../labels";
24
24
  import { roster } from "../../monetization.ts";
25
- import { AdSlot, BrandMark, EntryGate } from "../wingets";
25
+ import { AdSlot, BrandMark, EntryGate } from "../../wingets";
26
26
 
27
27
  /** the featured deploy units of the landing preview (the full directory
28
28
  * lives on /apps): the OS, the engine, the store and one studio — read
@@ -31,7 +31,7 @@ import { useCallback, useEffect, useState } from "react";
31
31
  import { Link } from "wouter";
32
32
  import { label } from "../../labels";
33
33
  import { markOnboardingStage } from "../../onboardingstate.ts";
34
- import { BrandMark, IntroFooter, IntroPlans, IntroSplash } from "../wingets";
34
+ import { BrandMark, IntroFooter, IntroPlans, IntroSplash } from "../../wingets";
35
35
 
36
36
  /** the lifecycle of the opening act: resolving (the motion preference
37
37
  * decides) → playing (the akash floor over the landing) → done (the