Every time you find a runtime bug, ask the LLM if a static lint rule could be turned on to prevent it, or have it write a custom rule for you. Very few of us have time to deep dive into esoteric custom rule configuration, but now it's easy. Bonus: the error message for the custom rule can be very specific about how to fix the error. Including pointing to documentation that explains entire architectural principles, concurrency rules, etc. Stuff that is very tailored to your codebase and are far more precise than a generic compiler/lint error.
Nobody is sleeping on anything. Linting for the most part is static code analysis which by definition does not find runtime bugs. You even say it yourself "runtime bug, ask the LLM if a static lint rule could be turned on to prevent it".
To find most runtime bugs (e.g. incorrect regex, broken concurrency, incorrect SQL statement, ...) you need to understand the mental model and logic behind the code - finding out if "is variable XYZ unused?" or "does variable X oveshadow Y" or other more "esoteric" lint rules will not catch it. Likelihood is high that the LLM just hallucinated some false positive lint rule anyways giving you a false sense of security.
> static code analysis which by definition does not find runtime bugs
I'm not sure if there's some subtlety of language here, but from my experience of javascript linting, it can often prevent runtime problems caused by things like variable scoping, unhandled exceptions in promises, misuse of functions etc.
I've also caught security issues in Java with static analysis.
The usefulness of using static code analysis (strict type systems, linting) versus not using static code analysis is out of the question. Specifically JavaScript which does not have a strict type system benefits greatly from using static code analysis.
But the author claims that you can catch runtime bugs by letting the LLM create custom lint rules, which is hyperbole at least and wrong at most and giving developers a false sense of security at worst.
Catch or prevent - linting only covers a tiny (depending on programming language sometimes more sometimes less) subset of runtime problems. The whole back pressure discussion feels like AI coders found out about type systems and lint rules - but it doesn’t resolve the type problems we get in agentic coding. The only „agent“ responsible for code correctness (and thus adherence to feature specification) is the human instructing the agent, a better compiler or lint rule will not prevent massive logic bugs LLMs tend to create like tests testing functions that have been created by the LLM for the test to make it pass, broken logic flows, missing DI, recreating existing logic, creating useless code that’s not being used anywhere yet pollutes context windows - all the problems LLM based „vibe“ coding „shines“ with once you work on a sufficiently long running project.
Why do I care so much about this? Because the „I feel left behind“ crowd is being gaslighted by comments like the OPs.
Overall strict type systems and static code analysis have always been good for programming, and I‘m glad vibe coders are finding out about this as well - it just doesn’t fix the lack of intelligence LLMs have nor the responsibility of programmers to understand and improve the generated stochastic token output
OP isn't claiming all runtime bugs can be prevented with static lints suggested by LLMs but, if at least some can, I don't see how your comment is contributing. Yet another case of "your suggestion isn't perfect so I'll dismiss it" in Hacker News.
Why is this such a common occurrence here? Does this fallacy have a name?
Clever! Sharing my lightning test of this approach.
Context - I have a 200k+ LOC Python+React hobby project with a directory full of project-specific "guidelines for doing a good job" agent rules + skills.
Of course, agent rules are often ignored in whole or in part. So in practice those rules are often triggered in a review step pre-commit as a failsafe, rather than pulled in as context when the agent initially drafts the work.
I've only played for a few minutes, but converting some of these to custom lint rules looks quite promising!
Things like using my project's wrappers instead of direct calls to libs, preferences for logging/observability/testing, indicators of failure to follow optimistic update patterns, double-checking that frontend interface to specific capabilities are correctly guarded by owner/SKU access control…
Lots of use cases that aren't hard for an agent to accurately fix if pointed at directly, and now that pointing can happen inline to the agent work loop without intervention through normal lint cleanup, occurring earlier in the process (and faster) than is caught by tests. This doesn't replace testing or other best practices. It feels like an additive layer that speeds up agent iteration and improves implementation consistency.
Yeah, I have written multiple almost completely-vibecoded linters since Claude Code came out, and they provide very high value.
It’s kind of a best case scenario use-case - linters are generally small and easy to test.
It’s also worth noting that linters now effectively have automagical autofix - just run an agent with “fix the lints”. Again, one of the best case scenarios, with a very tight feedback loop for the agent, sparing you a large amount of boring work.
I got tired of brittle literals like `http://localhost:3000` and `postgres://…@127.0.0.1/...` creeping into my code, so I wrote a few ESLint rules that detect “hardcoded infrastructure” strings and ask the agent to find the constant in the codebase — not by guessing its name but by `grep`-ing for its value.
The detection is based on dumb string literal heuristics, but has proven rather effective. Example patterns:
Claude Code is obsessed with using single letter names for inline function parameters and as loop control variables. I don't like it and I think it is sloppy, so I told it to stop in CLAUDE.md. In my experience, Claude Code will respect CLAUDE.md around 70 % of the time, it seems to cherry pick areas that it will respect more and less often and of course it kept ignoring this instruction. So I told it to add a pre-commit hook and invoke the TypeScript compiler and analyze the AST for single-letter variable names and tank the pre-commit check when it detects one with an error message indicating the offending symbols' locations. Now it can be non-deterministic as much as it wants, but it will never commit this particular flair of slop again as the adherence is verified deterministically. I already have a few more rules in mind I want to codify this way to prevent it from reproducing patterns it was trained on that I don't like and consider low quality.
Nice. The big picture strategy is figuring out the right mix of deterministic and probabilistic programming elements and how to mix them. I see agents ignore clear instructions all the time thus we need to codify the important instructions into deterministic rules, which probably take the form of tests or linters.
I realized this recently and I've been creating a RuboCop plug-in[1] to automatically have the LLM code better match my personal style. I don't think it'll ever be perfect, but if it saves me from moving a few bits around or adding spacing I'd rather see then it's wroth. The fun part is I'm vibe coding it, since as long as the tests verify the rules then it doesn't really matter much how they work. As a result adding a new rule is pasting in LLM generated code followed by what I'd prefer it look like and asking it to add a rule.
Anthropic ships an official plugin to create linters for you based on your Claude Code history or instructions, it’s great. You can vibe code your lint rules per repo.
I agree, I have 'written' a handful of rubocop rules that are hyper specific to the codebase I work on. I never would have bothered before claude code. Stuff like using out custom logger correctly, or to not use Rails.env because we have our own (weird of course) env system.
One thing to watch out for when using debounce/throttle is the poor interaction with async functions. Debounced/throttled async functions can easily lead to unexpected behavior because they typically return the last result they have when the function is called, which would be a previous Promise for an async function. You can get a result that appears to violate causality, because the result of the promise returned by the debounce/throttle will (in a typical implementation) be from a prior invocation that happened before your debounce/throttle call.
There are async-safe variants but the typical lodash-style implementations are not. If you want the semantics of "return a promise when the function is actually invoked and resolve it when the underlying async function resolves", you'll have to carefully vet if the implementation actually does that.
Another thing to watch for is whether you actually need debouncing.
For example, debouncing is often recommended for handlers of the resize event, but, in most cases, it is not needed for handlers of observations coming from ResizeObserver.
I think this is the case for other modern APIs as well. I know that, for example, you don’t need debouncing for the relatively new scrollend event (it does the debouncing on its own).
Debouncing correctly is still super hard, even with rxjs.
There are always countless edge cases that behave incorrectly - it might not be important and can be ignored, but while the general idea of debouncing sounds easy - and adding it to an rxjs observable is indeed straightforward...
Actually getting the desired behavior done via rxjs gets complicated super fast if you're required to be correct/spec compliant
Not really, but I feel like you might've misunderstood me.
The debouncing of rxjs just takes an observation and debounces, which is essentially throttle with inverted output (it outputs last instead of first).
That's almost never what the product owner actually wants, at least IME.
If they give you any kind of soec, you'll quickly realize that limit.
I.e. debouncing after the request happened is impossible, just like cleanly abortion requests on exit or similar.
There are also often a ton of signals you need to add to the observale for all the events the PO wants to respond to, such as opening dialogues, interacting with elements outside of the context of the debounces event chain etc pp
It just keeps getting more complicated with every additional thing they come up with. But if they're fine with just living with the technical limitations, all is fine.
That doesn't sound correct. An async function ought to return a _new_ Promise on each invocation, and each of those returned Promises are independent. Are you conflating memoization? Memoized functions will have these problems with denouncing, but not your standard async function.
this sounds interesting but it's a bit too early here for me. by any chance can we (not simply a royal we :D) ask you to provide a code example (of a correct implementation), or a link to one? many thanks!
What about performance? I wrote my thesis in OCaml and my recollection was that it had an amazing native code generating compiler that not infrequently output code that was almost as fast as C if you wrote it the right way. The story I heard about Haskell was far different at the time (admittedly decades ago).
As with all garbage collected languages, optimizing comes down to removing allocations, in Haskell this means strictness and choice of data structures. You can make C-speed programs but you may need to work for it, and you'll also need to know the compiler/evaluation model you're working against.
Sure, I think what I noticed was that even idiomatic OCaml code was relatively fast, maybe 2-3x slower than C, but plenty fast enough. Whereas I was under the impression that idiomatic Haskell was far more likely to have unexpected and harder to fix performance issues (e.g. requiring more of an architectural rewrite) because of its lazy evaluation model.
The problems brought about by the lazy evaluation (laziness when you don't want it) do not require architectural rewrites. It's mostly just profiling while setting a very low stack size limit, and then discovering which part of your code triggers a stack overflow. It can be solved by adding the right amount of seq (sequences evaluation), or ! (strict patterns). Maybe you'll also change a few incorrect uses of foldl into foldr. Even if you need to change from lazy Map to strict Map the change isn't disruptive; it's just changing some import and done; all the functions work. No architectural changes needed.
David Humbird's 2021 paper "Scale-up economics for cultured meat"[1] is a pretty damning study of the problems with lab-grown meat. His core conclusion: "Capital- and operating-cost analyses of conceptual cell-mass production facilities indicate economics that would likely preclude the affordability of their products as food."
Does anyone know if the problems that Humbird describes have somehow been solved?
I think the approach of this paper is akin to estimating the cost of Microsoft's BHAG ("a PC on every desk") based on the costs of building mainframe computers in 1970.
Here's the key leap of questionable logic (IMO):
> The capital cost of a conceptual bulk animal cell-culture process is developed from the bare-equipment costs of its most important items. From this purchased equipment cost, a total capital investment (TCI) is obtained through the application of cost escalation factors, which are understood to be rather high for biopharmaceutical cell-culture processes
The idea that at scale, it's going to cost $0.75M for a 1m^3 culturing chamber seems crazy to me. I'd guess these are expensive right now because they are specialist equipment (they are manufactured to the ASME bioprocessing standard, which was created for bioprocessing in a pharma/research context), and when they begin being mass-produced I'd estimate they will come down in cost by two orders of magnitude.
(For context, a ~400gal brewery fermentation vessel made of stainless steel can be purchased for about $5k, made in China. It's about 2x for a "made in USA" vessel. These bioreactor vessels are a bit more complex than the standard jacketed fermenters used by brewers, but eyeballing the schematics they do not seem more complex than a steam-jacketed mash tun, for example.)
At high scale, most of the cost is the bioreactors, the rest of the plant, and buildings. I can't find any real working for the capital costs beyond the bioreactors, but given the extremely pessimistic estimate there, I am skeptical about the broader plant estimates too.
TLDR; if you treat this as a pharma process, you will get pharma prices. If you treat this as a food process like beer (which also has sterility requirements, contamination risks, and clean-room cell line propagation requirements to overcome when manufacturing at scale) then the prices will be much lower. I treat this paper as a pessimistic worst-case scenario, and assume that process innovation will allow substantially lower prices.
The fundamental question is whether food-grade fermentation/culturing processes like those used in beer or yoghurt can suffice; for example it seems to me entirely plausible that we could lower the equipment quality requirements substantially, and still obtain a satisfactory safety profile by discarding contaminated batches. Not a cost-effective option for extremely expensive pharmacological products like vaccines, but potentially viable for simple food products like cultured meat.
> The fundamental question is whether food-grade fermentation/culturing processes like those used in beer or yoghurt can suffice
Analyzing probable cost of fake meat production by comparison with existing cultured food manufacturing is sensible, but fake meat has some differentiating aspects to be accounted for.
A prime difference between these fermentation processes and a hypothetical cultured meat system is that the single cells involved in making beer and yogurt are simpler, much faster breading species than the multicellular lines which develop into complex animal tissue. Another difference is that whereas fermentation involves partial digestion of a portion of the growth medium by the fermenting microbes, creating a volume of artificial meat would require synthesizing cell dense tissue to fill the entire volume. So with artificial meat you need more growth and the growth will be slower, factors which both expand the opportunities for contamination. So preventing contamination will be more important and more challenging with lab meat than with these fermentation products.
I agree with your assessment that the source paper is exceedingly pessimistic about the costs. There is no physical reason why cultured meat production couldn't eventually be cheaper than natural meat production, the hurdles are only technological.
This is a useful analysis of what "being an adult" means. I've noticed that the moment when I feel like avoiding social discomfort or potential conflict as the precise moment when I have a choice: either be an adult and understand what I want and communicate it, or avoid it and dislike myself and project those feelings onto others.
Invariably when I choose to behave like an adult I feel empowered and ultimately at peace with myself and others in the end. If I choose avoidance, resentment builds, and further avoidance follows.
The idea that avoidance behaviors can be selfish or agreeable cuts through much self-deception. This can be helpful when I tell myself "I'm just being nice" because it adds the proviso: "yeah, but I'm not being an adult." Which I could see being a really helpful inner monologue in those situations.
This is also intimately connected to the concept of "taking responsibility", which begins with not avoiding something which "someone else" might deal with so you don't have to.
Everything you said is true, but just to add a little nuance, I think it's possible that avoidance can still be the correct choice when confrontation is unhelpful. Confrontation for the sake of confrontation is another form of indulging yourself to avoid certain emotions, like feeling weak or disempowered. Managing that in the height of emotion takes some real meta-cognition.
Keep in mind that "avoidance" in this context refers to not confronting one's own feelings and intuition. After grappling with that feeling explicitly, avoiding overt conflict can certainly be an adult decision to make.
Our feelings are vast and bottomless. It is impossible to confront all of them, and for the same reason its undesirable. Avoiding your feelings can be useful too.
Maybe it’s just personal experience, but I vehemently and totally disagree with this.
There has never been a time in my life where I was better off because I ignored my feelings. Literally never.
There are times that we should avoid acting on some of our feelings. But to do that well, and without further self-harm, requires that you know what they are, and what those feelings are influencing you to do.
It is absolutely not impossible to confront all of your feelings. Difficult, yes. Exhausting, yes. Impossible? Absolutely not. And I really think it’s doing yourself a disservice to ever believe that you have depths that you yourself are incapable of facing.
I can think of a time when I was better off because I ignored my feelings.
I've struggled with anxiety a lot throughout my life, especially in the lead up to something like a public speaking engagement. For a time, I always tried to reason through it. Why was I feeling anxious? Was it feelings of inadequacy? Perfectionism? Not wanting to disappoint my peers? Any attempt to interrogate those feelings and confront them usually had the opposite effect: I'd feel even more anxious.
On one particular occasion I was scheduled to present to a client at a new job, and the feelings of anxiety started bubbling again. But, this time, I’d had enough. None of my past strategies had ever worked, so I decided I wasn't going to do them. I thought, if my brain is going to flood my body with stress hormones, then it can go right ahead. If I was anxious, then I'd deliver the presentation anxious. I sat in the lobby and allowed the feelings to envelope me. To my surprise, the anxiety began to lift.
What I eventually realized is that my anxiety in those situations was caused by a fight or flight response. My body was trying to spur me to action, and by pausing to think about those anxious feelings — where they were coming from, how I might address them, etc. — I wasn’t doing anything to address the response itself. When I instead choose to ignore the feeling and do the action regardless, it sends a signal to my brain: I’ve chosen to fight. The stress response is no longer necessary, and the feeling goes away.
I don't think the parent meant ignore in the same sense you're taking it.
You still engaged with what you felt. You named what you were feeling, and decided to act on it. In the past, you acted in accord with it; in the instance you cite, you acted in defiance of it, and then on further after-the-fact examination identified what was going on inside of you and determined that acting in defiance of it served you better.
I believe the parent was not using 'ignore' in the sense of "don't act in defiance to how your emotions would incline you to behave", but in the sense of, literally, to pay no attention to it. If you were not paying attention to how you felt, you would still have avoided; your emotions ensured that was the 'easy' and 'natural' choice. It was only by recognizing the feeling, and how your past responses to it didn't serve you, that you were able to decide to act differently.
> When I instead choose to ignore the feeling and do the action regardless, it sends a signal to my brain: I’ve chosen to fight.
I think many psychologists would say you did the opposite of ignoring the feeling of anxiety.
> I thought, if my brain is going to flood my body with stress hormones, then it can go right ahead. If I was anxious, then I'd deliver the presentation anxious.
This is exactly what processing and acknowledging a feeling is like.
Avoiding it can take the form of distracting yourself—literally trying not to think about—but it can just as often take the form of arguing with it or "confronting". It's less about avoiding the existence of the feeling and more about avoiding experiencing the feeling. Not avoiding it means acknowledging it, letting it flow through you, and then letting it pass.
I will permit it to pass over me and through me.
And when it has gone past, I will turn the inner eye to see its path.
Where the fear has gone there will be nothing. Only I will remain.
I think maybe the point of disagreement may be due to "ignoring" vs. "succumbing" to one's feelings.
I think it's almost always useful to acknowledge emotions, but it doesn't mean you have to reactively give in to them. It's sometimes better to view them as a car on a railroad track that will soon be out of sight than to hop on that car and see where it takes you.
I don't think the person you're responding to is suggesting a deep meditation on the unlimited ramifications of one's feelings at every moment. They are talking about avoidance coping, which is pretty well-documented (https://en.m.wikipedia.org/wiki/Avoidance_coping). The admonition is to avoid that, more often than not. It's not the same as excessive navel gazing.
Confronting does not mean naming and categorizing everything. It is to introspect, and sometimes the only takeaway is "here be dragons", and flagging that particular terra incognita for exploration later.
In the short-term avoiding overwhelming feelings can sometimes be necessary to deal with something else that is more urgent, or to simply not go insane. In the long run you can't avoid them without some bad consequences.
And while our feelings may be vast and bottomless, they are usually finite in type. Almost any unpleasant feeling can be traced back to our fear for survival.
There's a difference between being "assertive" and "aggressive". I've had this discussion in the past on HN and it seems people want to treat both as the same, not saying that you are. Aggression is rarely, if ever, useful, both directed at someone or coming from someone.
Taken too far, the "what do I hope to gain" thing can be kind of life-shrinking (because it's not always clear what you'll gain from interactions up front, and that lack of clarity tracks with the quality of what you'll gain too, in some situations) BUT it's definitely a higher-order consideration that way too few people employ.
Yeah. IMO reducing everything to cost-benefit analysis feels like one of those "Silicon Valley" endeavours the feature article talks about - sounds attractive, but ultimately we ought to grow out of the good/bad one-dimensional thinking
How does this culture work at the boundary? How does it work when meeting with people outside Amazon? I'm all for this idea but I can see it quickly breaking down for certain key roles, like product managers, who often interface with customers.
At our organization, we use doc-meetings to drive core operational meetings, core strategic questions etc. We still put together presentations for partners, our all-hands etc.
A thing that my coach told me at one point is "You can shape how your company and especially your reports communicate with you to make things work better for you" but the opposite is also true, you should proactively shape how you communicate with others to work for them.
That doesn't really answer the question posed though--how does a tour stay up to date as code is changed? Does someone have to go in constantly and keep it up to date, pointing at the right spots, etc? It sounds like an incredible burden without dedicated staff or time to maintain--i.e. this is fine for projects established enough to have technical writers, evangelists, etc. but for 99% of projects it's just more burden and burnout. It's not really something you can farm out to your community or first time contributors either as deep analysis and understanding of a codebase takes real time and effort from the core devs.
I originally added the Git ref solution, as a simple way to enable "resilient playback" for some scenarios. In practice, that seems to work pretty well for many folks. But I agree that this isn't a full solution to the problem of code churn. I'm working on an enhancement right now, that will attach the steps to code in a more robust way.
In general, I've seen a pretty great reaction from folks about the concept of CodeTour, and so I'm very focused on making them maintainable, since I believe that's the "big rock" needed to make them a worthy investment for more teams.
Pointing to git refs should be sufficient for code that's not super volatile.
I personally envision using it for onboarding new developers to a code base, in which case I think being on an older ref should be fine, since I'm just trying to show the general structure of a project.
I could also see using it in a code review context, in which case pointing it at the branch would also be fine.
Also, if you look at the schema it generates for a tour, it would be pretty easy to go through and update the line numbers directly in the JSON.
In the last 18 months I've lived with 2 kids in a condo in SF with a car, a downtown condo in an Asian megacity without a car, and in suburban silicon valley with a car and large yard. For us, by FAR the best quality of life has been in the suburbs.
Having a yard is exceptionally valuable with kids. They can be free to run around, play yard games, explore - all without draining the emotional reserves of parents. You can do this while you make dinner, work, or do other things that are unrealistic at an urban park. And you can play with them too. It is not that expensive to get someone to care for your yard if you have some financial flexibility.
In a family there are many kind of resources - time, money, energy, emotional reserves. Scarcity in the first two are easy to focus on because they're quantitative. But scarcity in the latter two - especially emotional reserves - is actually the limited resource in many families. Having to deal with the stresses of children (even if they are mostly well behaved!) puts a real strain on relationships. And the friction from an urban environment, especially one like SF which is not child-friendly, or a giant megacity that has very high density, just drains away the scarcest resources that a family like mine actually has.
If you have some financial flexibility and need serenity and quiet to be your best, combining kids with an urban environment in exchange for spending less is a very poor allocation of resources. It's an example of optimizing for the thing you can easily measure, instead of what's truly important.
(1) This issue isn't going away, no matter who wins the next election.
(2) Data collection is not the only goal or threat. The article mentions other critical systems: energy, financial, healthcare, transportation, military. Even agriculture is heavily software dependent now[1]. Also, once you depend on a cloud service, the open source used by it is brought into the attack surface.
(3) Open source is theoretically reviewable, which is good. But even if resources were brought to bear to review it at scale, you'd need to do it continually and track what has passed. This brings pressure to fork. Worse, because review is imperfect even with the best people and tools, it will never be enough by itself to establish that a system doesn't contain malicious code. Current program verification technology is simply not up to the task of formally verifying the behavior of large scale software systems. Maybe it could be used for smaller libraries.
Linux isn’t all of open source, nor likely to be the most attractive vector of infiltration for any given target, and not all of even Linux is examined with the same level of scrutiny.
Every time you find a runtime bug, ask the LLM if a static lint rule could be turned on to prevent it, or have it write a custom rule for you. Very few of us have time to deep dive into esoteric custom rule configuration, but now it's easy. Bonus: the error message for the custom rule can be very specific about how to fix the error. Including pointing to documentation that explains entire architectural principles, concurrency rules, etc. Stuff that is very tailored to your codebase and are far more precise than a generic compiler/lint error.