HNHacker News
TopNewBestAskShowJobs

rictic

3,387 karma · joined August 15, 2007

rictic@gmail.com http://github.com/rictic

I work on https://lit.dev/ at Google.

[ my public key: https://keybase.io/rictic; my proof: https://keybase.io/rictic/sigs/oWyFb0ZtJHIhMD8GbVGDmFDr2gH7PH4zmivg2IWAGp4 ]

submissionscomments
rictic··on Faster floating point math with Rust's new API
Yeah, it's my favorite bit of C lore, a program that reads two integers, adds them, and reports the sum isn't well defined.
rictic··on 200 Milliseconds
I'd be impressed with a touchpad and OS that can go from an actuation to a userspace process receiving a click event in 1.2ms. I'd expect something more like 10x that. My understanding is that most hardware samples between 90-130Hz, and even premium hardware only samples at 250Hz which would average 2ms before the kernel is aware.
rictic··on The classifiers Anthropic puts in front of Fable are too zealous
The honest way to say this is that Fable is not useful for bio-related work. The author is working on processing RNA sequences and similar biology tasks, and Fable's classifier has a hair trigger on those tasks.
rictic··on New AI tutor achieves 0.71-1.30 SD effect size in Dartmouth course [pdf]
Yes! Very exciting to see this.

Bloom's Two Sigma Opportunity suggests that there's another SD improvement available: https://en.wikipedia.org/wiki/Bloom%27s_2_sigma_problem

rictic··on The sigmoids won't save you
The author has written about stacked sigmoids in the past, e.g. in https://slatestarcodex.com/2018/10/15/is-science-slowing-dow...

I suspect that he started down the path of considering them more deeply here but found that they didn't add much to the analysis. A stack of sigmoids ultimately either gives you a single sigmoid if you run out of new innovations, or an exponential if you don't.

rictic··on Coding Agent VMs on NixOS with Microvm.nix
Yep. What nix adds is a declarative and reproducible way to build customized OS images to boot into.
rictic··on Lessons from 14 years at Google
Inflation adjusted incomes are up in the US across the board. The affordability problem is largely the price of housing because it's illegal to build.
rictic··on Avoid Mini-Frameworks
Agree, for modern React with hooks. A React component looks like a normal function, only you can't call it. Only React can call it, in order to set up its hooks state.
rictic··on Why the Sanitizer API is just `setHTML()`
You can disable it for your site using a trusted types content security policy.
rictic··on How/why to sweep async tasks under a Postgres table
Missing from the article: how to communicate progress and failure to the user?

This is much more complicated with task queues. Doable still! But often skipped, because it's tempting to imagine that the backend will just handle the failure by retrying. But there are lots of kinds of failure that can happen.

The recipient's server doesn't accept the email. The recipient's domain name expired. Actually, we don't have an email address for that recipient at all.

The user has seen "got it, will do, don't worry about it" but if that email is time sensitive, they might want to know that it hasn't been sent yet, and maybe they should place a phone call instead.

rictic··on Just use a button
A click handler can be doing a lot of things that aren't much like a button, like letting you close a modal if you click outside of it, capturing mouse events for a game, or passively recording events for analytics. All that a click handler tells you is that there's some code that sometimes cares about some clicks somewhere inside that element.
rictic··on Element: setHTML() method
A somewhat related spec, at the page level rather than the module level, are Content Security Policies, which let a page disable various unsafe browser features for a page: https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP

One of my favorite features in there is trusted types enforcement: https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Typ...

Lets you create your own API for what code is allowed to create arbitrary, potentially unsafe HTML at runtime, so you can allow secure templating systems but disallow code that just concats strings together naively.

rictic··on Element: setHTML() method
It is also painful when your app gets hacked, accounts get taken over and abused, user data is compromised, and so on. For serious sites it's worth the pain to turn on security enforcement features.
rictic··on JSON River – Parse JSON incrementally as it streams in
For anyone else following along, see https://github.com/rictic/jsonriver/issues/39
rictic··on First Self-Propagating Worm Using Invisible Code Hits OpenVSX and VS Code
So, they have a custom decode function that extracts info from unprinted characters which they then pass to `eval`. This article is trying to make this seem way fancier than it is. Maybe GitHub or `git diff` don't give a sense of how many bits of info are in the unicode string, but the far scarier bit of code is the `eval(atob(decodedString))` at the bottom. If your security practices don't flag that, either at code review, lint, or runtime then you're in trouble.

Not to say that you can't make innocuous looking code into a moral equivalent of eval, but giving this a fancy name like Glassworm doesn't seem warranted on that basis.

rictic··on JSON River – Parse JSON incrementally as it streams in
Oh this isn't about the public API, it's about the internal logic of the parser.
rictic··on JSON River – Parse JSON incrementally as it streams in
jsonriver's invariants do give you enough info to notice which values are and aren't complete. They also mean that you can mutate the objects and arrays it returns to drop data that you don't care about.

There might be room for some helper functions in something like a 'jsonriver/helpers.js' module. I'll poke around at it.

rictic··on JSON River – Parse JSON incrementally as it streams in
Only for numbers! Strings, objects, arrays, true, false, and null all have an unambiguous ending.
rictic··on JSON River – Parse JSON incrementally as it streams in
I've just published v1.0.1. It's about 2x faster, and should have no other observable changes. The speedup is mainly from avoiding allocation and string slicing as much as possible, plus an internal refactor to bind the parser and tokenizer more tightly together.

Previously the parser would get an array of tokens each time it pushed data into the tokenizer. This was easy to write, but it meant we needed to allocate token objects. Now the tokenizer has a reference to the parser and calls token-specific methods directly on it. Since most of the tokens carry no data, this keeps us from jumping all over the heap so much. If we were parsing a more complicated language this might become a huge pain in the butt, but JSON is simple enough, and the test suite is exhaustive enough, that we can afford a little nightmare spaghetti if it improves on speed.

rictic··on JSON River – Parse JSON incrementally as it streams in
Good feedback! Just updated the README with the following:

> The parse function also matches JSON.parse's behavior for invalid input. If the input stream cannot be parsed as the start of a valid JSON document, then parsing halts and an error is thrown. More precisely, the promise returned by the next method on the AsyncIterable rejects with an Error. Likewise if the input stream closes prematurely.

As for why strings are emitted incrementally, it's just that I was often dealing with long strings produced slowly by LLMs. JSON encoded numbers can be big in theory, but there's no practical reason to do so as almost everyone decodes them as 64bit floats.

rictic··on JSON River – Parse JSON incrementally as it streams in
Try import maps, something like:

    {
      "imports": {
        "express": "/usr/share/nodejs/express/index.js",
        "another-module": "/usr/share/nodejs/another-module/index.js"
      }
    }
Then run node like: `node --import-map=./import-map.json app.js`

The Debian approach of having global versions of libraries seems like it's solving a different problem than the ones I have. I want each application to track and version its own dependencies, so that upgrading a dependency for one doesn't break another, and so that I can go back to an old project and be reasonably confident it'll still work. That ultimately led me to nix.

rictic··on JSON River – Parse JSON incrementally as it streams in
Bare module specifiers aren't just for Node! Deno and browsers support import maps e.g.

The library doesn't use any APIs beyond those in the JS standard, so I'm pretty confident it will work everywhere, but happy to publish in more places and run more tests. Any in particular that you'd like to see?

rictic··on JSON River – Parse JSON incrementally as it streams in
Do any LLMs support constrained generation of newline delimited json? Or have you found that they're generally reliable enough that you don't need to do constrained sampling?
rictic··on JSON River – Parse JSON incrementally as it streams in
Yeah, getting numbers correct was one of the trickier wrinkles in the project. https://github.com/rictic/jsonriver/blob/5515be978bb564e9bdc...
rictic··on JSON River – Parse JSON incrementally as it streams in
Hi HN! Didn't expect this to be on the front page today! I should really release all the optimizations that've been landing lately, the version on github is about twice as fast as what's released on npm.

I wrote it when I was doing prototyping on doing streaming rendering of UIs defined by JSON generated by LLMs. Using constrained generation you can essentially hand the model a JSON serializable type, and it will always give you back a value that obeys that type, but the big models are slow enough that incremental rendering makes a big difference in the UX.

I'm pretty proud of the testing that's gone into this project. It's fairly exhaustively tested. If you can find a value that it parses differently than JSON.parse, or a place where it disobeys the 5+1 invariants documented in the README I'd be impressed (and thankful!).

This API, where you get a series of partial values, is designed to be easy to render with any of the `UI = f(state)` libraries like React or Lit, though you may need to short circuit some memoization or early exiting since whenever possible jsonriver will mutate existing values rather than creating new ones.

rictic··on JSON River – Parse JSON incrementally as it streams in
Is true. I wrote a ton of tests, testing just about everything I can think of, including using a reverse parser I wrote to exhaustively generate the simplest 65k json values, ensuring that it succeeds with the same values and fails on the same cases as JSON.parse.

Then added benchmarks and started doing optimization, getting it ~10x faster than my initial naive implementation. Then I threw agents at it, and between Claude, Gemini, and Codex we were able to make it an additional 2x faster.

rictic··on JSON River – Parse JSON incrementally as it streams in
SAX is often better if you don't need the full final result, especially if you can throw away most of the data after it's been processed. The nice part about this API is that you just get a DeepPartial<FinalResult> so the code to handle a partial result is basically the same as the code to handle the final result.
rictic··on JSON River – Parse JSON incrementally as it streams in
Funnily enough, this was one of the first users of jsonriver at google. A team needed to parse more JSON than most JS VMs will allow you to fit into a single string, so they had no choice but to use a streaming parser.
rictic··on JSON River – Parse JSON incrementally as it streams in
Cumulative is a good term too. I come from the browser world where it's typically called incremental parsing, e.g. when web browsers parse and render HTML as it streams in over the wire. I was doing the same thing with JSON from LLMs.
rictic··on JSON River – Parse JSON incrementally as it streams in
It mutates the existing value and yields it again (unless the toplevel value is a string, because strings are immutable in JS).
Page 1 of 28Next →