diff options
| author | Agando <roduccomm@gmail.com> | 2026-10-23 21:32:41 +0200 |
|---|---|---|
| committer | Agando <roduccomm@gmail.com> | 2026-10-23 21:32:41 +0200 |
| commit | fcee056449e500941ea1ee00db66b0fd7d9d3f44 (patch) | |
| tree | c445e5dca8f67c1cfa9a9fb2d479f61e2955b55e | |
| parent | 0090606421e32bc492f81f1c533bce9a41845a20 (diff) | |
fix(newos4): audit names broken refs instead of counting documentation (v4.6.86-87)
The reference checker ran /skill-view \S+/ over every skill's prose, so 'skill-view <name>' and a
quoted example in skills-system-guide were counted as missing skills: 'Broken refs: 2' with no
names, both phantom. Placeholders and quoted names are now ignored (trailing punctuation stripped
first), and the survivors are listed in the audit line and in the suggestion.
Verified: clean tree -> Broken refs: 0. A probe skill referencing 'ghost-skill' -> Broken refs: 1
(probe-broken-ref → ghost-skill), while '<name>.' and '"module-management"' in the same file are
ignored.
| -rw-r--r-- | help.html | 17 | ||||
| -rw-r--r-- | main.html | 6 | ||||
| -rw-r--r-- | modules/core/module-loader.js | 2 | ||||
| -rw-r--r-- | modules/ext/skill-pack-core.js | 21 |
4 files changed, 37 insertions, 9 deletions
@@ -1689,6 +1689,23 @@ listmods</pre> <h2>📋 Changelog</h2> <div class="version-item"> + <div class="v-header"><span class="v-num">v4.6.86–87 — October 2026</span> + <span class="v-date">audit honesty, static assets</span></div> + <ul> + <li><strong>"Broken refs: 2" named neither of them — because both were documentation.</strong> + The checker grepped for <code>skill-view <name></code> in every skill's prose, so + the placeholder and a quoted example counted as missing skills. Placeholders are now + skipped, and any real breakage is named: + <code>Broken refs: 1 (probe-broken-ref → ghost-skill)</code>.</li> + <li><strong>Two quick reloads no longer break the app.</strong> Opening newOS4 costs about + 35 module requests at once; the site-wide rate zone (60 r/min, burst 50) treated that as a + flood and served <code>503</code> for part of the bundle — measured 4 modules failing on a + third reload. Static module and skill files now have their own zone; HTML and API requests + keep the strict one.</li> + </ul> + </div> + + <div class="version-item"> <div class="v-header"><span class="v-num">v4.6.85 — October 2026</span> <span class="v-date">no invented numbers</span></div> <ul> @@ -1349,13 +1349,13 @@ </script> <!-- v4.5.63: A2A scratchpad fixes + agent-register arg fix --> -<script src="modules/core/core-bundle.js?v=v4.6.85"></script> +<script src="modules/core/core-bundle.js?v=v4.6.87"></script> <!-- Async dependency-ordered module loader now only initializes terminal and loads optional ext modules --> -<script src="modules/core/module-loader.js?v=v4.6.85"></script> +<script src="modules/core/module-loader.js?v=v4.6.87"></script> <!-- Critical ext bundle loads AFTER webx11 exists so registerModule calls work --> -<script src="modules/ext/critical-ext-bundle.js?v=v4.6.85"></script> +<script src="modules/ext/critical-ext-bundle.js?v=v4.6.87"></script> <script> // ═══ ONE TRUE VERSION SOURCE ═══ diff --git a/modules/core/module-loader.js b/modules/core/module-loader.js index 1b0f6d9..37212f3 100644 --- a/modules/core/module-loader.js +++ b/modules/core/module-loader.js @@ -4,7 +4,7 @@ // Core module bundle loaded synchronously in main.html. // This loader only handles version cache-busting, splash, terminal init, and optional ext modules. - const LATEST_VER = 'v4.6.85'; + const LATEST_VER = 'v4.6.87'; const CACHE = '?v=' + LATEST_VER; const stored = localStorage.getItem('webx11_cache_ver'); if (stored !== LATEST_VER) { diff --git a/modules/ext/skill-pack-core.js b/modules/ext/skill-pack-core.js index cba77b6..c2c95ba 100644 --- a/modules/ext/skill-pack-core.js +++ b/modules/ext/skill-pack-core.js @@ -1195,6 +1195,7 @@ after the behaviour itself was fixed in v4.6.58.`), var stale = []; var duplicates = []; var brokenRefs = 0; + var brokenList = []; // 1. Stale check const mg = this.terminal?.moduleManager?.modules?.['MemoryGraphModule']; @@ -1226,13 +1227,23 @@ after the behaviour itself was fixed in v4.6.58.`), } // 3. Reference check + // Documentation is not a reference: `skill-view <name>` and quoted examples inside a skill's + // prose were counted as broken skills, so the audit reported 2 phantom breakages and named + // neither. Placeholders are skipped and the survivors are listed. for (var name of allNames) { var content = fs.readFile('/skills/' + name + '.md'); if (!content) continue; - var refs = content.match(/skill-view\s+(\S+)/g) || []; + var refs = content.match(/skill-view\s+("[^"]+"|\S+)/g) || []; for (var ref of refs) { - var refName = ref.replace(/skill-view\s+/, '').replace(/\.md$/, ''); - if (!fs.readFile('/skills/' + refName + '.md')) brokenRefs++; + var refName = ref.replace(/skill-view\s+/, '').replace(/^"|"$/g, '').replace(/\.md$/, ''); + // prose puts punctuation after an example: "skill-view <name>." — strip it before + // deciding whether this is a placeholder or a real skill name + refName = refName.replace(/[.,;:!?)]+$/, ''); + if (!refName || /^<.*>$/.test(refName)) continue; // `<name>` is a placeholder + if (!fs.readFile('/skills/' + refName + '.md')) { + brokenRefs++; + brokenList.push(name + ' → ' + refName); + } } } @@ -1246,14 +1257,14 @@ after the behaviour itself was fixed in v4.6.58.`), this.terminal.print('Untracked: ' + untracked.length + ' (no usage telemetry — NOT stale)', 'info'); } this.terminal.print('Duplicates: ' + duplicates.length + (duplicates.length > 0 ? ' (' + duplicates.join(', ') + ')' : ''), duplicates.length > 0 ? 'warning' : 'info'); - this.terminal.print('Broken refs: ' + brokenRefs, brokenRefs > 0 ? 'error' : 'info'); + this.terminal.print('Broken refs: ' + brokenRefs + (brokenRefs > 0 ? ' (' + brokenList.join(', ') + ')' : ''), brokenRefs > 0 ? 'error' : 'info'); this.terminal.print('', ''); if (stale.length > 0 || duplicates.length > 0 || brokenRefs > 0) { this.terminal.print('Suggestions:', 'info'); for (var st of stale) this.terminal.print('• Archive ' + st, 'warning'); for (var dup of duplicates) this.terminal.print('• Merge ' + dup, 'warning'); - if (brokenRefs > 0) this.terminal.print('• Fix ' + brokenRefs + ' broken reference(s)', 'warning'); + if (brokenRefs > 0) this.terminal.print('• Fix ' + brokenRefs + ' broken reference(s): ' + brokenList.join(', '), 'warning'); } else { this.terminal.print('✅ All skills healthy', 'success'); } |