From a1da3dab728a8f5ea97ac5b62c03ed9eb57f4f9a Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Sat, 26 Sep 2026 22:12:53 +0700 Subject: [PATCH 1/2] specs(automation): version 2 of both browser specs, and what a green t27c does not prove (Refs #4838) Four `Not claimed` lines from this morning became claimable, and one of them was hiding a fifth defect. browser-pod-restart.t27 -> VERSION 2. The restart that shipped this morning could not have worked with any set of service variables: its lookup asked for `status: "SUCCESS"` and the live API answers HTTP 400, because the field is a filter of `in`/`notIn` lists rather than a value. Version 1 blamed two missing variables. The corrected query answers live with the deployment created at 2026-09-23T11:21:26Z -- exactly the last real restart version 1 recorded, which is the cross-check now asserted. The two leaks version 1 named and fixed nowhere are fixed (6-tab budget enforced where a tab is created, never on the person's own tabs; one admin session per errand, handed back in `finally`), with the pre-fix measurements kept: 40 targets behind 16 pages, 35 ghost sessions. The token only the owner could issue exists now, so MISSING_VARIABLES is 0 -- but UNATTENDED_RESTART_OBSERVED stays false, because nobody has watched one. browser-sign-in.t27 -> VERSION 2, with the census: 191 cookies, 6 networks signed in, 5 signed out, 4 unknown, and 6+5+4 == DOORS asserted so it cannot silently stop covering a door. Instagram was never signed in, rather than signed out by the outage -- a degraded Chromium cannot delete a cookie, it could not read a page. Cookies without a known login cookie stay `unknown` instead of being guessed as signed out. And the reason version 2's numbers were not checked by the compiler: on a copy of browser-pod-restart.t27 whose only edit was `TAB_BUDGET == 6` -> `TAB_BUDGET == 999`, `typecheck`, `test` and `check` all exit 0, and `test` prints `Tests: 8` either way -- it counts test blocks DECLARED. So both files' asserts were evaluated against the constants gen-js folded: 59 hold here, 44 in the sign-in spec, 0 fail, and the falsified copy fails exactly one. Co-Authored-By: Claude Opus 5 --- ...-2-and-t27c-test-does-not-check-asserts.md | 16 ++ specs/automation/browser-pod-restart.t27 | 148 +++++++++++++++--- specs/automation/browser-sign-in.t27 | 58 ++++++- 3 files changed, 199 insertions(+), 23 deletions(-) create mode 100644 docs/now/2026-09-26-both-browser-specs-reach-version-2-and-t27c-test-does-not-check-asserts.md diff --git a/docs/now/2026-09-26-both-browser-specs-reach-version-2-and-t27c-test-does-not-check-asserts.md b/docs/now/2026-09-26-both-browser-specs-reach-version-2-and-t27c-test-does-not-check-asserts.md new file mode 100644 index 0000000000..d746eba70e --- /dev/null +++ b/docs/now/2026-09-26-both-browser-specs-reach-version-2-and-t27c-test-does-not-check-asserts.md @@ -0,0 +1,16 @@ +# NOW -- Both browser specs reach version 2, and `t27c test` does not check an assert (2026-09-26) + +## Both browser specs reach version 2 (Refs #4838) + +- The two specs published this morning each carried a `Not claimed` block. Four of those lines became claimable by the end of the day, and one turned out to have been hiding a fifth defect, so both files are at VERSION 2. +- browser-pod-restart.t27: the restart shipped this morning could not have worked with ANY set of service variables. Its lookup asked the platform for `status: "SUCCESS"`, and the live API answers HTTP 400 -- the field is a filter of `in`/`notIn` lists, so the document was never a valid query. Version 1 blamed two missing variables; the query was the defect, and the corrected one answers live with the deployment created at exactly the last real restart, 2026-09-23T11:21:26Z. +- The two leaks version 1 named and fixed nowhere are fixed: 6-tab budget enforced where a tab is created (never on a tab the person opened), and one neko admin session per errand handed back in `finally`. Measured on the owner's pod before the fix: 40 CDP targets behind 16 pages, and 35 admin sessions, all ours, none connected. +- The token only the owner could issue now exists, scoped to the one project. So AUTOMATIC_RESTART_CONFIGURED_LIVE is true and MISSING_VARIABLES is 0 -- but UNATTENDED_RESTART_OBSERVED stays false. Nothing makes it impossible now; nobody has watched it happen. +- browser-sign-in.t27 gains the census, 191 cookies sorted by each network's own login cookie: 6 signed in, 5 signed out, 4 unknown, and 6+5+4 == DOORS is asserted so the census cannot silently stop covering a door. The one the owner asked about -- Instagram -- was never signed in, rather than signed out by the outage. A degraded Chromium cannot delete a cookie; it could not read a page. "The agent stopped getting into the networks" was one sentence over two different problems, and only the cookies tell them apart. +- A profile holding cookies for a site is not a profile signed into it: hh.ru and upwork.com hold 28 and 13, with no login cookie this reader knows, and are reported `unknown` rather than guessed either way. + +## `t27c test` counts test blocks; it does not evaluate an assert + +- This morning's entry said "10 of 10 test blocks pass under t27c test-report". That reading does not hold. On a copy of browser-pod-restart.t27 whose only edit was `assert(TAB_BUDGET == 6)` -> `assert(TAB_BUDGET == 999)`, `typecheck`, `test` and `check` all exit 0, and `test` prints `Tests: 8` either way -- it reports how many test blocks were DECLARED. `gen-js` is explicit about the same thing in a comment it emits for every block: a TestBlock is not emitted because it is "checked by the compiler". +- So a green compiler is evidence that a spec PARSES and TYPES, and no evidence at all that its claims agree with each other. Every spec that has ever quoted a passing test count as support for its numbers was quoting the count of its own claims. +- Version 2's arithmetic was checked by evaluating each `assert` line against the constants `gen-js` folded -- 59 hold in browser-pod-restart, 44 in browser-sign-in, 0 fail, and the falsified copy fails exactly one. A gate that does this for the whole corpus is the obvious next thing and is not claimed here either. diff --git a/specs/automation/browser-pod-restart.t27 b/specs/automation/browser-pod-restart.t27 index d0f85a5298..fa483b9713 100644 --- a/specs/automation/browser-pod-restart.t27 +++ b/specs/automation/browser-pod-restart.t27 @@ -18,11 +18,19 @@ // path, so stop, start and restart all keep the person's logins; only an explicit profile // delete wipes them. The code used to claim the opposite, and that stale line is why the one // cure looked expensive and was avoided. -// Claim status: the probe, the real restart, the refusal to claim an unconfigured one and the -// broker's false-on-failure are unit-tested with doubles (a-restart-that-did-not-happen.test.ts, -// 10 tests). The live restart on 2026-09-26 is a pod-log observation, quoted below. That the -// fix restarts the pod BY ITSELF in production is NOT claimed: it needs two service variables, -// one of which is a token only the owner can issue. +// WHY there is a version 2: the fix above shipped and STILL could not restart anything. Its +// query asked the platform for status: "SUCCESS", and the live API answers that with HTTP 400, +// because the status field is not a value but a filter of in/notIn lists -- so the document was +// never even valid, and no combination of service variables could have made the restart work. +// Nothing caught it because the test's double answers every query alike. Two leaks named as +// unfixed in version 1 are fixed in version 2, and the missing token now exists. +// Claim status: the probe, the real restart, the query's accepted SHAPE, the refusal to claim an +// unconfigured restart and the broker's false-on-failure are unit-tested with doubles +// (a-restart-that-did-not-happen.test.ts, 11 tests; a-browser-that-tidies-up.test.ts, 11). The +// live restart, the corrected query's live answer, and both leak measurements are observations +// of the owner's own pod on 2026-09-26, quoted below. That the pod has RESTARTED ITSELF +// unattended is NOT claimed: the variables and the corrected query are both in place, but no +// unattended restart has been observed since. // phi^2 + 1/phi^2 = 3 | TRINITY module automation::browser_pod_restart { @@ -30,7 +38,7 @@ module automation::browser_pod_restart { pub const KIND : str = "automation"; pub const ID : str = "browser-pod-restart"; pub const REPO : str = "999-multibots-telegraf"; - pub const VERSION : u8 = 1; + pub const VERSION : u8 = 2; // ---- HTTP liveness is not liveness --------------------------------------------------- // The pair of calls that failed is the pair the probe asks: open a blank tab, run @@ -77,6 +85,25 @@ module automation::browser_pod_restart { pub const TWO_TOKEN_KINDS_ARE_TRIED : bool = true; pub const DEPLOYMENT_ID_IS_LOOKED_UP_FIRST : bool = true; // it changes on every deploy + // ---- The status field is a filter, not a value (found 2026-09-26) -------------------- + // The lookup above asked for status: "SUCCESS" and got HTTP 400 "Problem processing + // request" every time. The field's type is an object of in/notIn lists, so a bare enum is + // not a wrong answer to the query -- it is not a query. This is why version 1 could not + // have restarted the pod even with all three variables set, and why the variables were + // wrongly suspected first. The corrected query was run against the pod's own service the + // same day and named the deployment below, whose creation time is exactly the last real + // restart recorded in version 1. + pub const STATUS_IS_A_FILTER_OF_LISTS : bool = true; + pub const STATUS_AS_A_BARE_VALUE_IS_REJECTED : bool = true; + pub const REJECTED_WITH_HTTP : u16 = 400; + pub const QUERY_SHAPE_IS_PINNED_BY_A_TEST : bool = true; + // The old test could not fail on this: its double replied to any query with a deployment, + // so the only thing that ever refused the malformed document was the live API. + pub const A_DOUBLE_THAT_ANSWERS_ANY_QUERY_PROVES_NO_SHAPE : bool = true; + pub const CORRECTED_QUERY_ANSWERED_LIVE : bool = true; + pub const CORRECTED_QUERY_NAMED_DEPLOYMENT : str = "4c99ba3f"; + pub const CORRECTED_QUERY_DEPLOYMENT_CREATED : str = "2026-09-23T11:21:26Z"; + // ---- What the person is told ---------------------------------------------------------- // A restart that did not happen must not be reported as one: the broker returns false and // starts nothing, and the round then says, in the person's own language, to press Close @@ -87,6 +114,38 @@ module automation::browser_pod_restart { pub const THE_ONLY_LIE_WAS_THE_RESTART : bool = true; pub const PERSON_IS_TOLD_WHAT_TO_PRESS : bool = true; + // ---- The two things that piled up ---------------------------------------------------- + // Both were measured on the owner's pod on 2026-09-26 and neither had a test. They are in + // this spec and not the sign-in one because what they degrade is the pod, not a procedure. + // + // TABS: 16 pages behind 40 CDP targets -- one subreddit six times over, each with its own + // recaptcha iframe. browser_open opened them; a tool to close them exists and was never + // reached, because an agent that got what it came for goes on, and a model with a small + // window has forgotten the tab it opened four steps ago. So the budget is kept by the + // server at the place a tab is created, not by a reminder in a prompt. Only tabs THIS + // server opened are ever closed, and the oldest of ours go first; a tab the person opened + // is not ours at any count. + pub const TAB_LEAK_FIXED : bool = true; + pub const TAB_BUDGET : u8 = 6; + pub const BUDGET_IS_ENFORCED_WHERE_THE_TAB_IS_OPENED : bool = true; + pub const ONLY_OUR_OWN_TABS_ARE_CLOSED : bool = true; + pub const OLDEST_OF_OURS_GO_FIRST : bool = true; + pub const A_TAB_THE_PERSON_CLOSED_IS_FORGOTTEN_NOT_CLOSED_AGAIN : bool = true; + pub const AN_UNREACHABLE_POD_STILL_RETURNS_THE_TAB : bool = true; // tidying is not the errand + pub const TARGETS_MEASURED : u8 = 40; + pub const PAGES_MEASURED : u8 = 16; + // + // ADMIN SESSIONS: 35 of them in the pod's own UI, all named admin, not one connected -- + // one per screenshot, per screen resize, per mouse handover since 2026-09-23. The waste + // was not only memory: the list that answers "is a person watching this browser?" was + // being read through 35 of our own ghosts. One session per errand now, handed back in the + // finally branch, and a failed handback does not fail the errand -- the picture was taken. + pub const ADMIN_SESSION_LEAK_FIXED : bool = true; + pub const GHOST_SESSIONS_MEASURED : u8 = 35; + pub const ONE_ADMIN_SESSION_PER_ERRAND : bool = true; + pub const SESSION_IS_GIVEN_BACK_EVEN_WHEN_THE_ERRAND_THROWS : bool = true; + pub const A_FAILED_LOGOUT_DOES_NOT_FAIL_THE_ERRAND : bool = true; + // ---- Live evidence ------------------------------------------------------------------- // 2026-09-26: the pod's own supervisor log, after a restart triggered by hand through the // platform: "13:08:27,026 INFO success: chromium entered RUNNING state". The profile row @@ -94,16 +153,31 @@ module automation::browser_pod_restart { pub const RESTART_WORKS_LIVE : bool = true; pub const RESTART_WORKS_LIVE_EVIDENCE : str = "chromium entered RUNNING state 2026-09-26 13:08:27"; pub const PROFILE_SURVIVED_THE_RESTART : bool = true; + // And the probe itself, run from inside the platform against the restarted pod: the pair + // of calls that hung for 21 s three days earlier came back in a fifth of a second. This is + // the measurement that says the browser is a browser again, and the only one that does. + pub const PROBE_ANSWERED_LIVE : bool = true; + pub const PROBE_ANSWERED_LIVE_IN_MS : u16 = 173; + // The leaks were also cleared by hand on the running pod, so the numbers above are a + // history and not the present state: the one session that could not be deleted was the + // deleting session's own. + pub const SESSIONS_AFTER_THE_SWEEP : u8 = 1; + pub const TARGETS_AFTER_THE_SWEEP : u8 = 33; + // The token the owner alone could issue now exists, scoped to the one project, and lives + // in the service's own variables. Its value appears in no file of any repository: a secret + // that reaches a tracked file is revoked, not deleted. + pub const TOKEN_EXISTS : bool = true; + pub const TOKEN_IS_SCOPED_TO_ONE_PROJECT : bool = true; + pub const TOKEN_VALUE_IS_IN_NO_REPOSITORY_FILE : bool = true; // ---- Not claimed --------------------------------------------------------------------- - // Two service variables are missing, one of them a token only the owner can issue, so - // until they are set the fix's honest answer in production is false and the person gets - // the sentence instead of an automatic cure. The tab leak and a second leak of admin - // sessions in the pod's own UI are named here and fixed nowhere yet. - pub const AUTOMATIC_RESTART_CONFIGURED_LIVE : bool = false; - pub const MISSING_VARIABLES : u8 = 2; - pub const TAB_LEAK_FIXED : bool = false; - pub const ADMIN_SESSION_LEAK_FIXED : bool = false; + // All three variables are set and the query is one the API accepts, so the pieces of an + // unattended restart are in place -- but a pod restarting ITSELF, with no hand on it, has + // not been observed, and this file will not say it has until a round does it. The honest + // reading of version 2 is: nothing now makes it impossible. + pub const AUTOMATIC_RESTART_CONFIGURED_LIVE : bool = true; + pub const MISSING_VARIABLES : u8 = 0; + pub const UNATTENDED_RESTART_OBSERVED : bool = false; // Every one of the three variables, or the restart does not exist. fn can_restart(token: bool, service: bool, environment: bool) -> bool { @@ -150,11 +224,47 @@ module automation::browser_pod_restart { assert(STATUS_SAID_RUNNING); assert(TABS_AT_THE_END > TABS_AT_THE_START); - test "the restart works live; doing it unattended is not claimed yet" + test "the query was never valid, so no variable could have saved it" + assert(STATUS_IS_A_FILTER_OF_LISTS); + assert(STATUS_AS_A_BARE_VALUE_IS_REJECTED); + assert(REJECTED_WITH_HTTP == 400); + assert(A_DOUBLE_THAT_ANSWERS_ANY_QUERY_PROVES_NO_SHAPE); + assert(QUERY_SHAPE_IS_PINNED_BY_A_TEST); + assert(CORRECTED_QUERY_ANSWERED_LIVE); + // The deployment the corrected query names was created at the last real restart. + assert(CORRECTED_QUERY_DEPLOYMENT_CREATED == LAST_REAL_RESTART_BEFORE); + + test "the tabs it opens are the only tabs it closes" + assert(TAB_LEAK_FIXED); + assert(TAB_BUDGET == 6); + assert(BUDGET_IS_ENFORCED_WHERE_THE_TAB_IS_OPENED); + assert(ONLY_OUR_OWN_TABS_ARE_CLOSED); + assert(OLDEST_OF_OURS_GO_FIRST); + assert(A_TAB_THE_PERSON_CLOSED_IS_FORGOTTEN_NOT_CLOSED_AGAIN); + assert(AN_UNREACHABLE_POD_STILL_RETURNS_THE_TAB); + // More targets than pages is the leak's own signature: iframes of tabs left open. + assert(TARGETS_MEASURED > PAGES_MEASURED); + assert(TARGETS_AFTER_THE_SWEEP < TARGETS_MEASURED); + + test "one admin session per errand, and it is handed back" + assert(ADMIN_SESSION_LEAK_FIXED); + assert(ONE_ADMIN_SESSION_PER_ERRAND); + assert(SESSION_IS_GIVEN_BACK_EVEN_WHEN_THE_ERRAND_THROWS); + assert(A_FAILED_LOGOUT_DOES_NOT_FAIL_THE_ERRAND); + assert(GHOST_SESSIONS_MEASURED == 35); + assert(SESSIONS_AFTER_THE_SWEEP == 1); // the sweep could not delete its own + + test "nothing makes an unattended restart impossible now, and none has been seen" assert(RESTART_WORKS_LIVE); assert(PROFILE_SURVIVED_THE_RESTART); - assert(!AUTOMATIC_RESTART_CONFIGURED_LIVE); - assert(MISSING_VARIABLES == 2); - assert(!TAB_LEAK_FIXED); - assert(!ADMIN_SESSION_LEAK_FIXED); + assert(PROBE_ANSWERED_LIVE); + // A fifth of a second, against 21 s three days earlier. + assert(PROBE_ANSWERED_LIVE_IN_MS < PROBE_TIMEOUT_MS); + assert(TOKEN_EXISTS); + assert(TOKEN_IS_SCOPED_TO_ONE_PROJECT); + assert(TOKEN_VALUE_IS_IN_NO_REPOSITORY_FILE); + assert(AUTOMATIC_RESTART_CONFIGURED_LIVE); + assert(MISSING_VARIABLES == 0); + assert(can_restart(TOKEN_EXISTS, true, true)); + assert(!UNATTENDED_RESTART_OBSERVED); } diff --git a/specs/automation/browser-sign-in.t27 b/specs/automation/browser-sign-in.t27 index 5d76ee53b2..507ca93944 100644 --- a/specs/automation/browser-sign-in.t27 +++ b/specs/automation/browser-sign-in.t27 @@ -17,10 +17,17 @@ // SITE WANTS is learned by the presses themselves and lives in browser_recipes, because // the labels are exactly what sites change. Cookie names and domains stay in logins.ts, // their one home, and are not copied here. +// WHY there is a version 2: the owner asked, on 2026-09-26, whether Instagram was signed in +// right now, and the question turned out to be answerable in seconds by the reader this spec +// already describes. The answer reframed the complaint. Instagram was not signed OUT by the +// outage -- it had never been signed in: no sessionid had ever existed in the profile. The +// census is written down here because "it stopped working" and "it was never done" need +// different work, and only the cookies can tell them apart. // Claim status: the order, the doors, the rules and the per-site scoping of lessons are -// unit-tested with doubles (a-sign-in-worth-repeating.test.ts, 13 tests). That the -// playbook CARRIES A SIGN-IN TO COMPLETION against a live network is not claimed: no -// sign-in has been completed through it yet. +// unit-tested with doubles (a-sign-in-worth-repeating.test.ts, 13 tests). The census below is +// an observation of the owner's own pod on 2026-09-26. That the playbook CARRIES A SIGN-IN TO +// COMPLETION against a live network is still not claimed: no sign-in has been completed +// through it yet, and the six networks that ARE signed in were signed in by hand, before it. // phi^2 + 1/phi^2 = 3 | TRINITY module automation::browser_sign_in { @@ -28,7 +35,7 @@ module automation::browser_sign_in { pub const KIND : str = "automation"; pub const ID : str = "browser-sign-in"; pub const REPO : str = "999-multibots-telegraf"; - pub const VERSION : u8 = 1; + pub const VERSION : u8 = 2; // ---- The order, the same for every site ---------------------------------------------- pub const STEPS : u8 = 5; @@ -91,6 +98,34 @@ module automation::browser_sign_in { pub const SIGN_IN_LESSONS_IN_STORE_BEFORE : u8 = 1; pub const PROFILE_SURVIVED_THROUGHOUT : bool = true; + // ---- The census, 2026-09-26 ----------------------------------------------------------- + // Read straight off the browser socket, 191 cookies in the profile, sorted by the login + // cookie each network is known by. Six networks are signed in with cookies good into 2027; + // five are not signed in at all; four hold cookies but no cookie this reader knows how to + // judge, and those are reported unknown rather than guessed either way. + // + // WHAT THE NUMBERS SETTLE: the outage did not log anyone out. A degraded Chromium cannot + // delete a cookie -- it could not even read a page. The six that were signed in stayed + // signed in through all three days, which is the same fact the profile volume gave from + // the other side. So "the agent stopped getting into the networks" was one sentence + // covering two different things: for six, the agent could not USE a live session; for + // five, there was no session to use, and never had been. + pub const CENSUS_TAKEN : str = "2026-09-26"; + pub const COOKIES_IN_PROFILE : u8 = 191; + pub const NETWORKS_SIGNED_IN : u8 = 6; + pub const NETWORKS_SIGNED_OUT : u8 = 5; + pub const NETWORKS_UNKNOWN : u8 = 4; + pub const CENSUS_COVERS_EVERY_DOOR : bool = true; + // The one the owner asked about, and the answer that changes what to do about it. + pub const INSTAGRAM_SIGNED_IN : bool = false; + pub const INSTAGRAM_WAS_EVER_SIGNED_IN : bool = false; + pub const THE_OUTAGE_SIGNED_NOBODY_OUT : bool = true; + pub const SIGNED_IN_SURVIVED_THE_OUTAGE : bool = true; + // A profile with cookies for a site is not a profile signed into it: hh.ru and upwork.com + // hold 28 and 13 cookies, and this reader knows no login cookie for either, so it says so. + pub const COOKIES_WITHOUT_A_KNOWN_LOGIN_COOKIE_ARE_UNKNOWN : bool = true; + pub const UNKNOWN_IS_NOT_REPORTED_AS_SIGNED_OUT : bool = true; + // ---- Not claimed --------------------------------------------------------------------- // The plan is tested; a completed sign-in through it is not. Nothing here asserts that a // network accepts the person, that a captcha can be passed (it cannot -- the rule is to @@ -162,4 +197,19 @@ module automation::browser_sign_in { assert(SIGN_IN_LESSONS_IN_STORE_BEFORE < ATTEMPTS_BEFORE); assert(PROFILE_SURVIVED_THROUGHOUT); assert(ONE_NETWORK_AT_A_TIME); + + test "the census tells a lost session apart from one never made" + assert(COOKIES_IN_PROFILE > 0); + // Every door is accounted for, in one of exactly three states. + assert(NETWORKS_SIGNED_IN + NETWORKS_SIGNED_OUT + NETWORKS_UNKNOWN == DOORS); + assert(CENSUS_COVERS_EVERY_DOOR); + assert(!INSTAGRAM_SIGNED_IN); + // The distinction the whole census exists to make. + assert(!INSTAGRAM_WAS_EVER_SIGNED_IN); + assert(THE_OUTAGE_SIGNED_NOBODY_OUT); + assert(SIGNED_IN_SURVIVED_THE_OUTAGE); + assert(COOKIES_WITHOUT_A_KNOWN_LOGIN_COOKIE_ARE_UNKNOWN); + assert(UNKNOWN_IS_NOT_REPORTED_AS_SIGNED_OUT); + // A signed-in network is not evidence for the playbook: these predate it. + assert(!SIGN_IN_COMPLETED_LIVE); } From b78c0ae915ef007d54eb604fc9fc9280ce4a7168 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Sat, 26 Sep 2026 22:38:01 +0700 Subject: [PATCH 2/2] specs(automation): the service restarted the pod, PID 1 proves it, logins survived (Refs #4838) Version 2 would not claim the pod had restarted itself. It had not, and the deployment list cannot say either way -- a restart reuses the deployment. PID 1 was the witness: 02:19:34 old, i.e. the afternoon's manual restart. So the path was run on purpose from inside the service, with the service's own variables and the corrected query -- the part that was genuinely unproven. The token reached the process, the API accepted the lookup, the mutation answered true, and PID 1 came back at 01:33. The browser answered a probe afterwards and all 194 cookies with all six logins were still there. Version 3 therefore splits what version 2 ran together: the mechanism is observed end to end, the trigger is not. UNATTENDED_RESTART_OBSERVED stays false, and a new constant says which half that covers. 74 asserts evaluated against the folded constants, 0 fail. Co-Authored-By: Claude Opus 5 --- ...-the-pod-itself-and-the-logins-survived.md | 20 ++++++ specs/automation/browser-pod-restart.t27 | 68 ++++++++++++++++--- 2 files changed, 80 insertions(+), 8 deletions(-) create mode 100644 docs/now/2026-09-26-the-service-restarted-the-pod-itself-and-the-logins-survived.md diff --git a/docs/now/2026-09-26-the-service-restarted-the-pod-itself-and-the-logins-survived.md b/docs/now/2026-09-26-the-service-restarted-the-pod-itself-and-the-logins-survived.md new file mode 100644 index 0000000000..2864593c9d --- /dev/null +++ b/docs/now/2026-09-26-the-service-restarted-the-pod-itself-and-the-logins-survived.md @@ -0,0 +1,20 @@ +# NOW -- The service restarted the pod with its own variables, and the logins survived (2026-09-26) + +## What was asked and what was true (Refs #4838) + +- Version 2 of browser-pod-restart.t27 left `UNATTENDED_RESTART_OBSERVED` false, and the owner asked the obvious question of that line: has the pod restarted itself? +- It had not, and the deployment list cannot answer it either way -- a restart reuses the deployment, so the pod's record still read `4c99ba3f ... SUCCESS 2026-09-23T11:21:26Z` exactly as before. The only witness is the container's own PID 1, and it read `02:19:34` against `date -u` of 15:27:58 UTC: started 13:08:24, which is the manual restart of that afternoon. +- Nothing had asked it to restart, either. The path fires when a round finds a dead browser, and the browser answered a probe in 173 ms. So a healthy browser is the reason no restart happened -- not a broken restart. + +## So the path was run on purpose, from inside the service + +- `restartBrowserAsAgent` is reachable only through the agent round (`rounds-wiring.ts:112`); no HTTP route exposes it. The restart it delegates to was therefore run inside the vibee-render container, with the service's OWN variables and the corrected query, which is what was actually unproven. +- Three live unknowns fell at once: the token reaches the process (43 characters, present), the API accepts the corrected `status: { in: ['SUCCESS'] }` lookup and names the pod's deployment, and `deploymentRestart` answered `true`. +- The pod then went down and came up: PID 1 aged `02:19:34` before and `01:33` after, a minute and a half against two hours and nineteen. No HTTP sensor could have told the difference -- which is the whole point of the spec this belongs to. +- The browser came back alive, not merely listening: a tab opened after the restart ran `(() => 1 + 1)()` and answered 2. +- The restart kept every login. 194 cookies in the profile, and the same six doors open: google, youtube, x, linkedin, tiktok, reddit. Nothing had to be signed in again, which is the claim that makes a restart a cheap cure rather than an expensive one. + +## What is still not claimed + +- Version 3 separates two things version 2 ran together. The MECHANISM is now observed end to end. The TRIGGER is not: nobody has watched a round find a dead browser and restart it with no hand on it. `UNATTENDED_RESTART_OBSERVED` stays false, and `WHAT_IS_UNOBSERVED_IS_THE_TRIGGER_NOT_THE_MECHANISM` says which half is which, so the next reader is not left guessing what the false line covers. +- The spec's arithmetic was checked the way yesterday's entry said it must be -- by evaluating each `assert` against the constants `gen-js` folded, since `t27c test` only counts declarations. 74 hold, 0 fail. `t27c test` prints `Total: 11 declarations` and would print it just the same if a number were wrong. diff --git a/specs/automation/browser-pod-restart.t27 b/specs/automation/browser-pod-restart.t27 index fa483b9713..befe0cc5ce 100644 --- a/specs/automation/browser-pod-restart.t27 +++ b/specs/automation/browser-pod-restart.t27 @@ -24,13 +24,19 @@ // never even valid, and no combination of service variables could have made the restart work. // Nothing caught it because the test's double answers every query alike. Two leaks named as // unfixed in version 1 are fixed in version 2, and the missing token now exists. +// WHY there is a version 3: version 2 would not claim that the pod had restarted itself, and the +// owner asked whether it had. It had not, and nothing had asked it to -- the trigger only fires on +// a dead browser. So the path was run on purpose from inside the service, with the service's own +// variables: the pod went down and came up (PID 1 aged 02:19:34 before, 01:33 after), the browser +// answered, and all 194 cookies with all six logins were still there. The mechanism is proven; the +// trigger is still the thing nobody has watched fire. // Claim status: the probe, the real restart, the query's accepted SHAPE, the refusal to claim an // unconfigured restart and the broker's false-on-failure are unit-tested with doubles // (a-restart-that-did-not-happen.test.ts, 11 tests; a-browser-that-tidies-up.test.ts, 11). The // live restart, the corrected query's live answer, and both leak measurements are observations -// of the owner's own pod on 2026-09-26, quoted below. That the pod has RESTARTED ITSELF -// unattended is NOT claimed: the variables and the corrected query are both in place, but no -// unattended restart has been observed since. +// of the owner's own pod on 2026-09-26, quoted below, as are the deliberate restart and the +// cookies that survived it. That the pod restarts itself UNATTENDED is still NOT claimed: the +// machinery is now observed working end to end, but no round has been seen reaching for it. // phi^2 + 1/phi^2 = 3 | TRINITY module automation::browser_pod_restart { @@ -38,7 +44,7 @@ module automation::browser_pod_restart { pub const KIND : str = "automation"; pub const ID : str = "browser-pod-restart"; pub const REPO : str = "999-multibots-telegraf"; - pub const VERSION : u8 = 2; + pub const VERSION : u8 = 3; // ---- HTTP liveness is not liveness --------------------------------------------------- // The pair of calls that failed is the pair the probe asks: open a blank tab, run @@ -170,14 +176,35 @@ module automation::browser_pod_restart { pub const TOKEN_IS_SCOPED_TO_ONE_PROJECT : bool = true; pub const TOKEN_VALUE_IS_IN_NO_REPOSITORY_FILE : bool = true; + // ---- The service restarted the pod, and the logins survived (found 2026-09-26) -------- + // Version 2 left one line unclaimed and the owner asked the obvious question of it: did the + // pod restart ITSELF? It had not, and nothing had asked it to -- the browser was healthy, + // and the restart only fires when a round finds a dead one. So the path was exercised on + // purpose, from inside the service, with the service's OWN variables and the corrected + // query: the token was present in the process, the API accepted the lookup, and the + // mutation answered true. The pod then went down and came up -- PID 1 aged 02:19:34 before + // and 01:33 after, which no HTTP sensor could have told us. + pub const SERVICE_RESTARTED_THE_POD_WITH_ITS_OWN_VARIABLES : bool = true; + pub const TOKEN_REACHED_THE_PROCESS : bool = true; + pub const MUTATION_ANSWERED_TRUE : bool = true; + pub const PID1_AGE_SECONDS_BEFORE : u32 = 8374; + pub const PID1_AGE_SECONDS_AFTER : u32 = 93; + // A restart is only cheap if it keeps the logins. It did: the profile volume came back with + // its cookies, and the same six doors are still open. Nothing had to be signed in again. + pub const BROWSER_ANSWERED_AFTER_THE_RESTART : bool = true; + pub const COOKIES_AFTER_THE_RESTART : u8 = 194; + pub const NETWORKS_STILL_SIGNED_IN_AFTER_THE_RESTART : u8 = 6; + // ---- Not claimed --------------------------------------------------------------------- - // All three variables are set and the query is one the API accepts, so the pieces of an - // unattended restart are in place -- but a pod restarting ITSELF, with no hand on it, has - // not been observed, and this file will not say it has until a round does it. The honest - // reading of version 2 is: nothing now makes it impossible. + // The mechanism is proven; the TRIGGER is not. A restart performed on purpose says the + // machinery works, not that the agent reaches for it on its own. What remains unobserved is + // narrower than version 2 said: a round finding a dead browser and restarting it with no + // hand on it. This file will not say that happened until it does. pub const AUTOMATIC_RESTART_CONFIGURED_LIVE : bool = true; pub const MISSING_VARIABLES : u8 = 0; + pub const RESTART_ON_PURPOSE_OBSERVED : bool = true; pub const UNATTENDED_RESTART_OBSERVED : bool = false; + pub const WHAT_IS_UNOBSERVED_IS_THE_TRIGGER_NOT_THE_MECHANISM : bool = true; // Every one of the three variables, or the restart does not exist. fn can_restart(token: bool, service: bool, environment: bool) -> bool { @@ -267,4 +294,29 @@ module automation::browser_pod_restart { assert(MISSING_VARIABLES == 0); assert(can_restart(TOKEN_EXISTS, true, true)); assert(!UNATTENDED_RESTART_OBSERVED); + + test "the service restarted the pod with its own variables, and PID 1 proves it" + assert(SERVICE_RESTARTED_THE_POD_WITH_ITS_OWN_VARIABLES); + assert(TOKEN_REACHED_THE_PROCESS); + assert(MUTATION_ANSWERED_TRUE); + // The only proof a restart happened: PID 1 is younger than it was. + assert(PID1_AGE_SECONDS_AFTER < PID1_AGE_SECONDS_BEFORE); + // And younger than the gap between the two readings, so it cannot be the same process. + assert(PID1_AGE_SECONDS_AFTER < 300); + assert(RESTART_ON_PURPOSE_OBSERVED); + + test "the restart kept every login it found" + assert(BROWSER_ANSWERED_AFTER_THE_RESTART); + assert(healthy(PROBE_ANSWER)); + // A profile that lost its cookies would hold fewer than the census counted. + assert(COOKIES_AFTER_THE_RESTART > 191); + assert(NETWORKS_STILL_SIGNED_IN_AFTER_THE_RESTART == 6); + assert(PROFILE_SURVIVED_THE_RESTART); + + test "what is still unobserved is the trigger, not the mechanism" + assert(RESTART_ON_PURPOSE_OBSERVED); + assert(!UNATTENDED_RESTART_OBSERVED); + assert(WHAT_IS_UNOBSERVED_IS_THE_TRIGGER_NOT_THE_MECHANISM); + // The trigger only fires on a dead browser, and the browser is alive. + assert(healthy(PROBE_ANSWER)); }