<feed xmlns='http://www.w3.org/2005/Atom'>
<title>newos4/scripts/build-changelog.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-06T10:40:54+00:00</updated>
<entry>
<title>fix(changelog): keep the newest commits of a build; wrap long detail URLs</title>
<updated>2026-11-06T10:40:54+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-11-06T10:40:54+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=7bdcd58762c60c9501657b9df2983999f276f8b1'/>
<id>urn:sha1:7bdcd58762c60c9501657b9df2983999f276f8b1</id>
<content type='text'>
Symptom: after bodies were rendered, this fix's own commit was missing from
its own entry, and a long URL inside an expanded detail was clipped at the
right edge on a 390 px screen.

Cause: items took group[:MAX_ITEMS] from a CHRONOLOGICAL list, so a 17-commit
build showed its first 14 and dropped the newest three (the count line said
"…and 3 more", hiding which three). And the injected detail CSS set no
overflow-wrap, so a 47-character URL pushed the paragraph to 320 px of
unbreakable text — the document stayed at 0 overflow only because the li
clipped it.

Fix: show group[-MAX_ITEMS:] and label the omitted ones "…and N earlier
commit(s)"; entry.commits follows the same slice. overflow-wrap:anywhere on
detail p/ul. The CSS block is now re-emitted from DETAIL_CSS behind
BEGIN/END sentinels instead of being write-once, and the first version's
sentinel-less block is stripped on sight so no page keeps two copies.

Verified: 390 px — p scrollWidth == clientWidth == 320, document overflow 0,
URL wraps; newest entry lists c759c50 and this commit; island 83 entries,
14 commit chips matching 14 shown items; CHANGELOG.md byte-identical on a
second run.
</content>
</entry>
<entry>
<title>fix(changelog): render the commit body, not just the subject</title>
<updated>2026-11-06T10:37:11+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-11-06T10:37:11+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=1983ce5796e45b312b142554cb717db7f8978bc8'/>
<id>urn:sha1:1983ce5796e45b312b142554cb717db7f8978bc8</id>
<content type='text'>
Symptom: the mirrored CHANGELOG.md (and the page) showed one-line commit
summaries while README promises "every shipped fix, symptom -&gt; cause -&gt; fix -&gt;
verified". A reviewer measured the gap from the public mirror and could only
conclude the claim overpromised.

Cause: scripts/build-changelog.py:59 formatted commits with %s only; %b was
never read, so the verification prose every fix commit carries (5b55af9 is a
typical one) was discarded before rendering. The MD writer then replaced every
tag with a backtick, so nothing richer could have survived anyway.

Fix: read %b with a %x02 terminator (line-based parser, multi-line body), split
it into paragraph/bullet blocks capped at 900 chars with a visible marker, and
render it twice from one source: as a native &lt;details&gt; per item on the page
(its renderer already assigns item HTML, so no JS change; CSS injected once
behind a sentinel) and as nested bullets under the line in CHANGELOG.md. The
"every build" gap note and the page dek were rewritten to describe what the
file now contains.

Verified: page 100 details render, first opens 23 -&gt; 232 px with 3 paragraphs,
no horizontal overflow, island parses (83 entries); two consecutive runs are
byte-identical for CHANGELOG.md; the double-escape bug this surfaced (code
spans shipped as &amp;amp;lt;sha&amp;amp;gt;) is fixed and grep for &amp;amp;lt; is 0.
</content>
</entry>
<entry>
<title>fix(changelog): stop prepending the preamble on every run</title>
<updated>2026-11-05T19:40:17+00:00</updated>
<author>
<name>WebX11 SysOp</name>
<email>darkmotox11@gmail.com</email>
</author>
<published>2026-11-05T19:40:17+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=842357847dee369da41e690a3069905200adf124'/>
<id>urn:sha1:842357847dee369da41e690a3069905200adf124</id>
<content type='text'>
write_md() put the H1 + description inside the generated body and also kept
old[:m.start()], so each regeneration added another copy: 44 runs left 44 H1s and
pushed the first release to line 179. Only the region between the markers is
generated now, an existing file with N copies is collapsed to one, and an assert
refuses to write a file containing two generated regions (proven RED by injecting
a duplicate). Regenerated: 83 entries, 185 commits, first heading v4.6.146 (was
v4.6.135 - the file had not been committed since 2026-11-02).
</content>
</entry>
<entry>
<title>fix(docs): apply the GLM-5.3 review to the changelog pipeline</title>
<updated>2026-10-27T16:42:46+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-10-27T16:42:46+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=cc9d0e34b9280b05fa4428d59c8dc16311091758'/>
<id>urn:sha1:cc9d0e34b9280b05fa4428d59c8dc16311091758</id>
<content type='text'>
Verdict was APPROVE WITH CHANGES: 21 findings, 17 fixed, 3 refuted with the command that killed
them, 1 kept with the audit that justifies it. The reviewer's best find was a design bug of mine,
not a typo.

- The age guard was unfixable by --fix and fired on a quiet week. check_changelog() regenerated only
  on a version mismatch, then returned from the version-match branch before the age check could act,
  so a page older than the threshold stayed red forever with the false diagnosis "the daily job is
  not running". Now --fix always regenerates (0.84 s) and age is read from a new `checked` stamp
  separate from `generated` (content-change time), which also stops a daily 65 KB rewrite of an
  unchanged page. Proved: seeded 641 h -&gt; FAIL + "run maintain --fix to refresh" -&gt; --fix -&gt; PASS.
- Atomic writes everywhere (temp + os.replace): nginx serves these files off disk, so an in-place
  truncate could hand a visitor half a page.
- The JSON island now escapes "&lt;/" (a commit subject containing &lt;/script&gt; would have closed it
  early and truncated the page). Proved by injecting exactly that subject: island still parses, no
  stray script tag, payload survives as data.
- Sibling drift is checked, not assumed: changelog.json's currentVersion is compared with
  LATEST_VER. Seeded v4.6.100 -&gt; FAIL "feed drifted", --fix repairs.
- Build tags are audited under --deep: 67 tags, each must be reachable from HEAD and name the
  version its commit tree carries. Proved by tampering (v9.9.9 on the root commit -&gt; FAIL) and by
  deleting it (-&gt; PASS).
- Feed: ids no longer hardcode 2026 or contain spaces, entries carry a &lt;link&gt;, timestamps are real
  iso-strict commit times instead of a fake T00:00:00Z on a local date, and summaries are truncated
  before escaping so no "&amp;l" tail. 0 ids with spaces, 0 broken entity tails.
- write_md refuses to overwrite a CHANGELOG.md that lost its markers; run() gained a 300 s timeout
  (a hung git used to block the whole 07:15 job); jumpToHash no longer stacks hint paragraphs;
  dead fields removed (KIND_ORDER, order, currentSynthesized, sourcesRead — each appeared exactly
  once in the page, i.e. only in the island the generator wrote).
- HTML nits: guide.html footer separator, empty "fixed in" line suppressed, help.html version
  bumped off v4.5.22. Header stat relabelled "Commits behind it" (it read "Bug records on disk"
  while counting commits — my own defect, not the reviewer's).
- Refuted: merge commits (repo has 0: `git log --merges | wc -l`), first-version board links (the 2
  multi-version notes both name the fixing build first), sources disclosure (the page already
  renders those module paths).

maintain --deep: node tests 20/20, changelog current, age 0.0h, 67 tags verified, result OK.
Mobile: ALL VIEWPORTS OK.
</content>
</entry>
<entry>
<title>feat(docs): tag builds, feed the changelog to machines, fail maintenance when it ages</title>
<updated>2026-10-27T16:28:56+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-10-27T16:28:56+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=7faf75f32e9f746869ca6fa9f9be8b0c376c11fa'/>
<id>urn:sha1:7faf75f32e9f746869ca6fa9f9be8b0c376c11fa</id>
<content type='text'>
Tasks 3, 4, 5, 6, 7 of the changelog plan.

- 67 build tags (v4.6.10 … v4.6.119) now exist, so a build is a ref instead of something that has
  to be re-inferred: `git log v4.6.118..v4.6.119` finally means something.
- The generator prefers tags, but via ONE `git for-each-ref` pass rather than a `git describe` per
  commit. That matters: describe-per-commit made the build 2.4-2.7 s against a 1.0-1.45 s baseline
  — i.e. tags made it slower, which the plan's gate said to treat as "tags bought nothing".
  The right fix was a bulk lookup, not dropping the tags: now 0.80-1.04 s (median 0.84 s) with
  output byte-identical to the untagged baseline (68 entries, same version order).
- changelog.json + feed.xml (Atom) are generated from the same page dict: 36 KB / 21 KB, 68/68
  entries, both HTTP 200, item markup stripped so a reader gets text not HTML.
- check_changelog() now also asserts the page was GENERATED recently, not merely that its version
  matches: a version match survives a dead cron forever. Seeded a 26-day-old timestamp -&gt;
  "FAIL: changelog: generated 640h ago (&gt;48h) - the daily job is not running", maintenance FAIL;
  restored -&gt; "PASS: changelog age 0.1h", maintenance OK.
- The exact cron pre-script was run end to end, not a stand-in: MAINTENANCE (--fix) block prints
  "PASS: changelog: changelog current: v4.6.119 (68 entries)" and "PASS: changelog age 0.2h",
  result OK, no second cron created.
- Scale trigger written into the generator's docstring (split by year at ~150 builds), not built.
- Mobile re-checked after the page gained the deep-link note: changelog + board both
  ALL VIEWPORTS OK at 360/390 px, light and dark.
</content>
</entry>
<entry>
<title>feat(docs): generate the changelog from git and keep it current in maintenance</title>
<updated>2026-10-27T16:18:30+00:00</updated>
<author>
<name>Agando</name>
<email>roduccomm@gmail.com</email>
</author>
<published>2026-10-27T16:18:30+00:00</published>
<link rel='alternate' type='text/html' href='https://newos.webx11.duckdns.org/newos4/commit/?id=7165c9eeccce44d4cd83194de5a200973e80c45a'/>
<id>urn:sha1:7165c9eeccce44d4cd83194de5a200973e80c45a</id>
<content type='text'>
The page at spaces/agando/downloads/changelog.html was hand-built from VFS notes by the
in-page agent: 11 entries, huge honest holes ("v4.6.59 - v4.6.100 unknown"), and it had
stopped at v4.6.101 while the app was running v4.6.119. A docs page that lags the release
reads as current, which is worse than no page.

- scripts/build-changelog.py derives every entry from git: it walks commits touching
  spaces/newos4, stamps each with the LATEST_VER that was live at that commit, and groups
  them into builds. Kinds map onto the page's own vocabulary (feat-&gt;release, fix-&gt;fix,
  test-&gt;review, docs-&gt;docs, chore/style/refactor-&gt;project), and a build's chip is its
  dominant kind. Commits whose prefix carries `backticks` render as &lt;code&gt;, escaped first.
- The page is its own template: everything visible comes from the #changelog-data JSON
  island, so regeneration swaps the island and refreshes the two prose blocks that
  described the VFS-only source. No second copy of the CSS or the 296-line renderer.
- Every unshowable thing is stated, not smoothed: commits before the first version stamp
  become one "before v4.6.10" bucket, build numbers that were bumped twice before a commit
  are called out as absent, and the page says entries summarise subjects, not diffs.
- CHANGELOG.md is generated from the same data between markers (app-scoped; the root
  CHANGELOG.md documents the platform's 0.2.x line and is left alone).
- newos4-maintain.py gains check_changelog(): FAIL when the page's build differs from
  LATEST_VER, regenerate under --fix, PASS when current. So the daily 07:15 job keeps the
  docs in step with the build instead of relying on someone remembering.

Verification:
- build: 68 entries, 158 commits, v4.6.10 - v4.6.119, page 63 327 bytes, CHANGELOG.md 15 840.
- live page renders 68 entries with kind chips, search, per-build anchors ("Copy a direct
  link to v4.6.119"), "68 of 68".
- stale detection proved by bumping LATEST_VER to v4.6.120 without rebuilding:
  "FAIL: changelog changelog stale: page says v4.6.119, build is v4.6.120"; --fix then
  "PASS: changelog regenerated: ... v4.6.10 - v4.6.120"; version reverted, page back to 119.
- maintain: PASS node tests 20/20, PASS changelog current: v4.6.119 (68 entries), result OK.
- mobile: verify-mobile.py at 360/390 px, light+dark -&gt; ALL VIEWPORTS OK, 0 overflow.
</content>
</entry>
</feed>
