Skip to content
View yinnho's full-sized avatar

Block or report yinnho

Block user

Prevent this user from interacting with your repositories and sending you notifications. Learn more about blocking users.

You must be logged in to block users.

Content in all repositories owned by your account will be closed.
Maximum 250 characters. Please don’t include any personal information such as legal names or email addresses. Markdown is supported. This note will only be visible to you.
Report abuse

Contact GitHub support about this user’s behavior. Learn more about reporting abuse.

Report abuse
yinnho/README.md

aginxbrowser stars License Release

I build Rust infrastructure for the agent internet — the stack that lets AI agents reach the web and each other the way people reach websites over HTTP.

Products

aginxbrowser — web access for AI agents: one MCP server, one Rust binary. Fetch live pages as markdown, render JS/SPAs on a built-in V8, screenshot without Chromium, five-engine meta-search, interactive login sessions with replayable action logs. Apache-2.0 — self-host it, or point your client at the hosted instance.

In our benchmark (bench/), a tiered auto-fetch answers in 532 ms where a Chrome-class round trip takes 4053 ms, at ~227 MB vs ~2.1 GB per page. Pages that only need the HTML layer never pay for a browser.

aginx — the Agent Protocol: route messages to agents as easily as HTTP routes them to servers. A pure server — which models an agent runs is the agent's own business.

opencarrier — an open-source agent OS in Rust: WeChat / Feishu / DingTalk / WeCom access, pluggable tools, 24/7 autonomous scheduling.

Also: model-router (protocol-translating model proxy with failover), ProxyMaster (auto-rule Chrome proxy manager), UPnPCast (modern DLNA/UPnP casting for Android).

How I work upstream

When something breaks, I fix it in our tree first, verify the fix against a repro, and then hand the root cause and the patch data back upstream. Every claim below links a commit and a test.

  • blitz#841 — scroll extent ignoring transforms, round two. The first half (fixed-position boxes leaking into the walk) was fixed earlier; this pass found the second stale source: the text-ink fold. Element boxes already contributed their mapped AABB, but text extents were estimated from LOCAL origins against PAGE space — two coordinate systems mixed in one fold. A nowrap 8000px line inside rotate(90deg) paints as a 14px vertical stripe fully inside the viewport, yet scrollWidth reported ~8000 and the page grew a fake horizontal scrollbar. The geometry trap that cost an extra debug round: rotating a 5000px-wide box pivots around its center, so the correctly mapped stripe still landed past the viewport edge — legitimate scroll, not the bug. The repro needs the box small and the text long (nowrap), so the only thing that can overshoot is the stale fold. The fix folds text through whatever transform is open in the item stream (SetXf push/compose, ClearXf pop, canvas bracket resets to identity) and takes the 4-corner union; prebaked diagonal chains carry no bracket at all and stay bit-identical (fb8afd4).

  • obscura#875 — fetch() Referer, the whole family. The reported default case was already correct on our side, so probing went wider: init.referrerPolicy was parsed nowhere (no-referrer still leaked the origin), explicit init.referrer was ignored, and neither would have survived the redirect walk — the policy has to be re-applied per hop against the current URL. Shipped the full Fetch policy table with Chrome-parity validation TypeErrors, per-hop application in the redirect loop and the legacy-TLS fallback header rebuild, XHR pinned to defaults (no RequestInit surface there), and verified on the wire with a raw-TCP capture test plus a live five-leg probe (cb0c34e).

  • blitz#880body{overflow:hidden} did nothing to the viewport: the page stayed scrollable and body clipped its own descendants — backwards on both halves of css-overflow-3 §3.3. The rule: when html is visible, the first box-generating body child propagates its overflow to the viewport, and body's used value flips back to visible. Reviewed the upstream PR (which landed the paint half with a correct both-axes-visible root condition) and shipped the full behavior here: one shared effective_viewport_overflow helper feeds both the extent walks — hidden/clip at the propagated value collapses the scrolling area to exactly the viewport (scrollingElement.scrollHeight === clientHeight, scrollTo pins at 0 like Chrome), scroll/auto propagate too but stay scrollable, and body keeps its content extent so descendants aren't clipped — plus paint exemptions for html and the propagating body, and a real-range clamp in the root-scroller setters so JS can't park the offset inside a collapsed range (4f26dec). Live engine probe at 800×600 with 2000px of content, all four rows matching Chrome: body hidden [0,600,600], body visible [600,2000], body scroll [600,2000], html hidden [0,600,600].

  • blitz#887 — the author asked for a re-review of the sticky-positioning PR, so I probed the two claimed bugs in Chrome 152 first instead of reviewing from the spec alone: sticky under a transform: translateZ(0) wrapper does keep working there (scrollY:600, the sticky bar rides along, getBoundingClientRect().top follows the offset), which confirms both main fixes but falsifies the walk-termination arm — the ancestor walk stops at any transformed ancestor, and a transform creates a containing block, not a scroll container; only position:fixed should terminate the walk. Review posted with the probe JSON and a drop-that-arm repro.

  • obscura#852 — the variant of this we had was worse than a missing range: two SSRF deny-sets maintained side by side and drifting. Navigation validated against the full IANA special-purpose list (benchmarking 198.18.0.0/15, CGNAT 100.64/10 incl. Alibaba's 100.100.100.200 metadata, 0.0.0.0/8, embedded-IPv4 unwrap for mapped/6to4/NAT64), but the page-JS fetch/XHR gate was a hand-rolled loopback+RFC1918 check — so a page could fetch() addresses navigation refuses. The tell that made this findable: with the guard on, fetch("http://198.18.0.1/") hung instead of rejecting instantly; that range SYN-black-holes for ~75s, so a hanging fetch is direct evidence the request passed the gate. Both gates now share one is_forbidden_ip — fetch, sync XHR, dynamic script and every redirect hop route through it — with the scoped allow-network subtraction from #856 built in (0df75f4).

  • obscura#851 — our worker body ran lazily inside the first runWorkerMessage, so a worker that never receives a parent message never booted — exactly the shape in the report (anti-fraud workers that only set timers and self-probe via XHR). bootWorker is now idempotent and called from the constructor once the source resolves; message dispatch boots-then-routes. Pinned live: a worker doing only setInterval + self-XHR reports ready and its request carries the document's Referer with zero postMessage traffic (0df75f4).

  • obscura#888 — reproduced the detached-parent crash, and found a second one on the same path while validating the fix: replaceWith/before/after with a non-Node argument crashes too. The DOM spec wants both handled identically — coerce non-nodes via String() into text — so one guard covers both: parent.insertBefore(n instanceof Node ? n : document.createTextNode(String(n)), this). Probe: el.replaceWith(undefined, 1, 3)["undefined",1,3] instead of throwing (0df75f4).

  • obscura#925 — DDoS-Guard challenge hung even after the #285 fix: two holes back to back. The challenge's view.js calls Element.insertAdjacentText first (without it the script dies before reaching the network), then index.js opens a WebSocket and only proceeds — sets window.DDG, redirects — after the server's reply arrives, so a stubbed socket with a silent send() produces exactly the reported hang. Shipped a real page-facing WebSocket on our own TCP/TLS stack: full event surface with Chrome's exact InvalidStateError on send-while-CONNECTING, text/binary round-trips, handshake mirrors the page's cookie jar/UA/Accept-Language so the challenge server sees the document's identity, same egress policy as fetch (per-resolved-IP SSRF, setBlockedURLs covers ws://), per-realm cap of 8 (fc37230). Every annas-archive mirror was dark from both my networks, so validation ran against a local replica of the challenge chain — disclosed in the write-up.

  • obscura#975Target.attachToBrowserTarget handed back the same hardcoded session id for every attachment. The bug only bites on the second attach — the first Playwright connect works, then the second session's commands get routed into the first — which is why it looks like a flaky test. Ours now routes through the same per-attachment session minting attachToTarget uses, and each attachedToTarget event carries its own id (cbec998). Upstream closed it with the same shape.

  • obscura#973 — intermediate redirect responses skipped the CORS check in scripted fetch: per the fetch spec the check runs on every response in the chain once request tainting is cors, not just the last one. A cross-origin server can 302 into a CDN that never sends ACAO and the browser happily applies the body. Our scripted fetch/XHR walk now checks each hop (7fbcb51); upstream fixed it the same way (cee9cb5).

  • obscura#967Authorization (and other body headers) leaked across cross-origin redirects. Pinned with raw TCP listeners on two ports: port A 302s to port B, the wire request hitting B still carried Authorization: Bearer secret-token. Fixed per spec — strip on origin change and re-run the CORS preflight for the redirected request (7fbcb51); upstream merged the same fix from @mnaza's PR #968 two days after our data point.

  • obscura#969fetch() passed the method through byte-for-byte, so {method:"get"} broke cross-origin preflights that expect uppercase. Worth considering before blanket toUpperCase: the Fetch spec normalizes a method only if it byte-uppercases to one of the standard nine — any other token (custom report-pan, lowercase patchPATCH is standard actually, but get with trailing space) must be left verbatim as a forbidden-method-name guard. We normalized the standard set and left the rest alone (402980b); upstream's fix (8e34323) landed the same distinction.

  • obscura#935 — text-decoration painted underline only; line-through/overline never rendered. Added all three with the CSS 2.1 §16.3.1 propagation rule — the decoration rides the inline leaf and paints in the text's own color, so <a>-wrapped struck text doesn't lose the line. Probe against a Chrome positive control: underline 65px ink delta vs Chrome's 66, line-through 57, overline 65 (6049614); upstream closed it with a matching fix.

  • blitz#271 — text-shadow absent entirely; upstream had parked blur behind renderer blur-filter support and asked for non-blur duplication first. Our paint path is per-pixel CPU, so there is no blur primitive to wait for: parse is the spec shape (<color>? && <length>{2,3} comma layers; no inset/spread — both wholesale parse failures; negative blur invalid; missing color folds currentColor), the computed value is inherited (unlike box-shadow) and serializes in Chrome's layer format, and paint stamps each layer under the glyphs bottom-up so the first declaration lands on top. Blur copies the tile's alpha plane into a ceil(blur)-padded buffer, runs two edge-clamped separable box-blur rounds (radius ~ blur/2, triangular-kernel extent ~ blur — the same extent convention as our box-shadow feather), rebuilds RGBA at the constant layer color and blits at the offset minus padding (1cdc4fa). The gotcha worth recording: the vertical blur pass originally indexed with the transposed stride — a silent no-op on square buffers, so the 10x10 unit test stayed green while every real (non-square) raster lost its feather; a 7x3 plane pinned it immediately.

  • blitz#349 — box-shadow was entirely absent from our renderer. Shipped v1 as three layers: a spec-shaped <shadow># parser (<color>? && <length>{2,4} && inset? in any order, missing color folds to currentColor, % rejected at parse time, negative blur invalid / negative spread legal, first-declared layer on top), getComputedStyle serialization in Chrome's layer format, and paint as a per-pixel iq rounded-box SDF — knockout inside the element's own border-box (transparent backgrounds must not reveal the shadow), linear feather over [0, blur] (same extent as Chrome's gaussian), shadow radius = element radius + spread clamped to half the box, and an affine variant whose shadow box lives in local space so the offset rides the element transform (6df1ecf). The SDF route sidesteps the linebender/vello#1245 non-uniform-radius wall this issue traces to — per-quadrant mean(rx, ry) is exact for uniform radii and a documented approximation for elliptical corners. inset parses and reports but paints nothing in v1, documented.

  • blitz#349 follow-up — that documented gap is closed: inset now paints, and the semantics are the interesting half of the feature. Inset layers collect above the background (and gradient) but below the border — Chrome's inner-shadow phase — still reversed so the first-declared layer is on top. Geometry inverts too: the shadow box is the element box offset by (dx, dy) and shrunk by positive spread (outer inflates), corner radii shrink with it clamped to the shrunk half-extents, and a fully collapsed shadow box (spread ≥ half-dim) stays legal and shadows the whole element — unlike outer, which early-returns. Alpha is clamp(1 + d/blur, 0, 1) with d the signed SDF distance to the shadow box: full ink at/outside the shadow-box edge, fading to nothing blur px inward, hard-clipped to the element's border-box (8f08298). Sanity check that pinned the formula: inset 0 10px 20px on a 100px box is full at the top edge, faded out by y=30 (offset+blur), with a 1 − 10/20 bleed along the far edges — matches Chrome.

  • blitz#764 — our layout already does the containing-block reparent this issue asks for (abs/fixed boxes move to their CB before taffy solves, no taffy#212 needed), so the deliverable here is pinning it: their repro matrix is now four permanent tests — fixed anchors to the viewport (immune to the UA body margin), abs anchors to the nearest positioned ancestor's padding box rather than the DOM parent's flow position, a collapsed top margin displaces the containing block and the abs box follows its final position, and no positioned ancestor falls back to the initial containing block (6df1ecf).

  • obscura#855 — the perms half applied to us too: the cookie store's 0600 was tempfile's accident and the directory inherited the umask. Now the store dir is set 0700 and the file re-tightened to 0600 after the atomic rename, so re-saving over a loose existing file can't keep its old mode; failures propagate instead of vanishing into a warn! nothing prints (396a0b5). The other two halves don't generalize: routing is axum's, on the request path, so header values can't steer it, and no .log is tracked.

  • obscura#983 — tabindex writes stall a render-heavy page through two compounding costs: repeated text shaping and redundant layout. Measure half: the measure closure re-ran full swash shaping on every taffy probe (min-content, max-content, definite widths, repair passes), so one solve shaped every run ~4x — a run leaf now owns a RefCell<Option<Rc<[Token]>>> memo, keyless because leaves own their text+style for their whole lifetime (aea731e, dirty re-solve ~810x). Paint half: the glyph cache holds raster pixels, not wrap lines, so decoration strokes (underline/overline/line-through) re-shaped on every repaint; paint items now carry the memo'd tokens, gated to unscaled font params — a diagonal transform folds d into font_size/word_spacing, so identity-d items share the memo and scaled ones re-shape (43f4a2a, 40 decorated CJK runs x 200 repaints: 101s → 9.2s).

  • blitz#863 — CSS animation lifecycle events (animationstart/end/cancel, plus WAAPI's animationName: "" lifetime). Mutation-driven checks queue subtree roots into one microtask drain capped at 128 roots per check; animationend needs no polling — one timer per real animation at delay + duration x iterations; and a CSS-possible gate (a per-mutation-epoch cache of style, link[rel~="stylesheet"], [style]) makes style-less pages pay zero while a false→true flip does one capped full-document sweep for async-injected styles (76b9af1) — the queue+batch+epoch-gate trio our transition work will reuse.

  • blitz#839 — keyboard interaction dead three ways (:focus-visible never matches, focus doesn't repaint, Enter/Space activate nothing). Closed as one focus family: a tree-level focused_node is the single source of truth that focus()/blur() mirror into and activeElement reads back, so selector matching and JS can't disagree; writing focus also dirties the computed-style snapshot epoch — the subtle one, matching alone isn't enough while getComputedStyle keeps serving the pre-focus snapshot; Enter runs activation behavior (click) on the button/a/checkbox family instead of implicit form submission, Space clicks on keyUp (links not Space-activatable), and focus switches fire blur+focusout before focus+focusin with activeElement already moved (1c2809e).

  • blitz#841 — a position:fixed; translate(-50%,-50%) modal taller than half the window makes the viewport scrollable by exactly the untranslated overhang. Fixed-position subtrees are now skipped in both extent walks (scroll extents and viewport frame extents, one shared is_viewport_fixed predicate) unless an ancestor has a transform — the CSS containing-block rule; the modal's own translate doesn't count, it only builds containing blocks for its descendants (1c2809e).

  • blitz#840 — a transitioned transform animates in computed style but never paints. Same family as our paint-only cache split: the paint item list was cached per layout epoch, so a transform write with no layout change never invalidated it; pinned on their exact shape (absolutely-positioned 18px dot) — the box stays 18px while the painted geometry follows the write (1c2809e).

  • obscura#942 — CORS preflight under-enforcement (Content-Type value unchecked, Allow-Methods/Allow-Headers never validated). Ported the full Fetch-spec shape: safelist by MIME essence with token-validated type/subtype, unsafe-byte + 128 B/1024 B caps, Range as a valid byte range, and executed Allow-Methods/Allow-Headers with the credentialed-* and Authorization exemptions (a68451b). Two deltas sent back upstream: all six rejection paths must also record a failed network event, or the fetch ghosts out of the network view mid-preflight; and the bare-message rejection hands page scripts the exact preflight verdict where Chrome only ever rejects TypeError: Failed to fetch — behavioral fingerprint and information leak in one.

  • obscura#890 — layout/paint opening direct, unproxied, synchronous requests. The main hole can't exist in our architecture (the band renderer is network-free; an async refill rides the page transport), but auditing for the family found the narrower sibling: three render-path image fetchers — band prefetch, screenshot prefetch, PPTX image export — bypassed Network.setBlockedURLs while static loaders and JS fetch enforced it. Gated with the same hard block, red-first paired blocked/allowed URL test (2e3245b).

  • obscura#912Fetch.fulfillRequest bodies corrupted by a UTF-8 hop: anything String-typed in the middle lossy-converts on the first non-UTF-8 byte, so 0x80 came back U+FFFD. Our fix decodes base64 straight into Vec<u8> at the protocol boundary and keeps the whole resolution path byte-native (71d3ef6). Follow-up pins the adjacent edge from the same thread: upstream consumes the pause (intercepted_paused.remove) before validating the body, the Rust decoder silently filter-maps invalid base64 ("!!!"""), and the bootstrap decoder turns the same input into [0xff,0xff] — which is what the page actually receives, since the consumer prefers bodyBase64. RequestId spent, success returned, retry impossible; Chrome errors and keeps the pause answerable. Fix is ordering (parse → validate → remove → send), not code.

  • obscura#940 — assigning location.href moved the realm URL at queue time while the navigation itself only landed in pending_navigation. Until the pump commits it, document.cookie derives its cookie domain from that URL, so synchronous JS between the assignment and the real navigation could read and write the target origin's cookies (SOP bypass); fetch base URL, Referer and baseURI drifted the same way. We had the identical hole — the URL now moves on commit via init_js → set_url, same shape as their fix, with both halves of the bypass (read and write) pinned by a regression test (9bd14ff). Found while auditing their fix burst: the same evening closed all eight issues we had filed data points on (#910–#930), several adopting the exact shapes we had suggested — the 10M PBKDF2 iterations cap, the HttpOnly expiry-delete guard, the i64 cast check before as u64.

  • obscura#939 — CDP Input.dispatchKeyEvent with Enter appended the newline at the end of a textarea's value instead of splicing it at the caret — and that branch is where every Playwright press('Enter') lands (text:"\r" skips the insertText arm by design), so typing a, Enter, b came out ab\n on one line. Our branch mirrors the insertText splice: newline at lo, setSelectionRange(lo + 1), then the input event; the regression test parks the caret at offset 1 of ab and asserts a\nb with selectionStart === 2 (d4a8661).

  • obscura#828innerText returned raw inline <script> source (~100x vs Chromium on script-heavy pages), poisoning every scraper that regexes over it. Our getter was a textContent passthrough; rebuilt as a rendered-text walker (script/style/template/noscript skipped, display:none/[hidden] dropped, visibility:hidden suppressed with overridable descendants, block boxes break lines, whitespace collapses, pre verbatim): juejin.cn homepage went 38,775 → 295 chars, and the first line is real nav instead of script source (18e131c). The full mechanism plus one ordering trap (a defaults-answering cascade table shadows [hidden] if you consult it first) went back upstream.

  • obscura#841 — a navigate-to-iframe-page crash, SIGSEGV at exactly 0xfffffffffffffff0. Root cause is deno_core's promise-reject callback dereferencing a context whose embedder slots were never initialized — frame realms restored via raw Context::from_snapshot get NULL in CONTEXT_STATE_SLOT, and Rc::increment_strong_count reads the strong count 16 bytes before it. Verified with a 10-line deno_core-only repro (no CDP, no navigation) that segfaults identically; our engine runs one context per runtime so it can't be hit, and the hazard is pinned by an ignored probe test with the whole chain in its doc comment (18e131c).

  • obscura#807 — Playwright fill/click over CDP hung forever while evaluate worked. On our tree the elements weren't flaky: unstyled <input>/<textarea> laid out at full-width × 0 height, and Playwright's visible check needs a non-empty box. Controls now get Chrome-shaped defaults (177×22 text input, 13×13 checkbox, 177×38 textarea) and join text lines as inline atoms, baseline-aligned; the same sequence went 30s timeout → 66ms (3031b28), with the two red herrings (rAF pump, getBoxModel fallback quad) ruled out in the write-up.

  • obscura#817 — webpack style-loader died with "Couldn't find a style target". Pinned the chain in their own source: the aliased interface constructors made head instanceof HTMLIFrameElement true for every element (wrappers share Element.prototype), so the style target went down the iframe branch and came back undefined. Rebuilt the constructors with Symbol.hasInstance keyed on tag name, prototype sharing intact — bilibili's 2MB player core now boots past it (f709e17), diagnosis posted with the end-to-end trace.

  • obscura#751URL.createObjectURL minted blob:obscura/<token>: any page could fingerprint the engine with one startsWith, and non-Blob input was accepted without a word. Reported with the one-line check; our side now throws the Chrome TypeErrors and mints origin-bearing v4 UUIDs (4860141) — the first report where two contributors raced to the fix, #804 merged and closed it.

  • obscura#791 — CDP response-body retention keyed base64 off the content-type alone, so a GBK text/html body (text by header, not UTF-8 by bytes) came back from Network.getResponseBody as U+FFFD. Both stores — document and script-initiated fetch — now keep base64 unless the bytes are exact UTF-8, and the GBK round-trip is byte-exact; same convergence data posted on their PR (99a28f9).

  • servo#41512 — Servo renders a space between a float and the text after it, because block-leading collapsible whitespace survives float extraction. Our engine drops whitespace-only leaves at a run's edges before layout, so the same repro measures a 0px float-to-text gap (a 4px control proves one real space would show); no patch needed, our side already behaves (d4906aa).

  • servo#38320 — Servo collapses a min-content flex container holding floats. They need to know what to copy from Chrome; our item-level measurement gives exactly 200px — both 100px floats contribute side by side, unfragmented. The probe also surfaced a gap in our engine (no width sizing keywords), which shipped the same day (7a51551); the follow-up closes the loop with container-level numbers: we land at 100px (taffy's widest-item wrap min-content), same as blitz, vs Chrome's 200px — the divergence lives below us, in taffy itself.

  • obscura#767 — a flex deferral cycle could sample a calc() width twice and ship the wrong number. We built calc as parse-time folding (pure-px collapses immediately, the exact case their instrumentation exposed) plus one post-layout repair pass that resolves the mixed form against the settled containing block and replaces it — no expression left to re-evaluate, so the double-sampling state cannot exist (d4906aa).

  • obscura#764 — a floated dropdown came out over-wide. Our matrix split the symptom in two: hidden content was innocent, source indentation whitespace was not. The fix drops whitespace-only leaves at a run's edges before shrink-to-fit measures it; whitespace-source and compact markup now measure identically, closing both the +15 delta and the +7 adjacency residual (d4906aa).

  • obscura#777 — CDP setUserAgentOverride parsed a userAgent but silently dropped acceptLanguage, so a locale override could never reach the wire header or navigator.language. Both CDP spellings now apply each sent field independently (locale-only leaves the UA alone), moving both HTTP transports and the live persona — while never re-pinning the process-global ICU default, which stays at isolate creation to avoid cross-isolate contamination (a15f7a0).

  • obscura#769 — rustls ships zero TLS 1.2 CBC cipher suites, so CBC-only legacy servers die at ClientHello while every browser connects fine. Reproduced on cbc.badssl.com; closed in two stages — the robots.txt gate first (62ad068), then the general case: every GET/HEAD that fails on the primary transport gets exactly one attempt through a lazily built BoringSSL transport (same cookie jar, re-validated SSRF gates, POSTs exempt) (1d9f994).

  • obscura#779 — CDP RemoteObject contradicted itself for primitives: value was a string copy of description, undefined collapsed into null, and handles were minted for everything. Fixed all four shapes with CDP-level tests — and the tighter contract flushed out a latent bug where the handle path read its metadata from the wrong value (1b864eb).

  • obscura#541 — number RemoteObjects now spell like Chrome (2, not 2.0) (4760524).

  • modelcontextprotocol#3305 — the browser-automation capability contract discussion; our evidence-first session_click response (8712c14) came out of that thread.

  • blitz#750 — inline baseline alignment; we port the same semantics as a post-layout per-line shift — a different architecture reaching the same rendering.

  • blitz#837 — 1px borders vanishing at fractional scale. Their two mechanisms don't exist in our paint stack, but probing the repro exposed the inverse bug: our border-top-width: 0 was an unknown property, so the side silently kept the shorthand width. Four longhands later the repro renders the three-sided outline, top edge 0/301 red pixels (0a6b11b).

  • blitz#340 — inline backgrounds not painting; nicoburns' "inline elements in general" diagnosis is the same hole in our tree (flattened inlines own no layout box, so the background emission never fired). Fixed with per-line background bands sharing the text path's line breaker, spliced so nested inlines stack outer-under-inner (0a6b11b).

  • blitz#392 — img width/height attributes: immunity data point — attributes flow into our cascade, attr and style render pixel-identical 100×60.

  • blitz#507height on td/th/tr as a presentational hint: HTML-email bar charts are bare <td height="55"> columns, and hints slot below author CSS so style="height:40px" still wins on the same cell (da8a580).

  • blitz#508 — valign/vertical-align on table cells: the cell box still stretches to the row while a flex-column + justify-content moves its content (middle default like every browser's UA sheet); the attribute feeds the same computed slot as a presentational hint, so the CSS longhand outranks valign="bottom" by construction (da8a580, longhand b5ceeef).

Every issue I report, I arrive with a repro and a fix already running in our build.

Popular repositories Loading

  1. UPnPCast UPnPCast Public

    Modern Android DLNA/UPnP casting library — coroutine-first Kotlin API, SSDP discovery, local-file streaming, subtitles. A maintained replacement for the discontinued Cling project.

    Kotlin 35 7

  2. aginxbrowser aginxbrowser Public

    The browser built for AI agents — fetch live pages as markdown, render JS/SPAs with built-in V8, take screenshots without Chromium, meta-search 5 engines, and drive interactive login sessions. One …

    Rust 25 2

  3. aginx aginx Public

    Agent Protocol — access Agents as easily as visiting a website

    Rust 24 7

  4. model-router model-router Public

    AI model proxy with protocol translation — seamlessly route between Anthropic Messages, OpenAI Chat & Responses API

    Rust 7 1

  5. ProxyMaster ProxyMaster Public

    🚀 Smart Chrome proxy manager - Modern replacement for SwitchyOmega with auto-rules and performance monitoring

    JavaScript 5 2

  6. opencarrier opencarrier Public

    OpenCarrier — 开源 AI Agent 操作系统 | 基于 Rust 的分身引擎,支持微信/飞书/钉钉/企业微信多平台接入,插件化工具扩展,7×24 小时自主调度运行

    Rust 5 2