Whether tis nobler to suffer the exceptions

Streamed

Devcontainers PR. .editorconfig PR merged. Fieldset/legend PR for accessibility improvements. High contrast logo PR for better screen reader support. The Brave browser ban. Story merging UI issue and database schema redesign; scoring. Solid Cache expiration. ?? after change id in jujutsu.

scratch


topics
  PRs
    devcontainers https://github.com/lobsters/lobsters/pull/1796
    .editorconfig https://github.com/lobsters/lobsters/pull/1802
    fieldset/legend https://github.com/lobsters/lobsters/pull/1792
    high contrast logo https://github.com/lobsters/lobsters/pull/1780
  brave ban
  database gets oomkilled during stream; improved this error message
  username UI
  email vs e-mail
  story merging UI https://github.com/lobsters/lobsters/issues/1456


select key from solid_cache_entries where key not like 'production:rack::attack%' and key not like 'production:c_%' limit 3;
select key from solid_cache_entries where cast(key as text) not like 'production:rack::attack%' and cast(key as text) not like 'production:c_%' limit 3;

now:

  stories
    user_id
    title
    url, normalized_url
    description, markeddown_description
    hotness
    score, flags (these are rollups, but there's FKs from Vote)
    short_id
    token
    comments_count (rollup)
    user_is_author

replacement:
  stories
    headline_id
    -merged_story_id
    -stories_count
    -last_comment_at
    -hotness
  headlines
    story_id (primary among the merged stories for _list_detail)
    token
    comments_count
    hotness, score, flags
    last_comment_at
  does stories have headline_id or a is_headline boolean?
    would solve the chicken-and-egg of which column has to allow 'not null'

check every story_id column


title

post-stream
    

Transcripts are generated with whisperx, so they mistranscribe basically every username and technical term. They're OK but not great, advice appreciated.

Recording



02:45Okay. I'll start here, I guess. pushcx Ask questions anytime!
So howdy. This is Lobster's Office Hours. I'm Peter. Ask questions. And this is Lobster's. So here in Lobster's Office Hours, you can drop in, ask any kind of questions anytime. or otherwise just hang out and I'll work on maintenance. ChaelCodes Hey! How's it going?
And, oh man, classic article.

03:30Let's see how that goes. So the last stream, hey Cheo, the last stream left off with me in progress on improving some UI around usernames and adding some, rate limiting is the wrong word, but limitations to changing usernames. You can't just snipe a username somebody used 10 minutes ago. And I'll see how that goes. I wonder why this has a question mark. I don't know what that indicates in the jujitsu output. And if I... All right, I guess it was something about being out of sync maybe it's that one branch had that main and the others didn't yet.

04:49All right. So let's see. So jail as long as you're here, I was going to start with the username stuff but i'll i'll jump over to your PRS if you wanted any attention there. I looked at your. pull request about dev container and had a bunch of questions I tried to ask about why it exists. graefchen Heya. limesDance
Because I don't, not the PR, the tool itself, because it seems to do the same thing, just one level up. Looks like there hasn't been any activity since the last stream, but if you want to jump into that, we could. Hey, Griff.

05:53ChaelCodes I tried rewriting the PR to explain some of those details.
Oh, I didn't see that you tried rewriting the PR.

06:32ChaelCodes From a description and comments
ChaelCodes I need some extra time to test functionality changes because it's 30m per test.
Not being especially familiar with div container or Docker, I can't immediately see the differences because code I know I can kind of memorize, but unfamiliar code doesn't stick as well.

...52Oh, you're saying it's an in-progress thing you haven't pushed. Okay. That's... Why is it such a big amount of time? Something about building the container?

07:15I've heard of this.

...23It's worth a try.

08:01ChaelCodes Like, I tried to answer your questions from the stream in the PR description.
ChaelCodes Because I watched the vod.
oh here i didn't see your description i see i thought you were i thought you were saying you rewrote the the edits the commits of the pr i didn't get that you were saying you rewrote the description of the pr i i parsed it now all right let me go read it again but slower

...52ChaelCodes And yes, I rebuild the container from scratch every time to have a clean test.
When you say VS Code is running inside the Docker container, is it doing a multi-process thing where your UI is running on the outside and then the core of the editor is running on the inside so that it can consider the file system local? I think I've heard something about that. Maybe I heard that with regard to like dev boxes where some companies have people spin them up on EC2 rather than do work locally on there. you know, the actual hardware they can touch.

10:06ChaelCodes I don't know how it works. I know herb lsp, Ruby lsp, and test explorer work in devcontainers and don't work with straight docker
This part's familiar.

...14icecoldw1tch EW MICROSOFT
Bundle install on the Docker failed without Clang and libclang-dev. Weird. I can't guess why that would be.

...28ChaelCodes I want to retest that part
Hey, icecoldwitch, that's not particularly helpful. We're not that kind of peanut gallery. That's a really interesting limitation on Docker and dev containers. And yeah, I wish I could help debug, but I really have no experience to have even a guess.

11:08ChaelCodes That's a functional part I want to review to make sure that's true and give you the actual error message.
ChaelCodes The clang part.
version. Hmm. In the current zero passing the correct Ruby version in the make file or on Docker compose up it grabs. Ruby version was most recently set in your end bars.

12:06Yeah, the clang thing puzzles me, but it is probably not... ChaelCodes That part changed while I was still getting your current docker containers working.
I'm not sure that we actually need the answer to that mystery in a functional sense. If you think it's required, it's going to be required. So I was just... And I don't necessarily have to understand the code. It part changed when you were getting the existing containers working. I guess that kind of... reaches towards another question that I didn't explicitly ask. Can the two of these solutions, the existing Docker file and the dev containers Docker file, can they be combined so we only have one that is used with both, or are they different in some fundamental way? ChaelCodes Maybe. The problem is the ruby-version argument.
And I guess that's part of what trips me up building my mental model is because we have one Docker compose file that's been working and then we have a second one and I'm not sure what it adds. The problem is the Ruby version argument. And maybe like this section about the database should just roll into the existing one because if you're using the existing one, you probably want to have a container with the database.

13:57ChaelCodes The current one ONLY works if you use make docker-serve
ChaelCodes I applied the db changes to both.
Because it requires the setup from the Makefile. I got to look at the Makefile to picture that one.

14:15Right, because it's doing this export. ChaelCodes The ruby-version argument is the ONLY deal-breaker.
I follow.

...31ChaelCodes I have two possible directions.
And that'd be why it was grabbing the version from your environment variable. Cause if you use any kind of Ruby version manager at this point, they all work by setting those end bars. Hmm.

15:04I'm curious what that is i'm going to get this editor convert config thing merge while you're typing. Because I looked at it before stream so I already kind of made my decision on that.

...39ChaelCodes 1. I discover a previously unknown piece of documentation that lets me pass it in. I then get to go update everyone else with our solution.
ChaelCodes (This isn't ruled out!)
yeah i know that feeling of it feels like it should be possible but you just can't find the doc i mean at that point also one of the things i've gotten into is like ChaelCodes 2. We build from a linux container, and install ruby, instead of starting with a ruby image that already has it installed.
using strace to watch what environment variables and file names and things a process tries to look at because sometimes they just don't document where a config file is supposed to be or where something is going to be installed or what network port they really want because they might try one and then close it

16:52And a minute since I've seen one of those best stream viewer spams. Build from a Linux container and install Ruby instead of starting. ChaelCodes linux image*
When you say build from a Linux container, in a practical sense, that means change the Docker compose. ChaelCodes Dockerfile
ChaelCodes Both setups affected, but no need for the argument.
yeah i followed what you meant about linux image hmm change the docker file for it okay right because we're saying pull from the version in the environment variable

17:59I can see how that would work.

18:09Are there... And again, this is one of those things you're going to know better than me. Are there other projects that have this kind of setup? What does Ruby Events do?

...31ChaelCodes I wrote Ruby Events 😅
icecoldw1tch why does ur vs code look weird
ChaelCodes It's the Ruby image
They use Kamal and they've got a Docker file. Aha. So they just declare it here. And I guess by they we mean you. Blame. ChaelCodes Me and another person
People have been touching it.

...58I guess.

19:04icecoldw1tch thx
ice cold which there's if you click on a link under the twitch screen there's a link to the fact that has like the fonts and the stuff about editor config so chill do you have a ruby version file that goes the other direction here then like i don't have a no you just have two files and you keep it in sync okay ChaelCodes Yup! 💯
That's not the end of the world. I just, I just know I'm going to forget to maintain it. And I worry about hassling other maintainers, especially because this Ruby version, if this, this is such a pet peeve for me, because this is its own ChaelCodes And the big magic of Docker, is that whoever needs it, starts from the existing and fixes it.
fig file with its own format we can't add a comment that says like hey Peter don't forget you also have to touch the other file if it was Ruby I could put the comment in in docker file I can put the comment in but I can't put it in both places so I'm more bothered by having to repeat this fact and keep it in sync it starts from the existing and fixes it

20:31ChaelCodes And then it works for everyone else.
Oh, the way the Docker file kind of creates a series of layers. Are you saying that if you edit step seven, it doesn't rerun steps one to six. It just kind of pops its layered file system and goes from there. I think I've heard a little about that.

...58icecoldw1tch just make a templating build system that imports the comment for both files :)
Hmm.

21:10ChaelCodes I'm used to fixing other app's broken docker setups as a first PR.
Yeah, Ice Cold Witch, that kind of thing is tempting. And having read Pragmatic Programmer at an impressionable age, I always think about code generation.

...29Yeah. Yeah, had a lot of PRs to projects that are, here's something that doesn't work in the setup steps. Because of course, ongoing maintainers don't need to rerun the setup steps over and over. And time is at such a premium that we don't make time for it. graefchen Code Gen, because the Code doesn't write itself limesGiggle
So I guess I'm coming back to my statement of high level goals, because you've explained the issues better, and I understand them better. But this is still the situation where ChaelCodes I'm going to make a talk based on our conversation. ✨
You are the expert, and so you can make the best technical recommendation, and I'm the guy who's going to have to maintain it, and I'm trying to not set myself up to make it harder on other folks when I don't remember to update these things. And, you know, I would prefer to have perfect recall, but I don't. Let's add a test. Hey, how about that, Chael? Let's write a test. And by us, I mean you. Why don't you write like a two-line RSpec test and just load the Ruby version and then do some kind of grep or regular expression to pull the Ruby version out of the Dockerfile and fail the build if they're different numbers how about that then they can be in two places and there will be something that forces us forces me to keep it in sync because that's my goal is a good experience for new developers i'm less particular about the actual solution. And I'm open to this dev container thing if it's useful. I know VS Code is fantastically popular. So it makes a lot of sense to have a setup that's easy for folks using VS Code. So I guess with an eye towards you can also improve the existing Docker setup to minimize the thickness of the dev container layers if that's useful to you. ChaelCodes How do you feel about an independent gh action?
Yeah, if you would... Is lobsters down? I'll look. Hmm. Did the site crash since I started the stream? Well, that's bad. graefchen I can't get on the site. So I assume yes.
Let's go look at the logs. So I'm looking at the logs. Chill... The thing I like about an RSpec test is I actually run those local. If it's an independent GitHub action, I won't know until I've pushed a break. And because the only notification is like that email or that bat or stuff, main can be broken for a minute before I catch on. So let's look at log. What's up here? ChaelCodes Brave complaint is showing up.
Reasonable memory and disk usage, so it's not those familiar ones.

25:17Looks like the database is taking a nap. Let's go to DBO1.

...31ChaelCodes PWA is unhappy.
MariaDB was OOM killed. Yeah, it's not running. Why didn't it come back up, though, buddy?

...50PWA? I don't... Do we have... I can't remember if I ever merged code for the manifest file for a persistent web app. All right. Okay, we're back up.

26:54ChaelCodes Whatever gives me the pretend lobsters app. I use it all the time.
ChaelCodes PLA is happy.
Let's close some things. Pretend lobsters happen. ChaelCodes What do you use to block brave users?
Yeah, I think that's just iOS letting you take a bookmark to your home screen. We don't actually have a... ChaelCodes Oh, it works REALLY WELL.
I thought it was called manifest. I've done very little with... Manifests didn't know somebody in the lobsters IRC channel asked about the. icecoldw1tch i ban commits that make it easier for other setups which has the added advantage that i never get any PRs
If we have a donation page and I am trying to find my comment. Nope see I have searched for this comment before.

27:55Is this the one?

28:08Yeah. Yeah. I actually have a note about that where if you look at the top of the gitignore file, because I was getting many pull requests about this, where people were wanting to submit things related to their editor. And I added this note about how you can do it in your own setup locally. And then I stopped getting those PRs. icecoldw1tch what was the issue with website
So I'm really happy with this kind of point of confusion, targeted comment. That's why I was like, let me put in a comment about the icecoldw1tch wow
version in the dot ruby version file ice cold which maria db ran out of memory and was killed by the colonel's oom killer so it allocated too much ram which is a little odd because it has its max ram but that can happen occasionally as for brave users that's its own thing shale ChaelCodes I read the why.
That is also worth searching for so I can find the last time I talked also in the search box, you get to I guess I need to add to the stream fact so. A hassle we had with brave. Is yeah. there's the recent why stuff, but there is the older one where.

29:58ChaelCodes Listening ears on.
Maybe I linked it from the issue. I am trying to find the issue, but where?

30:15I'll have to dig for the link apparently, but when we first turned the block on, There is an issue in the Brave issue tracker where an employee specifically calls out lobsters as a site that is breaking or blocking the Brave browser because of... Honestly, I don't remember what that event was. I'd have to dig back on that too. And... they linked to our implementation of it so that they could most effectively circumvent it and running this code base open source is great for transparency but if we can't maintain a security perimeter because the attackers are literally reading our code to figure out how to break it that's hard so If we go in Hatchbox, is it in pre?

31:33icecoldw1tch is brave bad or smth
I can't remember if I put it in the pre or the post or the primary.

...54Oh, I know where I can find it faster. It's in the gitignore. Or no, it's not. It's in the shared. Shared is the word.

32:20I was trying to find the specific line of the caddy files I here, it is, I was looking right at it this second line, there are one or two lines of caddy config that are not in the repo specifically for the brave block because. If they are reading our code and using that to better disguise their browser. We can't afford an arms race against a commercial product as a nonprofit with a little bit of development time. icecoldw1tch like harrassment
graefchen Brave is ... complicated.
Ice Cold Witch, let me just throw you that search URL rather than recap all of it.

33:10pushcx https://lobste.rs/search?q=comm…
icecoldw1tch thx
Was it this one? Yeah. Brave. has done a bunch of very surprising stuff where they claim to follow specs. Well, they imply they follow the specs, but they only say they respect the spec, if I recall exactly. icecoldw1tch oh i see
And one of the things they do that we would prefer they not do specifically is stop scraping the site and selling it to AI training data. And instead of following the robots.tech spec, they respect the robots.txt spec and they use their users as mules to scrape sites and then sell your data, which, you know, if we had a legal budget that is so obviously copyright infringement,

34:43Oh, yeah, I think the... Was the original issue them injecting ads into sites? That's a thing they did for a minute. I don't remember if they still do it.

35:47icecoldw1tch privacy-focused AI training botnet B)
ChaelCodes I just tried to access the blocking text, because I thought it mentioned collecting info on siteowners behalf.
ChaelCodes *collecting crypto
oh yeah the crypto on site owner's behalf that's exactly what it was yes here I can find you a copy of that text give me one second it's in

36:32ChaelCodes But I'm able to access lobste.rs on brave mobile...
pushcx Lobsters has blocked the Brave browser <a href='https://github.com/lobsters/lob…>since a scam in 2019</a>. We still block it because they <a href='https://web.archive.org/web/202…>lie about following standards to they scrape and sell copies of websites</a>. I'm sorry for the inconvenience, but they have previously targeted Lobsters by name and have a years-long pattern of bad behavior.
Yeah, here we go. I can throw this into the Twitch chat. Yeah, they're different browsers behave differently and have different... I don't know what the right term here is for... They have... They present differently with different user agents, different other headers, different order of headers, and especially on iOS, their rendering engine is of course WebKit rather than Firefox.

37:33ChaelCodes Ohhhh
ChaelCodes Weird and interesting
ChaelCodes Android
So if you're on iOS, I actually don't... I know the rendering engine is going to be WebKit, and I don't know if it even has a different user agent. Android? Okay, well, they should have their own engine, but... Again, there are... There are a bunch of little differences, and... ChaelCodes Fair.
I'm limited in how much time and energy I want to put into stopping bad behavior because all of that time is just a loss. And I get kind of fired up when there's a new scandal, and then I spend an hour or two, but I really... Like, I have literally never blocked a browser by user agent before in... 30 years of making websites, and I would prefer not to do this one, but just the endless bad behavior from them. Yeah.

39:41I guess I can throw in here at the, great band came up.

40:09icecoldw1tch btw why dont u rewrite the whole site to rust since it ends in dot rs? isn't it legally required all dot rs sites be written in rust
Wait, I don't understand this.

...32You know, Ice Cold Witch, it's just because we do so much string handling. Maybe RS can also stand for Rails.

...58icecoldw1tch fair enuff
What do we... Okay, so this... FedEmp has written a couple of comments about this contrast thing, so I didn't understand the state this was going to be in.

41:12So it sounds like when the browser has this prefers contrast more setting, it's actually stricter than our existing low contrast or high contrast mode because it limits the site to using just a handful of colors. And so this thing of just hiding the logo and putting in an L. Yeah, it's a small amount of CSS. Okay.

42:29graefchen Serbia would not be amused if everyone would rewrite their websites in Rust. limesO
as far as i know from talking to a handful of serbian programmers or seeing their conversations online they're pretty delighted by the rust association except for this couple of systems programmers who really dislike rust all right so

43:39That one I merged. Why does it say it was updated three days ago? Are we rounding off? Yes. OK.

...58So this thing. Sure.

44:18Let's be specific. One of the other helpers does it, right?

...28Link to different path. Tag. Okay.

...56to correctly label filtered tags let me see that diff again because the

45:38Fit this thing too.

46:11ghost_user_1984 didn’t we already say that it would be Haskell and not Rust if we ever moved away from rails?
Ghost user, given my personal toy programming language ideas, that is tempting, yes. But in reality, probably the oddest language I'd move to is like Elixir. icecoldw1tch haskell is actually pretty good for web dev
And Python would be a pretty strong competitor. icecoldw1tch or like underrated
because it's been a few years, few years, God, it's been a decade, more than a decade, but you know, I did actually know Django at one point, so.

...54ghost_user_1984 python has always given me horrific prod issues.
icecoldw1tch backend that is
Is it good for web dev? graefchen Why not snobol4? limesGiggle
I feel like so much of web dev is just mushing state and strings around. yeah yeah the biggest knock ghost user on python is dependencies and i've been using uv to run tools written in python on my personal machine and i've been using that for at least six months now and it works when i could never keep python tools running before so i'm pretty impressed but ghost_user_1984 that Ansible setup..
I've had so much pain with Python packaging and dependencies and keeping a development install working that I don't know if I'm ready to love again. Maybe I should use dev containers for it. ghost_user_1984 ehh no
Maybe that would solve all of my problems, actually. icecoldw1tch nah just give up on python not worht it tbh
That's, I mean, I'm saying it a little bit tongue in cheek and as a callback to our opening discussion, but that's probably an effective solution. Ansible. Oh God. Yeah. Ansible was real hard to keep running for a couple of years there.

48:10icecoldw1tch ruby is better anyway
Hmm.

...59templates templates all right i do appreciate that fedemp is giving us a bunch of attention to our accessibility and testing things out in a screen reader we have a handful of visually impaired users who've mentioned they use screen readers and i have been very happy to fix things for them but they do not review every last thing and i i imagine that if one had to use a screen reader for the most or all of their browsing you'd kind of get used to and tired of sites being broken and Probably burn out real quick on reporting stuff that never gets fixed. The fact that I've gotten praise for being mostly text and working, but a lot of that is just if you don't have fancy dynamic JavaScript features, there's less to go wrong. graefchen Making things more accessible is always good. limesNodders
I guess there's one more benefit to leaning for that widely available CSS standard. So there's a related issue to this about, I don't know, it's not related because that one was about the list of tags and this one is about the new story form, which, yeah, I think I saw this on the mod edit version.

51:03Let me pull that up on my iPad off stream here. So it's lobsters slash stories slash new. Yeah.

...33And I think also on the mod edit, let me double check.

...48Yes.

...58That is present on the suggest form because if it's on those,

52:24WhiskyFueled42 hey. hope you all are doing well.
Oh, hey again, Whiskeyfield.

...32This one, I thought we were going to kill this bug when we moved forms to grid, because we saw this one once or twice before. And I think I should add this as actual text here.

...54Thank you.

54:03yeah why did they maybe we didn't do this form or we reverted this form hmm oh and i got a response here this was the one where my review was unfortunately hanging out in a pending state for two or three weeks OK, so they resolved these comments and pushed a bunch of commits. So let's take a look at those changed code.

...55I mean, right off, I am suspicious from the first character of the diff because it's still an instance variable. thought we could avoid passing it.

55:27And this is still passing it down.

...35And this is, oh, I don't like that working by side effect. That's some temporal coupling that's going to be hard to maintain where this thing is reaching in from the inside and it knows how the hydrator works.

56:15So did we get these queries up to the initializer? I think so. Yes.

...51I thought I had one more comment here. I must have written this comment and then lost it by not submitting it. So let's see if I can remember what I was suggesting a month ago. there was a way to make the common vote hydrator a pass-through object yeah i think if we made it if we gave it an each

57:54And then it becomes a decorator or presenter. I can never remember the difference between the two.

58:25So this

59:50First one here, sure.

01:01:32It's the number with the delegate.

01:02:07Is each going to do the right thing? No, it's not because it's not going to invoke the hydration. Yeah.

...39hold it at comments right yeah you

01:03:10How does this work if comments is sometimes an array? Is it always a hash?

...25Making custom classes for collections is so uncommon that I never remember the things you have to do. So these are already looping over comments.

...52And they are.

01:04:04Let's move this.

...13I'm It's hard to figure out where to leave this comment because it's kind of touching three places in the code. And that's the point.

...37Yeah, and this one.

01:06:02There we go. I think that's all the pull requests. What's this one? This one is going stale.

...42So where was I? I was working on catching those 500s.

01:07:07And

...15We've got a rescue or a set of rescues.

...28Double checking what exception was thrown on prod about Trilogy being gone.

...46Trilogy EOF error.

...54No. Trilogy syscall econ refused. That's a big one.

01:09:06It's that username stuff. Oh, I didn't get any of this on the topic list.

...37pushcx Ask questions about Lobsters anytime!
all right so let's see we're a little over an hour in so i will do my little bumper that this is office hours for lobsters and just questions cheers

01:10:18All right, so get that running in the background and let's look at our diff, right? So I was working on the settings page and I believe the test suite was green and then I was validating the username timeouts. That's why it was. Yes, these things needed tests. Let me check the build is green. There may be a test related to this. There may be every test failing related to this. What are we mad about? Syntaxer. Define method for nil. Okay, so if a username hasn't been created,

01:11:27This feels like a thing that's only going to fail in test data. Let's let's copy this strategy here instead of saying. So usernames. With this user, we will order I rated at. Let's be explicit. Sending. grab the last one and grab the created app outfit did that actually change anything no it was the oh it's the where i was going to move the yeah all right

01:12:41there we go so that should be valid both in tests and all right yes build is getting back to green definitely have to test those two validations because temporal logic right Everything with time and time zones and durations and timeouts does surprising things.

01:13:40Bye.

01:14:16is three years enough i'm thinking of we've just had a couple of these let's say five we've really only had one or two places where people have wanted to use usernames and they've been fairly generic but but then if you look at an old comment well you'll see so if Alice renames to Bob and then six years later someone else registers as Alice all of the old comments will have been renamed to Bob yeah there's the option now of denormalizing comments so that they appear with the username they were printed under. That would have to be a going forward change because it would really surprise people who have renamed away from things. And then it would make a real hash out of ever reusing a username because

01:15:43The old comments would start linking to the new user. Yeah, that would be pretty bad. So definitely not changing that. All right. So let's say Alice is a user. Now let's just create a, a username.

01:16:21So let's say created seven years ago, named away at four years ago.

...40And then we expect we have a new user

01:17:07New user errors.

...32Let's put the wrong assertion in so I can see the failure.

...46I already created a username spec and this is testing the user model. So there's the pending relation failed user must exist. Okay. So I do have to create a user.

01:18:25Oh, all right. So hang on. How do I want to... I made the moth sit on the username class, didn't I? Can I just run through that? Yes. All right. So Alice. Let's call it old because I want to reuse it. So create a user, the username Alice, and created at seven years ago. The created username. Probably isn't going to pick that up, is it? That's such a test hassle. Oh, no. OK. Copies created at over. I was thinking ahead. And then let's say username and name. user is old from alice to bob by also the old user because they can do it themselves and then add here's the valuable one we will say only four years ago now if i make a new user named Alice. I should see the error.

01:20:06Has already been taken. Now, that implies my rename silently failed. It shouldn't because all of these things are bang methods.

...43So we have a username, Alice, that was created at seven years ago and renamed away four years ago. And then we have Bob. Does rename not handle the user model? It just handles the username side.

01:21:30just handles the username side. So the user record stayed the same. So we will still need to say old. This feels like our job for a service object, but I don't want to do that. Yeah.

01:22:22NoGoodNick_ hello
I don't remember which of these take key, comma, value, and which ones take a hash. NoGoodNick_ I was reading the chat history and noticed a typo in "lie about following standards to they scrape and sell copies of websites" around the to
And find method username. That's a new one. That's an edit mistake.

...51Oh, is there a typo? Lie about following standards. Yep, there is. Thank you. Let me go fix that. So this is not appearing on screen because it's all mixed up with the actual rule.

01:23:24I think I was trying to say so they scrape and yeah.

...33Yeah, I'm just dropping the word day. That's a valid grammatical sentence. Thanks. No good, Nick.

...46And the test is passing now. Good.

...58Let's also expect that user by Alice is nil. Just kind of checking the box, because I got that wrong. Oh, yeah, not expect to be nil or not to be nil. That is the question, whether it is nobler to suffer the exceptions of no method error or to have a sound type system with some types.

01:24:56played with mega test on another project and you know it's not doesn't say it's ready for a public beta just yet but it feels just about ready to start using it's nice it's fast it doesn't have a DSL

01:25:31Okay, so we'll go from Alice to cool Alice six months ago, and then we will update her username to cool Alice. We expect we don't find it. And then we say user.

01:26:14Really cool, Alice. Is the user valid? They are not. Hey, wait a minute. This should have errored. Okay, so that test is broken. This one should also have a message in it. Let's fix the easy one first. In fact, the old, that's not the easy one. That's miming it up instead of using a structural editor. And I'm not reading closely.

01:27:15Yeah. So what I really want to say is there's this array And one of them.

...54One of those hassles.

01:28:30I feel like mutation testing is impacting the kind of test I write. Although it's not that I've spent a lot of time on mutation testing, but a little bit of it and then also a lot of maintaining tests over years and watching them fail to break or successfully break kind of informs that intuition about what are you actually doing an exception on, which I want to do down here as well. I want to say the new user, haha, see I remembered, has been used.

01:29:10And it's not three, it's five. I'm using it on two lines and already got it wrong before I finished the commit. Means I should probably extract that to a constant. Did that work?

...43I must not have saved or something. So I didn't expect that to work. I thought I was gonna have to pick something else over here. All right, so now that I'm getting the failure I expected,

01:30:04So if there is a username. Record with this username.

...36that was renamed away at, this is backwards, greater than or equal, no, hold on. I always have to stop to think about it with dates. If renamed away at is, yeah, after five years ago, then it should show up here, yeah. Good test failure.

01:31:08There we go.

...21Instead of having these sort in different orders, we will just make them both do the same thing of using last. Which. Like here, there can only be one, but that's a very high-level business rule.

...47I guess it's a little more expressive to say descending and give me the first one. It also means we can lean on SQL a little more in the tiniest of ways. Check these. And then I'll run the whole suite. And then I think I'm done on the username side. Should be nice. It's been hanging out for a while.

01:32:34I left the puts in there, didn't I?

...42OK. Did I have an open issue about usernames? Trying to make sure I'm using that dropdown completion so that I keep getting the better sort. I don't think so. no these two things are new rules and then it's better ui let's take one more look at that settings page because i touched a couple of things there so now username is still up here password moved away show email came up oh there's that email verse email thing let's put that on the to-do list

01:33:40Now all the security settings are together. Comment reply, comment mention. Yeah, so the form does a lot, but that's okay. Let's double check that I can do this. So current password is test. We will change it to dev and dev and say, where's my save button? Save. This needs some spacing. Boy, that really vanished in there. Let's log out. And say log in as test with the password dev. Good. Let's go look at that. Settings index.

01:34:43So that save account settings. So this one is fine, but only because of this. The other one kind of vanishes because it's... Oh, it really vanishes. I was looking for it and I went right by it. So let's give it some more vertical spacing.

01:35:27I will accept that. I know it's not the right CSS way to do it. We have a bunch of these. All right. It is not the thing I want to fight with.

01:36:36All right. Oh no, I merged that one thing. Let's bump this and rebase.

...59I only moved the one thing, not both. Let's also rebase

01:37:30These little things are only useful for the actual view you're looking at. Let's check that we got we want to really care what order those two commits are in. See, here's that double question mark again.

...52Why is that?

01:38:14dzwdz it's confused too by the looks of it
command and there is one instance of the double question mark but control f is not finding it Which means it's... Sometimes it's under these floating headers, which is one of the reasons I never like to use them.

...58Or it's invisible in some way. How do I deal with conflicted bookmarks? Okay.

01:39:47dzwdz oh, not only confused but conflicted
It's just something about having been out of sync. No, it's not. It's not a bookmark. It's a double question mark. next to the change ID.

01:40:08This indicates is now divergent. There are two visible commits with the same change ID. What is this in the middle of explaining? I accidentally changed files in the wrong commit. I think I did a force push a week or so ago.

...50dzwdz i think you might've scrolled past another heading there? might be wrong
OK, one of these is going to be the actual commit. Let's find the ID that's up on prod. Also starts with an 8, 26c. 26c. So let's abandon that one.

01:41:17Could not modify. Commutable commits are used to protect shared history. It's also his branch. Oh, I guess it's doing this because I rebased his commit onto main rather than have an extra merge bubble. And then because I've started fetching his repo, because I typically add somebody's repo whenever they've submitted a PR or two. Okay.

01:42:01So, don't need that. Oh, yeah, DZ, I think I'm pretty sure that this is, I fetch from, federico's repo and i did do a fetch between when he opened the pull request and when i did a rebase of it and so it sees this change under two commit ids which is true and the the other way to resolve this would be just wait because he's gonna delete this branch or Just forget about it. Or I could delete this branch and stop tracking it. Either way, this is transient. This is mostly me being puzzled by the jujitsu UI because I didn't know what the double question marks meant. All right, so let's go ahead and deploy.

01:43:16Set some nice fixes to the settings.

...25What else do I have going? Well, there's the story merging UI stuff I could come back to.

01:44:00Alright. Wouldn't have to blow this smoke off of that, the dust off of that. Let's find that issue.

...41pushcx https://github.com/lobsters/lob…
I don't think I have any. Let's look at where we were at with this. So let me share this issue for anybody who's curious. This has been a whole bunch of stuff that's been going most of the year.

01:45:23Doesn't look like I have a branch laying around about this, so... I guess that means I hit a good stopping point?

...49So I chewed a lot on... what to call these tables. And I think the least churn is to leave it called stories and separate out a headline model. And we can do these incrementally.

01:46:22Has there been any other discussion lately? No.

01:47:58How do we want to do this? We want to merge a model headline. And what are our fields?

01:48:29Fields are going to be title, which is a string, description, which is also a string. Do I want to do marked down description, or do I want to start fragment caching that? The admin UI has been pretty happy with fragment caching.

...56let me let me look at that real quick so i'm logging into prod and jumping into the current folder and there's the storage directory now where's the yeah with the cache And the only reason i'm doing this off screen, as I know, in about two seconds i'm going to pull an entry or something so. I look at the cash and I grabbed some keys.

01:49:41Something.

01:50:10Bill.

...39Huh. So I'm saying, show me the ones where the key doesn't start with rack attack. And the first thing it gives me is something where the key starts with rack attack. And I would pull it on screen to debug, but it's got an actual user's IP address on it. The SQLite not like the like operator. Doesn't even exist here because cache is off.

01:52:21So the query I want to run looks like this. Well, that's the shorter one. The longer one is. Also ignoring the comment redirects that I did on stream, maybe four or five streams back for the production. performance issue we said where the key is not like is it treating the colon as a special character

01:53:23Cause when I'm getting back as a bunch of, I hear, let me, let me censor the IP address off screen and then I can paste what this is.

...40So this is probably just some data center, but I say not like percent and I get Like, what am I missing between these two things? This feels like there's some very obvious typo. So if I want to select a key from solid cache entries where the key is not like, it's got to start with that.

01:54:25Am I so sleep addled that I'm reversing this? No, I'm not.

01:55:00Yup. I'm doing something silly.

...10I'm making some kind of very obvious mistake here. Cause I'm just looking right through it. Select key or key is not like production rack attack. And then I get a key that starts production rack attack.

...31Does like not work on blobs? Is that what this is?

...50Because the key is a blob rather than a text.

01:56:10Where is your definition of like? Can I say like?

...55Application defined functions like x, y. What is the third option? Escape. OK.

01:57:10I think this is just failing because it's a blob.

...55How do I cast it? Do I just affix it with cast? So I will say cast key as text.

01:58:18OK, that does what I want. All right, so this was a type issue. no it wasn't oh that's a typo all right and then i can bring this thing back on screen i can Let's get some of these IP addresses off the screen. And close that buffer. So it is actually grabbing. There's how much stuff here?

01:59:2322 for it's about right for the mod activities i don't know what the keys are for these fragment caches i'm gonna put away the this because it occurs to me if i grab the contents of a

...54entry, there's just going to be stuff like actual mod notes.

02:00:32Okay, this is promising. So as an example, I grabbed the key where they're like activit, which is the thing that's getting cached. So these are, this is the name of the partial. This is the hash of the partial so that the cache is busted when it's cleared. And then this is the individual thing and whether the user is off. These are all the attributes to the, template caching call so how many are in here 76 yeah that's about how many should there be in the last so many days

02:01:29Let me bump that.

...40I guess what I could have done is turn on dev caching, but I keep foot gunning myself with that. So the answer is where cast key as text.

02:02:03and cast key as text because this had a knot i was reversing it so thing that matched nobody wait why do i have a limit three on there right so i just off screen loaded the mod activity page to fill the cache which took of 32 seconds

...37And then reloading it takes a tenth of a second.

02:03:00Yeah. Most of these are going to be rack attack, though.

...18Yeah.

...24I could have just queried for what I actually wanted.

02:04:01So we've got 23,000 of these cached. All right. So the thing I'm thinking about is on the story model and on the comment model, we have

...33We cache the Markdown rendered text for performance, and we cache it at the model level because we predate Rails having all this nice Russian doll fragment caching. And I'm kind of wondering how much pressure we're having on the production cache, because frankly, the mod activities should mostly have been cached.

02:05:21cache is 4.7 gigs, which is significantly larger than the Mac size. Wow. That's interesting.

...47Let's figure that one out.

02:06:43rewriting increments a counter once the counter reaches half of the expiry batch size it does it on a background thread that doesn't seem to be happening

02:07:17So aside from that number being low, because we are in production exceeding the cache size by, what, 140%?

...48So how do we know the expiry batch size? The batch size to use when deleting old records, default 100. So every 50 or so checks.

02:08:28It doesn't enforce size, it really only enforces age.

...46So it'll delete up to 100 entries provided they're all older. So because I set a high timeout on this, because after the first couple hours, a comment text can't change, an activity text can't change, people can't edit. So why not cache these for a long time? Then the max size is getting ignored. It's really not a max size. It's just a filter, a predicate on whether the thing runs at all.

02:09:30That is not at all how I imagined. I thought it was going to delete everything older than max age and delete when above max size.

...50I also kind of want to split out the rack attack cache from everything else from the i mean the full page cache and the fragment caching have real different behaviors oh right full page cache isn't in here but i want it to be hmm

02:10:38So what do I want out of this cache? I'm not too worried about the size on disk. But this implies The mod activity cache should have been full because the mod activity screen shows what's happened in the last three months.

02:11:25Hmm.

02:12:09So now I don't understand the cache size in the other direction. Why isn't it bigger? It must be. It must be that I touched the template.

...40So this renders public log. Those things haven't changed. And the notes still haven't changed.

02:13:17So I was wondering if that tree was the whole, the hash of the whole app views folder or something.

...51And those are the elements I saw in the key.

02:14:58so the reason i went down this rabbit hole is the headline is going to want to have actually it's not going to have a description field well

02:15:26Yeah, because it shows it needs to replicate the fields from the top story. That whole distinction, the whole thesaurus exercise about top or headline or etc. Hmm.

02:16:08I guess it has to have that. I guess I don't want to add more of those common marker fields for the cache data. I want to use fragment caching. I feel like I don't know why things were moving out of the cache. I'm taking on a performance risk by doing this. where if we're constantly re-rendering these things, that just generally increases the load. Hmm. All right.

02:17:45Don't need to have a normalized Europe, though. Yeah, because the search engine will still hit Stories. It does need a short ID.

02:18:03Score. Flags is an ugly one, though. are we well all voting are we voting on the headline or are we voting on the individual story all right so i need more notes so right now we have stories that has User ID, title, URL, URL, description, markdown, description, even if that's up on story text, taking it a little more logically. Score, flags, which are adding things up, but like, these are, they're not counter caches. What's the term where they, for, They're caching the summed value of them, like the number of scores, number of flags.

02:19:34I guess I care about... every foreign key in the song let's check every story id column title description yeah short id Is this going to be for the headline story? I also have a token. Hotness. Yeah.

02:20:27Comments count. Another roll up. user is author that's happy to come over and then i mean it needs all of the fields present in list detail which is title, URL, user ID, description. And then it's going to use hotness, which is not explicitly shown. Score, flags, board ID, token, comments count, cross all stories. And I guess this is across all stories.

02:21:43This is paying down some tech debt. Then I guess they'll also have a token.

02:22:00I feel like maybe instead of duplicating all of this it should have headline story id which is the primary one so like because then i don't have to copy all these fields It would get its own comments count, its own score. Well, hotness, spore, flags. And these would just be the values that merge. Yeah, so I was thinking of this as like duplicating these things.

...54Boy, is Active Record not gonna like this one.

02:23:03Because this stuff like domain ID. That's going to be on. Each story.

...18Could grab last comment, yeah.

...25Which.

...32Now the story doesn't need that anymore. And the story doesn't need stories count.

...52And it doesn't need a merged story ID. It needs a headline ID.

02:25:00I don't think this has flags. It has many flags through story, through votes.

...22And I really think I want to slow walk this migration where I'll add the headlines table. And I'll add these things and then I will slowly convert the view to use them, but I'm not gonna be dropping these columns for a while.

...59Yeah. All right, so reference, references, just references, plural. Why is it plural if it's a single column? Because Rails.

02:26:41Should the headline have a short ID? So we have the slash S route. That's kind of the primary route on the site.

02:27:06So if I click in, We are on S and then the short ID. And so headline would become kind of the top level model on this page, especially for merge purposes, which I don't think the test data creates any.

...36So we have a token. I guess it wants to use the short ID of the top story. That's the least behavior changing. So comments count as an integer. And then hotness is going to be a floating point on there.

02:28:11scores or roll-up flags isn't needed because we're recalculating yeah there's hotness

...57that we list the flags count anywhere, but hotness uses it.

02:29:07So let's make hotness easier. These levels of caching are raising a concern in my head.

...35Seems pretty good.

02:30:05I think last comment at can be null. I guess if there's no comments, fine. I thought it was going to be the created at, but that's fine.

...30All right, let's see what that gets us. We're also going to need to say story find each.

...43Where merged story ID is nil. So these are the top levels.

02:31:11Token will get filled in automatically. The rest of these things are rollup values.

...41So I'm wondering if I should, I guess I should put this in the model.

02:32:22Get it a token. And then... So there's a... I want to verify that the story points at this headline and the headline points at this story.

02:33:04I guess it should just validate this side of it? Yeah.

...36That's it.

02:34:08Kind of have to think about the order of operations there for creating these things. Especially there's both the migration and then the creating them when the user is using the submission form.

...35Because, of course, it's my old gripe about Active Record is I have to write this on the model, but it's the transition I care about.

...52So this is only true on update. On create, we don't have an ID to compare to. This record has to be created. Yeah.

02:37:00Sitcom.

02:38:14Do stories need hotness anymore? I don't think so.

...25I don't think so.

...33Because they don't get sorted.

...41How does that... Story controller, sort them.

02:39:04Story merged into story.

...25So let's grab.

...43Doesn't actually have an order. That's probably not great. Put a default order on an association.

02:40:00funny that i got there yes so we will say the order is

...36Actually. I say it like this. All right. I was going to say I was.

02:41:04This is what's happening in production. I don't want to change that right this second. We'll keep that the same, but it's nice to be explicit.

...29Common count hotness.

...38token is taken care of score flags last comment that is now actually they don't have a last edited

02:43:33There's some chicken and egg happening here, but I'm not immediately seeing a better way to do these. So we'll save it a headline object with kind of BS numbers.

...53Well, if we know that we have to have a story.

02:44:08Well, that's already invalid. Yeah. So we can just, I think it's safe to assume that it exists and we'll get a no method error, which is not much better than what I was going to get otherwise. So, right.

...46Comment count include. No, it only is active.

02:45:00Doesn't this have a stories count? Needs one.

...32So right now, well, before the migration runs, I could say story.storiesCount, but that's only going to be true for now. All right, so we'll change this to say 1, 0. Just so we have something, and then

02:46:23I guess it has tags through stories.

...53I guess I got to say not delete it, right?

02:48:02Seems reasonable.

...18Oh, it does actually create some merge stories. Hold on.

...36OK, good. We did actually get five of those. So if I ran this migration, I would see something. That's good. I thought I was going to have to add that.

...56So for each top level story, create a headline that points to it. Save it so it has an ID. connect all of those things refresh the story roll up save that seems all right let's see what that gets me probably some exception from a typo but table lobster story id doesn't exist

02:49:38CaiusHardcore references doesn't take the _id from memory
No, belongs to story. But I got to delete the no. OK, let me run the records. References don't take the ID. That's very plausible. Thank you, guys. column story id on headlines does not match column on okay so this is big int yep so

02:50:44Unknown key, foreign key. All right. So how do I tell it the references has to be a big N? Because I'm saying reference, and it's not connecting that.

02:51:23Like, if you're going to compare against the other table, just don't give me the error. You make it a big int. Save.

02:52:01Unknown key signed. CaiusHardcore type: :bigint perhaps?
Can I pass a, well, I can pass a type. All right, so let's pass type bigint. Ah, we got there at the same time.

...23Still doesn't like it. I would like to see Rails actually print the create table query.

...41There's a way to do it, right? Yeah, that would do it.

02:53:12Story ID, big int. Yeah, see, it didn't put unsigned in there. Then it didn't like when I said unsigned. Scale default null has, oh, I can say colon unsigned instead of signed false. OK. Except I guess that's got to be the, do I say unsigned true?

...53Come around here. Type is big int, unsigned is true, null is false. What's the typo?

02:54:14CaiusHardcore :null:
Null got an extra call. Yeah, that one, I don't know where the lag is, but you, I saw the chat twitch in the 10th of a second before I saw it. So you beat me on that one. So undefined method save for nil. That's a weird one. Why would it be nil?

...48Which line? 19.

...55It's got to be the... Now I get the real fun of writing a migration. I get to clean up after the fail. Unfind method calculated hotness, because I didn't copy that over.

02:55:39CaiusHardcore Gotta drop, good luck :)
Thanks guys. Appreciate your commencing. Have a good one. So this, we gotta have as many tags through stories, which is itself has many through. So we'll see how that goes.

02:56:15So instead of being merged, it's just comments.

02:58:30And then this one, what is this?

...49Base. That math is wrong.

02:59:02Let's call this modifier. And then score is the existing score. So we're going to say score. That's already going to be score.

...35This is already going to be handled.

...47Should the comment points be capped at the number?

...56Yeah.

03:00:45kind of think through this behavior of one of the things that happens is one of the merge stories often gets a lot more comments than the others either because it's the main thing and the other stories are replies or the first thing is like a press release and then the other stuff merged in has all the interesting details Think I'm going to leave that alone.

03:01:52Wait, where do C points get used? Hold on, let's look at the original. You got order, sign, score. They're getting used in order.

03:02:21Why is the modifier a plus instead of a times?

...31God, that would be why the negative hotness modifiers never do anything. I mean, I've gotten the feeling that they don't do much. Has that always been a plus?

...50Let's try on GitHub. All right, so I'm going to run this down, and then I'm going to wind up the stream because we're coming up on three hours. So I'm turning on the last call banner if anybody has last questions about.

03:03:22GitHub, if you're going to override it, override it. Maybe this was the wrong call. Because what I really would like is to have a syntax-aware blame and follow the function back through time.

03:04:24Love how their search engine just kind of scrolls vaguely near it. This one is still plus.

...55Fix initial story hotness. Feels suspicious. Better hotness mod calculation. Here we go.

03:05:19Base is 10. subtract off no he always wrote it as huh so this really was written for the era when the site got like three or four upvotes on it because having a hotness mod of 0.5 i mean when the user that submits it gives one, if the hot mess mod is minus 0.5, that's not a lot. All right.

03:06:11So I'm thinking if we go multiply by modifier,

...23I'm aware this distributes, but

...54No, not distributes. Obviously I'm thinking of permutation. Yeah. Order is math.log. The score plus 1. Take the absolute value of that. But the score is at minus 1. Wait, what the heck? Because if the score is minus 1, then the score becomes 0. And if the score is like minus 9, and we take the absolute value of it, This could be why there's negative scored stories on the homepage occasionally. I wish this wasn't so tied to the database so that I could use it as a pure function a little more.

03:08:42Yeah, this does anything. Just the score handles it. I want to get rid of the abs. That can't be right.

03:09:36That seems pretty reasonable. And then I can compare some values.

03:10:14Oh, this is that value that we just saw the old version had a comment said, shrink this down to 12 or so. We have never shrunk it down. And there was just a conversation about

...56About how long these things can hang around on the site. I'm going to leave this at 22 so I can better compare numbers, but I'm going to have to restore a broad database dump so I get real stuff instead of just demos. And find method update columns for the relation.

03:11:38I can't say update columns. Is it update all? Yeah.

03:12:04Better. Didn't have the column yet.

...45there's a chicken and egg thing here where because i want the collection to point back to a primary member i don't know which to create first the alternate way to do it is to make the primary a column on the stories model oh all right i don't want to i gotta wind down here so All right. So

03:13:50All right. I'm going to roll out. Next scheduled stream is Thursday morning at 9 a.m. as usual. I will otherwise see you around the site, the IRC channel, etc. Thanks for tuning in, chatting. Take care.