summaryrefslogtreecommitdiff
path: root/modules/test/test-predictor-store-auth.js
diff options
context:
space:
mode:
authorHermes SysOp <sysop@webx11.duckdns.org>2026-11-12 17:02:47 +0100
committerHermes SysOp <sysop@webx11.duckdns.org>2026-11-12 17:02:47 +0100
commite452ce7785e5e47ec01a409d6da1f59564f8f365 (patch)
treee2dc45ecf479e55df571045390bba3d927d8a4e2 /modules/test/test-predictor-store-auth.js
parentf140aa7f920c687d0c576763da956dd7017c1a27 (diff)
fix(newos4): stop reporting network and VFS size as facts we do not have (v4.6.161)
1. The last two `navigator.onLine`-as-fact payloads - module-aiassist.js: the debug/health payload carried `online: navigator.onLine`, consumed by downloads/dashboard.html, which rendered "🔴 Offline" — on an Android WebView (reports false while fully connected) that told working users they were offline. The key is gone; the payload carries `network:'unknown'`, `networkKnown:false` and `networkHint`. - module-world-model.js: the snapshot had the same field, and it is also handed to the LLM through `_modelDigest()`/`ask()`, so the model was told the user was offline. Now `network:'unknown'` + `networkKnown:false`. - `_loadFromVFS()` scrubs `system.online` from a model persisted by an older build — otherwise the stale boolean would survive inside the digest for the life of the VFS. - downloads/dashboard.html: `networkText()` renders reachable/unreachable/http-* only when doctor produced them ("(doctor)"), `unprobed` as "— not probed", and everything else as "— unknown (run doctor for a live probe)". A legacy payload's `online:false` lands in "unknown", never "Offline". The row label is "Network", not "Online". - Neither payload invents a probe: SystemModule stores no last-doctor verdict, so 'unknown' is the honest value until one exists. 2. `vfsSize` in both payloads was a different unit again - aiassist: `JSON.stringify(fs.root).length / 1024`; world-model: `JSON.stringify(fs.root).length`. Same lie v4.6.160 fixed in `vfs-size` — UTF-16 code units plus serialisation structure. Both now sum UTF-8 bytes of file content (`_utf8Len`/`_measureVfs`, Blob → TextEncoder → code-point fallback, depth/node capped) and carry `sizeBytes` beside the human string so the rows reconcile. - world-model's `_gatherFileInfo().size` used a THIRD unit on an adjacent line (`JSON.stringify(fs.root).length/1024`); now the same measurement, plus `sizeBytes`. - `showModel()` renders exact bytes and tolerates a pre-fix persisted string. 3. Predictor made a guaranteed-401 request on every boot (UI-plan finding F6) - `_wdConfig()` returns `user:''`/`pass:''` when the saved WebDAV config has a URL but no credentials, and `_pullFromServer`/`_pushToServer` fetched the auth-gated `/spaces/<user>/_data/predictor.json` anyway — 107 × 401 in one day, logged by the browser as console errors. Both now refuse without credentials (`cache-only (no credentials)`). Verified: 42/42 node tests, 2 new files (38 payload/honesty assertions, 8 predictor-store assertions); the predictor suite is 4/8 against the pre-fix source, and the payload suite fails 14 assertions against HEAD (`online:false` present, vfsSize === JSON.stringify length). Live Chromium on v4.6.161, on the served dashboard: a legacy payload with `online:false` renders "Network — unknown (run doctor for a live probe)", the current payload renders "85.8 KB (87880 B)" and the same unknown, and a doctor-produced `unreachable` renders "⚠️ unreachable (doctor)". Served bytes identical for core-bundle.js, main.html and downloads/dashboard.html. `maintain.py --fix` all PASS.
Diffstat (limited to 'modules/test/test-predictor-store-auth.js')
-rw-r--r--modules/test/test-predictor-store-auth.js80
1 files changed, 80 insertions, 0 deletions
diff --git a/modules/test/test-predictor-store-auth.js b/modules/test/test-predictor-store-auth.js
new file mode 100644
index 0000000..6c37812
--- /dev/null
+++ b/modules/test/test-predictor-store-auth.js
@@ -0,0 +1,80 @@
+// node modules/test/test-predictor-store-auth.js
+// F6 (2026-11-09): the predictor store is an auth-gated /spaces/<user>/_data path, but _wdConfig()
+// returns user:''/pass:'' whenever the saved WebDAV config has no credentials — so every page load
+// made a guaranteed-401 request (measured 107 in one day) and the console reported it as an error.
+// No credentials must mean no request.
+const fs = require('fs');
+const path = require('path');
+const SRC = process.env.PRED_SRC || path.join(__dirname, '..', 'core', 'module-predictor.js');
+const src = fs.readFileSync(SRC, 'utf8');
+
+let pass = 0, fail = 0;
+const ok = (name, cond, detail) => {
+ if (cond) { pass++; console.log('ok ' + name); }
+ else { fail++; console.log('FAIL ' + name + (detail !== undefined ? ' — ' + detail : '')); }
+};
+
+function load(localStore) {
+ const store = Object.assign({}, localStore);
+ global.localStorage = {
+ getItem: (k) => (k in store ? store[k] : null),
+ setItem: (k, v) => { store[k] = String(v); },
+ removeItem: (k) => { delete store[k]; },
+ };
+ global.window = global;
+ global.setTimeout = global.setTimeout;
+ const Mod = new Function(src + '\nreturn PredictorModule;')();
+ const m = new Mod();
+ m.terminal = {
+ print: () => {},
+ fs: {
+ readFile: () => '{}',
+ fsReadJSON: () => null,
+ fsWriteJSON: () => true,
+ readDir: () => [],
+ mkdirRecursive: () => true,
+ },
+ };
+ return m;
+}
+
+(async () => {
+ const cfgNoCreds = JSON.stringify({ url: 'https://webx11.duckdns.org/spaces/agando', user: '', password: '' });
+ const cfgWithCreds = JSON.stringify({ url: 'https://webx11.duckdns.org/spaces/agando', user: 'agando', password: 'pw' });
+
+ // ---- 1. no credentials → zero requests, both directions ----
+ let calls = 0;
+ global.fetch = () => { calls++; return Promise.resolve({ ok: true, status: 200, json: async () => ({}) }); };
+ let m = load({ webx11_webdav_config: cfgNoCreds });
+ const pulled = await m._pullFromServer(true);
+ const pushed = await m._pushToServer();
+ ok('pull without credentials returns false', pulled === false);
+ ok('push without credentials returns false', pushed === false);
+ ok('no fetch was made without credentials', calls === 0, 'calls=' + calls);
+ ok('store mode names the reason', /no credentials/.test(m._storeMode), m._storeMode);
+
+ // ---- 2. credentials present → still talks to the server ----
+ calls = 0;
+ let sawAuth = null;
+ global.fetch = (url, opts) => {
+ calls++;
+ sawAuth = opts && opts.headers && opts.headers.Authorization;
+ return Promise.resolve({ ok: true, status: 200, json: async () => ({ dataPoints: [], accuracy: { total: 0 } }) });
+ };
+ m = load({ webx11_webdav_config: cfgWithCreds });
+ await m._pullFromServer(true);
+ ok('pull with credentials reaches the server', calls === 1, 'calls=' + calls);
+ ok('pull sends an Authorization header', /^Basic /.test(String(sawAuth)), String(sawAuth));
+ ok('store mode becomes server', m._storeMode === 'server', m._storeMode);
+
+ // ---- 3. no config at all → no request (unchanged behaviour) ----
+ calls = 0;
+ global.fetch = () => { calls++; return Promise.resolve({ ok: true, status: 200 }); };
+ m = load({});
+ await m._pullFromServer(true);
+ await m._pushToServer();
+ ok('no config still makes no request', calls === 0, 'calls=' + calls);
+
+ console.log('\ntest-predictor-store-auth: ' + pass + ' passed, ' + fail + ' failed');
+ process.exit(fail ? 1 : 0);
+})().catch((e) => { console.error('HARNESS ERROR', e); process.exit(2); });