@omega.js/desktop 0.53.0 → 0.54.1

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.
Files changed (161) hide show
  1. package/README.md +38 -38
  2. package/dist/cli-run.js +4 -1
  3. package/dist/cli.js +2 -2
  4. package/dist/commands/cdp/client.js +1 -1
  5. package/dist/commands/cdp.js +1 -1
  6. package/dist/commands/clean.js +2 -3
  7. package/dist/commands/dev.js +25 -0
  8. package/dist/commands/lib/ensure-target.js +12 -17
  9. package/dist/commands/lib/migrate.js +17 -0
  10. package/dist/commands/logs.js +1 -1
  11. package/dist/commands/release.js +1 -1
  12. package/dist/commands/test.js +4 -4
  13. package/dist/commands/update.js +5 -4
  14. package/dist/defaults/.github/workflows/build.yml +18 -18
  15. package/dist/defaults/_.gitignore +0 -2
  16. package/dist/defaults/_mas/README.md +3 -3
  17. package/dist/defaults/config/certs/README.md +1 -1
  18. package/dist/defaults/config/omega.json5 +36 -36
  19. package/dist/defaults/docs/README.md +3 -3
  20. package/dist/defaults/gulpfile.js +1 -1
  21. package/dist/defaults/hooks/build/post.js +1 -1
  22. package/dist/defaults/hooks/build/pre.js +1 -1
  23. package/dist/defaults/hooks/notarize/post.js +2 -2
  24. package/dist/defaults/hooks/release/post.js +1 -1
  25. package/dist/defaults/hooks/release/pre.js +1 -1
  26. package/dist/defaults/src/assets/scss/pages/about.scss +1 -1
  27. package/dist/defaults/src/assets/scss/pages/main.scss +1 -1
  28. package/dist/defaults/src/assets/scss/pages/settings.scss +1 -1
  29. package/dist/defaults/src/integrations/context-menu/index.js +11 -11
  30. package/dist/defaults/src/integrations/menu/index.js +5 -5
  31. package/dist/defaults/src/integrations/tray/index.js +9 -9
  32. package/dist/defaults/src/main.js +2 -2
  33. package/dist/defaults/src/preload.js +1 -1
  34. package/dist/defaults/test/README.md +3 -3
  35. package/dist/defaults/test/_init.js +1 -1
  36. package/dist/gulp/tasks/audit.js +5 -8
  37. package/dist/lib/restart-manager/index.js +1 -1
  38. package/dist/lib/restart-manager/install.js +1 -1
  39. package/dist/lib/restart-manager/protocol.js +1 -1
  40. package/dist/main.js +4 -3
  41. package/dist/preload.js +1 -1
  42. package/dist/test/suites/build/audit.test.js +20 -7
  43. package/dist/test/suites/build/build-workflow-jobs.test.js +2 -2
  44. package/dist/test/suites/build/cli.test.js +28 -0
  45. package/dist/test/suites/build/defaults-em-dash.test.js +22 -0
  46. package/dist/test/suites/build/defaults-scaffold.test.js +19 -5
  47. package/dist/test/suites/build/deploy-direct.test.js +7 -5
  48. package/dist/test/suites/build/deploy-dispatch.test.js +2 -1
  49. package/dist/test/suites/build/deploy-hook.test.js +4 -2
  50. package/dist/test/suites/build/dev-verb.test.js +67 -0
  51. package/dist/test/suites/build/ensure-target.test.js +11 -3
  52. package/dist/test/suites/build/merge-line-files.test.js +6 -6
  53. package/dist/test/suites/build/migrate.test.js +29 -0
  54. package/dist/test/suites/build/project-scripts-deps.test.js +6 -10
  55. package/dist/test/suites/build/runner-env-write.test.js +73 -0
  56. package/dist/test/suites/build/runner.test.js +9 -8
  57. package/dist/test/suites/build/setup-scripts.test.js +27 -0
  58. package/dist/test/suites/build/validate-config.test.js +13 -2
  59. package/dist/test/suites/build/verb-logs.test.js +20 -0
  60. package/dist/test/suites/renderer/window-desktop-surface.test.js +1 -1
  61. package/dist/utils/build-pipeline.js +4 -4
  62. package/dist/utils/runner-env.js +13 -28
  63. package/dist/vendor/config/company.js +46 -14
  64. package/dist/vendor/config/defaults.js +30 -7
  65. package/dist/vendor/config/edit.js +25 -3
  66. package/dist/vendor/config/env-delivery.js +1 -1
  67. package/dist/vendor/config/env-schema.js +3 -6
  68. package/dist/vendor/config/env.js +34 -22
  69. package/dist/vendor/config/index.js +13 -17
  70. package/dist/vendor/config/load.js +15 -7
  71. package/dist/vendor/config/repo.js +10 -27
  72. package/dist/vendor/config/schema-client.js +64 -0
  73. package/dist/vendor/config/schema-cloud.js +38 -0
  74. package/dist/vendor/config/schema-manager.js +118 -0
  75. package/dist/vendor/config/schema-overrides.js +68 -0
  76. package/dist/vendor/config/schema.js +99 -152
  77. package/dist/vendor/config/validate.js +97 -77
  78. package/dist/vendor/devkit/agents-md.js +233 -0
  79. package/dist/vendor/devkit/attach-log-file.js +15 -1
  80. package/dist/vendor/devkit/ci-workflows.js +30 -30
  81. package/dist/vendor/devkit/cli-router.js +13 -7
  82. package/dist/vendor/devkit/defaults-engine.js +9 -43
  83. package/dist/vendor/devkit/deploy-snapshot.js +44 -9
  84. package/dist/vendor/devkit/env-lines.js +183 -0
  85. package/dist/vendor/devkit/local.js +62 -10
  86. package/dist/vendor/devkit/lockfile.js +32 -13
  87. package/dist/vendor/devkit/logger.js +7 -2
  88. package/dist/vendor/devkit/merge-line-files.js +219 -176
  89. package/dist/vendor/devkit/omega-bin.js +208 -111
  90. package/dist/vendor/devkit/preludes/docs-sync.js +52 -0
  91. package/dist/vendor/devkit/preludes/index.js +1 -0
  92. package/dist/vendor/devkit/target-picker.js +45 -0
  93. package/dist/vendor/devkit/test/dashed-files.js +37 -0
  94. package/dist/vendor/devkit/test/run-verb-under-tee.js +71 -0
  95. package/dist/vendor/devkit/update.js +15 -15
  96. package/dist/vendor/devkit/verb-scripts.js +40 -0
  97. package/dist/vendor/devkit/verbs.js +170 -0
  98. package/package.json +18 -24
  99. package/dist/commands/install.js +0 -37
  100. package/dist/defaults/AGENTS.md +0 -119
  101. package/dist/defaults/CLAUDE.md +0 -1
  102. package/dist/vendor/config/env-retired.js +0 -137
  103. package/dist/vendor/config/retired-keys.js +0 -635
  104. package/docs/analytics.md +0 -140
  105. package/docs/app-state.md +0 -92
  106. package/docs/audit.md +0 -69
  107. package/docs/auth.md +0 -284
  108. package/docs/auto-updater.md +0 -243
  109. package/docs/boot-sequence.md +0 -44
  110. package/docs/build-system.md +0 -169
  111. package/docs/cdp-debugging.md +0 -169
  112. package/docs/common-mistakes.md +0 -21
  113. package/docs/config-schema.md +0 -120
  114. package/docs/context-menu.md +0 -112
  115. package/docs/context.md +0 -81
  116. package/docs/css.md +0 -84
  117. package/docs/deep-link.md +0 -186
  118. package/docs/environment-detection.md +0 -112
  119. package/docs/fontawesome.md +0 -109
  120. package/docs/hooks.md +0 -89
  121. package/docs/icons.md +0 -79
  122. package/docs/index.md +0 -328
  123. package/docs/installer-options.md +0 -165
  124. package/docs/ipc.md +0 -61
  125. package/docs/lib-modules.md +0 -53
  126. package/docs/logging.md +0 -227
  127. package/docs/menu.md +0 -160
  128. package/docs/releasing.md +0 -239
  129. package/docs/remote-config.md +0 -118
  130. package/docs/remote-scripts.md +0 -144
  131. package/docs/restart-manager.md +0 -144
  132. package/docs/runner.md +0 -290
  133. package/docs/sentry.md +0 -97
  134. package/docs/shared/agent-docs.md +0 -89
  135. package/docs/shared/analytics.md +0 -612
  136. package/docs/shared/brands.md +0 -57
  137. package/docs/shared/breaking-changes.md +0 -917
  138. package/docs/shared/config.md +0 -1948
  139. package/docs/shared/deploys.md +0 -341
  140. package/docs/shared/icons.md +0 -219
  141. package/docs/shared/local-dev.md +0 -167
  142. package/docs/shared/logging.md +0 -205
  143. package/docs/shared/monitoring.md +0 -167
  144. package/docs/shared/publishing.md +0 -187
  145. package/docs/shared/rulings.md +0 -34
  146. package/docs/shared/testing.md +0 -147
  147. package/docs/shared/theming.md +0 -629
  148. package/docs/shared/translation.md +0 -342
  149. package/docs/shared/updates.md +0 -61
  150. package/docs/signing.md +0 -293
  151. package/docs/startup.md +0 -142
  152. package/docs/storage.md +0 -59
  153. package/docs/templating.md +0 -101
  154. package/docs/test-boot-layer.md +0 -157
  155. package/docs/test-framework.md +0 -362
  156. package/docs/themes.md +0 -149
  157. package/docs/tooltips.md +0 -99
  158. package/docs/tray.md +0 -164
  159. package/docs/usage.md +0 -58
  160. package/docs/verts.md +0 -62
  161. package/docs/windows.md +0 -149
@@ -1,205 +0,0 @@
1
- # Logging — the tag contract and the file contract
2
-
3
- Two contracts live here. **What a line says**: every log line carries one identity tag.
4
- **Where a line lands**: every dev server, build, test runner, emulator and watcher tees
5
- its whole run to a greppable file ([#197](https://github.com/Omega-JS-Stack/omega/issues/197)).
6
- The tag contract first, the file contract from [The file tee](#the-file-tee) down.
7
-
8
- ## The tag contract
9
-
10
- Every log line in the ecosystem carries ONE identity tag: `[@omega.js/<package>:<module>]`.
11
- The module segment is the file's identity (`push`, `watcher`, `auth:sync` — sub-modules
12
- join with `:`). Ratified 2026-07-29 ([#12](https://github.com/Omega-JS-Stack/omega/issues/12)).
13
-
14
- ### The debug level (`OMEGA_DEBUG`)
15
-
16
- `debug` is the ONE opt-in level ([#230](https://github.com/Omega-JS-Stack/omega/issues/230)): a
17
- backend `ctx.debug(...)` line is dropped whole — console AND the log file — unless
18
- `OMEGA_DEBUG` is set (truthy STRING semantics, the house's `TEST_EXTENDED_MODE` idiom:
19
- `OMEGA_DEBUG=0` reads as on; read live per line). Fat payloads belong there: full user
20
- records, raw webhook bodies. Two related quieting rules from the same issue: boot-time
21
- environment notes (the TEST banner, the resolved-mode line) are suppressed under the
22
- emulator (`FUNCTIONS_EMULATOR`) and latched once-per-process everywhere else, and the
23
- `omega dev` leg output collapses consecutive duplicate lines into one plus a
24
- `(repeated N×)` note.
25
-
26
- ### PII and secrets
27
-
28
- **A log line names a user by address or uid, never by serializing the document.** A user
29
- document carries `api.privateKey`, the consent records, the signup IP and the attribution,
30
- and a backend line lands in Cloud Logging for the whole retention window — one
31
- `JSON.stringify(user)` stores a live credential there in plain text
32
- ([#632](https://github.com/Omega-JS-Stack/omega/issues/632)). The rule covers every object
33
- a caller hands in, not just user docs: log the identifier, not the payload — a payload's
34
- SHAPE (its top-level key names, a count) is fair game when the line needs it. A secret that
35
- has to be acknowledged at all renders through backend's `redactSecret()`
36
- (`***<last 4> (<n> chars)`), and a fat payload worth having while debugging goes to the
37
- `debug` level above, never to `log`.
38
-
39
- **A third party's credential is a credential.** An OAuth token exchange response holds the
40
- access, refresh and id tokens; the identity a provider answers with is the user's PII. Both
41
- used to ride `ctx.log` on every connection link
42
- ([#641](https://github.com/Omega-JS-Stack/omega/issues/641)) — a line names the provider,
43
- the uid and whether the exchange succeeded, and nothing else. The same rule reaches an
44
- HTTP helper's own switches: `wonderful-fetch`'s `log: true` prints its whole configuration,
45
- headers included, so it never rides a request carrying ANY credential header — an
46
- `authorization` token, or the `omega-admin-key` an internal call authenticates with
47
- ([#702](https://github.com/Omega-JS-Stack/omega/issues/702)). Backend's
48
- `test/security/fetch-log-secrets.test.js` scans the source and fails that pairing.
49
-
50
- ### The two surfaces
51
-
52
- - **Build-time** (CLI, gulp, tests, the manager's services): the devkit logger prints a
53
- timestamp bracket first — `[HH:MM:SS] [@omega.js/web:watcher] message`. Construction
54
- stays `new Logger('watcher')`; the package segment derives at construction from the
55
- constructing file's nearest `package.json` (stack-based, cached, non-throwing —
56
- fallback `@omega.js/devkit`). Home: `packages/devkit/src/logger.js`.
57
- - **Runtime** (browser, electron renderer/main, extension): NO timestamp — devtools
58
- stamps lines. Each runtime surface has its own logger emitting its own package
59
- segment: client `createLogger()` (`packages/client/src/modules/logger.js`), web
60
- core/js `createLogger()` (`packages/web/core/js/libs/logger.js`), and the
61
- desktop/extension `logger-lite` lineage.
62
- - **Backend** (Cloud Functions) is server-side runtime: in PRODUCTION Cloud Logging
63
- stamps every entry, so every level emits the tag ALONE —
64
- `[@omega.js/backend:<module>] <invocation-id>[ <logPrefix>]: message`. Outside
65
- production (the emulator's `>` prefix carries no time; plain local runs have
66
- nothing at all) the same `[HH:MM:SS]` bracket the build-time logger prints opens
67
- the line ([#130](https://github.com/Omega-JS-Stack/omega/issues/130)). The module
68
- segment is the invocation's function name, which the context already knows
69
- (`options.functionName || FUNCTION_TARGET`). Home:
70
- `packages/backend/src/omega/context/logging.js`. A shared backend module
71
- that logs outside a ctx carries its own file identity.
72
-
73
- ### Markers and exemptions
74
-
75
- - `[DRY RUN]` survives as a MARKER after the tag, never as an identity tag (casing
76
- unified; the lowercase form is retired).
77
- - The manager's reconciliation report is product output, not logging — it stays
78
- untagged by design (ruling 2026-07-29). That covers ALL its rows: the indented
79
- `✓ / ~ / +` lines AND the `[DRY RUN]` rows printed through the same report
80
- (there the marker may open the line, since the report carries no tags at all).
81
- - Backend's record classifiers (`skip`, `expire`, `authenticated`, `test-mode`, …)
82
- classify one function's records, not modules. They survive as leading WORDS, never
83
- brackets (`ctx.log('local: Clearing...')`) — a bracket there would read as a second
84
- identity tag ([#121](https://github.com/Omega-JS-Stack/omega/issues/121)).
85
- - Test harnesses and fixtures are exempt; web's `core/js/pages/test/` demo pages are
86
- NOT (they ship).
87
-
88
- ### Enforcement
89
-
90
- `scripts/log-tags.test.js` (runs in root `test:packages`) scans `packages/*/src` and
91
- `packages/web/core/js` for any log call whose message starts with a static bracket tag
92
- that is not `@omega.js/…` or the dry-run marker. It self-tests its own red path. New
93
- code uses the surface's shared logger — never a hand-written bracket prefix.
94
-
95
- ## The file tee
96
-
97
- Nothing an OMEGA surface prints is terminal-only. ONE abstraction does it —
98
- `packages/devkit/src/attach-log-file.js`, vendored into every framework — and every
99
- surface attaches it at its entry point.
100
-
101
- - **Both sinks, always.** A chunk reaches the terminal exactly as written (colors
102
- intact) and the file with ANSI escapes stripped, so `grep` and `tail -f` read clean.
103
- - **Synchronous fd writes.** A stream's buffer dies with the process, dropping exactly
104
- the lines that describe a crash. The per-write syscall buys the crash tail.
105
- - **Truncate on attach.** A new launch clears the previous run's log — no history, no
106
- rotation (the ruled retention, see below).
107
- - **Stackable.** `createTee()` returns an independent tee; an attach captures the
108
- CURRENT writers, so tees nest and each detach restores exactly what it found (LIFO).
109
- The default export is the process-wide singleton, which is what a CLI verb wants; two
110
- attaches of different paths on the singleton stack the same way (a verb run inside
111
- another verb's process), and its `detach()` pops the newest.
112
- - **`createChildLog()` for spawned children.** A child's stdout/stderr never pass
113
- through this process' writers; the caller mirrors each buffer to the terminal —
114
- which the verb's own tee then catches, making the verb log a SUPERSET of the child
115
- file — and hands it to a child log, which adds the one thing the tee has no use for — a
116
- mid-run `roll()`, requested by touching a reset sentinel, so a days-long emulator
117
- log can be freshened without restarting it.
118
- - **CI is a no-op.** Under `CI=true` / `GITHUB_ACTIONS=true` the tee declines: the
119
- runner captures its own output and no `logs/` is left in the workspace.
120
- - **A log it cannot open is a lost log, never a lost process.** The tee warns once and
121
- the run continues untouched.
122
-
123
- ## Where every log lives
124
-
125
- `<targetRoot>` is a target dir in a brand (`targets/web`, `targets/backend`, …);
126
- `<brandRoot>` is the brand monorepo root.
127
-
128
- | Surface | File | What's in it |
129
- |---|---|---|
130
- | **Per target** — every framework, same three names | | |
131
- | `omega dev` (web) · `omega serve` / `omega emulator` (backend) · `npm start` (desktop, extension) | `<targetRoot>/logs/dev.log` | the whole dev run: boot, ports, watcher rebuilds, the crash — plus every child chunk the verb mirrored (see below) |
132
- | `omega build` (web, backend) · production gulp build (desktop, extension) | `<targetRoot>/logs/build.log` | the whole production build |
133
- | `omega test` | `<targetRoot>/logs/test.log` | suite names, pass/fail, harness boot lines |
134
- | `omega deploy` (web, backend, extension, desktop) | `<targetRoot>/logs/deploy.log` | the whole deploy: the scaffold, the precheck and its refusals, the dispatch, then the followed run's job logs and its verdict ([#873](https://github.com/Omega-JS-Stack/omega/issues/873)) |
135
- | **Backend children** — firebase's own processes, beside firebase-tools' debug logs. The verb mirrors every child chunk to its own terminal, so the `logs/<verb>.log` above is a SUPERSET of these; a child file is the child-ONLY view (and the one that `roll()`s mid-run) | | |
136
- | the firebase emulator child | `<targetRoot>/dist/emulator.log` | emulator traffic: function invocations, Firestore/auth calls |
137
- | the `firebase serve` child | `<targetRoot>/dist/dev.log` | serve output; rolls on each reload |
138
- | the test runner child | `<targetRoot>/dist/test.log` | the runner's own output under `omega test` |
139
- | `omega deploy --direct` (the firebase child) | `<targetRoot>/dist/deploy.log` | the `firebase deploy` transcript (the verb's own record is `logs/deploy.log`, one row up) |
140
- | `omega logs` | `<targetRoot>/dist/production.log` | the Cloud Logging tail |
141
- | firebase-tools itself | `<targetRoot>/*-debug.log` | `firestore-debug.log`, `firebase-debug.log`, `ui-debug.log`, … — theirs, never swept by us |
142
- | **Desktop extras** | | |
143
- | the running app itself (main + preload + renderer converge) | `<targetRoot>/logs/runtime.log` (dev) · the OS log dir (packaged) | lifecycle, window and updater lines; kept across boots, rotating at 10 MB — `packages/desktop/docs/logging.md` |
144
- | `npx omega logs [runtime\|dev\|build\|test]` (desktop's own verb — read, not write) | tails whichever of the four `<targetRoot>/logs/` files was named, `runtime` by default | the print/follow/open surface for all of the above; backend's `omega logs` is a different verb (the Cloud Logging tail, one row up) |
145
- | `npm run release` (the same dispatch `omega deploy` delegates to) | `<targetRoot>/logs/deploy.log` | the GH Actions release run, streamed locally: one name for every target's deploy ([#873](https://github.com/Omega-JS-Stack/omega/issues/873)), where this was `logs/ci.log` |
146
- | Windows code-signing | `<targetRoot>/logs/signing.log` | JSONL signing events (local fallback; on CI it lands in the runner home) |
147
- | **Brand root** — every verb tees to its OWN `logs/<verb>.log` ([#623](https://github.com/Omega-JS-Stack/omega/issues/623)), so one verb never truncates another's record. A FAN-OUT log holds the walk's own verdict — its header, its loud skips, its summary — because `runCommand` spawns each target with stdio inherit, so a target's output goes past the tee into that target's own log above | | |
148
- | `omega manage` (the service walk) | `<brandRoot>/logs/manage.log` | the whole service walk |
149
- | `omega dev` (the fan-out) | `<brandRoot>/logs/dev.log` | the boot walk, then every dev leg's prefixed output (consecutive duplicate lines collapse to one ` (repeated N×)` note) |
150
- | `omega build` / `omega clean` (the fan-outs) | `<brandRoot>/logs/build.log` · `<brandRoot>/logs/clean.log` | the walk order, every loud skip, the per-target summary |
151
- | `omega deploy` (the fan-out) | `<brandRoot>/logs/deploy.log` | the delivery lane, then which target published in which order and the summary. Every target additionally keeps its own `<targetRoot>/logs/deploy.log` ([#873](https://github.com/Omega-JS-Stack/omega/issues/873)), and the backend its firebase transcript `targets/backend/dist/deploy.log` |
152
- | `omega update` (the fan-out) | `<brandRoot>/logs/update.log` | which target was checked and what it reported/applied |
153
- | `omega test` (the fan-out) | `<brandRoot>/logs/test.log` | which target ran which scope, and the aggregate verdict |
154
- | `omega pipeline` (the live full-cycle test) | `<brandRoot>/logs/pipeline.log` | the child invocation, the deploy/verify legs, the scorecard and the PASS/FAIL verdict |
155
- | the brand's cross-stack e2e (`@omega.js/devkit/test/e2e-harness`) | `<brandRoot>/test/e2e/.logs/` | `steps.log` (one `PASS` / `FAIL` per step — see below), `emulator.log`, `dev.log`, `page.log` |
156
- | **This monorepo** | | |
157
- | every root test lane (`npm test`, `npm run test:packages`, …) | `.temp/logs/<lane>.log` | the lane's own lines plus every child command's output — `test:packages` → `.temp/logs/test-packages.log` |
158
- | `npm start` (the watcher) | `.temp/logs/watch-all.log` | is it alive, did it respawn, what did it rebuild |
159
- | every e2e runner's per-step verdicts | `.temp/<lane>/steps.log` | one `PASS` / `FAIL` line per step — see below |
160
- | every e2e runner's environment | `.temp/<lane>/` | `emulator.log`, `page.log`, `sw.log`, `screenshots/`, the journey's numbered stage logs |
161
-
162
- The e2e lane dirs are `.temp/flows-e2e/`, `.temp/auth-token-e2e/`, `.temp/verts-e2e/`,
163
- `.temp/desktop-auth-e2e/`, `.temp/extension-auth-e2e/`, and `.temp/journey/`.
164
-
165
- ### steps.log — which step failed
166
-
167
- Every e2e runner writes its verdicts incrementally
168
- (`packages/devkit/src/test/steps-log.js`, re-exported for the root runners as
169
- `scripts/steps-log.js`, and used by the journey harness and the brand e2e
170
- harness alike), so a SIGKILLed lane still names the step it died on:
171
-
172
- ```
173
- PASS the playground emulator boots (hosting :5002, auth :9099)
174
- FAIL the popup reaches the background SW — timed out after 30s
175
- FAIL preflight — a playground emulator stack is already running (hosting :5002)
176
- ```
177
-
178
- `preflight` is the runner dying before or outside any step — the live-stack guard, a
179
- harness throw on the way up. One line, same shape, so one grep finds every failure:
180
-
181
- ```bash
182
- grep '^FAIL' .temp/*/steps.log brands/*/e2e/.logs/steps.log
183
- ```
184
-
185
- ### Retention (ruled 2026-08-05)
186
-
187
- **Clear on launch, sweep what is stale.** Every log truncates when its surface starts;
188
- nothing rotates and no history is kept — the question a log answers is "what did the
189
- run that just happened do?". The backend additionally sweeps its own stale `dist/*.log`
190
- files and reset sentinels at every verb start, and deliberately leaves firebase-tools'
191
- `*-debug.log` files alone (a crashed run is diagnosed from them). `logs/` is gitignored
192
- everywhere, scaffolded brands included.
193
-
194
- ### Grep the logs — do not re-run the process
195
-
196
- The whole point of the tee is that the answer is already on disk. A running dev server,
197
- emulator or watcher belongs to the user: never restart one, and never re-run a suite,
198
- just to see output.
199
-
200
- ```bash
201
- tail -50 targets/web/logs/dev.log # is the dev server up, what did it last build
202
- grep -i error targets/backend/dist/emulator.log # what the emulator actually served
203
- grep '^FAIL' .temp/*/steps.log # which e2e step broke
204
- tail -100 .temp/logs/test-packages.log # what the last lane printed
205
- ```
@@ -1,167 +0,0 @@
1
- # Monitoring — the one error-reporting contract
2
-
3
- `@omega.js/monitoring` is the ONE home of error-reporting policy across every OMEGA target
4
- ([#380](https://github.com/Omega-JS-Stack/omega/issues/380)). Private workspace package, CJS,
5
- vendored into the frameworks at prepare time — the same deal `@omega.js/analytics` gets.
6
-
7
- Before it, three surfaces each carried their own copy of "should we report, what release is this,
8
- what may we send": @omega.js/client's `modules/sentry.js`, @omega.js/backend's hand-rolled
9
- `Sentry.init`, and @omega.js/desktop's `lib/sentry/` split. They disagreed — on the release format,
10
- on whether an email rides, on whether a dev build reports. Now they share one core and each host
11
- supplies only what it alone can know.
12
-
13
- ## The doctrine (Ian, 2026-08-20)
14
-
15
- - **Server and framework errors ALWAYS report.** Backend routes, cron, event triggers, desktop main,
16
- extension background: our code, our fault, no filter.
17
- - **Client-side, only OUR framework code reports.** A web page shares its global with user-land
18
- scripts, ad and chat widgets, and whatever browser extension a visitor installed. None of it is
19
- ours to answer for, so a browser event reports only when an `@omega.js` bundle is on its stack.
20
- - **Capture lives at SEAMS**, never in scattered try/catch: process hooks, the route error handler
21
- (`ctx.report()`), the event-trigger catch, the SDK's own global handlers.
22
- - **PII is scrubbed by default.** The uid rides (it is the join key to the account); the email is
23
- OFF unless a config explicitly opts in.
24
- - **Everything is OFF when the DSN is unset** — and when it is off, the SDK is never `require()`d
25
- or imported at all.
26
-
27
- ## Config
28
-
29
- One block, `monitoring`, in omega.json5, with the monitor named as a KEY under `providers`
30
- ([#425](https://github.com/Omega-JS-Stack/omega/issues/425) — the same shape every role uses). DSN
31
- presence IS the enable signal at runtime — there is no separate runtime `enabled` flag (the same
32
- convention every other role section follows: a block's credentials are its switch); the role-level
33
- `enabled: false` is the manager's skip switch for the provisioning service. Per-surface DSNs are
34
- `targets.<name>.monitoring.providers.sentry.dsn` overrides.
35
-
36
- ```jsonc
37
- monitoring: {
38
- enabled: true, // role-level, optional — false skips the monitoring service
39
- providers: {
40
- sentry: { // presence picks the monitor; no entry = none chosen
41
- org: 'acme', // provisioning only (the manager's monitoring service writes it)
42
- dsn: 'https://…@o1.ingest.sentry.io/1',
43
- environment: null, // null = the host's gate names it ('production' / 'development')
44
- sampleRate: 1, // error events kept, 0..1 — the sampling knob
45
- tracesSampleRate: 0.1,
46
- replaysSessionSampleRate: 0, // browser only — session replay is opt-IN (0 = off, and off is the default)
47
- replaysOnErrorSampleRate: 0, // browser only — replay of an ERRORING session; either rate above 0 loads the integration
48
- scrubEmail: true, // set false to opt IN to sending emails
49
- attachScreenshot: false, // desktop only
50
- bundlePatterns: ['/assets/js/'], // browser only — the URLs that identify our bundles
51
- },
52
- },
53
- }
54
- ```
55
-
56
- Full schema: [config.md](config.md).
57
-
58
- ## The entries
59
-
60
- | Entry | Who requires it | What it does |
61
- |---|---|---|
62
- | `./core` | everything | Pure policy: config resolution, release tag, user scrub, the bundle filter. No `process`, no SDK, no DOM — it is safe inside a page bundle. |
63
- | `./env` | Node/Electron hosts | The `process.env` half of core's gate seam: the four switches below. |
64
- | `./node` | `@omega.js/backend` | Boots `@sentry/node` and hands the module back (or `null`). |
65
- | `./browser` | `@omega.js/client` | Builds the `@sentry/browser` init options — integrations plus the ONE `beforeSend` that decides what leaves a page. |
66
- | `./main` `./renderer` `./preload` | `@omega.js/desktop` | The `@sentry/electron` per-context wrappers. |
67
- | `.` | `@omega.js/desktop` | The Electron context delegator: `process.type === 'renderer'` picks the renderer module, anything else the main one. |
68
-
69
- Core is pure ON PURPOSE. The browser bundle imports it, so an env read there would be a
70
- ReferenceError on a live page — every environment signal is passed IN as a gate, and `env.js` is
71
- where the reads live for hosts that have a process. A package test pins this.
72
-
73
- ## The switches
74
-
75
- In the order they win:
76
-
77
- | Env var | Effect |
78
- |---|---|
79
- | `OMEGA_SENTRY_ENABLED=false` | Kill switch. Nothing reports, ever. |
80
- | `OMEGA_TEST_RUNNER` | A test run never pollutes a live project. |
81
- | `OMEGA_SENTRY_FORCE=true` | Report from a non-production run (local proving). |
82
- | the ONE environment | The default production signal, for a host that passes no runtime one. |
83
-
84
- The production signal is the host's to supply, and the DEFAULT is the one environment every OMEGA
85
- target answers from ([#817](https://github.com/Omega-JS-Stack/omega/issues/817)):
86
- `@omega.js/config/environment`'s `isProduction()`, read off the host the gates were asked for
87
- (`process.env.OMEGA_ENVIRONMENT` on Node, the host's baked `config.environment` in a browser-ish
88
- context such as a renderer bundle). `OMEGA_BUILD_MODE` used to be that default, which made it a
89
- FIFTH production signal with an opinion of its own: a build-mode run of a development artifact
90
- reported as production, and a packaged production app whose lane did not carry the flag reported as
91
- development. @omega.js/backend still passes its own answer in (`omega.isProduction()`, env-derived
92
- and stable for the life of the process), alongside its own `reportErrorsInDev` option, and a boolean
93
- a host supplies always wins. A context that names no environment at all throws by name, the same way
94
- every other read of the one environment does.
95
-
96
- ## Release tags
97
-
98
- **ONE format on every target (Ian, 2026-08-20): `<brand.id>@<version>`.** A Sentry release is only
99
- comparable across the backend, the desktop app and the browser bundles when all three spell it the
100
- same way, so `core.releaseTag({ id, version })` builds that shape and nothing else — miss either
101
- half and there is NO tag (a bare version is not a second format). `brand.id` is required config, so
102
- a missing id is a config hole, not a supported case.
103
-
104
- Each host supplies its own version identity:
105
-
106
- | Host | Version source |
107
- |---|---|
108
- | `@omega.js/backend` | the functions package version. The id is `brand.id`, falling back to the project id on a config missing one (which already warns at boot). |
109
- | `@omega.js/desktop` (main + renderer) | `app.getVersion()` — the packaged app version, with `brand.id` read off the resolved config |
110
- | `@omega.js/client` in `@omega.js/extension` | the extension target's package version, baked into the build blob as `config.version` |
111
- | `@omega.js/client` in `@omega.js/web` | the website target's package version, read off the target root's package.json and baked into the page's `OMEGA_BUILD_JSON.config` as `version` |
112
- | `@omega.js/client` in the `@omega.js/desktop` renderer | the desktop target's package version, folded into `OMEGA_BUILD_JSON.config` at bake time (the renderer only ever sees `buildJson.config`) |
113
-
114
- The client reads `config.version` and falls back to `config.buildTime`. Every host above bakes a
115
- version now, so the fallback covers only a blob that carries none — a surface embedding the client
116
- by hand. Nothing tags a build stamp by design.
117
-
118
- ## Where capture happens
119
-
120
- | Surface | Seam |
121
- |---|---|
122
- | Backend routes | `ctx.report()`: 5xx captures automatically, 4xx never ([backend guide](../backend/index.md)) |
123
- | Backend event triggers | `omega/events.js`: a handler that throws, or a handler file that will not load, goes through the SAME `report()` door. A deliberate block (an `HttpsError`, or an explicit numeric 4xx code) is the trigger's 4xx and never captures; a string `.code` (`ENOENT`, `messaging/invalid-token`) is a system error, not a block, and reports. |
124
- | Backend payment webhooks | the REFUSAL family's shared seam (`acknowledgeRefusal()` in `events/firestore/payments-webhooks/on-write.js`) captures ONE `warning` per refused event, tagged with the reason and the provider. A refusal is a decision, not a fault, so it never reports as an exception; a processed event reports nothing; and only IDS ride — the refusal stamp's own fields plus the event's ([#550](https://github.com/Omega-JS-Stack/omega/issues/550)). |
125
- | Desktop main | `@sentry/electron/main`'s own `OnUncaughtException` + `onUnhandledRejection` integrations. Desktop's process handlers log to `runtime.log` and are ADDITIVE — never a second capture. |
126
- | Desktop renderer | the SDK's window `error` / `unhandledrejection` handlers |
127
- | Browser (web, extension) | the SDK's global handlers, filtered by `beforeSend` to our bundles |
128
-
129
- ## The browser filter
130
-
131
- `core.createBundleFilter(patterns)` checks every stack-frame filename an event carries against the
132
- configured URL fragments. Default: `/assets/js/`, which is where both @omega.js/web and
133
- @omega.js/extension serve every framework bundle (the client runtime included).
134
-
135
- An event with **no matching frame is dropped**, and that includes an event with no frames at all — a
136
- cross-origin `Script error.` is exactly the third-party noise this exists to kill. Deliberate
137
- `omega.sentry.captureException(…)` calls are unaffected: they are thrown from page bundles, which
138
- ARE our bundles. The corollary: a deliberate capture must pass an Error CONSTRUCTED in framework
139
- code — hand it a frameless one (a bare cross-browser `fetch` TypeError, say, which some engines
140
- raise with no usable stack) and the filter drops it, by design.
141
-
142
- What survives the filter is scrubbed of credential-bearing auth params: `browser.scrubAuthParams()`
143
- strips `?authPrivateKey` and `?authCustomToken` from every navigation breadcrumb (`data.from`/`data.to`,
144
- which the SDK records around `history.replaceState` — including the strip that removes the key) and
145
- from `event.request.url` (which `httpContext` attaches at capture time). A module constant, not
146
- config: a page never opts its own credentials back into an event ([#661](https://github.com/Omega-JS-Stack/omega/issues/661)).
147
-
148
- ## How the config reaches a browser
149
-
150
- The client reads a `sentry: { enabled, config }` namespace on its init blob, and it maps that
151
- namespace from `monitoring.providers.sentry` ITSELF, once, for every framework
152
- ([#894](https://github.com/Omega-JS-Stack/omega/issues/894)): each browser surface bakes the
153
- canonical section into `OMEGA_BUILD_JSON.config` and `_canonicalConfiguration()` in
154
- `packages/client/src/index.js` turns a DSN's presence into the switch. That home outranks a
155
- stale `client.sentry` blob, which keeps reporting until a brand migrates
156
- ([#485](https://github.com/Omega-JS-Stack/omega/issues/485)); with no canonical DSN the off
157
- state rides first, so the legacy blob still decides.
158
-
159
- | Framework | Where the section is baked |
160
- |---|---|
161
- | `@omega.js/web` | the engine's per-build snapshot, written as `<outDir>/build.js` (#743) |
162
- | `@omega.js/extension` | `src/gulp/tasks/bundle.js` (`composeBuildJson`, written as `dist/build.js`) |
163
- | `@omega.js/desktop` | `src/gulp/tasks/bundle.js` (`composeClientBuildJson`, written as `dist/build.js` for the renderer) |
164
-
165
- The client's `sentry.config` is the PROVIDER block, flat — nothing role-level ever rides into
166
- `Sentry.init`. Node/Electron hosts pass the whole `monitoring` section instead and core's
167
- `providerOptions()` reaches in for them: one home for the nesting, on the runtime side.
@@ -1,187 +0,0 @@
1
- # Publishing — the runbook
2
-
3
- > The publish-proving checkpoint's script, run for real on 2026-09-09: the seven
4
- > publishables are on the registry ([#25](https://github.com/Omega-JS-Stack/omega/issues/25)) at 0.50.0, the
5
- > monorepo's own number (0.1.0 went out first that night and is deprecated: the family
6
- > carries ONE version, the root package.json's, by ruling 2026-09-10),
7
- > each with `publishConfig.access: public`, and published is the new normal. The unlatch
8
- > step below is history; versions move by changesets from here.
9
-
10
- ## What publishes, what never does
11
-
12
- | Publishes (seven) | Never publishes (vendored at prepare, six) |
13
- |---|---|
14
- | `@omega.js/backend`, `@omega.js/client`, `@omega.js/desktop`, `@omega.js/extension`, `@omega.js/manager`, `@omega.js/mcp-router`, `@omega.js/web` | `@omega.js/devkit`, `@omega.js/config`, `@omega.js/account`, `@omega.js/template-kit`, `@omega.js/analytics`, `@omega.js/monitoring` |
15
-
16
- The private six are `VENDORABLE_PACKAGES` in [packages/devkit/tools/vendor.js](../../packages/devkit/tools/vendor.js),
17
- which is the SSOT: the vendor tool throws on a dist reference to any `@omega.js`
18
- package not on that list, so read the count from there rather than from this page.
19
-
20
- `@omega.js/mcp-router` joined the set (Ian 2026-07-30, [#144](https://github.com/Omega-JS-Stack/omega/issues/144)):
21
- the manager's vendored Claude plugin declares the router, so the router has to be
22
- installable beside it — a real dependency, never vendored. It ships no docs tree
23
- (it is not in the vendor lane's `DOCUMENTED_PACKAGES`) and no `exports` map, so the
24
- plugin's launcher can deep-resolve `@omega.js/mcp-router/bin/mcp-router.js`.
25
-
26
- Registry-real internal ranges (everything else is workspace `*`): `@omega.js/client`
27
- in backend/web/desktop/extension; `@omega.js/backend` and `@omega.js/mcp-router` in
28
- manager — the EXACT family version (0.50.0 today), not carets, because the family is
29
- lockstep (below).
30
-
31
- ## Lockstep — the family ships ONE version ([#794](https://github.com/Omega-JS-Stack/omega/issues/794))
32
-
33
- Changesets carries the seven publishables as a single `fixed` group
34
- (`.changeset/config.json`; `scripts/changeset-config.test.js` holds that group
35
- and `release-check.js`'s `PUBLISHABLES` in parity, and release-check itself
36
- prints a `one version across the family` check). A bump on any one bumps all
37
- seven to the same number, and packages with no code change republish anyway.
38
-
39
- Why, in two sentences: ONE number for the family means a brand can never
40
- install a backend from one release beside a client from another — "everything
41
- is 0.5.x" is the whole compatibility contract, readable by a human and
42
- checkable in one comparison. The private internals are VENDORED copies inside
43
- each framework, so a config-schema change already forces every framework to
44
- republish; independent numbers only hid that, and let one omega.json5 be
45
- validated by two validators.
46
-
47
- `updateInternalDependencies` stays `patch`, so the exact ranges above move
48
- with the group on every release. In a brand, the same number lands as an exact
49
- PIN per target ([updates.md](updates.md)) and the manager's boot check refuses
50
- a brand that ever drifts ([../manager/brand.md](../manager/brand.md)).
51
-
52
- ## What prepare vendors into a tarball
53
-
54
- Every publishable's prepare `after` hook runs the devkit vendor lane, which
55
- ships two payloads: the private packages' MODULES into `dist/vendor/`
56
- (`tools/vendor.js`), and the DOCS into the package root (`tools/vendor-docs.js`
57
- — the package's guide as `docs/index.md` plus `docs/shared/`, and for
58
- `@omega.js/manager` also the repo-root map as `docs/AGENTS.md` (links
59
- retargeted) and `claude-plugin/` + `.claude-plugin/marketplace.json`, the
60
- plugin a consumer brand enables from its node_modules, `.mcp.json` included —
61
- its launcher resolves `@omega.js/mcp-router` from the install
62
- ([#144](https://github.com/Omega-JS-Stack/omega/issues/144))). All of it is
63
- generated and gitignored; `node --test scripts/vendor-docs.test.js` packs the
64
- six documented packages for real and asserts the tarball listings. A vendor
65
- failure ABORTS the prepare: every publishable sets `preparePackage.hooks.afterBlocking: true`
66
- (prepare-package 2.2.0, [#38](https://github.com/Omega-JS-Stack/omega/issues/38)),
67
- so a tarball can never build missing its vendored internals. Contract:
68
- [agent-docs.md](agent-docs.md).
69
-
70
- The MODULE payload is closed over itself ([#739](https://github.com/Omega-JS-Stack/omega/issues/739)): a vendored file's own cross-package requires are rewritten to the sibling vendored copy, and any vendorable only a vendored file needs is vendored too, so the raw-private-reference grep below reads `dist/vendor/` as strictly as the rest of the tree.
71
-
72
- ## The license check ([#320](https://github.com/Omega-JS-Stack/omega/issues/320))
73
-
74
- A published install needs a LICENSE to enable the payment system and remove the omega
75
- attribution. A license is a subscription bought on omegajs.dev and the key is that
76
- account's API key — `OMEGA_LICENSE_KEY` in the brand `.env`, never in omega.json5
77
- (secret-shape rule). One key per ACCOUNT, unlimited brands for now.
78
-
79
- **When it runs**: at DEPLOY time, per target, once — `resolveLicenseVerdict({ config, env, transport })`
80
- in [`@omega.js/devkit/license`](../../packages/devkit/src/license.js). Each target's
81
- deploy asks and bakes the answer into that artifact; runtime never phones home and the
82
- payment call stays pure, so a cancelled key holds until the next deploy (accepted — a
83
- boot or periodic re-check is additive later).
84
-
85
- | Verdict | When | `payments` | `attribution` |
86
- |---|---|---|---|
87
- | licensed | the key resolves an omegajs.dev account whose subscription plan is not the reserved `basic` free sentinel | `live` | `removed` |
88
- | keyless | no key, an empty key, a `demo-*` project, or a key whose account has no active subscription | `gated` | `shown` |
89
-
90
- **Loud failure**: a key IS present but the server is unreachable, answers non-2xx, or
91
- resolves no account → the resolver THROWS. A typo'd or dead key must never quietly ship a
92
- gated artifact for a brand that is paying.
93
-
94
- **The keyless-dev carve-out**: a `demo-*` (emulator-only) project short-circuits before
95
- the network call, key present or not — local dev and the test brands run keyless forever,
96
- payments in test mode, attribution shown.
97
-
98
- **The wire**: `GET https://api.omegajs.dev/omega/user?apiKey=<key>&brandId=<brand.id>`.
99
- The host is a CONSTANT, not config: every other api base in OMEGA derives from a brand's
100
- own `brand.url` (`api.<host>`) because it belongs to that brand, and this one is the
101
- PRODUCT's license server — the same host for every brand that installs OMEGA. Server side
102
- it is the ordinary `GET /user` route resolving an API key (`users` where
103
- `api.privateKey ==` it), and the plan comes from `@omega.js/account`'s
104
- `resolveSubscription`, the same derivation the backend and the client run. `brandId` rides
105
- along and the server ignores it today, so a future per-key brand limit is a server-side
106
- change alone. `transport` is the injected fetch, so the tests run fully offline.
107
-
108
- **Delivery**: the env schema declares `OMEGA_LICENSE_KEY` as `ci` for web, desktop and
109
- extension — their deploys build on Actions runners, so the check runs where the build runs
110
- — and declares NOTHING for the backend, which deploys straight from the CLI and reads the
111
- key out of the `.env` cascade in its own process. It never bakes: a baked license key is a
112
- license key anyone who unpacks the app can copy.
113
-
114
- **What each target does with the verdict**: the resolver's answer becomes ONE stamp —
115
- `resolveLicenseStamp({ config, production })` in the same module, which returns
116
- `{ status: 'licensed'|'keyless', payments, attribution }` and short-circuits to the keyless
117
- stamp for any build that is not a production one (so a dev build, a watch and a test never
118
- phone home).
119
-
120
- | Target | Where the check runs | What the artifact carries | What changes |
121
- |---|---|---|---|
122
- | web | `omega build` (the production build — on the runner for a deploy, locally for a local one) | `site.license`, a build fact beside `site.pricing`/`site.brandTokens` | the footer's "Powered by omegajs.dev" block renders only while `site.license.attribution == 'shown'` (themes/base `_includes/frontend/sections/footer.html`) |
123
- | backend | `omega deploy`, before the stage — the CLI reads the key from the .env cascade in its own process | `OMEGA_LICENSE_STATUS` in the composed `dist/.env` (the one COMPUTED key there; the KEY itself never rides the upload) | `libraries/payment/license.js` refuses Stripe/PayPal/Chargebee `init()` on `keyless`. The `test` provider is never gated, and an ABSENT status — every local lane, the emulator, a test — behaves exactly as before |
124
- | desktop | the bundle task, production builds only | `OMEGA_BUILD_JSON.license` (outside `config`, in the bundles' define and in the renderer's `dist/build.js`) | nothing at runtime: the artifact records what it was packaged as. Neither target has an attribution surface today, and their payments ride the backend's gate |
125
- | extension | the bundle task, production builds only (once per build: the one snapshot every browser target then copies) | `OMEGA_BUILD_JSON.license` in the artifact's `build.js`, likewise outside `config` | as desktop |
126
-
127
- **Honesty system** (spec call 6): plain readable checks, no obfuscation and no artifact
128
- signing. The legal backing is the Elastic License 2.0 below, whose terms forbid
129
- circumventing license-key functionality and removing notices.
130
-
131
- ## Pre-flight (any day, no GO needed)
132
-
133
- 1. `npm run release:check` — packs all seven through their real prepare (vendoring
134
- included), scratch-installs each tarball with local-tarball overrides, resolves,
135
- and greps the shipped trees for raw private references. **Must be 7/7 green.**
136
- This is the laptop mirror of CI's pack-smoke.
137
- 2. Full battery green: root `npm test` (packages → corpus → sandbox e2e → journey).
138
- 3. npm auth sanity: `npm whoami` (expected `itwcw2000`). Known parked mystery: `npm org ls omega.js`
139
- 403s on the empty org — the first real publish is the definitive test. If IT 403s,
140
- the org-owning account must grant publish rights for the `@omega.js` scope.
141
- 4. **License check** ([#349](https://github.com/Omega-JS-Stack/omega/issues/349)): every
142
- `packages/*/package.json` reads `"license": "Elastic-2.0"`, every publishable carries a
143
- root `LICENSE` naming the Elastic License 2.0 (npm ships it into the tarball regardless
144
- of `files`), and no MIT text survives anywhere:
145
- `grep -rL "Elastic License 2.0" packages/*/LICENSE` must print nothing and
146
- `grep -ril "MIT License" packages/ --include=LICENSE*` must be empty. A tarball that
147
- publishes under the wrong license cannot be recalled from the registry, so this runs
148
- before the unlatch, not after.
149
-
150
- ## Publish day (Ian's GO)
151
-
152
- 1. **Unlatch**: remove `"private": true` from the seven publishables' package.json,
153
- and ONLY those seven (the six vendorable privates keep theirs forever:
154
- `VENDORABLE_PACKAGES` in [packages/devkit/tools/vendor.js](../../packages/devkit/tools/vendor.js)
155
- names them, so the list is never re-typed here).
156
- 2. **Publish** each (changesets is configured lockstep + `access: public`, so the
157
- seven go out at ONE number; the direct form per package is equally fine):
158
- `npm publish --workspace=packages/<name>` — order matters only where a dependent
159
- waits on a dependency: **client and backend before their dependents**
160
- (web/desktop/extension need client on the registry; manager needs backend and
161
- mcp-router). Safe order: client → backend → mcp-router → extension → desktop →
162
- web → manager.
163
- 3. **Verify from the outside**: in an empty temp dir, `npm install @omega.js/web`
164
- (and one more, e.g. manager) — install + `require.resolve` must succeed with no
165
- overrides. That is the moment the untested-lane risk is retired.
166
- 4. **Flip the real brand (omega-omega) to registry specs**: from any TARGET root (`targets/web`;
167
- the manager has no `i` verb), `npx omega i live` — tree-wide `file:` → the EXACT
168
- family pin + one registry install (`restoreRegistrySpecs` writes the linked copy's version with no
169
- caret, because the family is lockstep; `omega i local` is the way back for
170
- local-era work). Commit the brand's manifest+lock change.
171
- 5. **Brand proof**: brand `npm run manage` (manage cycle) + a website build — the brand
172
- now runs on registry packages; CI-dispatch web deploys become buildable (the
173
- deploy guard stops refusing once no `file:` specs remain).
174
- 6. Record: CHANGELOG entry + close the tracking issue; re-latch nothing — published is the
175
- new normal, versions move by changesets from here.
176
-
177
- ## After the first publish
178
-
179
- - 0.x caret ranges float patch-only (npm's conservative 0.x behavior) — breaking
180
- changes bump minor and consumers move deliberately. A BRAND floats nothing: the
181
- manager pins every target exactly, so `omega update` is the one thing that moves
182
- a brand, and it moves the whole family ([updates.md](updates.md)).
183
- - **1.0.0 is NEVER published without Ian's explicit word** (ruling 2026-09-10): it is the
184
- official release, and it waits until OMEGA has survived on its own with Ian's brands.
185
- Every number below it is free to publish whenever he wants.
186
- - The publish is also the brand-CI-build unlock: no tarball vendoring exists by
187
- design — the registry is the lane CI installs from.
@@ -1,34 +0,0 @@
1
- # Standing rulings
2
-
3
- Ian's durable rulings, migrated verbatim from PROGRESS.md's Rulings lane when the board retired (v4 migration, 2026-07-27). These bind all work in this monorepo; new rulings land here (or in AGENTS.md when they are architecture). Per-item decisions live on their issues.
4
-
5
- - Ian 2026-09-09: same-name rule for global + specific values: wherever a site-wide default and a specific override describe the same thing (config default vs page frontmatter, brand vs target, company vs brand, shared vs instance), they share ONE name and ONE shape at every level, the specific level overrides, and a differently named pair is a defect (`seo.index` vs `meta.index` was the case; #564 folds it into `meta.index`). Applies to every config item, never only page-vs-site.
6
- - Ian 2026-07-21: adblock-safe naming — the ad system speaks vert EVERYWHERE (paths, DOM, collection, API, modules); only ads.txt, Google's own ad* tokens, `advertising` config key say ad
7
- - Ian 2026-07-21: "DO NOT USE EM DASHES… REWRITE EVERYTHING TO MAKE SENSE WITHUT IT" — site/brand copy never uses em dashes; manual rewrites, not deletions. Operating home with scope + exemptions: docs/shared/theming.md § Copy register (2026-08-15)
8
- - Ian 2026-07-10: continuous mode — iterate/build/test autonomously, checkpoint after checkpoint; stop only for serious errors or genuinely-Ian decisions
9
- - Ian 2026-07-19: "I refuse to run a single command — wrap it in npm start, self healing idempotent" — absorb, never hand back; blocked one-offs = framework gaps; wrapped verbs only
10
- - Ian 2026-07-20: mirrored-implementation rule — same feature, same shape, every framework (cp242 deploys enforced it)
11
- - Ian 2026-07-20: local-omega-in-production is a SUPPORTED feature — deploys auto-detect linked local frameworks and take local-artifact lanes
12
- - Ian 2026-07-18: "still use local … until we are fully locked on all decisions that may result in breaking changes" — the local era (file: specs) holds until then
13
- - Ian 2026-07-19: 0.x until live publishes are proven; 1.0.0 is a later deliberate graduation; zero npm publishes + zero GH releases until GO (old names ship from legacy repos)
14
- - Ian 2026-07-12: website target = GH Pages ALWAYS; Firebase hosting is the backend/api surface only; GH Pages DNS defaults correct as-is
15
- - Ian 2026-07-12: FA Pro = local folder route via OMEGA_FONTAWESOME_ROOT (no npm token); skins design within solid/regular/brands
16
- - Ian 2026-07-11/12: playground = live test infra (Blaze/break/delete); payment+adjacent gated; deploys sparing + named; other brands deploy ONLY on explicit ask
17
- - Ian 2026-07-13/14: ad-hoc writes to real ITW resources stay gated — manage services' own convergence paths are the sanctioned route (2b mints included)
18
- - Ian 2026-07-18: credential copies from existing ITW brands SANCTIONED (brand .envs + omega-manager/.brands); new brands mint fresh identity keys; classifier-blocked copies fall to Ian
19
- - Ian 2026-07-12 (final): NO ITW CLI login — cached browser-OAuth + normal CLI login cover all; never suggest firebase/gcloud login as ITW; npm start = the blessed form *(command superseded 2026-08-13 by [#227](https://github.com/Omega-JS-Stack/omega/issues/227): the blessed reconcile form is now `npm run manage`; `npm start` boots the dev stack)*
20
- - Ian 2026-07-10: data-shape preservation — Firestore shapes + route semantics presumed good; breaking changes needing migration = flag with plan, don't build
21
- - Ian 2026-07-06: no backwards compat (dual-read cancelled) — new way only
22
- - Ian 2026-07-09: legacy repos READ-ONLY (omega-manager, all framework + consumer repos); migrators/verifiers/B5 verify/audit port PINNED; MAM parked
23
- - Ian 2026-07-20: per-target docs retire in brand context — the brand root is the ONE home (AGENTS.md chain + one README/docs/CHANGELOG)
24
- - Standing: secrets never in omega.json5 (.env only; config hard-fails); npu never raw npm/npx; explicit `git -C`; commit-and-continue; de-ITW to config = standard scope
25
- - Standing: checkpoint discipline — survey → design → implement → tests → sandbox/fixture proof → docs → commit; live checks never touch real ITW resources outside sanctioned paths
26
- - Ian 2026-07-30: uniformity — commands/surfaces of the same TYPE act the SAME; no split defaults within one family (the CLI read/write emulator split was the offense: every backend CLI subcommand now defaults to the emulator, `--production` the only path to live)
27
- - Ian 2026-07-30: NO legacy accommodations in the new system — no code path accepting a superseded form; breaking changes get DOCUMENTED (register: #148) and migrated once, manually (playbook: #149); the config-convert input lane is the one sanctioned legacy-reading exception
28
- - Ian 2026-07-30: company membership is a POINTER, never the directory tree: brands never physically nest inside a company folder, and anything resolving the company follows the pointer (SUPERSEDED in mechanism by #677, 2026-09-12: the pointer is the config key `company: { id }`, resolved through the machine registry, and the `.omega/company.json` stamp is retired; the rule itself stands)
29
- - Ian 2026-08-06: harmonize at BUILD time, never in a later pass — when a mechanism lands in one framework, its shared home (devkit) and the mirroring evaluation happen in the same work item; "wait for the harmonization pass" is not an accepted answer (first application: the #200 captured-read helper lifted to devkit pre-ship)
30
- - Ian 2026-08-20: migrations converge by SHAPE, not by version steps — each fix detects its legacy pattern in the doc itself, converged docs are proven no-ops, still-invalid docs surface loudly in the audit; every future doc reshape adds its convergent fix to the migrations pipeline in the SAME work item (register: docs/shared/breaking-changes.md)
31
- - Ian 2026-08-20: writing real data is OPT-IN for one-off scripts/processes — any standalone script that mutates live data (Firestore docs, mailing lists, provider accounts) previews by default and writes only under an explicit `--execute`; the manage/reconciliation services (own `--dry-run` + convergence) and scripts that only write tracked files (git diff is the review) are out of scope; template: the migrations service (#394)
32
-
33
- - Ian 2026-09-03: `--target=<name>[,<name>]` is the ONE target picker on every brand-root fan-out verb (test, deploy, build, clean, dev, update); `--only`/`--except` are retired, not aliased: `--only` collided with Firebase's own `firebase deploy --only hosting` (register: https://github.com/Omega-JS-Stack/omega/issues/780)
34
- - Ian 2026-09-03: an ORPHANED process of the emulator family (parent gone, this user's uid, a strict command-shape match) is NOBODY's and every emulator boot reaps it, whatever project it names, with no config and no warning-only mode. The family's shapes are named once, where the reap is described: [backend/index.md](../backend/index.md). Supersedes the #293 line that another brand's orphans stay; the #293 lesson survives as the strict family match replacing the loose name regex (register: https://github.com/Omega-JS-Stack/omega/issues/781)