| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
review findings
Second pass over v4.6.105, driven by an independent review that reproduced each item.
- ollama-manager.js: chat() now reports the captured cause ("Ollama error: Failed to fetch",
"…: HTTP 500") instead of the generic "No provider responded"; _lastChatError is reset per
call so an old reason is never replayed. chatWithTools carries the reason in its error string.
- ollama-manager.js: _ensureConnected() bounds connect() with a deadline (connectTimeoutMs,
default 10 s). connect() uses a bare fetch(), so a blackholed endpoint previously left the
shared in-flight promise pending forever and hung every later message — the old code failed
fast. The attempt is now try/finally, so a throwing terminal.log() can no longer poison
_connecting and suppress the retry on the next message.
- ollama-manager.js: an automatic connect no longer silently rewrites the user's saved model;
the previous choice is restored in memory and in localStorage, and the user is told.
- ollama-manager.js: the DeepSeek empty-content branch returned top-level tool_calls with
content '', so the caller pushed an assistant message with no tool_calls and then a
role:'tool' reply — an orphan tool message, which is the HTTP 400 that branch exists to
prevent. tool_calls now live inside the message as well.
- module-aiassist.js: a no-argument list_files returned the ROOT instead of the cwd (readDir('/')
instead of ls()); it now means the current directory again. Error text keeps the path as the
caller wrote it, and write_file distinguishes a read-only virtual path (/sys/…) from a missing
parent instead of blaming the parent.
Tests: test-ollama-error-text.js (new, 14 asserts, RED 9/5 before the edit), test-ai-fs-tools.js
7 → 16 asserts (write onto a directory, /sys write, list a file, '/', no-arg cwd, relative path),
test-ollama-autoconnect.js 11 → 19 (blackholed endpoint settles + retries, saved model survives;
the old "connecting hint" assertion is now falsifiable — the reviewer showed it also matched
connect()'s pre-existing line). Suite: 10/10 files green. Live on v4.6.106: healthy auto-connect
42 ms with the hint; blackholed endpoint settles in 1242 ms with connectTimeoutMs=1200, prints
"timed out" and "unreachable", _connecting cleared.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
sees /sys
Three defects, each re-probed first and covered by a test that is red on HEAD.
- ollama-manager.js: nothing connects at boot; only the Ollama tab button called connect(),
so a user's first message died with "Ollama not connected. Use ollamaconnect first." even
when the endpoint was healthy. New _ensureConnected() runs from chat(), chatStream() and
chatWithTools(): one attempt, shared by concurrent callers, a "Connecting…" hint, and only
then the error — which now says the endpoint is unreachable instead of telling the user to
run a command they already expected to work.
- module-aiassist.js write_file tool: fs.writeFile()'s false return was dropped and the tool
answered "File written: …" anyway, sending the model on to a read that found nothing
(MAINT-012). It now returns "Write FAILED: … — parent directory missing or target is a
directory; nothing was written".
- module-aiassist.js list_files tool: the hand-rolled walk over root.content never resolved
the virtual mounts, so /sys — a directory the UI and `ls` both show — answered
"Directory not found" (MAINT-011). It now uses fs.readDir(), which resolves mounts and
returns null for a genuinely missing path.
Tests: modules/test/test-ai-fs-tools.js (7 asserts) and
modules/test/test-ollama-autoconnect.js (11 asserts). RED on HEAD: ai tools 4 passed/3 FAILED
(/sys → "Directory not found", write_file → "File written: …"), ollama 2 passed/9 FAILED
("Use ollamaconnect first"). GREEN now 7/7 and 11/11; maintain --fix reports "node tests 9/9 pass".
Live on v4.6.105: connectedBefore=false, _ensureConnected()=true in 41 ms, 37 models.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
MAINT-010 and MAINT-016, the two high items the review left open. Both were re-probed
before the change and the new test is red on HEAD (5 passed, 7 FAILED).
- virtual-fs.js rename()/copy(): they assigned dst.dir.content[dst.name] with no destination
type check, so `mv file /docs` replaced the /docs node and every child vanished while the
command printed "Moved: …". Refuse when the destination is a real directory node (the
virtual /sys entry is exempt). rename() also erased the file on `mv a a`, because assigning
and then deleting the same key removes it; that path is now an explicit no-op.
- module-fs.js mv/cp: a refusal used to surface as "No such file or directory", which sent
the operator looking for a missing source. The destination is now inspected first and the
message says "is a directory — refusing to overwrite it".
- module-fs.js ls: the path was only read from argv[0], so `ls -l /work` listed the cwd.
The first non-flag argument is now the target; the path-first form is unchanged.
Tests: modules/test/test-fs-mv-cp-guard.js (12 asserts) — RED on HEAD (A1-A3, B1, B2, C2, E1),
GREEN now; maintain --fix reports "node tests 7/7 pass". Browser on v4.6.104:
"mv: /vtest: is a directory — refusing to overwrite it", child and source intact,
"ls -l /vtest" lists /vtest (keep.txt), not the cwd.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
gate the build
Review of the 08:30 implementer run (v4.6.102, checkpoint name fix). The shipped fix was
correct; these are the defects it introduced or left behind, each measured first.
- virtual-fs.js rollback(): the snapshot strips _snapshots/_sessions/.trash for bloat. Restoring
it verbatim deleted every checkpoint, every agent session and the trash, made rollback
irreversible and unrepeatable. Re-attach the live copies after the root swap.
- checkpoint(): names are millisecond-resolution, so tight calls overwrote each other
(measured 6 calls -> 3 snapshots). Dedupe with a -N suffix, refuse names containing "/"
(written but unlistable), and prune by snapshot createdAt instead of filename sort, which
let a custom name ("aaa-oldest") evict newer auto-named checkpoints.
- module-predictor.js: legacy pre-v2 points have no `usable`, so a 0.079 s aborted run
re-entered similarity as evidence and floored every prediction at 1 s. Backfill `usable`
from the measurement on load, drop the ones it rejects, add a belt-and-braces guard in
_findSimilar and count only usable points as actual executions.
- newos4-maintain.py: run every node-runnable modules/test/test-*.js on each maintenance pass.
The v4.6.102 regression was written but no job ever executed it.
- newos4-steer.py: `done` now requires --commit <sha> that exists in the repo, and gains
`reopen`. A written plan was being closed as done at 06:17 while the predictor fix shipped
nowhere, so the implementer's pre-flight queue was empty.
- steering.json: predictor item reopened, checkpoint item stamped with f7249ff.
- maintenance board: MAINT-002/005/015 were fixed in v4.6.81-85 but still listed open/high;
closed with their commit ids, and MAINT-010/016 annotated with the probes that keep them open.
Tests: test-vfs-checkpoint 23/23 (RED 14/9 before), test-predictor-accuracy 38/38
(T1-T3 RED on HEAD), maintain --fix all PASS, browser round-trip
"Checkpoint created: <name>" -> "Rolled back to checkpoint: <name>" on v4.6.103.
Also carries the already-deployed 2026-10-26 syntax-gate hunk in newos4-maintain.py (syntax_failures + gated rebuild) that had never been committed.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Task 3 of plan 2026-10-27_061724-newos4-checkpoint-name-mismatch.md.
New modules/test/test-vfs-checkpoint.js loads the real VirtualFileSystem and
SystemModule with guarded localStorage/indexedDB/window stubs and asserts:
A1-A4 checkpoint('') returns the resolved name; two calls differ; the file
exists under the returned name
B1-B2 checkpoint-list shows the returned name; rollback(<that name>) is true
C1-C4 the `checkpoint` command prints exactly the name it created (and an
explicit name verbatim)
RED before the fix (v4.6.101):
FAIL C2 printed name exists on disk — printed=2026-10-27T07:31:21.575Z
listed=["2026-10-27T07:31:21.574Z"]
test-vfs-checkpoint: 2 passed, 8 FAILED
GREEN after:
$ node modules/test/test-vfs-checkpoint.js
test-vfs-checkpoint: 10 passed, 0 failed
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
multi-select, Web Share, 44px targets
Executes .hermes/plans/2026-10-24_051600-newos4-mobile-download-share.md (approved via the feedback
dashboard; marker autonomy: safe). Front-end only, v4.6.94 -> v4.6.95.
T1 modules/ext/filemgr.js — URL.revokeObjectURL ran in the same tick as a.click(); iOS Safari and
Android Chrome hand the blob: URL to the download manager asynchronously, so the transfer was
aborted while the status line still said "Downloaded". Now revoked after 30 s.
T2 download honours the multi-selection via _getSelectedPaths() (falling back to _selectedFile),
reports "⬇ Downloaded N files" and "❌ Skipped <path>" instead of a silent partial success.
T3 share: navigator.share -> clipboard.writeText -> inline read-only <input> (focused, selected).
prompt() is suppressed in iOS standalone PWAs and most Android WebViews, which is why tapping 🔗
did nothing. Unresolvable space now reports "🔗 Share unavailable — no space resolved".
T4 both preview toolbar buttons: min-height/min-width 44px, touch-action manipulation, 1em, gap 10px
(was 24px/0.85em/6px — the smallest tap targets in the UI).
T5 _previewShareUrl falls back _resolveSpaceName -> _detectSpaceName (webdav.js:22) -> page path,
and returns null rather than emitting /spaces//<path>.
T6 the URL helpers are now module-scope pure functions exported for Node, so
modules/test/test-download-url.js tests the shipped code instead of a local copy (4 -> 6 cases).
Also fixes a latent bug that made require() impossible: `typeof window.webx11` throws under Node
because typeof does not protect a member access on an undefined global.
Verified on the served bundle (filemgr.js is concatenated into critical-ext-bundle.js, NOT
core-bundle.js — the plan's T7 grep pointed at the wrong file): HTTP 200, 129 867 B, 2x
navigator.share, 3x fmBuildShareUrl, deferred revoke present, 11x min-height:44px.
Live browser probe on /spaces/newos4/main.html: _previewShareUrl('docs/a.md') ->
https://webx11.duckdns.org/spaces/newos4/docs/a.md (no double slash); with navigator.share absent
and clipboard blocked, clicking 🔗 produced .fm-share-input containing that URL; button style ends
min-height:44px;min-width:44px;touch-action:manipulation; toolbar gap:10px.
node modules/test/test-download-url.js -> 6 PASS. lint-no-undef clean (55 files).
maintain: PASS version v4.6.95 x3, syntax OK, HTTP 200 /main.html.
Also adds admin/docs/session-overview-2026-10-26.md (glm-5.3-compressed session record).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
(v4.6.57)
Acting on the "Request to the newOS4 team" packet (spaces/agando/guides/,
re-verified by its author on 4.6.56). Three verified defects fixed:
Packet 5 (predictor arithmetic) - module-predictor.js
- the persisted field named mape held a SUM while predictor-status divided by the
paired count: renamed to errorSum, older payloads read through
- errorPct is stored raw; the 500% clamp is now render-only, so a 475x miss stays
visible instead of being flattened to the ceiling
- predictions are floored at 1 s and marked floored; a floored prediction is
consumed but never scored as 100% error (a 0 s prediction is not a prediction)
- observations shorter than 1.5 s (aborted/instant runs) are marked unusable and
no longer train _findSimilar - one 0.079 s run was rounding the next prediction
to 0 s
- status prints an unpaired and an unscored count alongside the mean
Packet 10 (verification cannot see its own fixes) - module-aiassist.js
- view_module now returns the DEPLOYED source, prefixed with file and version,
and only falls back to the _mods copy with a "may be stale" banner. The
unversioned _mods/<Class>.js edit cache used to shadow the deployed file
forever, so the viewer showed pre-fix code while the bundle was new.
Proven by seeding a stale _mods/PredictorModule.js and calling the tool.
Packet 1b (ls exits clean with no output) - module-fs.js
- ls rendered only via printClickable(), which writes straight to the DOM, so any
capture (AI run_command, diagnostics) saw an empty result and reported "empty
directory". It now always prints a text line and keeps the clickable chips when
nothing is capturing.
Test: modules/test/test-predictor-accuracy.js 34/34 (new cases Q, R, S).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The accuracy readout was structurally 0%: module-predictor.js:187 incremented the
denominator on every observed run while the numerator only moved when a stored
prediction existed, and predictions were stored only by the manual `predict`
command (the AI tool predict_task computed one and discarded it). Replaying the
AI loop's own call path with 6 tasks printed "Predictions made: 0, Accuracy: 0/6".
- pending predictions with a 15m TTL, consumed by threaded id -> task hash ->
cli-only similarity >= 0.5; unpaired runs never enter the denominator
- duration scored within 30% or 3s (integer predictions vs fractional observations)
- errorPct capped at 500% so one miss cannot poison the mean error
- schema v2: v1 correct/total counters dropped on load, observed runs and the
prediction counter kept; task text stored as an FNV-1a hash only
- tuning (confidence-threshold, min-data-points, pair-ttl) persists
- min-data-points now scales confidence (was declared, printed, settable, unread)
- AI loop registers a prediction per turn and threads its id; predict_task
returns predictionId; durations exclude chat-lock queue wait
- status/dashboard say "n/a" instead of "N/A%", and carry paired count, mean
error, turns error, pending and unpaired counts
- test: modules/test/test-predictor-accuracy.js (26 assertions)
Live on main.html v4.6.56: fresh session -> "Accuracy: n/a (0/0 paired)";
one paired run -> "100% (1/1 paired) - mean error 5% - turns +-0.0".
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
dashboard (v4.6.55)
Root cause: splitPipe() splits on every '|', so `help |`, `| wc -l`, `a || b` produced a stage with
no argv and executePipeChain() called parts[0].toLowerCase() on undefined — 989 occurrences, first
filed 2026-10-20, unfixable from the report because bug reports dropped the stack that named
executePipeChain:3955. Same unguarded read existed in _classify().
- terminal.js: _classify() returns an inert classification for empty argv; executePipeChain()
parses each stage once, filters stages with no argv (so the last real stage stays final), warns
only when the whole pipeline is empty. Last-stage test now compares against the filtered length.
- module-system.js: `bug` diagnostics include the stack (10 frames, 1200 chars); auto-filed reports
carry it too — they are the majority of the inbox and were previously message-only.
- report.php: per-stack 2 KB cap; fingerprint pinned to message/source/count so adding `stack`
cannot break dedupe against reports filed before today.
- ingest.php: first_frame() parsed once on ingest, stored as `frame` on each signature.
- newos4-triage.py: FRAME| line with the first application frame.
- dashboard.php: frame under each Top Errors row.
- modules/test/test-pipe-guard.js: ordering tripwire (guard must precede the parts[0] read).
Verified: test RED exit=1 -> GREEN exit=0; browser matrix on v4.6.55 (help |, | wc -l,
echo hi || echo bye, ls | | wc -l, |) -> 0 new error signatures, "|" warns;
auto-filed report now carries stack (RPT-...f3e31124, archived after the probe);
frame = modules/core/core-bundle.js:3955:42; maintain OK; skill audit 7/7.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
skill audit
External review packet (os4-external-review-v4.6.51.html) triaged against the code:
2 findings confirmed and fixed, 4 could not be reproduced and were recorded as such.
- module-memory-graph.js: getStaleSkills() treated a missing lastUsed as 999 days
unused, so skill-audit recommended archiving every skill (22 of 22). Skills with no
usage telemetry are now collected by getUntrackedSkills() and never counted stale.
Live: "Stale: 0" + "Untracked: 22 (no usage telemetry — NOT stale)".
- module-world-model.js: _saveToVFS() ignored fsWriteJSON()'s return value and promoted
whatever a truthy read returned. Now write -> read-back -> byte compare -> promote,
with every return checked. Regression test modules/test/test-world-model-save.js
(red on the old code: promoted=true with errs=[]; green now).
- scripts/newos4-skill-audit.py: 5 mechanical probes (version x3, read_file paging +
context budget, selection symbols, required scripts, extKeys) + skill presence;
exits non-zero on drift. 7/7 pass today. Weekly job cb6bc2a16216 runs it Mondays.
Not reproduced (recorded in admin/docs/newos4-external-review-verification-2026-10-23.md):
world_model_query empty-payload throw (live call returns JSON), pipes-as-command-names,
ls skills empty (23 entries via fs.readDir), ~66 agent dirs (4 live).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
(v4.6.50)
`world-model-ask` was a 10-keyword lookup: any real question returned
"Unknown query. Try: modules, skills, ...". The documented example
("what changed since yesterday") compared nothing — it restated the current
snapshot.
- _modelDigest(): whitelisted snapshot (measured 942-965 chars on fixtures,
~3.3 KB live) + recent error sample + changesSinceLastSnapshot
- _buildAskPrompt(): "answer only from this JSON, never invent numbers, name the
command that would produce missing data"
- ask(): connects Ollama on demand, answers via chat(), falls back to the facts
path with a visible warning; --facts keeps the instant lookup
- _diffSincePrev(): keeps one previous snapshot in /system/world-model.prev.json
so "what changed" is a real diff (files 136 -> 140)
- world_model_query tool returns the snapshot (digest or detail:full) instead of
ten canned strings; no nested LLM call inside a tool call
- help text now says what it does; node test modules/test/test-world-model-ask.js
(11 assertions, runs the real class)
Verified live v4.6.50: facts "Loaded 46 modules" | LLM "The snapshot does not
contain information regarding the cause of memory growth ... use
world-model-refresh" | diff "files 136 -> 140" | tool snapshot 3,334 bytes.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
verified file links; preview fullscreen+share; files->WebDAV upload button (v4.6.45)
- download: URL built from _resolveSpaceName() (config url = logged-in user), not the page space
- WebDAV browser 🔗: shares selected FILES only, URL-encoded, HEAD-verified (200) before claiming success;
folders offer a tar fallback instead of a guaranteed-403 link
- file manager preview: ⛶ fullscreen + 🔗 copy-link toolbar (was none)
- file manager toolbar: ☁ WebDAV publishes selected/current file via webdav-push
- modules/test/test-download-url.js: 4 PASS
- rebuild bundles, bump v4.6.44 -> v4.6.45 (loader + 3 script tags)
|
| | |
|
| | |
|
| |
|