Tier 88 (context/plans/build-site.md): the registry had no unblocked task left; what remained to an
agent were criteria no task covered any more.
T-518. Criteria met by earlier tasks ticked with their evidence: gpu R11's review (T-513 and Codex's
2026-10-24 pass), content-blocking R7 (the bundle's sha check against NOTICE and the lists' README, the
README paragraph with cardview.jpg, round 26's licence reading), modern-web R1 (T-484 and run 2c; the
README's Caveats link) and T-500's two. T-501's stays [~] for MSE (below). The template placeholders
never filled (T500_KIT, T501_KIT, T501_DEVICE_RESULT in docs/MODERN-WEB.md, DEVICE_STATE_EVENING and
TRACE_PICKUP in PICKUP) are filled; .cavekit/config is the owner's one line again; the README's
"Where it stands" regenerated.
T-519. On the build with the review fixes (engine 0058), the 10 s scripted pan on six pages under
JIHAD_GPU_VERIFY=1 (docs/rounds/t519-2026-10-24/): 0 rows structurally wrong on all; 0 rows differ at
all on the long page, jihad-fixed-both.html (new: an opaque header AND footer, nothing else), sticky-mix,
scroll-js and Hacker News; Wikipedia 3 of 70 frames with resampling-class rows. The one miss is the
verify mode's own: on jihad-anim-css.html the animated block's 160 rows differ (the reference samples the
animation at its own compose time), every other row equal — R2's first criterion [~] with the engine
fix named. The dumps looked at frame by frame; Hacker News at 0.955 shows its right side and bottom.
R4's four ticked on the compositor's lines: the fixed-both page reads two bands with both kept, the long
page one kept, Wikipedia's see-through panels as 2 columns in 3-5 chunks; sticky-mix takes the whole path
as in T-503's rounds (its sticky layer changes every step). R3's table: the GPU path against NOGPU=1 on
every page, in docs/RENDERING-OPTIONS.md — the GPU path ahead on every page (long static 30-33 against 11-12.5 fps, Wikipedia 18.5-26 against 2.7-2.9, Hacker News 37-48 against 6-10). The frame rates were measured again
without verify after a first sweep read 5-6 fps under it (a whole reference per job):
tools/device/t502/README.md says so; pan-run.sh takes ROUND_DIR.
T-520. The blocker's device criteria on the Enyo card through the inject channel, the listed hosts mapped to the
host PC in the device's /etc/hosts for the run (only the blocker can then stop a load): a listed host opens
top-level; EasyPrivacy's ||123count.com^$third-party loads first-party (the page on that host) and is refused
third-party; an @@||host^ exception (a list copy with one added, exceptions 6+1083 against 5+1079) loads the
host; the master switch and hiding flip live through setpref (the observer re-applies the sheet); the
settings line shows the versions and a counter that rose 10 -> 16 on a page with 6 refusals; "Update the lists
now" moved the lists three times and the line followed; shouldLoad on 200 refused images is within 10 % of
blocking off (6.5 against 6.0 s, the floor the engine's own per-image work); MSE reports H.264 and AAC
(T-501's criterion closed). R4's cost criterion was NOT met: hiding on cost the MDN page's copy 3.7-7.5 s
against 2.6-3.0 off, the real cached page 15 against 11, and a daemon's first load 8-12 s.
T-522. Four variants of the cached sheet on the device named the cost: the 268 @-moz-document regexp groups
(one per site-excepted generic selector, each carrying the 160 generic-hide hosts' 2.4 KB regexp again),
evaluated per document; the same 13,079 keyed selectors under url-prefix scopes or bare cost nothing. The
compiler (version 11) keeps those selectors apart (excSel) and the component adds them to the per-document
sheet for every host the selector is not excepted on, with the generic-hide sites (hosts and address
prefixes) honoured there too; the global sheet keeps its one regexp group. Measured: the MDN copy with hiding on 2868, 3104, 2876 ms against 2712, 2578, 2846 off
(+8.7 %, within R4's 15 %), a daemon's first load 3.7 s where it took 8-12; generic hiding still applies
under a host name, a site-excepted selector is hidden where not excepted, and a $generichide host
(jetzt.de mapped to the host PC) gets neither; the compile reports 268 excepted selectors per document and
154 generic-hide sites with 4 address prefixes.
New test pages: jihad-fixed-both.html (an opaque header and footer), jihad-tp-first/third.html,
jihad-exception.html, jihad-hiding.html, jihad-excsel.html, jihad-mse-probe.html, jihad-plain-ok.png.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The kit's three criteria ticked with their evidence (the gate and the shipped daemons' three startup
lines, the 57 patches reproducing the pin, the docs' numbers); PICKUP's evening delta (T-505/T-511/T-517
blocked by the circuit breaker, the registry's cycle broken, detached builds); the README's progress
regenerated from the kits. Next: T-513, Tier 87's review.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The [jihad-gpu] lines of the engine and the daemon print only with JIHAD_GPU_LOG=1, or in a device
round's JIHAD_GPU_TIMELINE, JIHAD_GPU_VERIFY or JIHAD_GPU_DUMP_EVERY; failures and fallbacks print
anyway. One gate each: the engine's gfx/2d/JihadGpuLog.h (engine 0057, exported as
mozilla/gfx/JihadGpuLog.h) and the daemon's render/goanna/JihadGpuLog.h. A daemon on the GPU path now
logs three startup lines from the engine; a page's close logs its express-lane frame count, which
default-check.sh counts (all three interfaces pass on the bench, no fault or fallback). Hand-started
daemons (gpu-spike-start.sh) keep the lines (NOLOG=1 drops them).
Engine 0057 also puts the page's layer transactions on JIHAD_GPU_TIMELINE with their tile uploads
(T-517, rounds 349-357). Every JIHAD_GPU_* switch is in tools/device/t502/README.md; the README and
docs/RENDERING-OPTIONS.md carry the evening's numbers. The device scripts' per-run files are ignored.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The owner asked for the progress of Jihad Browser's parts shown in the README, with the release as
the goal. A section after "What it is" shows, per area of the browser (the engine and page drawing,
the GPU, the modern web, the three interfaces, touch, settings, add-ons and Personas, privacy and
security, building, tabs), a bar of the acceptance criteria met, and what is left split into work
to do, checks only a person can make (a finger on the device, the owner's decision) and items that
wait on tabs; then the road to release as a Mermaid diagram: complete areas, areas built and
waiting on a person, areas with work left, the owner's finger round, the last review, the release,
and tabs held.
Nothing in it is typed by hand: tools/readme-progress.py counts the "- [x]" and "- [ ]" criteria in
context/kits/ and the checks in docs/FINGER-TESTS.md and rewrites the section between the README's
progress markers (--check says whether it is current, --print shows it).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J67ZH8aYy8uzhgZDZ6Nvx9
The README no longer says Jihad draws in software or has no WebGL: pages are drawn on the GPU by
default (a pref goes back to software), frames keep coming while a page's script runs, WebGL 1 works;
the caveats give the measured frame rates and WebGL's missing extensions. docs/RENDERING-OPTIONS.md
gets the Tier 87 outcome: what the GPU path does, a table of what it measured against what it
replaced, and what it does not reach yet. tools/device/t502/README.md now names all 72 JIHAD_GPU_*
switches in the code (the eight older device-round ones were missing).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J67ZH8aYy8uzhgZDZ6Nvx9
The stall: a leaf-PC sampler in the daemon ($JIHAD_STALL_SAMPLER, GoannaRenderPage.cpp) and
tools/host/stall-resolve.py (the toolchain's addr2line against the unstripped libxul) name what
holds the main thread — the pages' own JavaScript two thirds, compile and the collections the
rest; the clock sat at 192–384 MHz under load (Palm's ondemandtcl, up_threshold 95). The clock
hold (JihadBrowserServer.cpp, jihad.cpu.hold) raises the frequency floor while the engine has
work and releases it after two seconds of idle ticks, on the no-page path too (daemon 18); it
never touches the governor, which wedged the kernel's cpufreq lock and cost a reboot.
H.264 and AAC: build/webos-oe/fetch-ffmpeg.sh + build-ffmpeg-arm.sh cross-build FFmpeg 4.4.5's
decoders (libavcodec.so.58, libavutil.so.56, LGPL v2.1+, decoders and parsers only); the bundle
ships them, NOTICE and licenses/runtime/ carry the terms; the codec page plays both to the end on
the device.
The layout viewport (T-499): GoannaRenderPage::SetLayoutSize and the once-per-page rule in
emitGeometry (jihad.viewport.followOverflow); the engine window resizes but the page still reads
innerWidth 768 — the paint path restores the card size; open.
Rendering options: tools/device/gpu-bench.c times the Adreno 220 through the vendor EGL/GLES2
(composite 4–13 ms, readback 11–14 ms, whole-texture upload 9–12 ms per 3 MB, tile sub-updates
160 ms) beside the CPU equivalents; docs/RENDERING-OPTIONS.md keeps the numbers; the report with
the decision table is the owner's doc. Ledger T-499…T-501, build site, kit, PICKUP, memories.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J67ZH8aYy8uzhgZDZ6Nvx9
The owner: "move all caveats in the readme into a dedicated caveats section at the bottom. also
change the language to be less corporate advertisement like while still being 2011 era
appropriate." The pitch headings and the bold claims are gone; what each part does is said once,
plainly. The device scope, the TLS fix's scope and the clock, software drawing, the slow single-page
applications, ES-module sites, DuckDuckGo's open menu, the bot checks that still refuse, what no
shim covers, palm-install and Flash's availability now sit together under Caveats, before Thanks
and Licensing. The hero, the table, the screenshots and the licensing text are unchanged.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J67ZH8aYy8uzhgZDZ6Nvx9
The identity harness (render/goanna/test/jihad-identity-server.py) fakes Cloudflare's header and
Startpage's /sp/captcha-block redirect, logs every request's User-Agent and takes each page's
navigator.userAgent back: on the device the no-loop branch held, a learned site's frames,
subresources and a third-party frame all carried the identity, and the redirect became the
component's second learn signature — the real Startpage learns, its home renders, its search
finishes Anubis's proof of work in ~4 minutes. eBay (Akamai 403) and old Reddit's login gate are
not the identity's: curl from the host gets the same with either token.
YouTube: the desktop watch page is 13.7 MB of script decompressed against the mobile site's 3.0 MB;
on the device a 24 s worst stall and 274 MB against 5 s and 162 MB, the mobile home feed in 18 s.
jihad.ua.sites in the identity component gives youtube.com a mobile Firefox identity, header and
docShell pin together; the daemon's youtube.com row is out (daemon 14). Settings → General shows
the rule.
The web-compat component (render/goanna/components/jihadWebCompat.js): a sandbox with the page's
principal defines on the page's own prototypes what the engine lacks and modern pages assume —
CSSStyleSheet.replace (Etsy's 47 adoptedStyleSheets errors, Lit's test), popover, inert,
Intl.ListFormat, reportError, checkVisibility, AbortSignal.any, URLSearchParams.size,
Array.fromAsync, Blob.text, Response.json, Promise.try, the Set methods, the iterator helpers,
ReadableStream iteration, crypto.randomUUID, scheduler.postTask, requestVideoFrameCallback,
canvas.roundRect — plus one agent sheet; jihad.compat.trace names the engine call that throws an
XPCOM result to a page, with the page's stack, and jihad.compat.probe runs a diagnosis script in
a page. 28/28 on its test page on the device; the API probe 131/169 (119 before). DuckDuckGo's
regular page renders its results; its menu panel standing open is the daemon's fit-zoom showing
what the page parks past innerWidth on a 1000-px layout in a 768 window — T-499, designed, open.
CSS :has() on in all three variants (the owner's call). The daemon's console line carries the
column. build-daemon-arm.sh's export check no longer uses grep -q under pipefail (it failed at
random). Ledger T-496…T-499, kit boxes, build site, PICKUP delta, finger tests, README.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J67ZH8aYy8uzhgZDZ6Nvx9
The owner: "the user agent should be 52.9 by default but adjust based on the
needs of the page". The base token stays; components/jihadUserAgent.js learns a
site whose top-level response carries cf-mitigated: challenge, cancels the
challenge page, pins the docShell to a Firefox/128 identity and loads the page
again once; the site's requests and documents (frames included) carry that
identity from then on, header and navigator.userAgent together — measured on
the device: w3.org and Medium learned, reloaded and rendered; the list
persists; Settings → General → Browser identity shows and forgets it. The
daemon's challenges.cloudflare.com row is out (it made the inconsistency).
The engine rebuilt with jemalloc in 22 minutes; on Linux UXP puts the
allocator in the program, so build-daemon-arm.sh expands libmozglue.a and
libmemory.a as xpcshell's link does and links them with -rdynamic, checked by
nm; the daemon's malloc_trim calls became a jemalloc purge; memory.free_dirty_pages
on. After three heavy pages and the last close: 149 MB resident, was 170;
heap-allocated reports (60 MB). Daemon 11 and the component on all three
variants. The ledger, kit R3/R6, the build site, PICKUP, README updated.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J67ZH8aYy8uzhgZDZ6Nvx9
The card view: Internet Archive (Mojo), BBC News (Enyo, blocker on), MDN
without adverts (Mochi), unthemed, on the Frutiger Aero backdrop — the image
the README and CREDITS describe (inspector F-6 closed).
Round 2's thirty rows in docs/MODERN-WEB.md, the shots and the analysis in
docs/rounds/: 17 render, 7 stopped by bot detection, YouTube by UA sniffing.
The user-agent experiment in EngineHost.cpp (Firefox/128 for those hosts,
daemon rebuilt, not yet measured). The benchmark: the JIT is live, allocation-
heavy JavaScript is 34–436× the host's — GC or allocator, to be apportioned.
v5.1 pushed to Enyo and Mochi and verified over http; Mojo's push fails on the
USB link. jihadPersonas.js guarded against a closed window. The probe page
jihad-apis.html and the round's host wrapper.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J67ZH8aYy8uzhgZDZ6Nvx9
The owner: "dont just breeze past that. document and fix issues loading the
modern web. build in an ad and tracker blocker if possible (following license
terms)", then "set up a new round of tests where you browse the modern web as a
pretend user for about 30 minutes … also address any performance issues".
Kits: cavekit-modern-web.md (R1 ledger, R2 slow-script guard, R3 Cloudflare,
R4 GitHub, R5 Wikipedia, R6 a user's half hour) and
cavekit-content-blocking.md (R1–R7); build site Tiers 85 and 86.
docs/MODERN-WEB.md: 19 sites on the device, every row with cause and
disposition; the console method (JIHAD_JS_CONSOLE=all, log windowed by line).
Fixed: dom.max_script_run_time 60 (The Verge renders, the endless script still
asks). Named from the console: GitHub (Turbo is not defined) and Mastodon
(import.meta) are ES-module loading, upstream; Cloudflare's Turnstile runs and
fails on its own verdict, the challenge-host UA rule alone does not pass it.
The blocker: render/goanna/components/jihadContentBlocker.js — EasyList and
EasyPrivacy (third_party/easylist/, snapshots 202610151429, GPLv3+ of the dual
licence, sha256-pinned, bundled raw) compiled on the device in slices (5.9 s,
cached): host, third-party, typed and path rules through nsIContentPolicy,
generic and site-specific hiding rules as one user sheet, 4-day updates from
easylist.to, Settings → Privacy → Content blocking (text and button row types),
NOTICE, CREDITS, about:jihad. Device (Mochi): google-analytics, doubleclick,
ads-twitter, facebook /tr refused; MDN's banner and sidebar advert gone. Open:
memory (+36 MB idle against a 12 MB budget), the updater's tests, the other two
variants after the package push, the inspector's review.
Also: tools/device/browse-round.sh + sites + analyse.py (the pretend-user round),
tools/host/count-blocklist.py, three test pages, the README's new section and
candid Known issues, the Frutiger Aero card-view backdrop in readme-art.py.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J67ZH8aYy8uzhgZDZ6Nvx9
The owner's brief: one slogan only ("UXP inside, webOS alive, inshallah!"),
simpler technical sections, oldest interface first, all screenshots retaken,
shorter, mostly what the stock browser and Atlas cannot do, as a member of the
UXP family; less TouchPad, HP only where attribution needs it.
README.md 278 → 178 lines. The per-distribution package table moves to
docs/DEVICE-BUILD.md, which pointed at the README for it. docs/screenshots/:
five images composed by readme-art.py from fresh device captures (card view
with the two bundled Personas worn, Bloxorz in Enyo, about:addons +
about:personas, Settings + about:config, howsmyssl); the Persona strip and
three pair images retired. CREDITS.md's screenshot sections follow the new
art. PICKUP carries the delta, the traps and the device state.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J67ZH8aYy8uzhgZDZ6Nvx9
The owner: "ensure that all software patent and trademark licenses in
the repo are being respected". A read-only audit of what the packages
carry found no blocker and these gaps, all closed here (the record is
impl-review-findings-6.md, "Licensing audit"):
- NOTICE names the runtime the engine ships with: glibc 2.23 as
crosstool-NG modifies it (LGPL-2.1), the GCC 9.4.0 runtime (GPL-3.0
with the Runtime Library Exception), and the eight Debian jessie
libraries, with the FreeType disclaimer, Lato, the hyphenation
patterns, and where the corresponding source is. licenses/ gains
LGPL-2.1, GPL-3.0 and the GCC exception from the pinned tarballs and
Debian's copyright files from the sysroot; every package ships all of
licenses/ and CREDITS.md, checked in the payload preflight.
- NOTICE names the modified engine's source (the fork, branch, pinned
commit, base release, the patches), as MPL-2.0 3.2 asks.
- README and LICENSE no longer call the packages Apache-2.0 and MPL-2.0
only; the dead licensing.shtml reference is replaced by the UXP
LICENSE and TRADEMARK files and Moonchild's legal and redist pages.
- Apache-2.0 4(b) change notices on the 29 HP-derived files changed
since import.
- A drawn magnifier is the DuckDuckGo engines' icon; Google's logo is
Google's only; the unused Bing logo is gone.
- The engine's services-sync.js defaults pointed at Moonchild's Sync,
key server and add-on host: blanked at bundle time, checked.
- The "Blazer" keyword, the Goanna-mark tagline, a stray screenshot and
a .bak dropped; the HP SDK's terms stated where it is downloaded;
CREDITS records the logo's origin and the screenshot strip's licence.
Deferred to the next engine build: about:credits' URL and
--disable-ffmpeg (the system-libavcodec path is dead on the device).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XM9EDSp83ZFRhggY4RCT9X
The inspector's review of b37795fb..9ff7d71a (2 P1, 7 P2, 16 P3; every
finding and its disposition in impl-review-findings-6.md, round 25).
Fixed: the toolchain container disables SELinux relabelling and runs as
any uid (world-writable /home/builder, HOME set, docker --user); both
adapter builds define QT_NO_DEBUG, so Q_ASSERT's __FILE__ no longer
bakes the checkout path into the impl (rebuilt: no home path, the shims
unchanged); build-all-device.sh initialises only the missing submodules
(an emptied one counts as missing), checks the container engine and the
device before the hour-long steps, treats a device library as present
only with the recipe's sha256, honours PDK_ROOT, captures its pipelines,
and copies only this run's three packages; the fetchers take the pin,
retry a wrong-bytes download past the CDN's cache and keep curl's error
visible; the sysroot script sources host-path.sh, fetches libpulse to a
.part, checks it on assemble and refuses a SYSROOT_OUT outside its
directory; in-container.sh forwards the scripts' settings (inside the
repository only) and rebuilds an image whose Dockerfile changed, with a
.containerignore per context; the review runner fails closed; the README
lists binutils and xz, calls docker rootful and unrecorded, starts
novacomd with sudo -b; the Mochi provenance names an outside source by
basename; build-novacom.sh uses the compiler it found; oe-env.sh's
sudo-mode checkout runs as the user; the kit's R11 criteria 2 and 4 are
back to [~] with two criteria added (public pins, path-independent
builds) and "eight" libraries.
Not fixed in code: the engine pin 706d4782 is not on the public fork.
tools/host/check-pins.sh fetches every gitlink from its URL and reports
it; the push is the owner's decision.
deploy/relay/: the Relay's jihad-splice.sh and hide-client-addresses.sh
as on the server (sha256 checked), with a README (T-478).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XM9EDSp83ZFRhggY4RCT9X
The README gains a Building section: the host packages for apt, dnf,
pacman, zypper, xbps and apk systems (git, podman, curl; plus a compiler
and libusb-compat for novacom), then clone with submodules, build
novacom, run build-all-device.sh, and install. It also says where each
input comes from: this repository, the submodules, the checksummed
downloads, and the eight libraries copied once from a TouchPad.
DEVICE-BUILD.md's procedure is now that one command, with a table of
each input and step and how it is obtained; the container invocation it
documented is what in-container.sh --arm runs. TOOLCHAIN.md's examples
use the repository's paths and name toolchain/build.sh and the
crosstool-NG submodule.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LcrVQFRMC2ANGDfVaRG9Ed
The owner's evening list:
- Opening about:settings, about:preferences, about:personas or about:addons takes the focus off
the address field in all three shells, so the keyboard goes down and the whole page shows
(device, all three: Jihad page -> BODY, example.org -> INPUT kept).
- The daemon clears the page's focus when the window grows back by a keyboard's height at the
same width with a field focused, so no caret is left behind (built; needs a finger).
- Installed Personas' cards draw an 800 px copy of their picture, made once beside it and pruned,
instead of the full header that the image cache kept dropping (device, Enyo).
- An add-on's preferences stack as blocks, dark text fields, trimmed desktop margins: nothing is
cut off or needs a sideways scroll (device, Mochi, Palefill).
- Mochi defines Mojo.handleGesture, LunaSysMgr's way of giving a card its flicks, which Enyo 2
lacks: a flick on the web view reaches the adapter, in whole numbers.
Inspector round 20 (Codex out of credits): about:addons measures only the shown view's items and
can shrink again; a page's own scroll jump inside the streaming window is judged once the stream
pauses instead of being lost; CREDITS keeps the three CC pictures in the README strip; AMO card
state, https-only redirects, a full /tmp answered; licences for the formerly bundled Personas;
the two sheets loaded apart and checked in the bundle; dead code removed; kits corrected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LcrVQFRMC2ANGDfVaRG9Ed
The inspector's review of 69c44675..efa6844a (Codex out of credits until 4:59 PM):
- A colour-only Persona's gradient is stretched over the bar (fit "stretch"), not drawn cover,
which showed one blended row. The component, the three shells and the Personas pane.
- The pane draws a layered Persona's first picture at its own size, not cover.
- Re-installing the Persona being worn under the same id repaints the cards (wearTheme through
rewear; LWTM sends nothing when currentTheme is set to the same id).
- Colour slots are parsed (inIDOMUtils.colorToRGBA) and sent as rgb()/rgba(); anything else is
dropped, so a value cannot carry more CSS into the shells' stylesheets.
- The per-Persona pixel budget is checked from each picture's header before it is copied or shrunk.
- about:personas ignores replies to requests it has since replaced, and takes the page number from
the reply.
- test-site-profile.sh: the backup is removed only after the copies and the CA check pass; files
absent at setup, an existing user.js, what the test added, a missing certutil and an empty
address are all handled.
- lightweightThemes.update.enabled is named false beside extensions.update.enabled
(check-engine-api.py knows both it and xpinstall.whitelist.add are read by the engine).
Found on the device: the restore's clean-up used grep -x, which the TouchPad's BusyBox 1.17 grep
lacks, so every file looked unlisted and Enyo's profile jihad-themes/ and extensions/ were emptied
by both of the day's restores. Membership is now decided in plain sh and must find the list's own
first line before anything is removed (run on the device against a scratch directory). Enyo was
repaired by hand: its 13 pictures copied from Mochi under the same names (md5-identical to Mojo's)
and Palefill re-offered (1.30, active).
Checked on the device (Enyo, Mochi, Mojo): the stretched gradient (Enyo measured #3e2164 top,
#7c3aa8 bottom for #3b1d5e/#7a3fa8), the pane's layered row, a same-id re-install repainting
(#cc2222), hsl() arriving as rgb() and a shadow value dropped, the setup/restore cycle, and against
the local site: the front page, an add-on page, a 404, about:personas' pager (page 1 of 2 → 2 of 2)
and "More on the web".
Kits: cavekit-persona-formats.md and cavekit-addons-site.md ticked with what was measured; R1/R2's
about:personas card, R4's index fields and R11's getMoreURL narrowed. Open: the site's layouts on
other screens, a typed search (a finger), the deploy (the owner's). Review round 14 recorded.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LcrVQFRMC2ANGDfVaRG9Ed
Owner, 2026-10-08: "implement custom 'get personas' repository similar to what other UXP browsers
have", "remove personas we dont have a license to bundle, include by default those we do",
"rename aero personas to be more creatively titled", "shorten the readme to focus on important
features". Kit cavekit-personas-ui.md R7-R9.
- about:personas (packaging/prefsui/content/personas.*; registered with about:settings' module):
the gallery Get Personas now opens (Basilisk's lightweightThemes.getMoreURL can point it
elsewhere). Cards with picture, name, version, author, licence and Wear; an optional online
index (jihad.personas.galleryURL, https, same format) installs through the usual confirm.
The component answers the page on "jihad-personas-gallery" (list / wear / install).
Device: 15 cards in Enyo; Wear on Space Fantasy wears it.
- The bundled set: five drawn for Jihad, renamed Bubble Lagoon, Cloud Nine, Meadow Morning,
Aurora Silk and Lime Fizz (byte-identical art, renamed in place in every profile; one
uninstalled under its old name stays uninstalled), plus ten Firefox-era Personas licensed CC
BY / BY-SA by their authors (import-third-party.py fetches them with pinned sha256; credits in
CREDITS.md, NOTICE and on every card; survey in docs/research/persona-licences.md). Added once
to every profile's list; listed Personas with a bundled picture get its credits. Device: all
three profiles.
- Removed: the Water-Like test assets (All Rights Reserved; the tests use Carbon Light, CC BY-SA),
and every README picture showing an unlicensed Persona (all retaken on the device today).
- README: 333 -> 201 lines; the features that matter, no long-press notes, developer notes cut to
pointers (docs/ENGINE.md, DEVICE-BUILD.md, PICKUP.md); html5test re-measured (447/588).
- Kits: finger checks marked deferred (owner: "Defer additional finger tests for later").
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LcrVQFRMC2ANGDfVaRG9Ed
- Undo's 30 s now run from when the worn Persona changed (noted in the manager's update, the
two updates of one change coalesced), not from when the pane was next opened. Found on the
device: after a Persona was installed on AMO, opening the pane showed an Undo whose tap went to
the wrong look. Device: Default look -> Wear takes the Persona off; Undo brings it back.
- Get Personas -> addons.mozilla.org: a Persona page's "Download file" link installs through the
usual confirm and the Persona is worn (README tip added; AMO's big button offers only Firefox).
- docs/PICKUP.md: the 2026-10-08 delta (what was verified, what is open, the device state).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LcrVQFRMC2ANGDfVaRG9Ed
- about:addons rows say "Uninstall" (owner: "use Uninstall instead of Remove").
- The Aero set's meadow is drawn higher (the hills now show in a 54 px bar); the set has an
edition, and a new edition replaces its older pictures in a profile (matched by name and
author; the worn choice carries over). Device: Mochi's earlier Aero Meadow retired.
- Daemon: a page's navigation to an about: page is re-driven by the channel's ORIGINAL address.
It used the resolved one (about:addons -> file:///.../extensions.xul), which the engine refuses
as XUL from a file, so Settings -> Manage Personas showed "This page uses an unsupported
technology". Device: Mochi, Manage Personas opens the Personas pane.
- README: Personas throughout; the section describes the manager and the bundled set; new strip
(no Persona, three Aero, three from AMO) and the prompt/pane pair, all taken today.
- Kit cavekit-personas-ui.md brought to what was built and verified (R3 rewritten to Wear + Undo,
R7 the bundled set); Tier 73 statuses.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LcrVQFRMC2ANGDfVaRG9Ed
Rewritten for the people who would install it, in the voice of a webOS-era App Catalog page and
release notes: a card-view hero of the three interfaces, a strip of themed toolbars (no theme and
five AMO themes), TouchPad-framed screenshots of a Flash game, the theme install prompt and
about:addons, a link-and-image long-press, about:config and Settings, Acid3 99/100 and html5test
450/588, and howsmyssl.com reporting TLS 1.3 - all taken on the device today.
"A word about HTTPS on webOS" explains, with sources, why the stock OpenSSL 0.9.8 (TLS 1.0, a
2010 root store) broke the web on webOS 1.4.5 through 3.0.5, what each community fix changes
(OpenSSL-Updater, root certificate updates, HTTP mirrors, SSL-bump proxies, nizovn's Qt browser,
Herrie82's TLS 1.3 Updates, webOS CE 3.1.0), and where Jihad's own NSS fits - and what it does
not fix. The old line "modern TLS with the device's own trust store" was wrong (pages are checked
against NSS's built-in Mozilla roots) and is gone.
docs/screenshots/readme-art.py rebuilds the art from raw device captures; it renders text with
the TouchPad's own Prelude fonts, which are not in the repository.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LcrVQFRMC2ANGDfVaRG9Ed
From the owner's 2026-10-07 finger-test report:
- Mojo: pages no longer shrink to a stripe. The daemon re-sent the meta viewport whenever its
computed initial scale changed; the Mojo WebView sizes its node from that scale, so each
re-send narrowed the page (768 -> 526 -> ... -> 76 px). Re-sent only when the page's
declaration changes, as the stock server does.
- Mojo: the command-row circles take the theme's accent colour (bookmark glyph included).
- Mochi: rounded dropdowns; the app menu sits flush with the left edge.
- Enyo: refresh glyph centred in the address field; a typed file:/// address opens instead of
searching.
- Home button default is DuckDuckGo Lite in all three shells and the settings page; a stored old
default moves once.
- Settings gains an About pane (interface, version, engine, Flash, licences), read at run time.
- README rewritten around what only Jihad does on webOS, with device screenshots.
- Flash test page (render/goanna/test/flash-test-page/) with five real archive.org games.
Inspector round 8b on the previous fixes (Codex out of credits mid-review):
- P1: every URL the daemon sends is bounded, and the shared YAP codec never drops a field
(an oversized string is sent empty) or yields NULL (an unreadable one reads as "") - a page
could otherwise crash the card host through strlen(NULL).
- History traversals keep their old re-drive; Open In New Card takes web addresses only; the
preview mark matches the engine's 30 s; the hold generation is per request and counts
pass-through gestures.
Still open (docs/PICKUP.md): Mojo pinch in-then-out goes grey (structural), Mochi text soft at
~1.43 zoom, long-press by finger not reproduced by script.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LcrVQFRMC2ANGDfVaRG9Ed
- Drop the stock/Atlas/Jihad comparison table; list the webOS-firsts Jihad has instead
(extensions, Flash+modern web in one engine, about:preferences/config, three shells,
modern TLS + platform cert store).
- Fix the install-table package ids from the orphaned dotted form to the hyphenated ids
the recipes actually produce (net.riverstonerelay.jihad-browser-mochi / -mojo).
- Honest status: reflect the offscreen paint ceiling + the ghosting fix; engine is now a
jihad-engine-mods commit, not only a patch queue.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Engine audio (gre-widgets R1/R7): switch cubeb ALSA -> PULSE backend, which is
what webOS's audio policy requires. mozconfig --enable-pulseaudio, pulse-0.9.22
sysroot headers matching the device ABI, and patch 0030 targeting JIHAD_PULSE_SINK.
Device-verified AUDIBLE (user-confirmed "I hear the tone"): decode -> cubeb pulse
-> DAC -> codec -> speaker/headphone. The prior ALSA backend was silent because it
presented as an anonymous ALSA-plugin stream that module-palm-policy muted; the
pulse-native stream identifies as the app and is left at full volume.
Chrome-page typing (preferences-ui R6): GoannaRenderPage::InsertText recovers a
null mFocusedEditable from document.activeElement, which dodges the focus-manager
window-scoping that made chrome documents (about:preferences) unable to receive
typed text. Device-verified: text now inserts into about:preferences fields.
Cert store (browser-services R5): new JihadCertStore dlopens libPmCertificateMgr
and integrates accept/trust with the webOS platform cert store; three defects fixed
(empty certFile, nsresult-in-Palm-ordinal-space, Trust-Always vs Trust-Once).
Device-verified end to end incl. the platform store write.
IPC contract (ipc-contract R1): vendored + patched the YAP generator so a
regeneration reproduces the shipped wire with zero hand edits.
Touch events (input-bridging R3): doTouchEvent enabled behind JIHAD_TOUCH_EVENTS,
28-byte NpPalmTouchEvent header re-staged, double-activation suppressor.
Non-blocking toast (gre-widgets R5): daemon PostNotification + Luna subscription +
card toasts; device-verified.
Mojo settings entry (preferences-ui R4): app-menu Settings item + settingsUrl(),
per product-owner direction reversing the earlier no-mojo-settings instruction.
All three variants now have a settings entry.
Plus: opal machine kernel string corrected (shortloin), prebuilt-input manifests,
build-goanna-arm.sh pipefail fix, desktop test harnesses (prefsui, xpi-mismatch),
and extensive device verification recorded in context/impl/impl-device-2026-08-15.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The daemon had no plugin search path at all, so nsPluginHost scanned nothing. EngineHost now
sets MOZ_PLUGIN_PATH before XRE starts -- nsPluginHost reads it once, at its first scan -- to
<profile>/plugins:<greDir>/plugins. Both live inside the variant's own footprint, so the
storage contract holds: user-installed plugins go in the profile, which this variant's prerm
removes. Deliberately not /usr/lib/BrowserPlugins, which is the stock browser's directory and
would give a plugin crash a cross-app blast radius. The profile plugin directory is created at
startup, because an absent directory is silently skipped and looks exactly like a plugin that
failed to load.
With that, the device's own Flash was tested, and the result is the opposite of what the
requirement anticipated. Every dependency resolves against our bundled loader -- including
libWebKitLuna, libPiranha and libLunaSysMgrIpc, the three singled out as likely blockers. It
takes libstdc++, freetype, fontconfig, pthread, glib, z, png12 and expat from our glibc-2.23
set and ssl/crypto 0.9.8, curl, lunaservice, hal, napp and powerd from the device. nsPluginHost
loads it far enough to read its NPAPI metadata, and about:plugins lists it as "Adobe Flash",
State: Enabled, with application/x-shockwave-flash (swf) and application/futuresplash (spl).
The daemon survived with no fault report.
This is enumeration, not instantiation. A plugin painting into a page still needs the
windowless port, which is the criterion that matters and is still open.
Adds a gettext <selector> inject command to read an element's text, since a rect proves an
element exists but says nothing about what a generated chrome page actually contains -- the
about:plugins numbers above are read out of the page, not inferred from a screenshot.
Also states in the README that Silverlight is not achievable on this device: it shipped x86/x64
for Windows and macOS, and the Linux implementation was Moonlight, x86-only and long dead.
There is no ARM binary to load. Worth saying plainly, because "NPAPI support" tends to imply it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The lessons, written where the next person will hit them:
- render/goanna/README.md and build/desktop/README.md: jsurl does NOT execute in a chrome
document. LoadURIWithOptions returns NS_OK, the inject line prints ok=1, and nothing
runs -- no effect, no exception, no console output. ok=1 means the load was issued, never
that the script ran. Click the real control instead, via rect/clickid's three lookup
forms, including anon: for the XBL anonymous content the about:addons row buttons live in.
- render/goanna/README.md: dialogs block on a deadline sized for a person, and there is no
signal distinguishing "on screen" from "nobody is there" -- do not add a liveness
heuristic on the reply pipe. A five-second version of that idea silently defaulted every
dialog a human answered in normal time while every harness passed.
- build/webos-oe/README.md: driving the device means an ad-hoc JIHAD_INJECT daemon (the
supervised job deliberately does not set it), launching the card AT a url because no
engine page exists until it navigates, and stopping with SIGTERM so state flushes.
- render/browserserver/README.md: what SIGTERM handling is for, and that anything on the
shutdown path is untested code until proven otherwise.
- cavekit-overview.md gains a "Driving the browser without a human" section collecting the
four traps, alongside the existing card-UI loop section.
Corrections:
- cavekit-engine-embedding.md R2's "shuts down cleanly at exit" was marked met but main()
never returned, so XRE_TermEmbedding never ran. Now met with evidence, plus two criteria
for the teardown ordering and the never-executed ~YapServer path it exposed.
- cavekit-device-build.md: engine prefs live in goanna.js and deploy with the engine; an
absent pref is not always inert, since several are read with a one-argument getCharPref
that throws instead of defaulting.
- The overview's totals were stale. They are now COUNTED (279 criteria, 232 met, 22
partial, 25 open) with the command to re-count in the text, so the next drift is cheap
to catch.
- The root README no longer claims the menupopup does not paint or that cookies do not
persist; both were fixed. Extensions now have their own paragraph.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The kits and READMEs had drifted from the code in ways that would mislead the next
reader — several said the card dev loop was broken, the <select> popup blocked, and
only the Enyo variant live on hardware. All three are now false.
Kits:
- overview: rewritten device-reality block (three variants live; dev loop restored and
how; select popup closed on all three; the -webkit- prefix constraint), priorities
re-ordered around the now-unblocked queue, and the per-domain requirement counts
re-derived from the kit files — the old "12 domains, 62 requirements" summary had
drifted from what it summarised. Totals are now counted, not asserted: 13 domains,
77 requirements, 274 acceptance criteria (204 met / 18 partial / 52 open).
- ui-shell R5, mochi R6: card-side <select> popup, device-verified. The Enyo one records
the standing rule the investigation established — there is no app-side popup code, and
re-adding an onOpenSelect handler or patching BasicWebView.showPopupMenu breaks it.
- mojo: R1-R3 and most of R4 marked met against device evidence, plus a new R6 for the
command-menu actions (new card / history / share, history without db8 kinds).
- offscreen R7 (new): "engine popups reach the user" — collects the separate-display-root
defect that had only lived in impl notes. Its <select> criterion is met; the
<menupopup> overlay-composite criteria are diagnosed and open, and are now the top
priority. addons R2 gains a tools-menu criterion pointing at it.
- Both UI kits record the platform constraint: the card WebKit ignores unprefixed
box-sizing/flexbox.
READMEs: root status/known-issues/roadmap rewritten (three variants live, scrolling and
long-press and <select> done, <menupopup> named as what remains); build/webos-oe gains a
deploy-scripts section explaining why push-card-js.sh distrusts a naive push; the three
app READMEs record their own popup story and the prefix constraint; AGENTS.md notes that
the adversarial reviewer is Opus, plus the novacom stdin-EOF race and the JS cache.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
README gains the add-ons infrastructure (about:addons and about:plugins open;
branding package, add-on prefs and the dual-GUID AppCompat mechanism ship; NPAPI
compiled in but windowless NPAPI must be ported for a cairo-headless build), a
Phase 3.5 roadmap entry for the add-ons + repaint-correctness work, and -- the
part that was missing -- an honest known-issues and deployment-reality block:
- scrolling exposes undrawn "grey" strips because the daemon paints exactly the
viewport with no pan headroom while the shared buffer is ~4x that size;
- chrome icons render but are slow (repaint-delivery latency, not decode);
- XUL menupopup support is untested; long-press contextmenu never reaches the page;
- only the Enyo variant is live on the test device. Mochi has worked before and is
a deploy regression; Mojo has never run on hardware. So per-variant independence
is verified in the packaging matrix but NOT with three variants running at once.
The cavekit overview gets the same reality check at the top of the status table,
so "verified on device" is not read as covering all three variants, plus the
cross-cutting open defects with pointers to their impl notes. The add-ons row is
rewritten: R2 and R8 are done, R3 is blocked on a daemon amIWebInstallPrompt, and
R7 is reframed from "enable NPAPI" to "port windowless rendering".
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JDvWTswwcSHQHVA1gD795L
Rebuilt the ARM daemon (the .ipk had been shipping the 2026-07-27 binary, which
predates JihadRuntimePaths.h and ignored JIHAD_STATE_DIR entirely). On device it
prints its own derivation --
variant=mochi (JIHAD_BS_NAME=jihad-browser-mochi) state=/var/palm/jihad/mochi
-- and created /var/palm/jihad/mochi/profile/ with cookies.sqlite, prefs.js,
cache2 and startupCache. cookies.sqlite had never once appeared on this device
before: it failed on VFAT, and moving the profile to ext3 fixed it, closing the
long-open browser-services R2 on-device gap in principle.
But that same binary then crash-loops: 117 respawns, ~2.6s each, never reaching
"engine up", 0 ABORT lines. The 2026-07-27 daemon on the same bundle and job
stays up, so the regression is in today's daemon changes. Recorded as F-18 (P0)
with the A/B and the suspect list; the shipping packages keep the older daemon
until it is fixed.
Also from the second fable review (findings recorded, fixes in flight):
- the three variants co-own their db8 kinds, so Mochi installed alone has no
data layer -- the one finding that actually breaks R7
- ipkg -o defers control scripts on removal too, then deletes them, so prerm
never runs on the documented install path
- the harness's own R8 assertion was the sixth `| grep -q` under pipefail and
failed OPEN; now captured, and recursive rather than top-level
- postinst raced upstart: a start issued before teardown finished was dropped,
which is why Mochi and Mojo showed no daemon in the first matrix run
Settled two UNPROVEN items: novacom does propagate remote exit status (so the
matrix assertions are real), and /var is its own rw volume (so the state dir
never falls through to /tmp).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JDvWTswwcSHQHVA1gD795L
Enyo, Mochi and Mojo now ship as three fully standalone browsers. Nothing is
co-owned, so nothing needs refcounting: each has its own MIME, adapter shim +
impl, YAP name, socket, upstart job, daemon process and runtime state dir. One
source builds all three -- identity arrives on the compiler command line, and a
half-defined identity is a compile error rather than a silent cross-variant
hijack.
Nothing is written to /media/internal any more. That vfat volume is the user's
USB storage; the engine, daemon and bundled glibc now execute in place from the
app's own cryptofs deviceroot, which is the Atlas model (attributed in NOTICE).
The rootfs footprint is bounded to the three files webOS forces on us and is
reversed exactly by prerm.
Verified on the TouchPad, Enyo variant, 0 failures: installs from a
self-contained .ipk, deploys its own shim/impl/upstart job, serves its own
socket, and runs its daemon out of the app bundle -- with every stock checksum
unchanged and /media/internal clean.
Four defects fixed to get there, each of which would have shipped:
- ipkg without -o installs into the rootfs, not the app partition
- the ARM dist's icudt78l.dat is a symlink into the build container, so the
bundler silently shipped no ICU data and no GRE resources; missing required
files now fail the build instead of the device
- ICU_DATA was never set, so libxul aborted in u_init() on every start
- `| grep -q` under `set -o pipefail` fails on SIGPIPE; the R8 "no
/media/internal" assertion was failing OPEN
Also fixes all nine findings from the fable adversarial review of the download
lifecycle (context/impl/impl-review-findings-downloads.md), including two P1s:
downloads were addressed to the last-connected card rather than the originating
one, and a failed temp-file setup emitted a start with no terminal, forever.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JDvWTswwcSHQHVA1gD795L
Stand up the reproducible Open webOS (build-webos + meta-webos, 2013 "dylan" /
bitbake 1.18) build so the whole Jihad stack cross-compiles from source into
installable webOS .ipks — no prebuilt-binary scraping.
Environment
- oe-env.sh: self-contained OE host on any Linux via a chroot into a downloaded
Ubuntu-14.04 rootfs. No container runtime, no systemd dependency; privilege via
sudo OR doas. Provisions the OE host tools + gcc-9 (UXP host req) + i386 libs
(Palm PDK) + the git:// → https rewrites.
- weboslayers.py vendored (dylan layer pins + tenderloin/opal machines); the Jihad
layer is wired into BBLAYERS after mcf. docs/OE-BUILD.md added.
Recipes (recipes-jihad/)
- goanna: cross-builds libxul.so (crosstool-NG gcc9 + Jessie sysroot via a generated
OE mozconfig); stages the whole engine dist for the daemon + bundle.
- jihad-browserserver: the render daemon, linked against the staged engine.
- browser-adapter-jihad: the NPAPI shim + impl via the Palm PDK (gcc 4.3.3).
- jihad-cross-toolchain-native: the toolchain edge.
- jihad-deviceroot: assembles the self-contained runtime bundle (daemon + libxul
.so closure + bundled glibc-2.23 + NSS + GRE) via a parameterized make-device-bundle.sh.
Packaging → two self-contained app .ipks + a Mojo skeleton
- jihad-app.inc: each UI product bundles the shared deviceroot + its app + the
adapter impl, with a postinst/prerm that deploy the coexisting daemon/shim/upstart.
- net.riverstonerelay.jihad-browser (Enyo 1.0) and .mochi (Enyo 2 + Mochi) are the
two shipping .ipks; the component recipes are stage-only (emit no .ipk).
- net.riverstonerelay.jihad-browser.mojo + app-mojo/: a scaffold for a future Mojo
UI port (engine/daemon/adapter come free from the bundle; only the UI is a stub).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ByeKWo8E8f23afU2ZKtfkx
Make the whole project reproducible from a clean `git clone --recursive` (no sibling repos,
no hardcoded workspace path):
- third_party/mochi, third_party/mochi-sampler (github.com/webOSArchive) and
third_party/enyo-layout (github.com/enyojs/layout @ 2.5.2) are pinned submodules, replacing
the sibling ../mochi, ../mochi-sampler and the non-repo webos-stacks layout the Mochi .ipk
build used. All pristine (no patches). build-mochi-ipk.sh resolves them from third_party/.
- build/webos-oe/fetch-pdk.sh extracts the proprietary Palm PDK from its .deb into
build/webos-oe/pdk/ (git-ignored). build-adapter-{pdk,arm}.sh find it there or via PDK_ROOT,
falling back to the legacy sibling location.
- build-adapter-{pdk,arm}.sh derive ROOT/REPO from the script location instead of the
hardcoded /home/notalexnoyle/... path.
Verified: the adapter builds with the rewired paths + fetched PDK, and the Mochi build
resolves all three UI submodule sources. See docs/UXP.md for the fresh-clone recipe.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ByeKWo8E8f23afU2ZKtfkx
Restructure the UXP/Goanna engine so it tracks Pale Moon upstream cleanly without a fork:
- third_party/uxp = git submodule -> https://repo.palemoon.org/MoonchildProductions/UXP,
pinned to b2594a4ace (never edited in place).
- All Jihad engine modifications are captured as ten themed patches in
build/desktop/patches/00NN-*.patch, each a clean diff vs the pinned upstream over a
DISJOINT set of files, so they apply independently (no ordering, no drift). This fixes
the previous set (which had drifted — 0011/0012 no longer restacked) and, critically,
captures the 26 engine mods that were NOT in any patch: the headless MOZ_WIDGET_TOOLKIT,
the NSS main-thread marshal fix, the plugin/gfx headless changes, and the branding strip.
- The branding strip moves from an inline sed in build-goanna.sh into 0010-branding-strip.patch,
so every engine change lives in one mechanism (the patch queue).
VERIFIED: a fresh pinned upstream checkout + all ten patches reproduces the engine source
tree exactly (only build-generated configure/__pycache__ differ). Update-from-upstream and
first-build workflows are documented in docs/UXP.md.
NOTE: the full clean-build gate (fresh submodule + patches -> libxul builds) is the remaining
verification; the working ../UXP tree is retained as the proven fallback until then.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ByeKWo8E8f23afU2ZKtfkx
Rotation: the landscape "3× tiling/scanlines" was LunaCE reading the raw plugin
dstBuffer at a fixed ~256px stride (768=3×256 tiled; 1024=4×256 clean). Composite
the offscreen through the device's transform-aware Piranha PGContext instead
(useGraphicsContext=true + PGSurface::wrap + bitblt) — correct in both orientations,
superseding the white-frame guard. Minimal PGContext.h/PGSurface.h ABI headers
(releaseRef is inline on the PGShared base, not a PGSurface symbol — Codex F1).
Verified on-device; the two PG symbols resolve against libWebKitLuna.
Zoom: SetResolution/SetFullZoom never magnified the offscreen RenderDocument capture
(its internal AppUnitsPerDevPixel/AppUnitsPerCSSPixel scale cancels the engine zoom ->
a 1/zoom quadrant = "things get cut off"). JihadRenderDocument now pre-scales the
gfxContext by Z and renders an absolute DOCUMENT rect (RENDER_DOCUMENT_RELATIVE) so
w/Z x h/Z CSS px fill the buffer at Zx and the whole page pans in both axes. Layout
viewport stays device-width (no reflow -> can't re-arm the landscape feedback loop ->
rotation safe); near-1 fit-zoom keeps the engine-scroll path (onscroll/fixed/sticky).
Versioned the extern-C entry point (_v2). UXP change is build/desktop/patches/0013.
Both adversarially reviewed with Codex 5.6-sol; all findings resolved. Detail in
context/impl/{rotation-fix-2026-07-26,zoom-fix-2026-07-27}.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ByeKWo8E8f23afU2ZKtfkx
- Top-level: status reflects interactive on-device use, both UI variants shipping,
the crash fix, history/bookmarks/downloads, and the real remaining work; Phase 3
roadmap split into done / in-progress / remaining.
- render/goanna: 'to be built' → the actual built file set (headless toolkit,
GoannaRenderPage/PageChrome, Dialog/Download services); renders on the TouchPad.
- build/webos-oe: toolchain gate marked cleared (crosstool-NG GCC 9.4/glibc 2.23).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FTDsTcrUkBYzor1aaS9RUG
Bring the NPAPI BrowserAdapter port into the repo as source (render/adapter/)
instead of relying on the out-of-tree ref-BrowserAdapter clone, restore the
reproducible build scripts, and update docs to the self-contained state.
render/adapter/ — imported the isis-project BrowserAdapter + AdapterBase source
(Apache-2.0, @@@LICENSE headers preserved) with the Jihad port applied:
- self-contained coexistence: MIME application/x-jihad-browser + YAP name
jihad-browser (BrowserAdapterJihad.so runs alongside the stock adapter)
- dstBuffer raw-blit handlePaint (+ rotation guard, pinch-zoom, scroll bar)
and single-tap -> asyncCmdClickAt, ported from Atlas (Herrie82, Apache-2.0)
Modified file carries an Apache-2.0 s4(b) change notice; NOTICE already
attributes isis + Atlas. Rebuild from render/adapter/ is byte-identical to
the on-device BrowserAdapterJihad.so (verified). build-adapter-{pdk,arm}.sh
now compile from render/adapter/.
.gitignore — un-exclude the reproducible build scripts/mozconfigs/OE recipes/
engine patches/READMEs under build/ (~59 small text files); keep excluding the
heavy/third-party parts: engine objects, device-bundle/ + *.tar.gz, toolchain,
device sysroot, and vendored adapter deps.
docs/readmes/kits — README, DEVICE-HANDOFF, DEVICE-BUILD, impl-overview,
cavekit-{overview,ipc-contract,device-build}, app/README,
render/browserserver/README, and new packaging/README describe the
self-contained coexistence model and the on-device working state (renders
example.com/slack.com, load-completion, refresh glyph). Drop the dead
../enyo-1.0 script tag from app/index.html.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016MYQTq14u2BT67nroRijWA
Per request: a second front-end built on Enyo 2 + the Mochi UI library
(app-mochi/), shipping as its own .ipk alongside the Enyo-1.0 variant — two
versions for the TouchPad — and device builds targeting the TouchPad Go (Opal)
as well as the TouchPad (Topaz), since isis-browser runs on both.
- Scaffold app-mochi/ (appinfo, Enyo2/layout/Mochi index.html, JihadBrowser
kind skeleton, README, CLAUDE.md, Jihad icons).
- New kit cavekit-mochi-ui.md (5 reqs); cross-link from cavekit-ui-shell.md.
- cavekit-device-build.md: R3 now builds BOTH UI .ipks; new R6 TouchPad Go
machine support; R4 covers both models.
- Build site: +6 tasks (T-049..T-054) → 54 tasks, 157/157 criterion coverage,
graph + summary updated. Overview/plan-overview/README updated.
Both UIs drive the same unchanged BrowserAdapter contract; engine work is shared.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Key out the baked checkerboard background of jihad-browser-logo.png to true
transparency (edge flood-fill, preserving interior highlights), autocrop, and
regenerate: app launcher icon (64), splashicon (256), Preferences header icon
(48), and a 512px README logo (docs/). Embed the logo in README.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>