why tf is git still running submodule hooks during clone at all. like think. youre cloning a repo which you didnt write it or audit it. and git just... runs a post checkout hook from a submodule it just fetched off the internet. even with this CRLF bug fixed, thats still bananas
what if we can make these diagrams synchronized with reality. you need the diagram to pull from the same source of truth as your actual infrastructure - whether that's terraform state, kubernetes manifests, or service discovery. that way diagrams become less historical artifacts and more of living documentation
I've written something like this for NixOS a while back [1], which generates infrastructure diagrams directly from the source of truth (albeit not as pretty as isoflow). I'm sure this could be applied to other declarative tech stacks aswell!
That's a great thought, I'd need to make some kind of translation between manifests and the json, getting knowledge of those relationships might be tricky?
Service discovery is another route, would hate to get someones IT department angry for aggressive port scanning though lol
I absolutely love cloudcraft, full disclosure one of our team at work wanted to use it, but we're a public sector org(no money), so I threw this together for him
this is another layer of abstraction on top of an already broken system. you're running html through an llm to get markdown that gets rendered in a terminal browser. that's like... three format conversions just to read text. the original web had simple html that was readable in any terminal browser already. now they arent designed as documents anymore but rather designed as applications that happen to deliver some content as a side effect
That's the world we live in. You can either not have access to content or you must accept abstractions to remove all the bad decisions browser vendors have forced on us the last 30 years to support ad-browsing.
If the web site is a SPA that is hydrated using an API it would be conceivable that the LLM can build a reusable interface around the API while taking inspiration from the original page. That interface can then be stored in some cache.
I'm not saying it's necessarily a good idea but perhaps a bad/fun idea that can inspire good ideas?
Think of it as a secretary that is transforming and formatting information. You may desire for the original medium to be something like what you want but you don’t get that so you can get a cheap dumber secretary instead.
>before this you had to trust that claude would follow your readme instructions about running linters or tests. hit and miss at best. now its deterministic. pre hook blocks bad actions post hook validates results.
>hooks let you build workflows where multiple agents can hand off work safely. one agent writes code another reviews it another deploys it. each step gated by verification hooks.
This nicely describes where we're at with LLM's as I see it: they are 'fancy' enough to be able to write code yet at the same time they can't be trusted to do stuff which can be solved with a simple hook.
I feel that currently improvement mostly comes from slapping what to me feels like workarounds on top of something that very well may be a local maximum.
> they are 'fancy' enough to be able to write code yet at the same time they can't be trusted to do stuff which can be solved with a simple hook.
Humans are fancy enough to be able to write code yet at the same time they can’t be trusted to do stuff which can be solved with a simple hook, like a simple formatter or linter. That’s why we still run those on CI. This is a meaningless statement.
The machine just needs to be coded to run stuff (as shown in this very post). My coworkers can’t be coded to follow procedures and still submit PRs failing basic checks, sadly.
Claude Code is an agent, not an LLM. Literally this is software that was released 4mo ago. lol.
1y ago - No provider was training LLMs in an environment modeled for agentic behavior - ie in conjunction with software design of an integrated utility.
'slapped on workaround' is a very lazy way to describe this innovation.
Someone described LLMs in the coding space as stone soup. So much stuff is being created around then to make them work better that at some point it feels like you'll be able to remove the LLM part of the equation
We cant deny the LLM has utility. You cant eat the stone but the LLM can implement design patterns for example.
I think this insistance on near autonomous agents is setting the bar too high, which wouldnt be an issue if these companies werent then insisting that the bar is set just right.
These things understand language perfectly, theyve solved NLP because thats what they model extremely well. But agentic stuff is modelled by reinforcement learning and until thats in the foundation model itself (at the token prediction level) these things have no real understanding of state spaces being a recursive function of action spaces and such stuff. And they cant autonomously code or drive or manage a fund until they do
Humans use tools, so does AI. Does us make any less valuable as humans because we use bicycles and hammers? Why would it be bad for an AI to use tools?
every developer knows safari is the new ie6 but we all just shrug and build native apps anyway because what else are you gonna do. leave 50% of your users on the table. classic embrace extend extinguish but in reverse. embrace web standards then purposely not extend them so you can extinguish competition
Every colleague in my company only targets and tests against Chrome because they honestly considers _everything_ and anything Chrome does as the standard.
As a FF user it hurts me because even if Apple and Mozilla has implemented some feature according to spec these people ignore that in favour of the Chrome way of doing things.
Calling Safari the new ie6 is ignorant of reality.
IE6 was stagnant and not standards compliant. Safari at least complies with standards. Chrome is the polar opposite of IE6. Turns out it doesn't really matter what you do, if one party controls too much of any market it's bad news for end users one way or another.
That’s not exactly accurate as standards for new web technologies didn’t exist back when IE6 was dominant. The WHATWG had to be founded and the standards made post facto before IE6 was non-compliant.
10kloc for command line parsing. TEN THOUSAND LINES. pico-args does it in 700 lines and probably handles 99% of real world use cases. compile times go to shit binary size bloats and for some edge case you'll never hit.most CLI tools need what three four flags max, maybe a subcommand or two. you don't need the swiss army knife of argument parsing for that. tried replacing clap with pico-args on three different projects last month. 80% reduction in compile time every single time. binary went from 8mb to 2mb on one of them.the "disk space is cheap" argument's acceptable partially but compile time isn't. developer experience isn't. startup time isn't. memory usage isn't
No help generation
Only flags, options, free arguments and subcommands are supported
A properer parser would knew that --arg2 is a key and will return an error, since the value is missing.
If such behavior is unacceptable to your application, then you have to use a more high-level arguments parsing library.
Yeah, no thank you. If we're talking about 700 LOC, I'm just going to write it myself rather than take on a dependency that won't even describe itself as a proper enough parser. This argument parser doesn't even handle the tedium of generating a help message for the user, and doesn't really parse the arguments -- what's the purpose of using it to do the argument parsing then?
So 700 LOC gets us a mediocre argument parser with no features. What do you get for an additional 9300 LOC? A "properer" parser (dev and user experience+). Help generation (dev experience+). Multiple interfaces (dev experience+). Color terminal output (user experience+). Suggested completions (user experience+).
Is it worth it? I dunno that's a per-project choice. If you absolutely need the smallest footprint and compile times possible, probably you don't want to go with clap. You also probably don't want to go with Rust.
Honestly, if you're doing something so small, even pico-args is a lot more than you need. Just use lexopt, and you get a very simple match-based DSL for defining your arguments, that even neatly sidesteps the limitations provided in pico.
in async code ,errors belong to the task ,not the caller.
in sync code ,the caller owns the stack ,so it makes sense they own the error. but async splits that. now each async function runs like a background job. that job should handle its own failure =retry ,fallback ,log because the caller usually cant do much anyway.
write async blocks like isolated tasks. contain errors inside unless the caller has a real decision to make. global error handler picks up the rest
Structured concurrency [1] solves the issue of task (and exception) ownership. In languages / libraries that support it, when spawning a task you must specify some enclosing block that owns it. That block, called a nursery or task group, can be a long way outside the point where the task is spawned because the nursery is an object in its own right, so it can be passed into a function which can then call its start() method. All errors are handled at the nursery level.
They were introduced in the Trio library [2] for Python, but they're now also supported by Python's built in asyncio module [3]. I believe the idea has spread to other languages too.
the thing is that the caller might want to rollback what they're doing based on whether the subtask was rolled back... and so on, backtracking as far as needed
ideally all the side effects should be queued up and executed at the end only, after your caller has successfully heard back from all the subtasks
for example... don't commit DB transactions, send out emails or post transactions onto a blockchain until you know everything went through. Exceptions mean rollback, a lot of the time.
on the other hand, "after" hooks are supposed to happen after a task completes fully, and their failure shouldn't make the task rollback anything. For really frequent events, you might want to debounce, as happens for example with browser "scroll" event listeners, which can't preventDefault anymore unless you set them with {passive: false}!
PS: To keep things simple, consider using single-threaded applications. I especially like PHP, because it's not only single-threaded but it actually is shared-nothing. As soon as your request handling ends, the memory is released. Unlike Node.js you don't worry about leaking memory or secrets between requests. But whether you use PHP or Node.js you are essentially running on a single thread, and that means you can write code that is basically sequentially doing tasks one after the other. If you need to fan out and do a few things at a time, you can do it with Node.js's Promise.all(), while with PHP you kind of queue up a bunch of closures and then explicitly batch-execute with e.g. curl_multi_ methods. Either way ... you'll need to explicitly write your commit logic in the end, e.g. on PHP's "shutdown handler", and your database can help you isolate your transactions with COMMIT or ROLLBACK.
If you organize your entire code base around dispatching events instead of calling functions, as I did, then you can easily refactor it to do things like microservices at scale by using signed HTTPS requests as a transport (so you can isolate secrets, credentials, etc.) from the web server: https://github.com/Qbix/Platform/commit/a4885f1b94cab5d83aeb...
Any ASYNC operation, whether using coroutines or event based actors or whatever else should be modelled as a network call.
You need a handle that will contain information about the async call and will own the work it performs. You can have an API that explicitly says “I don’t care what happens to this thing just that it happens” and will crash on failure. Or you can handle its errors if there are any and importantly decide how to handle those errors.
Oh and failing to allocate/create that handle should be a breach of invariants and immediately crash.
That way you have all the control and flexibility and Async error handling becomes trivial, you can use whatever async pattern you want to manage async operations at that point as well.
And you also know you have fundamentally done something expensive in latency for the benefit of performance or access to information, because if it was cheap you would have just done it on the thread you are already using.
> for example... don't commit DB transactions, send out emails or post transactions onto a blockchain until you know everything went through. Exceptions mean rollback, a lot of the time.
But what if you need to send emails AND record it in a DB?
I had the same question, actually; it is very common to perform multiple point-of-no-return IO in a workflow, so deferring all IO into a specific spot does not, in practice, bring any advantages.
It does. You queue ALL of these side effects (simply tasks whose exceptions don't rollback your own task) until the end. Then you can perform them all, in parallel if you wish.
> If any of the required subtasks fail, you don’t do the side effects. You ROLLBACK.
I'm afraid I am still not seeing the advantage here: the subtasks that can fail are IO almost exclusively. If the email is already sent when the DB update fails, that email can't be recalled.
Other than hash/signature verification, just what sort of subtasks did you have in mind that can fail and aren't IO?
If your task fails, yet you sent an email that it succeeded, that is bad.
You should wait until all your subtasks finish before sending the email.
Async subtasks typically ARE i/o, whether over a network or not.
The email shouldn't be sent if the DB update fails. The whole point is you wait until everything succeeds, before sending the email.
If your subtasks cause you to write some rows as if they succeeded, but subsequent subtasks fail, that is bad. You have to rollback your changes and not commit them.
If you charge a user even though they didn't get the thing they paid for, that's bad. Yes you can refund them after a dispute, but it's better not to have charged them in the first place.
The point is this: any subtasks that can cause your main task to fail should be processed BEFORE any subtasks that cannot cause your main task to fail.
> If your task fails, yet you sent an email that it succeeded, that is bad. You should wait until all your subtasks finish before sending the email.
A common sequence is "Send email, then update DB with the new count of emails sent". Doesn't matter which way you reorder them, there is no advantage to queuing those two tasks to go at the end because if the first success and the second fails you have still done half an atomic task.
> The point is this: any subtasks that can cause your main task to fail should be processed BEFORE any subtasks that cannot cause your main task to fail.
Do you have any examples that aren't IO? Because IO can always fail, and I am still wondering what sort of workflow (or sequence of tasks) you have in mind where you will see any advantage to queuing all the IO to run at the end.
If you have pure computation subtasks (such as checking a hash or signature), then sure, do the IO only after you have verified the check. Have you any idea how rare that workflow is other than for checksumming?
What workflow have you in mind, where we see a practical advantage from queuing IO to run at the end?
why is bot detection even happening at render time instead of request time. why can't tell you’re a bot from your headers, UA, IP, TLS fingerprint. imo making it a surveillance. 'you're a bot, ok not just go away, let’s fingerprint your GPU and assign you a behavioral risk score anyway'
You absolutely have options at request time. Arguably, some of the things you can only do at request time are part of a full and complete mitigation strategy.
You can fingerprint the originating TCP stack with some degree of confidence. If the request looks like it came from a Linux server but the user agent says Windows, that's a signal.
Likewise, the IP address making the request has geographic information associated with it. If my IP address says I'm in Romania but my browser is asking for the English language version of the page... That's a signal.
Similar to basic IP/Geo, you can do DNS and STUN based profiling, too. This helps you catch people that are behind proxies or VPNs.
To blur the line, you can use JavaScript to measure request timing. Proxies that are going to tamper with the request to hide its origins or change its fingerprint will add a measurable latency.
None of these are conclusive by any means. The IP address check you mentioned would mark anyone using a VPN, or English speakers living abroad. Modern bot detection combines lots of heuristics like these together, and being able to run JavaScript in the browser (at render-time) adds a lot more data that can be used to make a better prediction.
> If my IP address says I'm in Romania but my browser is asking for the English language version of the page... That's a signal.
jesus christ don't give them ideas. it's annoying enough to have my country's language forced on me (i prefer english) when there's a perfectly good http header for that. now blocking me based on this?!
Anubis is not meant to fully stop bots, only slow them down so they don't take down your service. This kind of bot detection is meant to prevent automation.
provenance model basically turns memory back into a typed value. finally malloc wont just be a dumb number generator, it'll act more like a capability issuer. and access is not 'is this address in range' anymore, but “does this pointer have valid provenance”. way more deterministic, decouples gcc -wall
Will this create more nasal demons? I always disable strict aliasing, and it's not clear to me after reading the whole article whether provenance is about making sane code illegal, or making previously illegal sane code legal.
All C compilers have some notion of pointer provenance embedded in them, and this is true going back decades.
The problem is that the documented definitions of pointer provenance (which generally amount to "you must somehow have a data dependency from the original object definition (e.g., malloc)") aren't really upheld by the optimizer, and the effective definition of the optimizer is generally internally inconsistent because people don't think about side effects of pointer-to-integer conversion. The one-past-the-end pointer being equal (but of different provenance) to a different object is a particular vexatious case.
The definition given in TS6010 is generally the closest you'll get to a formal description of the behavior that optimizers are already generally following, except for cases that are clearly agreed to be bugs. The biggest problem is that it makes pointer-to-int an operation with side effects that need to be preserved, and compilers today generally fail to preserve those side effects (especially when pointer-to-int conversion happens more as an implicit operation).
The practical effect of provenance--that you can't magic a pointer to an object out of thin air--has always been true. This is largely trying to clarify what it means to actually magic a pointer out of thin air; it's not a perfect answer, but it's the best answer anyone's come up with to date.
It's standardizing the contract between the programmer and the compiler.
Previously a lot of C code was non-portable because it relied on behaviour that wasn't defined as part of the standard. If you compiled it with the wrong compiler or the wrong flags you might get miscompilations.
The provenance memory model draws a line in the sand and says "all C code on this side of the line should behave in this well defined way". Any optimizations implemented by compiler authors which would miscompile code on that side of the line would need to be disabled.
Assuming the authors of the model have done a good job, the impact on compiler optimizations should be minimized whilst making as much existing C code fall on the "right" side of the line as possible.
For new C code it provides programmers a way to write useful code that is also portable, since we now have a line that we can all hopefully agree on.
This is basically a formalization of the general understanding one already had when reading the C standard thoroughly 25 years ago. At least I was nodding along throughout the article. It cleans up the parts where the standard was too imprecise and handwavy.
how deterministic is the emit really. if i feed same expression tree twice,same node layout same captures. do i get exact same bytes out every time (ignoring reloc) or not. if output produced is byte stable across runs for same input graph ,that opens up memoized JIT paths.worth checking if current impl already does this or needs a pass to normalise alloc order
Several possible reasons:
- parallelism
- concurrent machine code gen
- different optimisations for different runs, producing differing machine code order, etc