1616 * declaration, and nothing read this hint table's text.
1717 *
1818 * The defect being closed is that SILENT DRIFT, not the duplication as such.
19- * The literal is still declared three times (the roster key, serve's static,
20- * doctor's const) and this file does not change that — see the const's own
21- * docblock for why the roster cannot supply the name, and for the deletion
22- * condition that ends the duplication properly.
2319 *
24- * ── Two legs, and the second is the point ────────────────────────────────
20+ * ── Retargeted by #12492, not rewritten ── ────────────────────────────────
2521 *
26- * (i) RENDERED — the `isolated` bullet is rendered through the real gate
27- * and compared, whitespace included, against text built from the
28- * declaration.
29- * (ii) ROSTER — that declaration IS a key of the spec-owned
30- * `PLATFORM_PLUGIN_WIRED_RUNTIMES`.
22+ * That deletion condition has since been met. `doctor.ts` no longer declares
23+ * `ORGANIZATIONS_RUNTIME_PKG` or its own hint table: both moved to
24+ * `../utils/tenancy-posture-hints.ts`, which `os serve` reads too. These pins
25+ * moved with the declaration — ⛔ none of them was dropped, because what they
26+ * measure did not change: what `os doctor` RENDERS. Leg (ii) especially, which
27+ * is the load-bearing one (see below).
28+ *
29+ * ⚠️ The literal is still declared three times, not two: the roster key, the
30+ * shared module this file now reads, and `Serve.ORGANIZATIONS_RUNTIME_PKG`,
31+ * which must stay a string LITERAL in `serve.ts` or the host-anchoring sweep in
32+ * `serve-cluster-host-resolution.test.ts` can no longer resolve which package
33+ * that command's `import()` names. What changed is that no copy can drift in
34+ * silence any more: the serve↔shared pair is pinned equal by site 8 of
35+ * `serve-organizations-message-spelling.test.ts`, and each copy is separately
36+ * pinned as a roster key. Ending the duplication needs that sweep's resolver to
37+ * follow one more hop — a file this card does not own.
38+ *
39+ * ── Three legs, and the second is the point ──────────────────────────────
40+ *
41+ * (i) RENDERED — the `isolated` bullet is rendered through the real gate
42+ * and compared, whitespace included, against text built from the
43+ * declaration.
44+ * (ii) ROSTER — that declaration IS a key of the spec-owned
45+ * `PLATFORM_PLUGIN_WIRED_RUNTIMES`.
46+ * (iii) SHARED TABLE (#12492) — every posture bullet, `single` and `group`
47+ * included, renders the shared table's entry verbatim.
3148 *
3249 * ⭐ (ii) is the entire difference between a CHECKED duplicate and a third
3350 * SILENT copy. Leg (i) on its own pins doctor against itself: rename the
3451 * roster key and the hint and the expectation move together, so (i) stays
3552 * green forever while `os doctor` names a package that no longer exists.
3653 * (ii) is what makes that rename loud. Neither leg is optional.
3754 *
55+ * (iii) covers the half neither of the other two can reach. `single` and
56+ * `group` carry no package literal, so no roster leg is possible for them and
57+ * nothing ever watched them — that is the defect #12492 filed. Leg (iii) does
58+ * not check the PROSE (a reword moves the shared table and this expectation
59+ * together, and leg (i)'s hard-coded text is what reddens then); it checks that
60+ * doctor renders THE SHARED TABLE. Re-grow a module-local copy in `doctor.ts` —
61+ * exactly the state this card found — and it goes red on every posture at once.
62+ *
3863 * ── Why it reads the RENDERED text, not the source ───────────────────────
3964 *
4065 * "No bare literal outside the declaration" is the tempting stronger form and
@@ -51,9 +76,16 @@ import fs from 'node:fs';
5176import os from 'node:os' ;
5277import path from 'node:path' ;
5378import { PLATFORM_PLUGIN_WIRED_RUNTIMES } from '@objectstack/spec/kernel' ;
79+ import { TENANCY_POSTURES } from '@objectstack/spec/security' ;
5480
81+ // The declaration and the table both live here since #12492 — `os serve` reads
82+ // the same module, which is what makes leg (iii) below a reading of the SHARING
83+ // rather than of one command talking to itself.
5584import {
5685 ORGANIZATIONS_RUNTIME_PKG ,
86+ TENANCY_POSTURE_FIX_HINTS ,
87+ } from '../utils/tenancy-posture-hints.js' ;
88+ import {
5789 resolveTenancyPostureOrFinding ,
5890 readDotenvFiles ,
5991 type DotenvReading ,
@@ -108,17 +140,20 @@ afterEach(() => {
108140 }
109141} ) ;
110142
111- /** The `isolated` fix-list bullet, rendered through the real gate. */
112- const renderIsolatedBullet = ( ) : string => {
143+ /** One posture's fix-list bullet, rendered through the real gate. */
144+ const renderPostureBullet = ( posture : string ) : string => {
113145 process . env . OS_TENANCY_POSTURE = 'not-a-posture' ;
114146 const reading = resolveTenancyPostureOrFinding ( shellOnly ) ;
115147 expect ( reading . ok , 'the gate accepted a value that is not a posture' ) . toBe ( false ) ;
116148 if ( reading . ok ) throw new Error ( 'unreachable — guarded above' ) ;
117- const bullet = lines ( reading . result . fix ?? '' ) . find ( ( l ) => l . includes ( ' OS_TENANCY_POSTURE=isolated' ) ) ;
118- expect ( bullet , " the fix list no longer offers an `isolated` bullet at all" ) . toBeDefined ( ) ;
149+ const bullet = lines ( reading . result . fix ?? '' ) . find ( ( l ) => l . includes ( ` OS_TENANCY_POSTURE=${ posture } ` ) ) ;
150+ expect ( bullet , ` the fix list no longer offers a ' ${ posture } ' bullet at all` ) . toBeDefined ( ) ;
119151 return bullet as string ;
120152} ;
121153
154+ /** The `isolated` fix-list bullet, rendered through the real gate. */
155+ const renderIsolatedBullet = ( ) : string => renderPostureBullet ( 'isolated' ) ;
156+
122157describe ( 'doctor — the posture description an operator reads names the declaration (#12464)' , ( ) => {
123158 // LEG (i). Rendered through `resolveTenancyPostureOrFinding` rather than by
124159 // reading the hint table: the bullet's assembly (indent, `• OS_TENANCY_POSTURE=`,
@@ -148,6 +183,28 @@ describe('doctor — the posture description an operator reads names the declara
148183 expect ( row . edition , `edition drift for the runtime doctor names ('${ PKG } ')` ) . toBe ( 'enterprise' ) ;
149184 } ) ;
150185
186+ // LEG (iii) — the half legs (i) and (ii) cannot reach (#12492). `single` and
187+ // `group` carry no package literal, so no roster leg is possible for them;
188+ // before this card nothing anywhere read their text at either command, and a
189+ // reword of one command's copy drifted from the other in total silence. What
190+ // closes that is not a pin on the PROSE — it is this: the bullets an operator
191+ // reads here are assembled from the SHARED table, the same one `os serve`
192+ // renders. A module-local hint table re-grown in `doctor.ts` reddens this.
193+ it ( 'leg (iii) — every posture bullet renders the SHARED hint table verbatim, `single` and `group` included' , ( ) => {
194+ for ( const posture of TENANCY_POSTURES ) {
195+ const hint = TENANCY_POSTURE_FIX_HINTS [ posture ] ;
196+ expect ( renderPostureBullet ( posture ) ) . toBe (
197+ ` • OS_TENANCY_POSTURE=${ posture } ${ hint ? ` — ${ hint } ` : '' } ` ,
198+ ) ;
199+ }
200+ // …and the sweep above actually swept. A posture vocabulary that went empty
201+ // would satisfy every assertion inside the loop without reading anything —
202+ // the two entries this card is ABOUT are named explicitly for that reason.
203+ expect ( TENANCY_POSTURES ) . toContain ( 'single' ) ;
204+ expect ( TENANCY_POSTURES ) . toContain ( 'group' ) ;
205+ expect ( TENANCY_POSTURES ) . toContain ( 'isolated' ) ;
206+ } ) ;
207+
151208 it ( 'no posture bullet an operator reads names any OTHER scoped package' , ( ) => {
152209 // The sweep the excluded source-scan form was reaching for, done over the
153210 // rendering instead — where comments cannot reach and no exclusion list is
@@ -185,6 +242,21 @@ describe('#12464 CONTROL — these pins can say no', () => {
185242 expect ( renderIsolatedBullet ( ) ) . toBe ( expected ) ;
186243 } ) ;
187244
245+ it ( 'the shared-table comparison rejects a bullet whose hint was reworded (#12492)' , ( ) => {
246+ // If leg (iii) could not tell a reworded hint from the shared one it would
247+ // be decorative. Anchored on `group` — one of the two entries that had
248+ // nothing watching them at all before this card, and deliberately NOT a
249+ // substring game: 'closed engine' is a different claim, not a truncation.
250+ const real = ` • OS_TENANCY_POSTURE=group — ${ TENANCY_POSTURE_FIX_HINTS . group } ` ;
251+ expect (
252+ ' • OS_TENANCY_POSTURE=group — organization wall enforced by the closed engine, one shared database' ,
253+ ) . not . toBe ( real ) ;
254+ expect ( ' • OS_TENANCY_POSTURE=group' ) . not . toBe ( real ) ;
255+ // …and says yes to the real thing, so the two `not.toBe`s are a reading
256+ // rather than a pair of vacuous truths.
257+ expect ( renderPostureBullet ( 'group' ) ) . toBe ( real ) ;
258+ } ) ;
259+
188260 it ( 'the roster key check rejects a name the roster does not declare' , ( ) => {
189261 // Anchored on a term that is NOT a substring of the one under test: a
190262 // membership assertion is not a reading until the same instrument answers no.
0 commit comments