It's worth noting that you need both uniqueness and some form of stability. If you consistently show up as a diffent fingerprint every time you visit or for every different site, then that is a form of privacy as well.
I just downloaded a fresh install of LibreWolf to test this and it did indeed have a stable UUID for me at 1/62E6. Better than the 1/680E6 from regular Firefox, but still upsetting. Fonts and Audio fingerprinting seems to be where a lot of the entropy is coming from... Even after I enabled some of the flags to resist font enumeration it still is stable and high entropy. I'm not sure what to do to be honest about this, it is very discouraging.
One thing I've never fully grokked is how this differs from an observable pattern where one can publish new values to inputs, propagate that through the computation, and push newly computed values to listeners.
I guess there's probably optimizations around change detection and stopping the propagation if there's no change (though observables can do that as well). The stabilize command also makes things interesting as a way to batch changes together before recomputing (but again, doable with observables too).
Is the delta primarily coming from introspection and automatically building the compute graph? Or is there something more fundamental that I'm missing?
It depends on how you define the observable pattern.
The fundamental components here are laziness and weak connections between graph nodes. Node values are getting materialized only when you observe them, and the system is flexible for live structural changes.
Usually, you don't need to materialize the entire graph when you need to observe just some nodes. Additionally, you can halt computations at any point in time leaving the graph in semi-actualized state, make extra changes to the inputs, and continue materialization of the nodes of interest. The algorithm will sort out all changes for you.
Essentially, incremental computations is just a term covering these features. You can organize the same system in terms of observers and subscribers.
> You can organize the same system in terms of observers and subscribers.
Also, the differences between "hot" and "cold" observers and the use of schedulers.
I like that about the observable pattern that while hot versus cold is confusing, it is generally "explicit" in the dance of observers/subscribers. I also tend to like the way that observable schedulers and scheduling operators are often usefully explicit in halting computations while still being largely automated in the time domain.
Certainly my gut instinct with this specific library is seeing if the stuff being done with it might be a cleaner fit in something like RxOcaml, but I realize I'm in something of a minority in preferring explicit observable operators over implicit "computation signals".
So I remember having physics homework a quarter century ago at university where we had to use Excel to determine a static electric potential field, by defining all cells in the grid as "the average value of the four surrounding cells", except the edge cells and source/sink cells which would get actual concrete values.
I distinctly remember being amazed that it would just iterate until it reached equilibrium (maybe we had to change some setting somewhere first though, I never really used Excel before or after that). I think you could change a value mid-iteration, and the grid would just continue on with the previously calculated cell values, instead of start over from scratch. That's basically "weakly connected", isn't it?
I meant that the graph (DAG) structure is not necessary need to be sealed and defined upfront. It could be computed and changed on the fly by the same function that computes node's value. Assuming that the node value computation function is a pure function without side effects (e.g. it's output depends purely on inputs) the function may read other node values directly, and the act of reading would establish graph edges transparently for the user. The next time compute function is being invoked it could re-subscribe on the different nodes hence changing graph structure on the fly. The user also can remove or add new nodes in between of the node values materialization. In other words, the act of subscription between nodes in the incremental computation system is typically tracked more transparently for the user than in the system with explicit observer-subscriber primitives. Even though, this is implementation dependent. The observable pattern could be designed transparently too. Perhaps, "flexibility" would be better term.
How do you consistently update a DAG, like you describe in your medium article, if the functions corresponding to the nodes in the graph are free to create new dependencies willy-nilly? It seems like this would have to be pretty restricted and/or performance killing, because you'd have to evaluate the graph under the assumption that any node could depend on any other node (unless that dependency creates a cycle, presumably). This overhead may not matter if the node functions are expensive relative to the cost of managing the graph, though.
In the article it is assumed that the object of the node owns a vector of it's dependencies locally. We don't need to access the entire edges set all at once. The evaluation process is recursive. Once the node's function re-evaluate, the vector is being updated. Though, the re-evaluation is not happening for every node every time due to the caching system based on the node's value hash comparison and the two-layer monotonic versioning in case of present algorithm. Other incremental computation algorithm have different approaches in verifying on whether the node's function needs to be re-evaluated. Each approach have pros and cons.
You are right, it is assumed that in general the average node function evaluation is more expensive than the cost of graph management. It's not too expensive, but if by chance node's function is notably cheaper, this approach could be suboptimal in certain cases.
The key insight here is that it is assumed the end user don't need to actualize the entire graph each time any random input is being changed. The user observes only a small portion of the graph nodes in real time, and the incremental computation system ensures to minimize required evaluations. If this local observability is not a goal the system is not incremental by definition. For example, in case of Spreadsheets the entire table could be 10000x10000 cells, however the end user typically sees only a small portion of the table on the screen. On a general note the incremental computation systems are closely tied to the GUI-related tasks.
Roughly, you subscribe and listen to an observable. Incrementals are more like a cache across some DAG of computation + state that lets you optimize by only recomputing what needs to be recomputed.
I mean, it's fundamentally just a graph, but it's a way of correctly and efficiently computing changes in massive, dynamic graphs. Let's imagine you have a diamond shaped subgraph that fans out to hundreds of intermediary nodes before collapsing down again via and paths with different "lengths". And what if some of those paths have e.g. min(A, B) where the max side is the only one changing?
A naive observer approach will 1) compute that potentially exponential blow-up very inefficiently and 2) probably have "concurrency" issues. This library will be close to optimal and correct, even if you start dynamically changing the graph structure.
But yes, you can achieve the same thing with observers and other kinds of approaches. Most of them just a lot harder to get right while avoiding performance cliffs.
I'm curious to hear what bottlenecks you encountered in the traditional path. Of all the compute and data shuffling involved in LLM inference, I would have thought shuffling the raw input/output around would have been a trivial part of the overall cost, and thus not a big optimization target?
I addressed this a little bit in the comment below, but the cycles add up. I'm doing some pretty crazy things higher up in the stack, that I'm not quite ready to release yet. But even micro optimizations here add up at the scale I'm working at to allow me the headroom I need. I'm relying on a high-frequency recursive agentic loop that chokes a real-time guarantee without every optimization I can give it.
I started by removing the IPC overhead from a weaviate db connection, and doing all my vector math in house with a lightweight sqlite db. This became the next obvious target for optimization once I saw how much that saved me doing things in-house.
I'm by-and-large fine with XML, having used it for many a year; however I really like working with XML when I can use Guile's SXML layer. For Maven it's not that important because POMs are simple enough, but for more complex things it's nice having a useful tool.
I actually don't mind Ant very much, but I haven't had good luck using Ivy for dependency management. Maven's been very nice in the decade and a half I've used it, Gradle's always felt off to me. I think there was also another Java build tool written in like Ruby or something, but I'm blanking on the name at the moment.
Before Maven came to be, we had built nice macros on our Ant builds that were quite similar to how Maven works, but Ivy wasn't also around.
Eventually Maven grew on me, however I would rather go back to Ant than deal with Gradle, the time using it when I did Android development a few years ago, was more than enough.
Yeah I have long felt that if we think we need gradle, we should consider doing less crazy stuff in our build. Maven is plenty and any time I get back to a repo that has that instead of gradle or sbt I’m much happier.
I've found swearing at a model to be quite effective in getting it to rethink and correct its mistakes. This seems to apply across Codex, Claude, Qwen, and Gemma/Gemini.
I don't know if the model is picking up on a "need to lock in and be more rigorous" signal, or if the model providers are routing to smarter models if they detect a frustrated user. But if a model keeps making the same mistakes, swearing at it often helped kick it out of a glut and onto the right track.
Reminds me of this study: https://arxiv.org/pdf/2510.04950 . It demonstrates that being "rude" or "very rude" increases the accuracy of the results. A dubious but very fun read. The prompts in Table 1 (top of page 3) are awesome. I am sure they tried other prompts, but didn't include them to the paper.
I notice the same. Like you I am not even sure if it really helps, however, every day I find occasions where I see Opus will never do it correctly even though I calmly explain; swearing then suddenly fixes it. I had some issue yesterday where opus kept blaming the api for not sending some field while I knew it was there ; I showed it json, logs etc but it kept repeating that there must have been a glitch; frustration built, I called it all kinds of things in one sentence and the next solution was the right one. This after 10 similar misguesses. It was one of those increasingly rare cases where I should have just done it myself, but I can never know going in how stubborn it will be in continue blaming the (obviously) wrong thing. The around 11 prompts to get to the answer were in a /clear opus 4.7 context (1m) on xhigh.
So the correct strategy is a global CLAUDE.md with couple lines of colourful "you best behave or else" texts, so all your prompts get routed via the frustrated path?
I have a skill for exactly such case! Here's an excerpt :)
```
---
name: evidence-debugging
description: >
Use when debugging any failing test or bug, investigating unexpected
behavior, or tracing the cause of a reported defect.
---
# Debugging Discipline
## When to Use
- A test is failing and you need to understand why
- Behavior is unexpected and the cause is unknown
- The user asks you to debug or investigate a defect
- You need to verify what a value actually is at runtime
*When NOT to use:* proactive code exploration without a specific failure to investigate.
## STOP — Do This Before Anything Else
Before reading code, before forming a hypothesis, before typing anything — answer these:
1. *Do I have actual output from a running system?*
- No → instrument, run, save to file, read. Do not proceed until you have real output.
- Yes → read it. Do not re-run.
2. *Am I about to explain what the issue "probably is" or "must be"?*
- Yes → stop. That is deduction without evidence. It is a violation. Instrument instead.
3. *Am I about to touch passing code?*
- Yes → stop. Only instrument the failing scope.
If you find yourself already reasoning about likely causes — you are already violating Rule 1. Stop. Go back to step 1.
```
No worries! Here's the full prompt if you need it: https://sharetext.io/g6ibuxa5 (you'll probably need to update it, as there're specific things I wanted it to take into account)
Ultimately my point is to define small contexts grounding agents in tasks you expect them to do. Trying to define guidelines for everything will not work = telling it that it shouldn't delete prod AND that it's architect AND that it should review code using this and this principle AND milliard other things that you expect from yourself.
there already is a global claude using any cloud model is a high probability that theyre context stuffing trying to curate output for the normative use cases. see "dont talk about goblins"
Since the source code leaked showed they key off of swearing to trigger certain behavior, I actually intentionally swear when running into things like insufficient thinking and/or hallucinations. It also unironically makes it easier for me to grep later to run analysis on how often its happening.
This is interesting, because in the leaked code, it was found that they detected simple swearing keywords for analytics that get sent to Anthropic, but also had directions to keep the behavior the same for claude. I also have the feeling a 'wtf' does something, but it does feel good and might just be placebo, because 'that is still wrong' sometimes works the 4th time too. Or maybe they changed something.
I only used Claude a bit, but one of the things I dislike about it, is that it starts to 'push back' when you swear at it, saying things like 'if you continue like this, I won't be able to work with you' and such. I'm like MF'er you're a token prediction algorithm, what are you talking about, and it just makes me irrationally dislike it more. Codex otoh just lets you vent and straight up ignores such outbursts.
Wasn't it posted a few weeks ago that the frontend code for Claude or maybe Gemini or one of them had a swearing-at-model classifier that passed a flag to the backend? (Not sure why it was even done in frontend, but it was.)
I don't understand - are people's agents making so many mistakes? I'm using VSCode + Cline + Mimo to refactor big codebases and add features (including payment integrations) and it's rarely making any mistakes.
I use Claude Opus 4.7 on max thinking inside Claude Code and I gotta tell you, as context of the project grows, it starts slipping. No amount of whipping and cursing has helped.
Currently looking to start making my own hooks setup so it can be safer but nothing concrete yet.
I've found this to be effective as well. Claude generally immediately identifies the stupid code pattern it used and tries to fix it (with somewhat varying results).
I've found a mix of peppered in upper case words where you are effectively yelling at the LLM also gives it a strong signal. It is also a bit cathartic.
I tried it too. ChatGPT sometimes hits you with the "Can't help you with that" which was clearly introduced as a post-training highjack. So I just tell it "yes you can", and it proceeds with the previous prompt, slur acknowledgement included.
It's the only time the AI feel strictly like machines. Really simple if/else logic when if slur, no output, and you just tell it to proceed, and it fails the if clause because there was no slur in the last input.
Can you elaborate on this? I'm seen estimates of ~1.5bit per English letter, and tokens encode a lot more than that - sometimes full words, with multimodal even more. If KV cache embedding are storing more than just simple tokens but entire concepts with context and nuance, that'll bump the entropy up quite quickly.
> Can you elaborate on this? I'm seen estimates of ~1.5bit per English letter
The reference I always go back to is the GPT-3 paper. The cross-entropy loss (an upper bound for entropy) got down to 1.75 nats (2.5 bits). I took 2.1 because 2.5 is an upper bound and I wanted the estimate to end up as a round number.
> If KV cache embedding are storing more than just simple tokens but entire concepts with context and nuance, that'll bump the entropy up quite quickly.
Here's the thing: the concepts that the model stores in the KV cache are a deterministic function of the input tokens. Similar to the data processing inequality, this implies that no entropy is actually added.
Looking at it mechanically, a sufficiently powerful model only needs to encode the tokens and can recompute concepts later as needed.
VPS comes at the cost of potential for oversubscription - even from more reputable vendors. You never really know if you're actually getting what you're paying for.
One annoyance (I don't know if they've since fixed it) was that Docker Hub would count pulls that don't contain an update towards the rate limit. That ultimately prompted me to switch to alternate repositories.
How well do we understand the tokenization for Claude? I'd posit that the exact human-representation of this markup is likely irrelevant if it's all being converted into a single token.
Code length will itself become a problem. The instruction cache is limited in size and often quite small. Bloating instruction counts with lots of duplicated code will eventually have a negative effect on performance.
Ultimately, there's too many factors to predetermine which approach is faster. Write clean code, and let a profiler guide optimizations when needed.
Exactly. Memory access is a major factor in runtime, often more important than instruction counts. And in the vast, vast majority of cases it doesn't matter. I trust the compiler to make reasonable choices, something would have to be deployed at a very large scale before the programmer time of considering such things became cheaper than the hardware savings from doing it. And the vast majority of code simply doesn't execute often enough to matter one way or the other.
Save your brainpower for the right algorithms and for the inner loops the profiler identifies (I did not expect to learn that the slowest piece of code was referring to SQL fields by name!) Ignore the rest.