29 karma · joined July 9, 2024
I feel caught between two worlds, I know people both very 'for' and very 'against'. The business is very keen for people to use them to go faster.
For non-trivial changes, output so far does not meet my quality standard and I tend to spend a lot of time cleaning up after them, probably more than I would have spent doing the work myself. This being much more boring, I hasten to add.
Their comments suck so I feel like I have to go in and rewrite them all.
Maybe I should just let go of the quality standard and accept that in exchange for steaming ahead at full speed, but I'm reluctant (and not just for me, there are also coworkers who I feel like I would be letting down).
I think one thing that troubles me is that I so far have gotten quite far by 'caring about the little things'.
Now we live in a world where this feels, for the most part, unsustainable to keep up with. When directing LLMs to code something up, it's still occasional useful to have the knowledge and experience of those little things earned over years, but at the same time 1) it seems like I run into fewer opportunities to add to that experience and 2) it seems like you can often just prompt LLMs to 'grill' a design a few times, it will probably surface some of the most important tradeoffs
I mean, yes I do find the mathematical background of LLMs fascinating, but it's not going to be something that I can put to practical use (much), if that makes sense?
Pardon my lack of creativity but I'm not even sure what mastery with the new tools (LLMs) would look like. When you are so abstracted from the details and don't have to know anything, what _is_ mastery? (I am not asking rhetorically and if people have overcome this thought I would be interested in hearing from them.)
Knowing how to ask a machine questions in the right way? Playing as a manager in control of non-human developers? It all sounds really silly and something that is difficult to aspire to (and I can't imagine explaining my job to others with a straight face). I think I find it even more egregious because it's all built on paying rent to the LLM operators.
It's not that I don't enjoy results in their own right sometimes but I think I am definitely in the 'this is giving me an identity crisis' camp.
Kopia does not let you pipe into it without intermediate files, or at least not in a friendly way I could figure out.
Kopia seems quite designed around the backup server being the place where the config is set. IMO it's harder to configure if you have your own declarative config tooling (like Ansible, NixOS, etc)
The nicest way I found to ignore files declaratively is to configure a ignore-file pattern in the repository policy and then declaratively create `.kopiaignore` files.
The Kopia server is convenient if you have a server at home and want to back up laptops to it, with them being in a shared deduplicated repository without having to trust the clients not to get pwned and wipe out the backups. However I'm not aware of a nice way to then transfer those backups to aggregate them into a bigger repository. (So I just rsync them off-site and don't worry about getting deduplication with other backups) Also learnt the hard way that you can't set a bandwidth limit when backing up to the kopia server, which can tank wifi performance on laptops during the backup.
I am thinking of switching to Restic as it seems like it is more suitable for people who want a tool at the complexity level of tar/git CLI with declarative config, rather than something imperatively configured.
On a file of ~1M lines (350 MB), ripgrep returns a query matching 22k lines in 1.9s.
(Separately: We have gzip log rotation for old logs. A log with 1.9M lines (106 MB gzipped) on disk can be searched from cold in 1.3s by ripgrep, whilst still being ergonomic. Maybe a different compressor is better?)
On a service unit filter over ~218k lines, `journalctl -u service --since <...> -g query` returns 4.8k matching lines in 4.127s (and this is after having warmed the cache by returning the unfiltered query cold, in 11.9s. I don't have root to clear the disk cache
I should have ran the filtered query first but ah well, since the difference is already so large it doesn't matter that the filtered journalctl query gets an unfair advantage)
Comparing input rates:
ripgrep (plain): 576k line/sec
ripgrep (gz): 1.4M line/sec
journalctl (-u, --since, -g): 53k line/sec
I don't have a great deal of understanding of journald's internals, so perhaps there is some variable here that is unreasonably unfavourable to journald.Transcript
user@machine:~/log$ time rg query aservice.log | wc -l
22628
real 0m1.859s
user 0m0.109s
sys 0m0.909s
user@machine:~/log$ wc -l aservice.log
1071606 aservice4.log
user@machine:~$ time journalctl --since '2026-08-16' -u myservice@1.service | wc -l
218661
real 0m11.914s
user 0m10.729s
sys 0m0.798s
user@machine:~$ time journalctl --since '2026-08-16' -u myservice@1.service -g query | wc -l
4804
real 0m4.127s
user 0m3.727s
sys 0m0.186s
Probably more painful on the day to day is how `journalctl -fu myservice` seems to stall for on the order of 5 to 10s, sometimes. I can't reproduce at the moment and maybe it only happens on some machines, but if you were interested in 'real-world anecdata' it's something to maybe note.We have some services at work that log to text files and some to journald.
The log volume to file is >> the log volume to journald. Yet `rg query myservice.2026-08-01.log` seems to always wind up being faster and better than something like `journalctl -u myservice.service --since '2026-08-01' --until '2026-08-02' -g 'query'`. (The tab completion and discoverability is also better, I guess)
If you then Ctrl+A to select all and press backspace, I wonder if that would delete all those 3-line chunks...
I only used once, in February, so hopefully they didn't break it since then.
I guess I could be the odd one out but I'm not keen on the 'localisation' efforts that replace the cultural elements of the underlying media, e.g. how in Ace Attorney ramen is replaced with t-bone steaks (iirc?), prompting the meme 'Eat your hamburgers, Apollo'
Saying that, token-based pricing has misaligned incentives as well: as the editor developer (charging a margin over the number of tokens) or AI provider, you benefit from more verbose input fed to the LLMs and of course more verbose output from the LLMs.
Not that I'm really surprised by the announcement though, it was somewhat obviously unsustainable
maybe, but not entirely sure. 'Two wrongs don't make a right' kind of thinking on my side here.
But if they call it GFY and do what they want, then that would probably be better for everyone involved.
> they don't have the "Norway" problem because they intentionally don't apply the boolean value rules from YAML.
I think this is YAML 1.2. I have not done or seen a breakdown to see if GitHub is aiming for YAML 1.2 or not but they appear to think that way, given the discussion around merge keys
--
(though it's still not clear why flattening the YAML would not be sufficient for a static analysis tool. If the error report references a key that was actually merged out, I think users would still understand the report; it's not clear to me that's a bad thing actually)
I am not sure you can do this whilst having the granular job reporting (i.e. either you need one YAML block per job or you have all your jobs in one single 'status' item?) Is it actually doable?
Kind of a hard disagree here; if you don't want to conform to a specification, don't claim that you're accepting documents from that specification. Call it github-flavored YAML (GFY) or something and accept a different file extension.
https://github.com/actions/runner/issues/1182
> YAML 1.1 to be an important goal: they still don't support merge keys
right, they don't do merge keys because it's not in YAML 1.2 anymore. Anchors are, however. They haven't said that noncompliance with YAML 1.2 spec is intentional
I think it makes way more sense for GitHub to support YAML anchors given they are after all part of the YAML spec. Otherwise, don't call it YAML! (This was a criticism of mine for many years, I'm very glad they finally saw the light and rectified this bug)
There are performance footguns (like recursion, for which you'd have to consult your GraphQL server library for mitigations). There is often a built-in 'introspection' endpoint, which many consider a security faux-pas (to which I disagree — I think it's pretty noble, like having built-in OpenAPI docs) BUT you can easily craft a recursive query using just this endpoint that will take (some) GraphQL servers down. There are plenty of posts written on the matter and I'm sure there are mitigations, but my first exposure to GraphQL was on someone else's project (a respectable engineer who I consider very skilled) and within the first day I had noticed this intriguing structural hazard and taken the server down...
It therefore seems to be a tool that is possibly difficult to 'hold correctly'; at least people should be cautious about going in without doing their research about these things. Probably a maturity issue, but one that people ought to be aware of?
Other gripes:
It's displeasing how the HTTP status code does not correlate with the actual success response of the API, which makes typical request logging less useful.
I guess it also makes it harder to provide optimised hot paths on the server (because your client team might shift their queries around, or whatever).
In previous experience I also find that having easily-recognisable names for API endpoints (like `GET /repositories`) makes talking about them, and recognising them, easier than the more-opaque-feeling GraphQL approach.
Perhaps some of the page-level Copy-on-Write databases (LMDB?) might do this, since they have to rewrite ancestor pages anyway.
Would be interested in doing something similar
I think the blog post is not focussing on error handling too much, but in any case this is 'safe', just could likely be handled better in a real-world case.
the question mark `?` denotes the fact that the error is bubbled up (kind of like an exception, but with stronger typing and less silent)
Or if you wanted to do it on bytes, you could also do this, with (`b'+'`).
Unsure if that would provide a meaningful boost or not
[1]: https://doc.rust-lang.org/std/primitive.str.html#method.pars... [2]: https://doc.rust-lang.org/std/str/trait.FromStr.html
`n` has the same type as the input of the `match` block. In other words, it's a fallback case. (In this case, it's `&str`; the same as `"+"`, `"-"`, etc)
If you're wondering how `n.parse().unwrap()` has its type computed, well that part is because type inference is able to look at the definition of `Token::Operand(u32)` and discover that it's `u32`.
From my experience: The compiler can do this, as long as the first usage of the unknown-typed-thing gives it a type. If the first usage of it doesn't, then it won't try any harder to infer the type and it won't compile unless you add your own annotations on.