@@ -182,6 +182,7 @@ import {
182182 readBundle ,
183183 readSpecBlob ,
184184 readStamp ,
185+ uniqueCandidates ,
185186 writeStamp ,
186187} from './console-spec-probes.mjs' ;
187188import { isEntrypoint } from './invoked-as.mjs' ;
@@ -216,11 +217,12 @@ const SELF_TEST_BATTERIES = Object.freeze({
216217 '13. THE BLIND SPOT (objectstack#20646): the build-time derivation must choose' : 6 ,
217218 "14. OBJECTUI'S OWN TEXT IS NOT EVIDENCE: a probe the console's own source carries" : 23 ,
218219 "15. A PIN CARRYING .objectstack-sha: the reference is objectui's own build of it" : 17 ,
220+ '16. EVERY DISTINGUISHING LITERAL IS LONG OR ESCAPED (objectstack#24663).' : 16 ,
219221} ) ;
220222
221223// DELETING an entry silences that battery's floor exactly as effectively as
222224// zeroing it, so the roster's own size is pinned too.
223- const SELF_TEST_BATTERY_FLOOR = 13 ;
225+ const SELF_TEST_BATTERY_FLOOR = 14 ;
224226
225227// The key an assertion is filed under when no battery is open. It is not a
226228// declared battery, so it reds by the same set difference rather than silently
@@ -1176,6 +1178,95 @@ function selfTest() {
11761178 expect ( 'and its replay names the commit it was judged against' , sameReplay . out . join ( '\n' ) . includes ( `objectstack ${ PIN . slice ( 0 , 12 ) } ` ) , true ) ;
11771179 }
11781180
1181+ // 16. EVERY DISTINGUISHING LITERAL IS LONG OR ESCAPED (objectstack#24663). The
1182+ // shape of the 12dc7b47 pin: the reference and this tree differ only in a
1183+ // describe literal over 160 characters whose em dash the dist writes as a
1184+ // `—` escape. The whole-literal rule skipped it, both pools came out
1185+ // empty, the build stamped `freshWitness: null`, and the assertion passed
1186+ // the control bundle. The runs between escapes are the candidates now.
1187+ battery ( '16. EVERY DISTINGUISHING LITERAL IS LONG OR ESCAPED (objectstack#24663).' ) ;
1188+ {
1189+ const assert = path . join ( ROOT , 'scripts' , 'assert-console-spec-injection.mjs' ) ;
1190+ const PIN = 'd' . repeat ( 40 ) ;
1191+ const host = makeHostTree ( path . join ( root , 'le-host' ) , {
1192+ '.objectstack-sha' : `${ PIN } \n` ,
1193+ 'packages/plugin/src/index.tsx' : 'export const d = "Unrelated host text";\n' ,
1194+ } ) ;
1195+ const runAssert = ( injected , vendored , dist ) =>
1196+ spawnSync (
1197+ process . execPath ,
1198+ [ assert , '--injected' , injected , '--vendored' , vendored , '--objectui' , host , '--assets' , path . join ( dist , 'assets' ) ] ,
1199+ { encoding : 'utf8' } ,
1200+ ) ;
1201+ const stampOf = ( dist ) => ( fs . existsSync ( path . join ( dist , STAMP_BASENAME ) ) ? readStamp ( dist ) . packages [ 0 ] : null ) ;
1202+ // A spec dist written as a bundler writes it: each description a JS string
1203+ // literal, `—` spelled as the six-character escape.
1204+ const writeDist = ( dir , literals ) => {
1205+ makeSpecPkg ( dir , [ ] ) ;
1206+ fs . writeFileSync ( path . join ( dir , 'dist' , 'index.mjs' ) , `${ literals . map ( ( l ) => `z.string().describe("${ l } ")` ) . join ( ';\n' ) } \n` ) ;
1207+ return dir ;
1208+ } ;
1209+ const ESC = '\\u2014' ;
1210+ const HEAD = 'Execution identity for the run: system = elevated (bypasses RLS), user = the triggering user' ;
1211+ const FRESH_RUN = ' system flows keep system privileges; after a pause the run resumes as the trigger user until a human decision' ;
1212+ const STALE_RUN = ' the run keeps that identity across every pause and resume of a long-running flow, whatever its trigger' ;
1213+ const LONG_SHARED =
1214+ 'A shared description over one hundred and sixty characters long that both specs carry byte for byte, so no run cut out of it can tell them apart in either direction' ;
1215+ const SHARED = 'Shared text in both specs for the long-literal fixtures' ;
1216+ const injectedLiteral = `${ HEAD } ${ ESC } ${ FRESH_RUN } ` ;
1217+ const pinnedLiteral = `${ HEAD } ${ ESC } ${ STALE_RUN } ` ;
1218+ const injected = writeDist ( path . join ( root , 'le-injected' ) , [ injectedLiteral , LONG_SHARED , SHARED ] ) ;
1219+ const reference = path . join ( root , 'le-cache' , 'spec' ) ;
1220+ writeDist ( reference , [ pinnedLiteral , LONG_SHARED , SHARED ] ) ;
1221+ fs . writeFileSync ( path . join ( root , 'le-cache' , '.stamp.json' ) , JSON . stringify ( { source : 'pin' , sha : PIN } ) ) ;
1222+
1223+ // The fixture has the pin's shape: no distinguishing literal the whole-literal
1224+ // rule accepts — each is over 160 characters AND carries an escape.
1225+ expect ( 'the injected literal is over 160 characters' , injectedLiteral . length > 160 , true ) ;
1226+ expect ( 'the pinned literal is over 160 characters' , pinnedLiteral . length > 160 , true ) ;
1227+ expect ( 'the long shared literal has no escape and is over 160 characters' , LONG_SHARED . length > 160 && ! LONG_SHARED . includes ( '\\' ) , true ) ;
1228+
1229+ // The candidate source itself: runs between escapes, never the whole literal.
1230+ const injectedBlob = readSpecBlob ( injected , 'injected' ) ;
1231+ const pinnedBlob = readSpecBlob ( reference , 'vendored' ) ;
1232+ const candidates = describeCandidates ( injectedBlob ) ;
1233+ expect ( 'the run after the escape is a candidate' , candidates . includes ( FRESH_RUN ) , true ) ;
1234+ expect ( 'the escaped literal is never a candidate whole' , candidates . includes ( injectedLiteral ) , false ) ;
1235+ expect ( 'a 32-to-160 plain literal is still taken whole' , candidates . includes ( SHARED ) , true ) ;
1236+ expect ( 'the unchanged run before the escape is not unique' , uniqueCandidates ( candidates , pinnedBlob ) . includes ( HEAD ) , false ) ;
1237+ expect ( 'a long literal both specs carry yields nothing unique' , uniqueCandidates ( candidates , pinnedBlob ) . includes ( LONG_SHARED ) , false ) ;
1238+ expect (
1239+ 'a quote cuts a run, since a bundler may re-quote it' ,
1240+ describeCandidates ( `x.describe("${ 'q' . repeat ( 40 ) } \\"${ 'r' . repeat ( 40 ) } ${ ESC } ")` ) . join ( '|' ) ,
1241+ `${ 'q' . repeat ( 40 ) } |${ 'r' . repeat ( 40 ) } ` ,
1242+ ) ;
1243+
1244+ // GREEN: this tree's bundle, where the bundler emitted the dash raw.
1245+ const good = makeDist (
1246+ path . join ( root , 'le-good' ) ,
1247+ `console(${ JSON . stringify ( `${ HEAD } —${ FRESH_RUN } ` ) } );console(${ JSON . stringify ( SHARED ) } )` ,
1248+ undefined ,
1249+ ) ;
1250+ const goodRun = runAssert ( injected , reference , good ) ;
1251+ expect ( 'this tree\'s bundle against the pinned build verifies' , goodRun . status , 0 ) ;
1252+ const goodStamp = stampOf ( good ) ;
1253+ expect ( 'the stamp carries a non-null witness: the changed run' , goodStamp ?. freshWitness , FRESH_RUN ) ;
1254+ expect ( 'the stamp carries the pinned run as its detector' , goodStamp ?. staleDetector , STALE_RUN ) ;
1255+ expect ( 'and records skew' , goodStamp ?. skew , true ) ;
1256+
1257+ // RED: the control bundle — objectui's own build of the pin, escape kept.
1258+ const control = makeDist (
1259+ path . join ( root , 'le-control' ) ,
1260+ `console("${ pinnedLiteral } ");console(${ JSON . stringify ( SHARED ) } )` ,
1261+ undefined ,
1262+ ) ;
1263+ const controlRun = runAssert ( injected , reference , control ) ;
1264+ expect ( 'the control bundle fails the build' , controlRun . status , 1 ) ;
1265+ expect ( 'the failure names the pinned run it found' , controlRun . stderr . includes ( STALE_RUN ) , true ) ;
1266+ if ( goodStamp ) fs . copyFileSync ( path . join ( good , STAMP_BASENAME ) , path . join ( control , STAMP_BASENAME ) ) ;
1267+ expect ( 'and the good stamp replayed over it fails too' , evaluate ( { distDir : control , specDir : injected , requireStamp : true } ) . code , 1 ) ;
1268+ }
1269+
11791270 fs . rmSync ( root , { recursive : true , force : true } ) ;
11801271
11811272 // ── The floor: every declared battery RAN, and ran its cases (#13489) ───
0 commit comments