| Commit message (Collapse) | Author | Age | Files | Lines |
| ... | |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
(v4.6.64)
Packet 8. `new RegExp(pattern)` sat unguarded in the terminal grep handler and in
VFS find()/grep(), so a bad pattern threw out of the command handler into the error
ledger -- the same ledger packet 2 had to stop trusting.
- module-fs.js grep: compile in try/catch, print
"grep: invalid pattern: <pattern> (<engine message>)" as a warning and return
- virtual-fs.js find()/grep(): same guard, return [] and stash the message on
_lastPatternError instead of throwing into the module error wrapper
Verified live on v4.6.64 with the packet's own repro: `grep "/\bug_id\" file` prints
the message, the error counter stays 0 (was: one ledger entry per call), a valid
pattern still matches, and fs.grep('[') returns [] instead of throwing.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
(v4.6.63)
Packet 6 and 7.
6 — four agents showed `sleeping` and nothing distinguished "waiting for work" from
"never handed a task". Added tasksAssigned/lastTaskAt to the agent record (counted
where a task is actually assigned), and the status line now reads
idle — NEVER SCHEDULED (0 tasks since 2026-10-23 16:22)
idle — waiting for work (3 task(s), last 2026-10-23 16:22)
parked — NEVER SCHEDULED ...
plus "Dispatch: 0/3 agent(s) have ever been given a task" and a warning that
spawning is not dispatching.
7 — /guides/ was reachable by nobody. New `guides` command lists it newest-first
with sizes and the preview/cat hints; help.html gained a Guides nav entry and
section with links to the published guides.
Verified live on v4.6.63: `guides` → 2 entries after seeding two files;
orchestrator-status shows 3x NEVER SCHEDULED on a fresh session (the packet's own
observation), and "waiting for work (3 task(s) ...)" once a counter is set, with
"Dispatch: 1/3".
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Packet 4. The matcher tested the whole query as one substring against
name+description+tags: word order decided the outcome ("telemetry dashboard" = 0
while "telemetry" = 1), a sentence could never match, and skill bodies were never
searched at all.
- _skillTokens(): lowercase, split on non-word chars, drop <3-char words and a
stopword list; a query made only of stopwords keeps its literal form
- scoring: name 3, description 2, tags 2, body 1 + up to 1.0 for repeated hits,
multiplied by token coverage (0.5 + 0.5 * matched/total), +3 phrase bonus so word
order can never zero a real hit
- results carry score and matchedTokens ("2/3"); top 3 by score, name as tiebreak
- zero results now name the tokens searched and the closest skill names instead of
"No matching skills found"
Verified live on v4.6.62 via the real runTool entry point:
"telemetry dashboard" and "dashboard telemetry" both return the same 2 skills
(was 0 and 0); "how do I regenerate the skill index" returns skills-system-guide
first (8.96, 2/3) where a sentence previously matched nothing; "info" returns 3
body matches; a nonsense query returns 0 with the tokens and closest names.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Packet 2 (three surfaces, three answers). Measured first: `errors` scanned
/logs/current.log for [ERROR] lines, but that file only ever receives explicit
terminal.log('ERROR', ...) calls -- exactly one call site in the whole app -- so it
read 0. The dashboard added DebugSupervisor._errorDB plus failed tool calls (18),
and the world model read the debug DB alone (11).
- terminal.countErrors() / countLogErrors(): the single counter, exposed on the one
object all three surfaces already hold
- `errors` prints the canonical total with its breakdown, the entry list (hash,
count, severity, message), and reports the log scan separately as a mirror
- dashboard health.errors and health.errorBreakdown derive from it
- world model telemetry.recentErrors derives from it, plus errorsBySource
- terminal.log('ERROR', ...) now also records into DebugSupervisor, so the log is a
human-readable mirror of one store instead of a second store almost nobody wrote
Verified live on v4.6.61: with a seeded debug entry + failed tool call, all three
report 2; a single log('ERROR') call moves debug 1->2 and the total by exactly 1
(the mirror line is counted once, in the log, and reported separately).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Packet 1 and 3 (silent wrong answers from a shell-less terminal).
- detectComposition() in the security gate refuses ; && || | before dispatch.
`;` used to fail loudly, but `&&`/`||` folded the right-hand side into the left
command's argv (wc -l f && grep -c x f returned "42 42"), and a `|` arriving from
the AI run_command tool bypassed splitPipe entirely and degraded the pattern to
empty -- which matches every line. Operators inside quotes are untouched.
- wc accepts multiple paths: one line per file plus a total, per-file errors for
missing paths. `wc -c a b` used to print only `a` and exit 0.
- help.html: "There is no shell" callout at the top of the command reference,
plus the v4.6.57/58 changelog entry.
Verified live on v4.6.58 by replaying the exact call sequence used by both paths:
interactive `wc -c a b` -> "14 a / 10 b / 24 total"; `&&` and `;` refused;
`echo "a && b"` still echoes; AI run_command semantics with `|` and `&&` refused;
single command and multi-file wc still return real output.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
(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.
|
| |
|
|
|
|
|
|
| |
2026-10-18
Report RPT-20261018-164646-89352963 ("this.fs.emptyTrash is not a function") was filed by the auto-filer and never fixed: terminal.js:1777 called a method VirtualFS never defined, so 'empty-trash --confirm' threw instead of emptying. Added emptyTrash() returning true only when it removed something.
Verified live on v4.6.54: put -> rm -> empty-trash --confirm => 'Trash emptied.'; second run => 'Trash is already empty.'; .trash entries 0.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
(v4.6.52-53)
Root cause: _syncToBackend() re-sent the whole error DB with cumulative counts every
300s, and ingest.php did count += client count per batch. 33 real signatures had
accumulated 116,696 "occurrences" (one self-referential row alone: 46,133).
Backend
- ingest.php: per-(session,hash) synced map, adds only the delta, resets prev when the
client count shrank (cleared localStorage), caps delta at 5000, bounds synced at 500
hashes and sessions at 200, normalises timestamps to +00:00, 30-day retention that
also purges dropped hashes from every synced map, returns `accepted` (entries) next
to `ingested` (occurrences).
- stats.php/dashboard.php: total_errors = occurrences, unique_errors = signatures,
last-ingest card. The two numbers were inconsistent by ~3,500x.
- health.php: reports self_referential count and status=degraded instead of ok.
- Pruned live data: 33 -> 23 records, 116,696 -> 58,759 occurrences, max cluster
110,226 -> 52,387 (archive kept in data/debug/archive/).
- nginx: stats/errors/clusters/dashboard/agent-replies now behind
auth_request /_wx11_admin_auth (302 without a session); ingest/report/health stay
public for telemetry. Verified: reads 302, ingest 200, report 400.
Client
- module-debug-supervisor.js: sends only hashes whose count changed (persisted
webx11_debug_synced), records synced counts only after success, stops auto-filing
aborts/timeouts and debug-pipeline requests as bug reports (2 of the last 5 reports
were "user aborted a request").
Verified with a scratch php -S copy: same batch POSTed 3x -> count stays 5;
count=99999 -> clamped to 1000; retention dropped 10 legacy rows.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
(v4.6.51)
Two defects, both verified live before/after:
1. The World Model panel always said "Not synthesized yet". The page had a
renderer for data.worldModel and _collectDashboardData() never set it -- the
model was right there in WorldModelModule._model. Now collected and mapped to
the renderer's exact keys (model has modules.loaded/skills.count/memory.nodes,
the page reads modules/skills/memoryNodes), plus changesSinceLastSnapshot and
the recent-error sample, with an honest "not synthesized" fallback.
2. The page discarded any payload older than 10 s and its own 5 s auto-refresh
then showed "Cannot connect to newOS4". Stale payloads are now rendered with
their age ("Data as of 1:20:14 AM - 3m ago"), labelled amber past 5 min.
Also: the Refresh button wrote a localStorage key nobody read -> the terminal now
listens for it and re-collects (page says "No terminal tab answered" when no
terminal tab is open); storage events repaint instantly; the dead /api/dashboard
fetch (404 on all three paths, 5 s stall) is gone; `dashboard --watch` / `--stop`
re-collects every 5 s; header says the data is this browser's instance.
Verified v4.6.51: panel rows "Synthesized 34s ago / v4.6.51 / 46-22 / 136-3 /
1 nodes 0 edges / OK / none recorded"; 130 s-old payload still renders with
"- 3m ago" and no banner (previously "Cannot connect"); storage event moves the
footer 13s -> 0s; watch timer advances the payload, --stop clears it; mobile
360/390 px all OK; 0 console errors.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
(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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
live run (v4.6.49)
Agent session surfaced two real defects:
1. The A4 prompt told it to use grep -n / sed -n 'N,Mp' / wc -l / head -N — none of those flags
parsed: grep treated '-n' as the pattern (6/6 variants failed), wc read '-l' as a filename,
head looked for a file named '-2', sed had no range parser. Fixed the tools, not just the text:
grep now accepts -n/-i/-c/-v/-l (line numbers were already printed), wc accepts -l/-w/-c,
head accepts -N and -n N, sed accepts Np and N,Mp, tail no longer prints a blank line for a
trailing newline. Prompt re-ranked to the working forms.
2. Loop guard keyed calls by tool name plus the raw arguments field. When arguments was already
an object (parsed upstream), the key became 'run_command:[object Object]', collapsing distinct
batched commands into one signature and producing false "called 3x" warnings. Now the key is
JSON.stringify(arguments) whenever it is not a string (3 sites: sig, _sigR, _sigD).
Verified live v4.6.49: grep -n/-c, wc -l, head -2, sed -n '2,3p', tail -n 1 all correct.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
- loop guard: a mutation unblocks the replay but no longer erases the repeat counter
(identical mutating calls could loop forever)
- tool traces are per agent tag, flushed in a catch as well as on success, ring-buffered
(first 2 + last 10) so verification reads survive
- read_file notes are metadata only (path/range/next_offset); no file bodies, no secrets,
and web_search/web_fetch output is excluded from durable context (injection surface)
- trace is role:'system' (was 'assistant' — the model re-read it as its own answer)
- surrogate-safe pagination, 500 floor / 16000 cap, prompt limits aligned
- prompt now names checks that exist in the in-page terminal (test, grep -n, wc -l)
- compressed summary capped at 4000 chars; denied-destructive tool result carries tool_call_id
|
| |
|
|
|
|
|
|
|
|
| |
read/tool/verify prompt rules (v4.6.46)
- read_file: offset/limit + JSON {total_chars,truncated,next_offset} (was a hard 8000-char cut with no resume)
- tool results now leave a per-turn trace that is persisted into session context and survives compression
- maxContextTokens 2000 -> 12000; compression keeps 8 exchanges and 400 chars/msg
- system prompt: page big files, prefer grep -n / sed -n / head, re-read + verify after every edit
- verified in the live browser: 30k file pages 0->8000->16000, prompt section present, v4.6.46 served
|
| |
|
|
|
|
|
|
|
|
|
|
| |
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)
|
| |
|
|
|
|
|
|
|
|
| |
reconciliation
- spawnAgent() accepts an idHint and is idempotent; boot team uses agent-<role>
- _reanimateFromVFS() adopts newest dir per default role, fs.rm()s duplicates/orphans
- _bootAgents() awaits async VFS hydration before reconciling, then spawns only gaps
- scripts/test-agents-reload.js: 5-boot regression + hydration-race test
- v4.6.44 bundle rebuild + cache-bust
|
| |
|
|
| |
capture, preview)
|
| | |
|
| |
|
|
| |
generator, telemetry-loop fix)
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| |
|
|
| |
daily maintenance+cron) + free store card
|
| | |
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
| |
Discovered by dav-health-check.sh E2E (10/10 pass now):
- nginx dav module REQUIRES trailing slash on MKCOL (no-slash → 409)
and on directory DELETE (no-slash → 409/404); existing dir + slash
MKCOL → 405 (the real 'already exists' signal)
- _normalizeRemotePath now PRESERVES trailing slashes (collection ops)
- _ensureDir MKCOLs with trailing slash
- _deleteFile retries with slash on 409/404 (collection delete)
- health-check expectations corrected (405 = existing, slash required)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Root cause fixes (mindtech incident):
- webdav.js: _normalizeRemotePath strips full URLs/space prefixes, applied
to all request entry points + _absoluteUrl for MOVE/COPY Destinations
- _ensureDir: __list__ existence fast-path (kills MKCOL 409 storms)
- dashboard-files.js: updateFilesJson parses __list__ autoindex (no more
'#' entries), ensureSpaceExists only re-inits on genuine 404
- 20-test regression suite: scripts/test-webdav-paths.mjs
Resilience:
- dav-auth-check.py: server-side WebDAV write auth microservice (nginx
auth_request on 8904) — anonymous/wrong-token writes now 401
- fail2ban-telegram.py: ban alerts + auto-unban for known space users
- backup-spaces.sh: daily hardlink snapshots, 14-day retention
- space-health-check.py: junk dirs / myfiles.json / version drift / session
sanity → Telegram alerts
- dashboard-files.js: visible 503 error panel with Retry + auto-retry
- v4.6.16: main.html + module-loader LATEST_VER aligned (was drifted)
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|