| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
unknown
Three follow-ups from the merge review, each with the assertion that pins it.
module-memory-graph.js
- _normalizeEdges no longer mutates stored weights. It capped legacy 'failed' edges
from 0.8 to 0.2 in memory, and the next debounced save made that permanent - an
irreversible migration of the user's graph with no schema version. The cap moved to
_effectiveWeight(), which ranking (showStats "Strongest relationships"), the session
view and prune() now use; the stored record is left exactly as written.
- config.json is stamped version: 2 so a future format change can migrate deliberately.
ext/webdav.js
- the two fallback parsers emit size: null instead of 0. They cannot see the size
column, and 0 rendered as "0 B" - the same "every file looks empty" symptom as the
parseInt bug fixed in e639c2d, one regex miss away.
- _formatSize(null) renders '—' (unknown) rather than '0 B'; 0 still renders '0 B'.
module-aiassist.js
- the lock timeout now says what to do: "AI is still busy with another turn (waited Ns).
Wait for it to finish, or run 'ai-stop' and retry - the running turn's lock is left
alone." It used to be a dead-end string.
Tests: test-memory-graph 39 (T6.4 rewritten to the read-time contract: stored weight
stays 0.8, effective 0.2, success unaffected), test-webdav-sizes 28 (A14d null -> '—').
maintain 26/26, live v4.6.141: _effectiveWeight 0.2 with the edge object unchanged,
_formatSize(null) '—', '0 B' still '0 B'.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Closes STEER-20261102-205416-facd and STEER-20261102-204031-f82a.
WebDAV (modules/ext/webdav.js):
- listings showed "21 B" for a 21 KB file: nginx emits humanised sizes
(autoindex_exact_size off, vhost :412) and _parseAutoindex did parseInt("21K").
_parseAutoindexSize() handles K/M/G, decimals, lowercase and "-"; PROPFIND's
exact getcontentlength path is untouched.
- webdav-pull into a missing local directory printed "Pulled: ... (N bytes)" and
wrote nothing: it ignored fs.writeFile's false return (virtual-fs.js:561).
It now creates the parent chain, checks the write, and only reports success
after a confirmed write. The byte count uses TextEncoder, not .length
(a Cyrillic file under-reported ~2x).
- _formatSize gained the GB branch the parser already accepted (3 GB printed
"3072.0 MB") and no longer prints "NaN MB" for a missing size.
MemoryGraph (modules/core/module-memory-graph.js):
- addEdge averages weights, so every repeat pulled a strong edge toward the
call site's constant (0.9 -> 0.7 -> 0.6). Now Math.max, with decay left to
applyDecay(); prune() untouched.
- task ids were `task-${Date.now()}`, so re-submitting a task never deduped:
now a hash of agent + normalised text.
- recordFileAccess no longer records the graph's own /.memory_graph/ store.
- failed tool calls were weighted 0.8 vs success 0.5, so showStats ranked
failures as strongest: now 0.2. Legacy 0.8 failures are capped on load.
- concept ids keep punctuation ("concept:(v2!),"): slugged, and the slug uses
\p{L}\p{N} so Cyrillic/CJK/accented text still yields nodes -- an a-z0-9 slug
silently produced none.
Review findings folded in from the regression pass: the non-Latin regression
(a-z0-9 slug), the GB formatter asymmetry, and the pull byte count were all
found by review, not by the patch authors, and each now has a test.
Tests: test-webdav-sizes.js 27 (was RED 15/24 before the fix), test-memory-graph.js
37 (RED 17/32), both auto-discovered by newos4-maintain -- 26/26 node tests.
Live on v4.6.140: _parseAutoindexSize('21K') 21504, _formatSize -> "21.0 KB",
_formatSize(2GiB) "2.0 GB", slug Cyrillic "исправить-парсер-ошибок", 0 console errors.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
a corrupt memory graph
The three items the last review and probes left open, each with a test that is red on HEAD.
- MAINT-023 (module-aiassist.js): one agentic turn grew without limit — every role:'tool' body
was pushed verbatim and only this.context was trimmed BETWEEN turns (measured 6 -> 112 705
tokens across 8 model calls against maxContextTokens 12 000). Observations are now clipped to
maxToolResultChars (6 000) with a note saying how much was withheld and to re-read with
offset/limit, and _boundToolContext() elides the oldest tool bodies once the running total
passes toolContextBudgetChars (24 000), always keeping the newest 4 verbatim. The ceiling is
turn-independent: the same ~26 k chars at 8 turns and at 20.
- MAINT-024 (modules/ext/skill-pack-core.js): the command printed "✅ Skill created" with
fs.writeFile()'s boolean discarded (probe: fresh VFS, success printed, no file), stripped
invalid characters instead of rejecting the name (My-Skill -> y-kill, DevOps_Thing ->
evpshing), and treated an unreadable /path argument as the skill body. Now: kebab-case is
validated (uppercase normalises and the final name is reported; anything else is refused),
/skills is created on first use, the write and index results are checked, and an unreadable
body path is an error.
- MAINT-003 (module-memory-graph.js): a corrupt store looked exactly like a fresh install —
fsReadJSON returns null on a parse failure, so 85 nodes could vanish with no warning and no
copy. The probe confirmed the loss: seed 6 nodes, truncate nodes.json and export.json, reload
-> 1 node, no message, nothing in .trash. _quarantineCorrupt() now keeps the unreadable file
as <name>.corrupt, warns, and then loads from whatever remains.
Tests: test-tool-context-bound.js (11), test-skill-create.js (16), test-memory-graph-recovery.js
(8). RED on HEAD: tool-context crashes on _clipToolResult (exit 1), skill-create 16 assertions
fail on the missing file/index, memory-graph B1/B2/C1 fail (no warning, no .corrupt copy).
Suite now 13/13 files green; maintain --fix reports "node tests 13/13 pass".
Live on v4.6.107: skill-create My-Skill -> ✅ "my-skill"; DevOps_Thing -> Invalid skill name;
/does/not/exist.md -> Cannot read skill body; only my-skill in the index.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
getStaleSkills() returned daysUnused=999 for a skill that had useCount 0 and no lastUsed — a
placeholder rendered by the audit as '999d unused', indistinguishable from a measurement. It told
the operator to archive procedural memory that had simply never been instrumented.
Now: daysUnused null + neverUsed true when there is no lastUsed; real day count otherwise; the
audit prints '(never used)'.
Verified: probe skill with no telemetry -> {daysUnused: null, neverUsed: true}; one last used
2026-08-01 -> 83; no 999 anywhere in getStaleSkills() or the audit output.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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).
|
| | |
|
| |
|