<feed xmlns='http://www.w3.org/2005/Atom'>
<title>newos4/scripts/newos4-feedback-collect.py, branch main</title>
<subtitle>newOS4 - the browser terminal that runs WebX11 user spaces</subtitle>
<id>https://newos.webx11.duckdns.org/newos4/atom?h=main</id>
<link rel='self' href='https://newos.webx11.duckdns.org/newos4/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/'/>
<updated>2026-11-02T19:31:05+00:00</updated>
<entry>
<title>feat(feedback): chat plane on the dashboard + honest triage ranking</title>
<updated>2026-11-02T19:31:05+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-11-02T19:31:05+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=431cef232d2804c0568ff3f3c1e95caaa6be6870'/>
<id>urn:sha1:431cef232d2804c0568ff3f3c1e95caaa6be6870</id>
<content type='text'>
Tasks 3-8 of the chat-plane plan:
- cron newos4-chat-ingest (0cc4bb4d2f82, */10, script-only, silent when idle)
- collect.py: plan_key() normalises the two ledger spellings on read (5 rows
  carried a plan name without .md and were silently unmatched); per-item
  bulk_pass for the 2026-10-26 pass; counts.chat_total
- feedback.html: 5th tile "from chat"; card shows who closed an item and when,
  with a bulk marker
- triage: UNFILEABLE class -&gt; top_real now ranks actionable errors only
  (first row went from an 18 203 fetch failure to the 989 toLowerCase runtime
  error); network/abort signatures move to policy_noise
- AGENTS.md: the chat plane documented as an intake

Verified: autoreview --dry-run over the 5 chat reports -&gt; "nothing provable
(5 left for the operator)" (R6 refuses auto:false); maintain 16 PASS 0 FAIL;
feedback.html inline JS node --check OK; collect -&gt; awaiting 5, chat_total 5.
</content>
</entry>
<entry>
<title>fix(newos4): pipe stage quoting, maintain ordering, help cost row, plan status (v4.6.131)</title>
<updated>2026-10-29T11:42:30+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-10-29T11:42:30+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=320877d2c8a3bb6be3d32780ecfc6e7d14528f66'/>
<id>urn:sha1:320877d2c8a3bb6be3d32780ecfc6e7d14528f66</id>
<content type='text'>
Four items closed in one batch; three ran as parallel subagents on disjoint files, the bundle was
rebuilt once by the parent (rebuild-bundles.py serialises the working tree, which carries other
sessions' work — see 161372f).

1. PIPE STAGES KEEP THEIR QUOTES. `js "a b".length | wc -c` reached eval as `a b.length` and printed
   a ReferenceError. terminal.js executePipeChain() now keeps `stages[i]` aligned 1:1 with
   `pipeParts[i]` (the `.filter(argv =&gt; argv.length &gt; 0)` shifted the index; replaced by a lastStage
   scan + `if (argv.length === 0) continue`) and forwards the stage's own text to the dispatcher.
   The core path alone was dead code: ShellModule.init() replaces terminal.executePipeChain
   (shell.js:144), and that override is what runs in the browser (`executePipeChain.toString()`
   contained `cmdText.split`, not `lastStage`). Both now pass `cmdText`/`pipeParts[i]`.
   test-pipe-guard.js was rewritten for the new shape and now also asserts the shell override
   forwards raw text — the assertion that would have caught the shadowing. RED on HEAD: both flags
   false; GREEN now.

2. MAINTENANCE --fix CAN CLEAR ITS OWN WARN. check_index() ran before check_atlas(), which is what
   regenerates course/atlas.json, so --fix rebuilt modules-index.json from the stale atlas and the
   same WARN reappeared every run. check_atlas() now runs immediately before check_index().
   modules-index.json regenerated: cost/usage present, 349 commands, version 2026-10-29-atlas.

3. `cost` DOCUMENTED. modules/core/module-billing.js registers `cost [on|off]` (an alias of `usage`);
   help.html had no row. Added above the `usage` row. help coverage 362/363 -&gt; 363/363.

4. SHIPPED PLANS STOP ASKING FOR A DECISION. The applier only flips review&lt;-&gt;safe, so every executed
   review-gated plan kept counting as an open decision (5 of 5). newos4-feedback-collect.py now reads
   the body: a `## Status` / `## Implementation` heading followed by shipped|executed plus a version,
   commit or date is `status: done`; those stay in `plans` (visible as shipped) but leave
   plans_review and awaiting_decision. Counts: plans_review 5 -&gt; 0, awaiting_decision 4 -&gt; 1
   (the remaining one is a real open report, RPT-20261027-160751).
   admin/feedback.html read `it.status[0]`, which would render `d` for a string status; it now
   prefers `status_lines[0]`.

Also carried, authored by earlier uncommitted sessions and already live in the bundle (attributed,
not silently absorbed): modules/core/module-billing.js (new, BillingModule: cost/usage),
its CORE_FILES entry in scripts/rebuild-bundles.py, and the BillingModule registry entry in
terminal.js. The bundle was rebuilt from HEAD + this batch with ollama-manager.js taken from HEAD,
so another session's in-flight `_httpError` refactor is deliberately NOT in the shipped bundle
(grep -c _httpError core-bundle.js = 0).

Verification
  node modules/test/test-pipe-guard.js   -&gt; {"empty":[],"blank":[],"classifyGuarded":true,"pipeGuarded":true,"shellForwardsRaw":true}
  node modules/test/test-parse-args.js   -&gt; 28/28 pass
  maintained job                          -&gt; node tests 21/21 pass
  scripts/newos4-maintain.py             -&gt; maintenance result: OK (modules-index 349, help 363/363,
                                            changelog current v4.6.131)
  live v4.6.131 (real DOM, no print monkey-patch):
    js "a b".length | wc -c   -&gt; 1        (js printed 3, one byte)
    js "a b".length           -&gt; 3
    js "abc".toUpperCase()    -&gt; ABC
    echo "two words"          -&gt; two words
    node -e "import('fs')"    -&gt; red error + Node-builtin hint
    js 6*7                    -&gt; 42
    unhandledrejection        -&gt; 0
  livePipeImpl: shell-override, livePipeForwardsRaw: true, costRegistered: true
</content>
</entry>
<entry>
<title>feat(feedback): autonomous first-pass reviewer — decide what is provable, leave the rest</title>
<updated>2026-10-26T13:50:54+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-10-26T13:50:54+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=5512726541dc7f7e7144695677c3e1d63cba02ad'/>
<id>urn:sha1:5512726541dc7f7e7144695677c3e1d63cba02ad</id>
<content type='text'>
The operator asked: "when I don't do anything, an agent can do it for me and I can just follow up
or steer it." This is that agent, deterministic (no LLM): same input, same decision, and every
reason is a grep or a commit hash that can be checked.

spaces/newos4/scripts/newos4-feedback-autoreview.py — rules, first match wins:
  R1 duplicate      same fingerprint already decided                     -&gt; resolve
  R2 already-fixed  identifiers absent from modules/**/*.js AND
                    `git log -S&lt;token&gt;` proves a commit removed them     -&gt; resolve
  R3 noise          fetch/abort/probe patterns                          -&gt; reject
  R4 still-present  auto report + stack + identifiers still in code     -&gt; approve (max 2/day)
  R5 plan / R6 user report                                             -&gt; never decided

Writes to the same append-only decisions.jsonl with actor=auto-reviewer, note + evidence; the
applier's last-wins rule means any operator click overrides an agent decision. Kill switch:
data/feedback/autonomy.json {"mode":"off"} (safe default, aggressive = cap 5).

Cron job e31ac58a559e, 07:40 and 19:40, no_agent, silent unless it decided something.

Fixture proof (6 cases, /tmp corpus, git repo with a real removal commit):
  RPT-A duplicate        -&gt; resolve (duplicate of already-decided RPT-B)
  RPT-C already-fixed    -&gt; resolve (goneFromCode removed from modules/ in fc4eaf3)
  RPT-D noise            -&gt; reject
  RPT-E still-present    -&gt; approve
  RPT-F user report      -&gt; SKIP
  RPT-G never existed    -&gt; SKIP   &lt;- caught the first draft, which called it "already fixed"
Live dry-run on the real corpus: "nothing provable (0 left for the operator, mode=safe)" and
`git log -S emptyTrash -- spaces/newos4/modules` resolves to 563a9be, i.e. the report I wrongly
approved by hand tonight would have been auto-resolved correctly.

Dashboard: agent-decided cards carry a 🤖 badge + the reason + "Any button below overrides it",
and the tab shows "🤖 feedback agent: N decided on its own in its last run (safe mode, M left for
you)".
</content>
</entry>
<entry>
<title>feat(newos4): filter network-class auto reports at ingest — count, don't file</title>
<updated>2026-10-26T13:45:36+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-10-26T13:45:36+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=4179025e04093eecedb11d1d5355e994d755c14f'/>
<id>urn:sha1:4179025e04093eecedb11d1d5355e994d755c14f</id>
<content type='text'>
The debug supervisor files an auto report for any failed fetch, so a flaky phone connection or a
retired endpoint became a review card. One cluster held 14 407 + 1 031 occurrences and produced
3 of the 19 cards in the queue; 10 of 21 items reviewed on 2026-10-26 were noise for this reason.

api/debug/report.php: an auto report whose *every* error is network-class (fetch failed /
failed to fetch / network error / load failed / aborted / signal is aborted / ERR_INTERNET_*)
now increments data/debug/network_failures.json (per day, per source path, top 40 kept) and
returns 202 {filtered:"network"}. No RPT file, no card.

Never filtered: any report with auto=false (user content), and any auto report carrying a
stack/TypeError, i.e. a real defect. Verified on a throwaway tree and live through nginx:
  auto network poll.php   -&gt; 202 filtered, no file
  auto network /ollama/   -&gt; 202 filtered, no file
  auto TypeError + stack  -&gt; 201 filed (RPT-20261026-134455-95f10612)
  user report w/ "fetch"  -&gt; 201 filed (RPT-20261026-134455-ab0f2cd4)
Live: counter total=1 by_source {'/spaces/newos4/api/chat/poll.php': 1}, reports stayed at 19.

The dashboard now shows the counter instead of silence:
  "🌐 1 network failure counted at ingest today, not filed as cards — /spaces/newos4/api/chat/poll.php ×1"
</content>
</entry>
<entry>
<title>feat(feedback): preview a plan or report in a modal before deciding</title>
<updated>2026-10-26T12:58:12+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-10-26T12:58:12+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=2c5e5a7693af9591ec91282af7d3acdddfd365c1'/>
<id>urn:sha1:2c5e5a7693af9591ec91282af7d3acdddfd365c1</id>
<content type='text'>
The cards only carried a title, a path and buttons — approving blind was the only option.
The page cannot read .hermes/plans/*.md itself (600 darkbot, php-fpm is www-data), so the
collector — already running as darkbot every 10 minutes — now embeds what a decision needs:

  plans   -&gt; excerpt (first 60 lines, 2.4 KB cap), task headings, status/implementation lines
  reports -&gt; body, page url, newOS4 version, user agent, first 3 error strings

Modal: click a card title (or, on a report, read it in place) -&gt; title, meta line with
path/size/modified/task count/decision, the text in a scrollable monospace block, and the
same Approve / Reject / Noise / Resolve actions. Esc, backdrop and the X close it; on a
phone it is full-screen. Cards and modal share one actButtons() helper instead of
duplicating markup.

Also fixes a bug I introduced earlier: recent_apply() referenced APPLIED, which was never
defined — the NameError was swallowed by the function's own except, so the "last decision
applied" line could never render. It now shows, e.g. "last decision applied 2026-10-26
12:47:03 UTC (plan:…mobile-download-share.md → approve)".

Verified: node --check on the inline script; browser harness against the real snapshot
(plan modal shows Goal + 9 tasks + status, report modal shows message/errors/page/ua,
Esc closes); verify-mobile 390/360 x light/dark ALL VIEWPORTS OK with the modal open;
collector py_compile + run (recent_apply 8 rows).
</content>
</entry>
<entry>
<title>feat(feedback): review dashboard, public guide, terminal commands (v4.6.94)</title>
<updated>2026-10-26T12:03:11+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-10-26T12:03:11+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=66d30f637b763c6f4c5061e4fde306cc66ef7f59'/>
<id>urn:sha1:66d30f637b763c6f4c5061e4fde306cc66ef7f59</id>
<content type='text'>
Dashboard (/admin/feedback.html, admin-gated)
- User-feedback tab over the live :8908 API: list, filter, search, publish reply,
  archive/reopen. Reply is what the reporter sees in /stear -&gt; Your reports &amp; replies.
- Agent-items tab: 3 plans parked at autonomy:review + 19 defect reports, one click each.
- Snapshot age line + stale warning (&gt;30 min), and the last apply outcome with failures.
- Existing /admin/ tab relabelled "Client error log" (it renders feedback_log.json, not
  the feedback store) and now links to the review dashboard.

Decision path
- admin/api/feedback-decide.php: exact-match nginx location + auth_request, Origin check,
  item_id allowlist, append-only decisions.jsonl with fwrite+fsync verification.
- scripts/newos4-feedback-apply.py (darkbot): last decision per item wins, superseded rows
  recorded, reject reverts safe-&gt;review, per-item try/except, ledger saved per mutation,
  realpath containment, exact standalone-line marker flip, file mode preserved, queue
  rotation at 1 MB. Steering directives now carry the report title.
- scripts/newos4-feedback-collect.py: snapshot for the dashboard, 40-line plan head,
  steering shape assert (-1 = unknown), recent_apply outcomes.
- newos4-feedback-sync.sh: flock -n so overlapping runs cannot double-apply.

Guide + terminal
- feedback-guide.html: which channel (terminal feedback / /stear / automatic reports),
  expectations, exact payload per channel, how to write a report that gets fixed.
  Linked from /stear, index.html footer and help.html.
- newOS4: feedback list|read|reply|archive|reopen|stats|dashboard|help (+ feedback-admin
  alias), admin-token derived per call, argument-validated dispatch so a sentence like
  "feedback list is broken on mobile" is still a message, "feedback -- &lt;text&gt;" forces it.
- help.html: 8 rows, coverage 362/362.

Review: glm-5.3 REWORK -&gt; 15 findings fixed, 5 refuted with evidence, 2 doc-only.
Guide corrected (invented "60 MB per batch" replaced by the real 512 KB/5-per-10-min limits).
</content>
</entry>
</feed>
