aboutsummaryrefslogtreecommitdiff
path: root/modules/core/module-aiassist.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/core/module-aiassist.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/core/module-aiassist.js')
-rw-r--r--modules/core/module-aiassist.js50
1 files changed, 47 insertions, 3 deletions
diff --git a/modules/core/module-aiassist.js b/modules/core/module-aiassist.js
index a9b8fcc..84127d2 100644
--- a/modules/core/module-aiassist.js
+++ b/modules/core/module-aiassist.js
@@ -5118,9 +5118,45 @@ maxFetchChars: this.maxFetchChars,
}
};
walk('/');
- data.vfs = { files: fileCount, dirs: dirCount, size: (JSON.stringify(fs.root || {}).length / 1024).toFixed(1) + 'KB' };
+ // Stored bytes: the UTF-8 length of each FILE's content, summed. The
+ // old JSON.stringify(fs.root||{}).length counted UTF-16 code units
+ // plus the serialisation structure (braces, quotes, keys, commas) —
+ // ~2x for plain ASCII and wrong the other way for non-ASCII. This is
+ // the unit `vfs-size` and `doctor` report.
+ var u8 = function(s) {
+ if (typeof s !== 'string' || s.length === 0) return 0;
+ if (typeof Blob !== 'undefined') { try { return new Blob([s]).size; } catch (e) {} }
+ if (typeof TextEncoder !== 'undefined') { try { return new TextEncoder().encode(s).length; } catch (e) {} }
+ var n = 0;
+ for (var j = 0; j < s.length; j++) {
+ var cp = s.codePointAt(j);
+ if (cp > 0xffff) j++; // surrogate pair consumed
+ n += cp < 0x80 ? 1 : cp < 0x800 ? 2 : cp < 0x10000 ? 3 : 4;
+ }
+ return n;
+ };
+ var measure = function(node, depth) {
+ var out = { bytes: 0, files: 0 };
+ if (!node || !node.content || depth > 64) return out;
+ for (var k in node.content) {
+ if (!Object.prototype.hasOwnProperty.call(node.content, k)) continue;
+ var c = node.content[k];
+ if (!c || typeof c !== 'object') continue;
+ if (c.type === 'file') { out.bytes += u8(c.content); out.files++; }
+ else { var sub = measure(c, depth + 1); out.bytes += sub.bytes; out.files += sub.files; }
+ }
+ return out;
+ };
+ var vfsB = measure(fs.root, 0);
+ data.vfs = {
+ files: fileCount, dirs: dirCount,
+ sizeBytes: vfsB.bytes,
+ size: vfsB.bytes < 1024 ? vfsB.bytes + ' B'
+ : vfsB.bytes < 1048576 ? (vfsB.bytes / 1024).toFixed(1) + ' KB'
+ : (vfsB.bytes / 1048576).toFixed(2) + ' MB'
+ };
}
- } catch (e) { data.vfs = { files: 0, dirs: 0, size: '0KB' }; }
+ } catch (e) { data.vfs = { files: 0, dirs: 0, size: '0 B', sizeBytes: 0 }; }
// Ollama
data.ollama = {
@@ -5180,7 +5216,15 @@ maxFetchChars: this.maxFetchChars,
data.health = {
modules: data.modules.loaded + '/' + data.modules.total,
vfsSize: data.vfs ? data.vfs.size : '?',
- online: typeof navigator !== 'undefined' ? navigator.onLine : true,
+ vfsSizeBytes: data.vfs && typeof data.vfs.sizeBytes === 'number' ? data.vfs.sizeBytes : null,
+ // NO `online` boolean. `navigator.onLine` reports false on a fully
+ // connected Android WebView, which is how the debug panel and the
+ // dashboard told working users they were offline. `doctor` owns the only
+ // reachability verdict; SystemModule exposes no last verdict, so until one
+ // is probed the honest value is 'unknown'.
+ network: 'unknown',
+ networkKnown: false,
+ networkHint: 'run doctor for a live probe',
errors: totalErrors,
errorBreakdown: errCounts,
predictorAccuracy: predictorAcc