Question thread #150
2026-May-01, Friday 18:22The rules:
- You may ask any dev-related question you have in a comment. (It doesn't even need to be about Dreamwidth, although if it involves a language/library/framework/database Dreamwidth doesn't use, you will probably get answers pointing that out and suggesting a better place to ask.)
- You may also answer any question, using the guidelines given in To Answer, Or Not To Answer and in this comment thread.
Broke (short story)
2026-May-01, Friday 18:21https://miriam-english.org/stories/short-stories/broke/broke.html
I hope it makes you smile.
Follow Friday 5-1-26
2026-May-01, Friday 03:09Here's the plan: every Friday, let's recommend some people and/or communities to follow on Dreamwidth. That's it. No complicated rules, no "pass this on to 7.328 friends or your cat will die".
Habermas Presentation and Other Scholarly Activities
2026-Apr-29, Wednesday 21:28In my other, more formal scholarly activities, I've smashed through the University of Chicago's course on science and climate modelling, completing the material in about half the expected time. Mind you, it does help if one is pretty familiar with the content, though one should recognise that some of it could be updated. I will also say that the user interface of the professor's models could be improved. With these caveats, however, the content is quite excellent and what one would hope for from someone who has been a professor of geophysical sciences for almost 35 years. I admit I am intrigued by the follow-up make-your-own modelling course.
On a somewhat related manner, I have also organised multiple researcher talks at work involving a variety of researchers who have used our supercomputer and have some publications as a result; one has the charming title of "CRITTERS: Climate, Resource, and Image Tracking in Tiny, Ecologically Representative Systems". The second, "Threshold-Calibrated Word Sense Disambiguation: Semantic Broadening Without Sense Redistribution in Schizophrenia", and the third "Skuas as sentinels of high pathogenicity avian influenza H5N1 on the Antarctic Peninsula in the 2024/2025 austral summer" (my own recent trip to Antarctica in the same area witnessed more than a few of these well-travelled birds). All quite different but equally important subjects that, in their own way, needed the processing power we could offer to model and verify theories and to seek matches with empirical data; this is how real science progresses.
faking 3D ripples
2026-Apr-29, Wednesday 12:16This is a cute way of faking 3D. First it plots this wave, with each line shifted down by two scanlines and right by one pixel. That draws an isometric image, but I fake perspective by gradually widening each line at its right edge. And I fake hidden line removal by drawing each line as a solid made up of vertical black lines, each topped with a white pixel.

#! /bin/awk -f
# ripple
#
# Miriam
# Wednesday 2026-04-29 08:45:20 am
#
# fake a 3D view of a ripple
#
BEGIN{
# Read canvas size (close it if getline needed again)
"echo \"size\" | candraw" | getline
wide = $1
high = $2
print "clear"
xl=10 # drawn left edge
xr=390 # drawn right edge
xoffset=200 ; yoffset=300 # ripple offset
ystart=100 # top of image
yend=300 # last scan
for (y=1 ; y<yend ; y+=2){ # leave gap between lines to fake shade
xr++ # fake perspective on right edge
for (x=xl ; x<xr ; x++){
xa=x-xoffset ; ya=2*y-yoffset
c=sqrt(xa*xa+ya*ya)+1
a=c*0.06+0.6 # frequency
m=sin(a+a/6)/a/sqrt(a)*100 # amplitude
xp=x+y/2 ; y1=y+ystart+15 ; y2=y-m+ystart
if (xp>0 && xp<wide && y1<high){
print "line " xp, y1 " (black) - " xp, y2
print "pset " xp, y2 " (white)"
}
}
}
}
And since awk doesn't have any graphics commands I send the output of the awk program to my candraw bridge program which connects to my graphics server.
./ripple.awk | candraw[dreamwidth/dreamwidth] 5b483b: DW::Search: drop mysql_enable_utf8 to match bytes-...
2026-Apr-27, Monday 21:37Branch: refs/heads/main Home: https://github.com/dreamwidth/dreamwidth Commit: 5b483b9dd7ee5b52211b7da808b7d2a5fec60d35 https://github.com/dreamwidth/dreamwidth/commit/5b483b9dd7ee5b52211b7da808b7d2a5fec60d35 Author: Mark Smith mark@dreamwidth.org Date: 2026-04-28 (Tue, 28 Apr 2026)
Changed paths: M cgi-bin/DW/Search.pm
Log Message:
DW::Search: drop mysql_enable_utf8 to match bytes-everywhere convention
Was causing Wide character in syswrite from Starman.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
To unsubscribe from these emails, change your notification settings at https://github.com/dreamwidth/dreamwidth/settings/notifications
New Year's Resolutions and Other Goals
2026-Apr-27, Monday 18:06We talk about different goal systems, pros and cons of resolutions, arts and crafts for tracking goals, human psychology, and more. You can share your resolutions or other goals. There are weekly check-in posts in January, and monthly ones in the rest of the year, for folks to talk about their accomplishments. December-January is the most active period, and it starts ramping up in November as lots of people begin thinking about their goals for the next year.
2026 Free Printable Calendars, Planners, and More is the guide post for this years goal-setting activities. For more details on relevant topics, see "Things You Can Talk About Here."
( Read more... )
Newcomers
2026-Apr-27, Monday 18:01( Read more... )
BASIC vs awk
2026-Apr-27, Monday 23:59BASIC was first run in 1964 at Dartmouth College in UK, where it was created.
UNIX was first created in 1971. It was just 16Kb in size.
In 1975 the Altair -- the world's first personal computer was released; it ran an absolutely minimal BASIC, just 4Kb in size. They later released a more capable version of BASIC, 8Kb in size.
The first TRS-80 was released in 1977, the same year awk was released inside AT&T Bell Laboratories. It wasn't until another year or two that awk was released world-wide as a part of Unix, and in 1988 the Free Software Foundation released gawk, which is today the most used version of awk.
The TRS-80 initially had a 4Kb BASIC, but later was upgraded to a more complete 12Kb BASIC.
The first Tandy Color Computer (CoCo) had an 8Kb BASIC. That was later upgraded to a 16Kb extended BASIC.
These are all still very small figures when compared to modern computer languages, which tend to be megabytes or even gigabytes in size.
So how big is gawk -- the most used version of version of awk?
It is about 3Mb on my 64-bit computer.
But that's a bit of an unfair comparison. Those earlier computers were 8-bit computers, not 64-bit. Also, the machine code was hand-written, whereas awk is written in C and compiled, which never creates code that's as efficient as a human can. (Though modern AIs might one day improve on that.)
So, how big might awk be if rewritten for an 8-bit computer? Well it just so happens that the Tandy CoCo was able to switch out its BASIC ROMs and run OS-9, which is a Unix-like operating system, and it has an implementation of awk (actually gawk) which is 36Kb in size -- a lot smaller, but it's still compiled from C. It makes me wonder how small it would be if hand-coded in assembler. Of course we will probably never know.
Would it be possible to make awk the operational language for a small, 8-bit computer? I don't know. It is difficult to imagine.
What a pity Unix/Linux/OS-9/flex... or some similar variant never took over the early 8-bit computer market. We might be so much further ahead of where we are now.
I do have to admit though, that the early Microsoft BASICs were masterful. They fitted tremendous functionality into extremely small spaces.
Is the ticket-tout ban endangered ?
2026-Apr-27, Monday 15:31https://www.facebook.com/whichuk/posts/pfbid02Z7TbTooKtwXSVDmmXoDKJfTRPNJLhBkT8zbnTmc7bqjAQyx23Fbxp6nfrH7DoD5vl
(no subject)
2026-Apr-27, Monday 22:14The population of cockroaches has plummetted, and I think they may be responsible. Unfortunately the cute little barking geckos seem to have disappeared too, which saddens me.
Also, I like to keep a small population of several non-venomous spiders (I believe that's their actual name) in my room, spinning frail webs around the ceiling to keep me safe by snaring any mosquitoes that get in. But they're gone too.
That puzzles me. How would the hunstman spiders get them? The webs are far too weak to let a huntsman venture out onto them. Perhaps they use the jumping spiders' trick of tapping the web in a way that feels to the little non-venomous spider like prey caught in it, then grabbing the unsuspecting spider when it comes to investigate.
They seem to be cleaning the house.
[dreamwidth/dreamwidth] 74b8d9: ecs-shell + dwtool: pick the worker container, ded...
2026-Apr-26, Sunday 21:59Branch: refs/heads/main Home: https://github.com/dreamwidth/dreamwidth Commit: 74b8d9586e2a47978ec4faae27b184e25425a788 https://github.com/dreamwidth/dreamwidth/commit/74b8d9586e2a47978ec4faae27b184e25425a788 Author: Mark Smith mark@dreamwidth.org Date: 2026-04-27 (Mon, 27 Apr 2026)
Changed paths: M bin/ecs-shell M src/dwtool/internal/aws/ecs.go
Log Message:
ecs-shell + dwtool: pick the worker container, dedupe selection logic
The container-resolution logic in bin/ecs-shell and dwtool was duplicated across four spots and missed log_router as a sidecar. For worker tasks where the first container in the list happened to be log_router, both tools picked it — bin/ecs-shell got TargetNotConnected because log_router has no shell, and dwtool's dashboard CONTAINER column showed log_router instead of the actual worker container.
Centralized to one source of truth per language, with cross-references:
bin/ecs-shell — single $APP_CONTAINER JMESPath fragment defined once at the top, used by both list_tasks (display) and resolve_container (connect/exec). connect_to_task now just calls resolve_container instead of inlining the same query.
src/dwtool/internal/aws/ecs.go — single pickAppContainerIndex helper. ecsTaskToModel (which fills task.ContainerName) and findAppContainer (which feeds FetchServiceImages) both delegate via a containerNames adapter. The unused exported ResolveContainer is removed.
Selection policy in both: prefer "web" (web tasks) or "worker" (worker tasks); fall back to anything that isn't cloudwatch-agent or log_router; final fallback to the first container.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
To unsubscribe from these emails, change your notification settings at https://github.com/dreamwidth/dreamwidth/settings/notifications
Review: What We Are Seeking
2026-Apr-26, Sunday 19:04Review: What We Are Seeking, by Cameron Reed
| Publisher: | Tor |
| Copyright: | 2026 |
| ISBN: | 1-250-36474-4 |
| Format: | Kindle |
| Pages: | 339 |
What We Are Seeking is a bit hard to classify beyond science fiction. I think I would call it anthropological science fiction, but it's also a first contact story and a planetary colony story. It is a standalone novel (well, so far as I know; see later in the review for caveats). This is Cameron Reed's second novel after the excellent and memorable cyberpunk novel The Fortunate Fall, first published in 1996 under Reed's former name of Raphael Carter.
John Maraintha is a doctor from the world of Essius. He took what he thought was a temporary job on the Free Ship Edgar's Folly, where he's endured considerable culture shock. As the novel opens, John learns that the colonists on Scythia have requested a translator to talk to one of the native life forms, and a doctor since they're down to only one. John will be that doctor. The captain has decided, and by the rules of the free ships, John does not get a choice in the matter.
The Scythian colony is about four hundred people, now located in a desert climate since the complex native life forms destroyed their previous settlement. The colonists are a split between Ischnurans and Zandaheans, two other human civilizations from the scatter of colony worlds left after Earth embraced AIs (aiyis here) and turned inward. Both of those groups marry, something John considers a moral abomination. Neither of them seem likely to understand Essian sexual ethics. More devastatingly, John had intended to spend some time as a ship doctor and then return home to a new place in Essian society. Once he lands on Scythia, the chances of that are gone; it is highly unlikely any ship would pick him up again and take him home.
I have been trying to find the right books to compare What We Are Seeking with ever since I read it. The best I've come up with are Ursula K. Le Guin (particularly The Dispossessed), Eleanor Arnason's A Woman of the Iron People, and Becky Chambers's To Be Taught, If Fortunate. The start of the book felt like an intentional revisiting of an earlier era of science fiction, with somewhat updated science and politics, but the last half of the book, where the action picks up considerably, is a meditation on gender, social systems, religion, and small-group politics. All of that is mixed with biological exploration and a first-contact story with some quite-alien aliens.
This is the sort of novel where the protagonist's culture is as foreign to the reader as any of the other cultures he counters, so the reader is assembling several jigsaw puzzles at once. John is dropped into an established colony with its own social norms and established hierarchies. The one other outsider, the translator Sudharma Jain, is, as his name implies, a Jain who keeps very strict religious observances. Half of the colony is from something akin to a fundamentalist Christian religious sect that practices patriarchy and strict marriage codes. The other half is more gently sexist (but still sexist) and has its own tradition of a third gender that becomes central to the story. John, meanwhile, is a strong believer in the Essian approach to social organization: Any two partners of any gender freely have sex by mutual consent and without obligation, and family is based solely on blood relations. These beliefs do not fit comfortably together, even when people are trying (as they mostly do) to be welcoming.
The first half of this book is very slow. This gives all of the characters space to breathe and become comfortable, and the characterization is superb, but it is a book to start when you're in the mood for something slow and observational. There is a plot that gradually becomes apparent, or rather there are several plots that are intertwined, but tension and urgency are mostly reserved for the second half of the book. Instead, the book opens with a lot of close observation of alien flora and fauna and the untangling of subtle social dynamics among the Scythians.
There is also a visitor from earth, much to the distress of the Scythians. Earth presence means the ships will not return and the colony may be cut off from any sort of technological resupply. Despite speaking a common language, that visitor is as mutually alien to the other groups as they are to the native flora. Her life is fully integrated with aiyis, giving her essentially godlike powers and the ability to turn off inconvenient emotions and disregard anything she doesn't want to see. What she and the Earth aiyis are doing on the planet is one of the early mysteries.
The dialogue in this book is truly excellent. Each characters has their own voice, there are fascinating digressions on different words that lead to tidbits of world-building, and some of the culture-specific idioms are delightful.
"I'm making a mess of this. None of that matters. Let me fall out the window and come in the door again. This is how my story ought to start:"
The challenges for the characters in this story are slow but deep ones: belonging and self-definition, the conflict between cultural tradition and personal circumstance, and the sacrifices required to live with small groups in situations where civil war is viscerally attractive. It has one of the most comprehensive and fascinating treatments of transgender issues that I've read in science fiction. Its commentary on current politics is subtle and estranged in the way that science fiction does best, but still pointed and satisfying. And, well, there are passages like this that I absolutely adore:
"I wouldn't go that far. It could be they are right, the universe we see exists because a mind like ours created it — at least, a mind enough like ours that we can say it wants one thing and not another, and when it acts it does so with intent. That's as good an idea as any. But it is certainly not plausible that such a being believes that people everywhere should marry, or that men should never visit men, or no one should become a jess. Look at what they have created. The universe could have been nothing at all, or one atom of hydrogen floating in a void, or a diamond crystal infinite in all directions, if their mind cared for simplicity or tidiness. Instead we have stars and planets and black holes and nebulas. It could have all been cold and dead, but there is life. They could have made one species for each world, or just a few, which could have stayed the same forever, but instead we have millions and millions, all of which are changing every moment, varying among themselves and boiling off in all directions. Such a god is like an artist who fills up a library of sketchbooks with their drawings of strange creatures, and when every scrap of paper in the place is used up, goes back with a different color ink and scribbles over them again. They are obsessed with variation — they gorge themselves with it and never grow full. Do you really think a mind like that could want us all to live in the same way?"
I had one problem with this book, though, and for me it was a big one: There is no ending. Reed effectively builds tension, gets me caring about all of the characters, sets up several problems, starts down a path towards resolution, and then the book just... ends.
Long-time readers of my reviews will know that I'm a denouement fanatic. I want the scouring of the shire, I want the chapter set in the happily ever after, I want the catharsis of an ending. This made me so grumpy!
To be clear, this is not sequel bait (at least so far as I can tell). I can write a philosophical defense of the ending. The types of problems and lives that Reed set up don't have clear endings; this is, to some extent, the point. We muddle through, and then those who come after us muddle through some more, and the cumulative effect is called human civilization. And there is some denouement; Reed doesn't leave the reader at a cliffhanger or anything that egregious.
But still, I wanted the happy ending, even though that was unrealistic for the style of story this is, because I'm a happy ending reader. This is not an ending sort of book; it's the sort of book where I get a sinking feeling at the 95% mark because there aren't enough pages left for the number of remaining unresolved problems. I've gotten less annoyed in the days since I finished the book, and I can appreciate the thematic point made by how the book ends, but I still feel like it's worth an advance warning if you're a reader like I am.
I would be delighted by a sequel, but it didn't feel like that was the intent.
Apart from that, this was both excellent and rather unlike a lot of current science fiction. I think the closest comparison I can make among recent novels I've read is Sue Burke's Semiosis. What We Are Seeking has a similar sort of world-building, but I liked these characters so much more. It felt like a classic literary science fiction novel, but very much written in 2026. Highly recommended, just beware of the lack of closure.
Content notes: Sexism, homophobia, stomach illness, and some religious abuse.
Rating: 8 out of 10
Another cute little graphics program
2026-Apr-26, Sunday 23:57

My program was written in my current favorite computer language, awk, and used my graphics server which lets any computer language do graphics, even awk, which has no graphics commands.
#! /bin/awk -f
# hopalong
#
# by Miriam
# Friday 2026-04-24 01:36:14 am
# adapted from my CoCo program
# which was adapted from
# Scientific American, Computer Recreations (Sept '86)
# awk doesn't have abs() or sign() functions, but they're easy to add
function abs(num) {return num < 0 ? -num : num;}
function sign(num) {return num==0 ? 0 : num<0 ? -1 : +1;}
BEGIN{
# Read canvas size
"echo \"size\" | candraw" | getline
wide = $1
high = $2
# clear the canvas
print "clear"
xv=yv=0
loops=200000000
a=-1000 ; b=0.1 ; c=-10
reduction=0.05 ; soffset=-500
for (n=1 ; n<loops ; n++) {
x=(xv/reduction)+soffset
y=(yv/reduction)+soffset
if (x>0 && x<wide && y>0 && y<high) print "pset " x, y
xx=yv-sign(xv)*(abs(b*xv-c))^0.5
yy=a-xv
xv=xx
yv=yy
}
}The program is meant to be invoked as:hopalong.awk | candrawIt pipes the print statements out to my graphics server through candraw, which acts as a bridge between the awk program and the server.
Here is the "hopalong.bas" program that I wrote in BASIC way back in 1986 for my Tandy Color Computer (CoCo):
1 ' adapted from Computer Recreations 2 ' Scientific American Sept. '86 10 XV=0:YV=0 20 LOOPS=600000 30 A=-1000:B=.1:C=-10 32 PMODE4,1:COLOR0,1:PCLS 34 SCREEN1,1 35 LINE(0,0)-(255,191),PSET,B 36 REDUCTION=.2:SOFFSET=128 40 FORL=1TO LOOPS 42 X=(XV/RED)+SOFFSET 44 Y=(YV/RED)+SOFFSET 46 IF X>255 OR X<0 OR Y>191 OR Y<0 THEN 60 50 PSET(X,Y) 60 XX=YV-SGN(XV)*(ABS(B*XV-C))^.5 70 YY=A-XV 80 XV=XX 90 YV=YY 100 NEXT 110 GOTO110
The awk program is so much clearer and easier to read. It amazes me that I learned anything in that dense BASIC language, but it is actually surprisingly capable. I still occasionally use a CoCo emulator and a TRS-80 emulator on my computer. Sometimes it is just easier.
It is funny to think that awk is so much more modern... it was initially released in 1977 -- the same year as the first Tandy TRS-80.
[dreamwidth/dreamwidth] 94382a: search-tool/SearchCopier: depth-based dispatch, sk...
2026-Apr-25, Saturday 12:18Branch: refs/heads/main Home: https://github.com/dreamwidth/dreamwidth Commit: 94382a85a692de7e4c9184cc808301b916ab406d https://github.com/dreamwidth/dreamwidth/commit/94382a85a692de7e4c9184cc808301b916ab406d Author: Mark Smith mark@dreamwidth.org Date: 2026-04-25 (Sat, 25 Apr 2026)
Changed paths: M bin/search-tool M cgi-bin/DW/Task/SearchCopier.pm
Log Message:
search-tool/SearchCopier: depth-based dispatch, skip controls, timestamped logs
bin/search-tool import-all: - Pace dispatches against SQS queue depth instead of a fixed inter-job sleep. Default cap is --max-depth 100; when local-tracked depth hits the cap, the dispatcher waits for SQS-reported drain. Reconciliation with the real ApproximateNumberOfMessages happens every 50 dispatches and is logged when drift exceeds 20. - Keep a small per-dispatch sleep (50ms) as a cushion against ApproximateNumberOfMessages staleness — the real depth can lag behind the local counter, and without a sleep we can overshoot the cap in tight loops. - Fix queuedepth: a queue with 0 visible messages was being treated as "no depth signal" because '0' is falsy; use defined-check. - Show MAX(userid) up front for ETA scope (PK-index lookup, vs COUNT(*) which would scan). - Timestamp every log line "[YYYY-MM-DD HH:MM:SS] ...". Progress lines emit current count, userid position, jobs/min, ETA duration, local depth. Wait/resume transitions log the wait duration. Final line reports total elapsed.
cgi-bin/DW/Task/SearchCopier.pm:
-
lj::SKIP_SEARCH_IMPORT: list of journalids to short-circuit. Checked
at the top of work(), so it applies to all task types — full
recopies, chunks, single-item updates. Adding a journalid drains
any queued chunks for that journal fast (workers immediately
return COMPLETED for them) so the operator can defer specific
large journals while the rest of an import-all run progresses.
- $LJ::SEARCH_MAX_COMMENT_RECOPY: limit for the comment recopy pass.
In copy_comment's mass-dispatch path, if MAX(jtalkid) for the
journal exceeds this value, the comment recopy is skipped (entries
still process). Unset means no limit.
Both are additive config options; defaults are unset so prior behavior is unchanged until an operator opts in.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
To unsubscribe from these emails, change your notification settings at https://github.com/dreamwidth/dreamwidth/settings/notifications
Review: The Genocidal Healer
2026-Apr-24, Friday 21:44Review: The Genocidal Healer, by James White
| Series: | Sector General #8 |
| Publisher: | Orb |
| Copyright: | 1991 |
| Printing: | May 2003 |
| ISBN: | 0-7653-0663-8 |
| Format: | Trade paperback |
| Pages: | 255 |
The Genocidal Healer is the eighth book in James White's medical science fiction series about the Sector General hospital. As with the rest of the series, detailed memory of the previous books is not required and the books could be read out of order if you didn't mind spoilers.
I read this as part of the Orb General Practice omnibus.
Surgeon-Captain Lioren is a Tarlan doctor who was in charge of the medical response to a newly-discovered civilization. The aliens were suffering from an apparently universal plague and an ongoing vicious war waged entirely through hand-to-hand combat, putting them on the edge of extinction. Lioren rushed the distribution of a possible cure against the advice of the doctors working on developing it, with catastrophic results. As The Genocidal Healer opens, Lioren is insisting on a court-martial in the hope of receiving the sentence it believes it deserves and was denied: death.
(It pronouns are the convention in the Sector General series for all alien races and formal discussions, because even someone prone to bouts of gender essentialism such as White understood the need for avoiding gender assumptions in a science fiction medical context.)
Predictably, both Sector General and the Monitor Corps that technically runs the hospital are flatly unwilling to execute Lioren. Instead, he is assigned as a new apprentice in the psychology department under the legendary O'Mara, where he is ordered to investigate the psychological fitness of a senior doctor named Seldal. This leads him to talk to Seldal's patients, which in turn leads to a challenging set of ethical dilemmas.
The first five chapters (and more than sixty pages) are the story of Lioren's trial and a recounting of the events on Cromsag. The series is full of medical and cultural puzzles like this, and usually I like them, but I thought this one was less successful. We know the vague (and horrible) outline of the ending in advance, and the massive simplification and artificial universality that is required to make this puzzle work is particularly blatant. A universally infectious disease is more of a fiction plot than a believable biological concept, and the number of failures of communication, analysis, and misunderstanding that have to line up to create White's predetermined outcome were a bit much for me.
Once the story gets past that and into Lioren's psychological work, the novel improves. Lioren is guilt-ridden and irrational, but also rather arrogant about his guilt and his concepts of professional responsibility in a way that I think mostly worked. Most of the novel consists of Lioren slowly discovering that people like him and enjoy talking to him, much to his bafflement. In that, it has the gentle kindness and sense of universal basic decency that is characteristic of this series. There are, of course, medical puzzles to solve, although this time they are primarily psychological in nature. Various characters from previous books make an appearance, but White re-explains their background in sufficient detail that you don't need to remember (or have read) those previous books.
There are a lot of similarities between this book and the previous one, Code Blue—Emergency. Both feature nonhuman viewpoint protagonists and amusing descriptions of human facial expressions from an alien perspective. Both feature protagonists with overly rigid ethical structures that partly clash with the generally human policies of Sector General. The Genocidal Healer is a bit more subtle and nuanced, although a lot of Lioren's psychological evaluation rests on an ethical difference that I found somewhat unbelievable. This book, though, tackles a subject the previous book did not: religion. The treatment isn't horrible, but I have some complaints.
My primary issue is that Lioren, who starts as an atheist, does extensive research into religion to help a patient and then starts making statements summarizing the religions beliefs of the majority of known species that are just... Christianity. As someone raised Christian, I recognized it immediately as the sort of abstracted Christianity that Christians claim is universal while completely ignoring the opinions of the adherents of any other religion.
Key components of this majority galactic religious pattern, according to Lioren, include an omnipotent and omnibenevolent creator god, a religious figure who preaches forgiveness and mercy and is persecuted, and emphasis on redemption. This simply is not some abstract universal religion. This is just Christianity in disguise. Even in religions that have some of those elements in their traditions, they do not get the same emphasis and are not handled the way that Lioren describes them. I therefore found Lioren's extended discussions of religion rather annoying, since he kept claiming as relatively universal principles beliefs that are not even held by the majority of religious adherents on Earth, let alone a wildly varying collection of alien races with entirely different biology and societal constructions. It caused a lot of problems for my suspension of disbelief, on top of the annoyance at this repetition of, frankly, Christian propaganda.
Lioren goes, from that research, into theodicy (the problem of evil). The interesting part of this is White's earnest portrayal of a doctor's approach to societal problems: a desire to find workarounds and patches and fixes for anything that makes people unhappy, whether medical or social. It makes sense, given the horrible biologic hands that some of the aliens in this series have been dealt, that they would question the idea of a benevolent god, so this philosophical digression is justified in that sense. But you might guess that a mid-list science fiction author is not going to say something new about one of the oldest problems in Christianity, and indeed he does not. Lioren arrives at the standard handwaving about the unknowability of divine intent, which I found tedious to read but at least not fatal to the plot.
White, thankfully, doesn't take the religious material too far. The characters recognize how sensitive of an issue religion is in a hospital, Lioren never adopts religion fully, and the resolution of the plot is as much biological as philosophical. White is going somewhere with the introduction of religion, and although some of the path there annoyed me, I think the destination worked. White was from Northern Ireland, and therefore well aware of the drawbacks of religion, and he abhorred violence (hence Sector General as a setting), so the reader is in better hands with him than with most authors who might attempt this plot.
I think I know a bit too much about religion to be the best audience for this entry in the series, and I'm not sure the introductory five chapters quite worked. But as with all of the other books in the series, this kept me turning the pages and I'm glad I read it. The Genocidal Healer probably isn't worth seeking out unless you're reading the whole series, but if you're enjoying the rest of the series, you'll probably like this too.
Followed by The Galactic Gourmet.
Rating: 6 out of 10
All Work and No Play
2026-Apr-25, Saturday 10:22One fortunate side of my work in supercomputing is the access to some particularly big iron, which might be useful in these situations. The University's own system, Spartan, has grown from being an innovative experimental system on a shoestring budget to become one of the world's top supercomputers. But another part of my role is working with the West Australian Pawsey Supercomputing Centre, home of Setonix, Australia's most powerful system (named after the quokka, you know). This week, we had a visitor from WA, from Pawsey, to discuss the system, and I was involved in wrangling a lecture theatre full of Spartan researchers to come along and hear about how to get access to this grander system. It was a bit of a highlight for the week, as I'm also organising a major project which includes a couple of major transitions which I strongly disagree with on a technical level, which I know will come back and bite us in the future. But I have long been an advocate of not letting work decisions upset me, and I am all too familiar with people acting as if technical limits are negotiable.
I rather suspect that next week is going to be a bit like the past week; the combination of full-time work and full-time study often means there are periods when my social life suffers quite a lot, and this is one of those times when the pointy end of multiple deadlines is looming. It is times like these that I feel a great deal of gratitude for the especially calm and studious Rookery I've built for myself, and for finding myself in a profession where extended periods of solitude are highly beneficial for output. I guess in the past people found themselves in a secluded hermitage; instead, I find myself in the midst of a vibrant city with the plentiful beauty of art and nature, and it takes some willpower to stay focused.
Follow Friday 4-24-36
2026-Apr-24, Friday 00:07Here's the plan: every Friday, let's recommend some people and/or communities to follow on Dreamwidth. That's it. No complicated rules, no "pass this on to 7.328 friends or your cat will die".
[dreamwidth/dreamwidth] d0f4a9: devcontainer: install Manticore and tighten .docke...
2026-Apr-23, Thursday 20:09Branch: refs/heads/main Home: https://github.com/dreamwidth/dreamwidth Commit: d0f4a97384fd81eef7ce77dd92157eef6e473d34 https://github.com/dreamwidth/dreamwidth/commit/d0f4a97384fd81eef7ce77dd92157eef6e473d34 Author: Mark Smith mark@dreamwidth.org Date: 2026-04-23 (Thu, 23 Apr 2026)
Changed paths: M .devcontainer/Dockerfile M .devcontainer/config/etc/dw-etc/config-local.pl M .dockerignore M etc/config-local.pl.example
Log Message:
devcontainer: install Manticore and tighten .dockerignore
Manticore Search is installed but not auto-started, so developers who
don't touch search pay no runtime cost. Enable with a commented
lj::MANTICORE line in config-local.pl plus searchd --config
/etc/manticoresearch/manticore.conf.
.dockerignore now mirrors .gitignore so docker build . is hermetic on
dev hosts with local state (extlib, build, ext/local, node_modules, etc.);
CI checkouts were already clean.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
Commit: 8faae76d08f5ff7e152dfb5084d28257f996fd08 https://github.com/dreamwidth/dreamwidth/commit/8faae76d08f5ff7e152dfb5084d28257f996fd08 Author: Mark Smith mark@dreamwidth.org Date: 2026-04-23 (Thu, 23 Apr 2026)
Changed paths: M bin/worker/sphinx-copier M cgi-bin/DW/Controller/Search/Journal.pm M cgi-bin/DW/Controller/Support/Search.pm A cgi-bin/DW/Search.pm M cgi-bin/DW/Task/SphinxCopier.pm R t/search-manticore.t A t/search.t
Log Message:
Add DW::Search: unify Manticore and Sphinx behind one module
Controllers now call DW::Search::{search_journal,search_support}
directly; the Gearman/Storable dispatch lives inside the module.
lj::MANTICORE picks the synchronous SphinxQL path,
lj::SPHINX_SEARCHD
falls through to the legacy Gearman worker, and templates see the same
result shape either way.
Both copier paths fan out to SearchCopier when
lj::MANTICORE is set
— DW::Task::SphinxCopier and the legacy bin/worker/sphinx-copier —
so writes hit both backends during migration without having to redeploy
the webservers.
t/search.t replaces t/search-manticore.t and targets SphinxQL, since Manticore 25.0 dropped the legacy Sphinx binary API Sphinx::Search used.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
Compare: https://github.com/dreamwidth/dreamwidth/compare/ba7e09ed3116...8faae76d08f5
To unsubscribe from these emails, change your notification settings at https://github.com/dreamwidth/dreamwidth/settings/notifications
[dreamwidth/dreamwidth] ba7e09: Add t/search-manticore.t: end-to-end test for Sphi...
2026-Apr-23, Thursday 10:16Branch: refs/heads/main Home: https://github.com/dreamwidth/dreamwidth Commit: ba7e09ed3116998f6a745752a3a9bc840415912d https://github.com/dreamwidth/dreamwidth/commit/ba7e09ed3116998f6a745752a3a9bc840415912d Author: Mark Smith mark@dreamwidth.org Date: 2026-04-23 (Thu, 23 Apr 2026)
Changed paths: A t/search-manticore.t
Log Message:
Add t/search-manticore.t: end-to-end test for Sphinx::Search against Manticore
Validates the read path of sphinx-search-gm will work when retargeted
at
lj::MANTICORE — specifically that Sphinx::Search's binary protocol
is accepted on Manticore port 3312, that the filter semantics match
what we expect, and that BuildExcerpts works.
The test creates a throwaway RT table (dw1_selftest) in Manticore via
SphinxQL CREATE TABLE, populates it with a curated set of docs covering
each test scenario, runs queries, and drops the table at END. Skips
entirely if
lj::MANTICORE isn't configured, so CI without a Manticore
instance won't fail.
Covers 15 test cases: 1. Baseline keyword match via Sphinx::Search 2. Phrase match (SPH_MATCH_PHRASE with quoted query) 3. Public entry visible in global search; other entries excluded 4. Private entry hidden by security_bits filter 5. Private entry visible with ignore_security path 6. Friends-only entry: matching allowmask bit returns doc 7. Friends-only entry: non-matching allowmask bit excludes doc 8. is_deleted=1 filtered out 9. allow_global_search=0 excluded from global 10. Journal-scoped search (journalid filter) 11. Comments excluded when SetFilterRange('jtalkid', 0, 0) 12. Comments included when that filter isn't applied 13. Sort by date_posted, ASC and DESC 14. BuildExcerpts returns highlighted keyword snippets 15. Defensive SetFilter('security_bits', [0], 1) exclusion (protects against malformed docs with a 0 in their MVA)
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
To unsubscribe from these emails, change your notification settings at https://github.com/dreamwidth/dreamwidth/settings/notifications
[dreamwidth/dreamwidth] b8e8de: SearchCopier: rewrite as direct port of SphinxCopi...
2026-Apr-23, Thursday 01:36Branch: refs/heads/main Home: https://github.com/dreamwidth/dreamwidth Commit: b8e8ded3b31d3871f41a68cf0dc160db5ce18d94 https://github.com/dreamwidth/dreamwidth/commit/b8e8ded3b31d3871f41a68cf0dc160db5ce18d94 Author: Mark Smith mark@dreamwidth.org Date: 2026-04-23 (Thu, 23 Apr 2026)
Changed paths: M bin/search-tool M cgi-bin/DW/Task/SearchCopier.pm
Log Message:
SearchCopier: rewrite as direct port of SphinxCopier patterns
The prior SearchCopier took its own shape — bulk selectall_arrayref, ad-hoc chunking, per-doc log lines, wholesale DELETE-then-rebuild per journal — and missed practices SphinxCopier has been using in prod for years. Rewrite it as a near-mechanical port of SphinxCopier, with Manticore-specific deviations only where Manticore's semantics require them.
What's now matched with SphinxCopier:
- work() dispatch structure, arg shape (jitemid, jtalkid, jitemids, jtalkids, full recopy), and log messages at INFO
- sphinx_db()/manticore_db() opens the connection with a SET NAMES 'utf8' and errstr check
- logcroak() after every query against the cluster DB and the search DB, so failures fail the task loudly and the queue retries
- Full-recopy entry pass diffs dw1 vs log2 and batch-deletes missing jitemids; does NOT wipe the whole journal up front. Search stays available for the journal during the recopy.
- Full-recopy comment pass has the "short path" for
[dreamwidth/dreamwidth] 39a949: SearchCopier: stream from cluster DBs, match Sphin...
2026-Apr-23, Thursday 01:03Branch: refs/heads/main Home: https://github.com/dreamwidth/dreamwidth Commit: 39a9497745cdab9f36c8d8cd669f7457a3595fd6 https://github.com/dreamwidth/dreamwidth/commit/39a9497745cdab9f36c8d8cd669f7457a3595fd6 Author: Mark Smith mark@dreamwidth.org Date: 2026-04-23 (Thu, 23 Apr 2026)
Changed paths: M cgi-bin/DW/Task/SearchCopier.pm
Log Message:
SearchCopier: stream from cluster DBs, match SphinxCopier logging
importfull was doing selectall_arrayref on both log2+logtext2 and talk2+talktext2 for the journal, which loads every row into perl memory before doing anything. Workers were OOMing on real-world accounts.
Switched both loops to prepare + execute + fetchrow_hashref with mysql_use_result=1 so DBD::mysql actually streams rather than buffering the full result set client-side. Also merged the old "fetch metadata, then fetch text in batches of 1000" comment path into a single talk2 + talktext2 join, since we're streaming now. Working memory is bounded at one row at a time plus the %entry_bits map (jitemid -> bits arrayref) kept around for comment security inheritance.
Also upgraded work()'s logging to match SphinxCopier's verbosity so
it's actually possible to tell who a job is for from the logs:
"Search copier started for [Unknown site tag](
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
To unsubscribe from these emails, change your notification settings at https://github.com/dreamwidth/dreamwidth/settings/notifications
[dreamwidth/dreamwidth] 776ac7: Add DW::Task::SearchCopier path and bin/search-tool
2026-Apr-22, Wednesday 19:10Branch: refs/heads/main Home: https://github.com/dreamwidth/dreamwidth Commit: 776ac7cd8c2185b53beb87c4c460205d19f00be3 https://github.com/dreamwidth/dreamwidth/commit/776ac7cd8c2185b53beb87c4c460205d19f00be3 Author: Mark Smith mark@dreamwidth.org Date: 2026-04-23 (Thu, 23 Apr 2026)
Changed paths: A .github/workflows/tasks/worker-dw-search-copier-service.json M .github/workflows/worker22-deploy.yml R bin/schedule-copier-jobs A bin/search-tool A bin/worker/dw-search-copier A cgi-bin/DW/Task/SearchCopier.pm M cgi-bin/LJ/DB.pm M config/workers.json M etc/workers.conf
Log Message:
Add DW::Task::SearchCopier path and bin/search-tool
Stand up the new manticore-rt write path side-by-side with the legacy sphinx-copier. Nothing in production dispatches to it yet — only bin/search-tool's import-* subcommands. The two paths can run in parallel through cutover.
cgi-bin/DW/Task/SearchCopier.pm: new task class. Auto-routes to its own SQS queue (dw-prod-dw-task-searchcopier) via class-name derivation. Mirrors SphinxCopier's argument shape (full recopy, single jitemid, single jtalkid) and its security_bits / state / text-decode handling, so the search worker's filter contract stays intact when we eventually flip readers over. Tracks per-run stats (entries/comments/deletes ok/err); summary log is debug on clean success, warn when there are errors. Independent 24h memcache throttle on full recopies (separate key from sphinx-copier's).
bin/worker/dw-search-copier: 36-line runner cloned from dw-sphinx-copier; pulls from the new queue, calls work().
etc/workers.conf: add dw-search-copier: 1 so worker-manager spawns it.
bin/search-tool: CLI helper for the migration. Subcommands import-user, import-all, import-support, search, show, delete, count, flush. import-user delegates to SearchCopier->work() so the CLI and the worker share one code path. import-all replaces the retired bin/schedule-copier-jobs (deleted in this commit).
config/workers.json: register dw-search-copier as an ECS Fargate worker (256 cpu / 512 mb, spot, target 30% cpu, scale 1-10). The .github/workflows/ files are the auto-generated CI artifacts from running update-workflows.py.
LJ/DB.pm: incidental tidyall whitespace-only fixup.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
To unsubscribe from these emails, change your notification settings at https://github.com/dreamwidth/dreamwidth/settings/notifications
New blog post
2026-Apr-22, Wednesday 15:55Search maintenance
2026-Apr-22, Wednesday 09:19Happy Wednesday!
I'm taking search offline sometime today to upgrade the server to a new instance type. It should be down for a day or so -- sorry for the inconvenience. If you're curious, the existing search machine is over 10 years old and was starting to accumulate a decade of cruft...!
Also, apparently these older machines cost more than twice what the newer ones cost, on top of being slower. Trying to save a bit of maintenance and cost, and hopefully a Wednesday is okay!
Edited: The other cool thing is that this also means that the search index will be effectively realtime afterwards... no more waiting a few minutes for the indexer to catch new content.
[dreamwidth/dreamwidth] d1fab4: Revert self-hosted log shipping, stay on Grafana C...
2026-Apr-21, Tuesday 21:25Branch: refs/heads/main Home: https://github.com/dreamwidth/dreamwidth Commit: d1fab43e780fd9a699983326b4f82f034763d16d https://github.com/dreamwidth/dreamwidth/commit/d1fab43e780fd9a699983326b4f82f034763d16d Author: Mark Smith mark@dreamwidth.org Date: 2026-04-21 (Tue, 21 Apr 2026)
Changed paths: M .github/workflows/tasks/worker-birthday-notify-service.json M .github/workflows/tasks/worker-change-poster-id-service.json M .github/workflows/tasks/worker-codebuild-notifier-service.json M .github/workflows/tasks/worker-content-importer-lite-service.json M .github/workflows/tasks/worker-content-importer-service.json M .github/workflows/tasks/worker-content-importer-verify-service.json M .github/workflows/tasks/worker-directory-meta-service.json M .github/workflows/tasks/worker-distribute-invites-service.json M .github/workflows/tasks/worker-dw-change-poster-id-service.json M .github/workflows/tasks/worker-dw-distribute-invites-service.json M .github/workflows/tasks/worker-dw-embeds-service.json M .github/workflows/tasks/worker-dw-esn-cluster-subs-service.json M .github/workflows/tasks/worker-dw-esn-filter-subs-service.json M .github/workflows/tasks/worker-dw-esn-fired-event-service.json M .github/workflows/tasks/worker-dw-esn-process-sub-service.json M .github/workflows/tasks/worker-dw-import-eraser-service.json M .github/workflows/tasks/worker-dw-incoming-email-service.json M .github/workflows/tasks/worker-dw-latest-feed-service.json M .github/workflows/tasks/worker-dw-lazy-cleanup-service.json M .github/workflows/tasks/worker-dw-mass-privacy-service.json M .github/workflows/tasks/worker-dw-send-email-service.json M .github/workflows/tasks/worker-dw-sphinx-copier-service.json M .github/workflows/tasks/worker-dw-support-notify-service.json M .github/workflows/tasks/worker-dw-synsuck-service.json M .github/workflows/tasks/worker-dw-xpost-service.json M .github/workflows/tasks/worker-embeds-service.json M .github/workflows/tasks/worker-expunge-users-service.json M .github/workflows/tasks/worker-import-eraser-service.json M .github/workflows/tasks/worker-import-scheduler-service.json M .github/workflows/tasks/worker-incoming-email-service.json M .github/workflows/tasks/worker-latest-feed-service.json M .github/workflows/tasks/worker-lazy-cleanup-service.json M .github/workflows/tasks/worker-paidstatus-service.json M .github/workflows/tasks/worker-process-privacy-service.json M .github/workflows/tasks/worker-resolve-extacct-service.json M .github/workflows/tasks/worker-schedule-synsuck-service.json M .github/workflows/tasks/worker-ses-incoming-email-service.json M .github/workflows/tasks/worker-shop-creditcard-charge-service.json M .github/workflows/tasks/worker-spellcheck-gm-service.json M .github/workflows/tasks/worker-sphinx-copier-service.json M .github/workflows/tasks/worker-sphinx-search-gm-service.json M .github/workflows/tasks/worker-support-notify-service.json M config/update-workflows.py
Log Message:
Revert self-hosted log shipping, stay on Grafana Cloud
With the planned source-side log volume reduction, Grafana Cloud's per-GB pricing becomes negligible and the operational overhead of self-hosting (bandwidth, maintenance, availability) isn't worth it. Points Fluent Bit back at logs-prod-042.grafana.net with the Loki creds from SSM.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
Commit: 28416189e56cdbf33dffa19ff486b97ffdad2848 https://github.com/dreamwidth/dreamwidth/commit/28416189e56cdbf33dffa19ff486b97ffdad2848 Author: Mark Smith mark@dreamwidth.org Date: 2026-04-21 (Tue, 21 Apr 2026)
Changed paths: M cgi-bin/LJ/ESN.pm M etc/log4perl.conf
Log Message:
Reduce log volume: trim log4perl layout and drop duplicate ESN rejection log
Two small changes that together cut log bytes substantially:
etc/log4perl.conf: drop %F:%L %M from the conversion pattern. File, line, and function name added ~80 bytes of framing to every line system-wide; they're rarely useful since the trace prefix and message already identify the code path, and esn-trace searches by trace ID rather than file/line.
cgi-bin/LJ/ESN.pm: remove the filter_reject debug log in unique_matching_subs. The callee-side log in JournalNewComment::matches_filter already logs every rejection with strictly more information (reason, wanted_jtalkid), so the caller- side log was pure duplication. The dw.esn.filter metric stays.
Together these eliminate roughly half of every ESN filter-rejection pair plus ~40% bytes on every log line.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
Compare: https://github.com/dreamwidth/dreamwidth/compare/005e4d64c9d3...28416189e56c
To unsubscribe from these emails, change your notification settings at https://github.com/dreamwidth/dreamwidth/settings/notifications
[dreamwidth/dreamwidth] c5763c: Fix stringified site object in extacct stats tag
2026-Apr-21, Tuesday 20:26Branch: refs/heads/main Home: https://github.com/dreamwidth/dreamwidth Commit: c5763c345a2ef2f8e69074808482cb6361f66c7e https://github.com/dreamwidth/dreamwidth/commit/c5763c345a2ef2f8e69074808482cb6361f66c7e Author: Mark Smith mark@dreamwidth.org Date: 2026-04-20 (Mon, 20 Apr 2026)
Changed paths: M cgi-bin/DW/External/Userinfo.pm
Log Message:
Fix stringified site object in extacct stats tag
DW::External::Site->get_site_by_id returns a blessed hashref, and concatenating with "site:" triggered Perl's default stringification, producing values like 'site:DW::External::Site::DeadJournal=HASH(0x...)'. The hash address was effectively a new label value per process, so every worker restart created a fresh set of unique series that lingered in the active-series count until they aged out. Use ->{hostname} to emit stable values like 'site:livejournal.com'.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
Commit: 005e4d64c9d3d9359de4cff0c3232d2887b06632 https://github.com/dreamwidth/dreamwidth/commit/005e4d64c9d3d9359de4cff0c3232d2887b06632 Author: Mark Smith mark@dreamwidth.org Date: 2026-04-21 (Tue, 21 Apr 2026)
Changed paths: M .github/workflows/tasks/worker-birthday-notify-service.json M .github/workflows/tasks/worker-change-poster-id-service.json M .github/workflows/tasks/worker-codebuild-notifier-service.json M .github/workflows/tasks/worker-content-importer-lite-service.json M .github/workflows/tasks/worker-content-importer-service.json M .github/workflows/tasks/worker-content-importer-verify-service.json M .github/workflows/tasks/worker-directory-meta-service.json M .github/workflows/tasks/worker-distribute-invites-service.json M .github/workflows/tasks/worker-dw-change-poster-id-service.json M .github/workflows/tasks/worker-dw-distribute-invites-service.json M .github/workflows/tasks/worker-dw-embeds-service.json M .github/workflows/tasks/worker-dw-esn-cluster-subs-service.json M .github/workflows/tasks/worker-dw-esn-filter-subs-service.json M .github/workflows/tasks/worker-dw-esn-fired-event-service.json M .github/workflows/tasks/worker-dw-esn-process-sub-service.json M .github/workflows/tasks/worker-dw-import-eraser-service.json M .github/workflows/tasks/worker-dw-incoming-email-service.json M .github/workflows/tasks/worker-dw-latest-feed-service.json M .github/workflows/tasks/worker-dw-lazy-cleanup-service.json M .github/workflows/tasks/worker-dw-mass-privacy-service.json M .github/workflows/tasks/worker-dw-send-email-service.json M .github/workflows/tasks/worker-dw-sphinx-copier-service.json M .github/workflows/tasks/worker-dw-support-notify-service.json M .github/workflows/tasks/worker-dw-synsuck-service.json M .github/workflows/tasks/worker-dw-xpost-service.json M .github/workflows/tasks/worker-embeds-service.json M .github/workflows/tasks/worker-expunge-users-service.json M .github/workflows/tasks/worker-import-eraser-service.json M .github/workflows/tasks/worker-import-scheduler-service.json M .github/workflows/tasks/worker-incoming-email-service.json M .github/workflows/tasks/worker-latest-feed-service.json M .github/workflows/tasks/worker-lazy-cleanup-service.json M .github/workflows/tasks/worker-paidstatus-service.json M .github/workflows/tasks/worker-process-privacy-service.json M .github/workflows/tasks/worker-resolve-extacct-service.json M .github/workflows/tasks/worker-schedule-synsuck-service.json M .github/workflows/tasks/worker-ses-incoming-email-service.json M .github/workflows/tasks/worker-shop-creditcard-charge-service.json M .github/workflows/tasks/worker-spellcheck-gm-service.json M .github/workflows/tasks/worker-sphinx-copier-service.json M .github/workflows/tasks/worker-sphinx-search-gm-service.json M .github/workflows/tasks/worker-support-notify-service.json M config/update-workflows.py
Log Message:
Switch to self-hosted log service
I don't really want to pay hundreds/month for storing logs and I have a server hanging out that has fast disks/RAM, might as well just self-host it. It's not production so if it dies, I can always revert/fix.
Compare: https://github.com/dreamwidth/dreamwidth/compare/ad345841bf9b...005e4d64c9d3
To unsubscribe from these emails, change your notification settings at https://github.com/dreamwidth/dreamwidth/settings/notifications
A Farewell to Draggon
2026-Apr-20, Monday 19:30So Belovedest draped it over the lounge chair on the porch, to dry out.
And there it sat.
I admit that I am short-tempered sometimes.
It's lounging season, I think a little early this year. So the dragon and I have been sharing the chair. And much to my annoyance, we have been sharing it with tiny black ants. Which have been using the deflated dragon as a pathway to climb up onto the chair's side tables (it's a retired infusion chair, so it reclines, has tables, and a place to attach an IV pole) and even on to my very person. I discovered this yesterday.
What losing my temper looked like this time was an enticing Craigslist ad for the salvage-condition dragon (free to the first to arrive), along with reviving my ad to get rid of the aftermarket KitchenAid beater that just barely didn't fit my mixer bowl. Which had been hanging around for months and was starting to develop lichen.
They were both gone by the time I got outside this afternoon.
enhance pictures easily
2026-Apr-21, Tuesday 08:18There are a few picture enhancing operations I do a lot, and it often feels like overkill to load Gimp to do them. Gimp is wonderful, but it is enormous.
So last night I got the idea to try using one or more of the image suites (ImageMagick, G'MIC, NetPBMtools, or some other) to do what I wanted, or even code my own simple tools.
Very little time was spent actually writing the program. Most was spent doing my favorite thing: learning what would work. In the end, all I needed was ImageMagick to do the enhancements of the images, and feh to display the results.
First a word about feh. When I downloaded it from the respository it had been compiled with auto-updating display turned off, for some strange reason. I recompiled it with auto-updating turned on. That's easy, because it was the default.
So, here is the result -- a tiny program that loads and runs quickly and easily so I can do my alterations without loading in enormous Gimp.
#! /bin/bash
# image_fix
# by Miriam
# Monday 2026-04-20 07:55:54 pm
#
# Enhances an image using auto or manual levels
# gamma curve or S-curve to the image's shades.
# And displays a histogram as a guide.
# Uses feh to display the image and the histogram
# because feh can auto-update its display when the image changes
#
# function to make the histogram image of the current picture
function hist {
magick "$tempfile" -colorspace Gray -define histogram:unique-colors=false histogram:/tmp/hist.png
}
# copy the image to /tmp and work on that
# so if I make a mistake I can revert to the original
tempfile="/tmp/img_fix_$1"
cp "$1" "$tempfile"
feh "$tempfile" &
MSGPID1=$!
# display the histogram too
hist
feh /tmp/hist.png &
MSGPID2=$!
# make the menu one column
COLUMNS=1
# set up the menu with highlighted first letters
select menu in $'\e[46ma\e[0muto-level' $'\e[46ml\e[0mevel values (black level, white level)' $'\e[46mg\e[0mamma curve (>1 lightens, <1 darkens)' $'\e[46mS\e[0m-curve (contrast x midpoint)' $'\e[46mm\e[0modulate (brightness, saturation)' $'\e[46mu\e[0mndo' $'\e[46mw\e[0mrite back to original image' $'e\e[46mx\e[0mit'
# loop forever
do
if [ "$REPLY" = "1" -o "$REPLY" = "a" ] ;then
echo "auto-level"
magick mogrify -auto-level "$tempfile"
hist
fi
if [ "$REPLY" = "2" -o "$REPLY" = "l" ] ;then
echo "level values"
read -p "Black level % " black
read -p "White level % " white
magick mogrify -level "${black}%,${white}%" "$tempfile"
hist
fi
if [ "$REPLY" = "3" -o "$REPLY" = "g" ] ;then
echo "gamma"
read -p "Gamma value (>1 lightens, <1 darkens) " gamma
magick mogrify -colorspace RGB -gamma "$gamma" -colorspace sRGB "$tempfile"
hist
fi
if [ "$REPLY" = "4" -o "$REPLY" = "s" ] ;then
echo "s-curve"
read -p "Contrast (0 is none; 3 is typical; 20 is a lot) " contrast
read -p "Midpoint (0 is white; 50 is gray; 100 is black) " midpoint
magick mogrify -colorspace RGB -sigmoidal-contrast "${con}x${mid}%" -colorspace sRGB "$tempfile"
hist
fi
if [ "$REPLY" = "5" -o "$REPLY" = "m" ] ;then
echo "modulate brightness and saturation"
read -p "brightness (50 is half, 100 unchanged, 200 twice) " bright
read -p "Saturation (0 grayscale, 100 unchanged, 200 oversaturated " saturation
magick mogrify -modulate "$brightness,$saturation" "$tempfile"
hist
fi
if [ "$REPLY" = "6" -o "$REPLY" = "u" ] ;then echo "undo"; cp "$1" "$tempfile" ; hist; fi
if [ "$REPLY" = "7" -o "$REPLY" = "write" ] ;then echo "write"; cp "$tempfile" "$1" ; hist; fi
if [ "$REPLY" = "8" -o "$REPLY" = "x" ] ;then echo "exit"; break ; fi
done
# clean up temporary files
rm "$tempfile"
if [ -e /tmp/hist.png ] ; then rm /tmp/hist.png ; fi
# and kill the histogram view
kill $MSGPID1
kill $MSGPID2
[dreamwidth/dreamwidth] 6dc7b3: Drop high-cardinality username tag from extacct stats
2026-Apr-20, Monday 16:11Branch: refs/heads/main Home: https://github.com/dreamwidth/dreamwidth Commit: 6dc7b32ef3eed8378f40270d35c3a0b7a45dd21b https://github.com/dreamwidth/dreamwidth/commit/6dc7b32ef3eed8378f40270d35c3a0b7a45dd21b Author: Mark Smith mark@dreamwidth.org Date: 2026-04-20 (Mon, 20 Apr 2026)
Changed paths: M cgi-bin/DW/External/Userinfo.pm
Log Message:
Drop high-cardinality username tag from extacct stats
The username:$user tag on dw.worker.extacct.{success,failure} tracked each remote external-site user individually, making it the top metric by active series count in Grafana Cloud billing. Site alone is bounded to the DW::External::Site enum and gives the actionable dimension.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
Commit: ad345841bf9b424ceb6bf65be2136b88fb612301 https://github.com/dreamwidth/dreamwidth/commit/ad345841bf9b424ceb6bf65be2136b88fb612301 Author: Mark Smith mark@dreamwidth.org Date: 2026-04-20 (Mon, 20 Apr 2026)
Changed paths: M cgi-bin/DW/Controller/Importer.pm M cgi-bin/DW/Logic/Importer.pm
Log Message:
Validate importer hostname against source whitelist
The /tools/importer UI offered a dropdown of three allowed sources (livejournal.com, insanejournal.com, dreamwidth.org), but set_import_data_for_user accepted whatever hostname the POST carried and INSERTed it straight into import_data. A crafted POST could inject arbitrary hostnames, which then flowed into the new hostname: tag on dw.worker.importer.job_completed as a cardinality-injection vector.
Extracts the allowed-source list into DW::Logic::Importer->allowed_sources so the controller's dropdown rendering and the logic layer's validation share one definition, and rejects any hostname not in the list.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
Compare: https://github.com/dreamwidth/dreamwidth/compare/00b8f85a98e0...ad345841bf9b
To unsubscribe from these emails, change your notification settings at https://github.com/dreamwidth/dreamwidth/settings/notifications
queer book club!
2026-Apr-20, Monday 19:24just wanted to promote my new DW comm
the community is a no pressure book club dedicated to fiction books of all genres that are queer in some way! each month we take suggestions on what the next month's book should be and we vote on it. if you're not interested in the book for the month, that's perfectly fine! you are free to come and go as you please. :)
we plan to start in may and currently book nominations for may are open until april 26th.
hope to see you there!
Review: Surface Detail
2026-Apr-19, Sunday 21:26Review: Surface Detail, by Iain M. Banks
| Publisher: | Orbit |
| Copyright: | October 2010 |
| Printing: | May 2011 |
| ISBN: | 0-316-12341-2 |
| Format: | Trade paperback |
| Pages: | 627 |
Surface Detail is the ninth novel in Banks's Culture science fiction (literary space opera?) series. As with most of the Culture novels, it can be read in any order, although this isn't the best starting point. There is an Easter egg reference to Use of Weapons that would be easier to notice if you have read that book recently, but which is not that important to the story.
Lededje Y'breq is an Indented Intagliate from the Sichultian Enablement. Her body is patterned from her skin down to her bones, covered with elaborate markings similar to tattoos that extend to her internal organs. As an intagliate, she is someone's property. In her case, she is the property of Joller Veppers, the richest man in the Enablement and her father's former business partner. Intagliates are a tradition of great cultural pride in the Enablement. They are a living representation of the seriousness with which debts and honor are taken, up to and including one's not-yet-born children becoming the property of one's debtor. Such children are decorated as living works of art of the highest skill and technical sophistication; after all, the Enablement are not barbarians.
As the story opens, Lededje is attempting, not for the first time, to escape. This attempt is successful in an unexpected way.
Prin and Chay are Pavulean researchers and academics who, as this story opens, are in Hell. They are not dead; they have infiltrated the Hell that Pavuleans are shown to scare them into proper behavior in order to prove that it is not an illusion and their society does indeed torture people in an afterlife, in more awful ways than people dare imagine. They have reached the portal through which temporary visitors exit, hoping to escape with firm evidence of the existence and horrors of the Pavulean afterlife. They will not be entirely successful.
Yime Nsokyi is a Culture agent for Quietus, the part of Contact that concerns itself with the dead. Many advanced societies throughout the galaxy have invented and reinvented the ability to digitize a mind and then run it in a virtual environment. Once a society can capture the minds of every person in that society from that point forward, it faces the question of whether to do so and, if it does, what to do with those minds. More specifically, it faces the moral question of whether to punish the minds of people who were horrible in life. It faces the question of whether to create Hell.
Vatueil is a soldier in a contestation, a limited and carefully monitored virtual war. The purpose of that war game is to, once and for all, resolve the question of whether civilizations should be allowed to create Hells. Some civilizations consider them integral to their religion or self-conception. Others consider them morally abhorrent, and that conflict was in danger of spilling over into war in the Real. Hence the War in Heaven: Both sides committed to fight in a virtual space under specific and structured rules, and the winner decides the fate of the galaxy's Hells. Vatueil is fighting for the anti-Hell side. The anti-Hell side is losing.
There are very few authors who were better at big-idea science fiction than Iain M. Banks. I've been reading a few books about AI ships and remembered that I had two unread Culture novels that I was saving. It felt like a good time to lose myself in something sprawling.
Surface Detail does sprawl. Even by Banks's standards, there was an impressive amount of infodumping in this book. Banks always has huge and lovingly described set pieces, and this book is no exception, but there are also paragraphs and pages of background and cultural musings and galactic politics. We are introduced to not one but three new Contact divisions; as well as the already-mentioned Quietus, there is Numina, which concerns itself with the races that have sublimed (transcended), and Restoria, which deals with hegemonizing swarms (grey goo nanotech, paperclip maximizers, and their equivalents).
Infodumping is both a feature and a bane of big-idea science fiction, and it helps to be in the right mood. It also helps if the info being dumped is interesting, and this is where Banks shines. This is a huge, sprawling book, but it deals with some huge, sprawling questions and it has interesting and non-reductive thoughts about them. The problems posed by the plot come with history, failed solutions, multi-sided political disputes, strategies and tactics of varying morality and efficacy, and an effort to wrestle with the irreducible complexity of trying to resolve political and ethical disagreements in a universe full of profound disagreements and moral systems that one cannot simply steamroll.
It also helps that the characters are interesting, even when they're not likable. Surface Detail has one fully hissable villain (Veppers) as a viewpoint character, but even Veppers is interesting in a "let me check the publication date to see if Banks was aware of Peter Thiel" sort of way. The Culture ships, of which there are several in this story, tend towards a gently sarcastic kindness that I find utterly charming. Lededje provides the compelling motive force of someone who has no involvement in the broader philosophical questions and instead intends to resolve one specific problem through lethal violence. Vatueil and Yime were a bit bland in personality, more exposition generators than characters I warmed to, but their roles and therefore the surrounding exposition were fascinating enough that I still enjoyed their sections.
I'm sure this is not an original observation, but I was struck reading this book in the first half of 2026 that the Culture functions as an implementation of what the United States likes to think it is but has never been. It has a strong sense of shared ethics and moral principles, it tries to export them to the rest of the galaxy through example, persuasion, and careful meddling, but it tries to follow some combination of pragmatic and moral rules while doing so, partly to avoid a backlash and partly to avoid becoming its own sort of hegemonizing swarm. That is a powerfully attractive vision of how to be an advanced civilization, and the fact that every hegemon that has claimed that mantle has behaved appallingly just makes it more intriguing as a fictional concept. In this book, like in many Culture books, the Culture is painfully aware of the failure modes of meddling, and the story slowly reveals the effort the Culture put into staying just on a defensible side of their own moral lines. This is, in a sense, a Prime Directive story, but with a level of hard-nosed pragmatism and political sophistication that the endless Star Trek Prime Directive episodes never reach.
Surface Detail does tend to sprawl, and I'm not sure Banks pulled together all the pieces of the plot. For example, if there was a point to the subplot involving the Unfallen Bulbitian, it was lost on me. (There is always a possibility with Banks that I wasn't paying close enough attention.) But the descriptions are so elaborate and the sense of politics and history are so deep that I was never bored, even when following a plot thread that meandered off into apparent irrelevance. The main plot line comes to a satisfying conclusion that may be even more biting social commentary today than it was in 2010.
A large part of the plot does involve Hell, so a warning for those who haven't read much Banks: He adores elaborate descriptions of body horror and physical torture. The sections involving Prin and Chay are rather grim and horrific, probably a bit worse than Dante's Inferno. I have a low tolerance for horror and I was able to read past and around the worst bits, but be warned that Banks indulges his love for the painfully grotesque quite a bit.
This was great, and exactly what I was hoping for when I picked it up. It's not the strongest Culture novel (for me, that's either The Player of Games or Excession), but it's one of the better ones. Highly recommended, although if you're new to the Culture, I would start with one of the earlier books that provide a more gradual introduction to the Culture and Special Circumstances.
Followed, in the somewhat disconnected Culture series sense, by The Hydrogen Sonata.
Content warnings: Rape (largely off-screen), graphic violence, lots of Bosch-style grotesque torture, and a lot of Veppers being a thoroughly awful human being as a viewpoint character.
Rating: 8 out of 10
[dreamwidth/dreamwidth] 00b8f8: Add JSON access log middleware for Grafana Loki
2026-Apr-19, Sunday 12:35Branch: refs/heads/main Home: https://github.com/dreamwidth/dreamwidth Commit: 00b8f85a98e039eaaf2046ccb2bbc7e1ff07d60e https://github.com/dreamwidth/dreamwidth/commit/00b8f85a98e039eaaf2046ccb2bbc7e1ff07d60e Author: Mark Smith mark@dreamwidth.org Date: 2026-04-19 (Sun, 19 Apr 2026)
Changed paths: M app.psgi M bin/starman A cgi-bin/Plack/Middleware/DW/AccessLog.pm
Log Message:
Add JSON access log middleware for Grafana Loki
Replace Starman's default Apache Combined access log with a DW::AccessLog
middleware that emits one JSON object per line to psgi.errors. Fields include
method, path, status, bytes, duration_ms, host, remote_ip, and user_agent —
all natively parseable by Loki's | json pipeline for dashboards.
Use --no-default-middleware to suppress Plack's built-in AccessLog, and enable ContentLength explicitly in app.psgi to preserve that behavior.
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com
To unsubscribe from these emails, change your notification settings at https://github.com/dreamwidth/dreamwidth/settings/notifications
Review: Collision Course
2026-Apr-18, Saturday 21:52Review: Collision Course, by Michelle Diener
| Series: | Class 5 #6 |
| Publisher: | Eclipse |
| Copyright: | November 2024 |
| ISBN: | 1-7637844-0-1 |
| Format: | Kindle |
| Pages: | 289 |
Collision Course is the sixth novel in the Class 5 science fiction series and the first that doesn't use the Dark X naming convention. There are lots of spoilers in this story for the earlier books, but you don't have to remember all the details of previous events. Like the novella, Dark Ambitions, this novel returns to Rose, Sazo, and Dav instead of introducing another Earth woman and Class 5 ship.
In Dark Class, Ellie discovered an interesting artifact of a previously-unknown space-faring civilization. Rose, Sazo, and Dav are on their way to make first contact when, during a routine shuttle flight between the Class 5 and Dav's Grih military ship, Rose is abducted. The aliens they came to contact have an aggressive, leverage-based negotiating strategy. They're also in the middle of a complicated war with more sides than are readily apparent.
What I liked most about Dark Horse, the first book of this series and our introduction to Rose, was the revealed ethical system and a tense plot that hinged primarily on establishing mutual trust when there were excellent reasons for the characters to not trust each other. As the series has continued, I think the plots have become more complicated but the ethical dilemmas and revealing moments of culture shock have become less common. That is certainly true of Collision Course; this is science fiction as thriller, with a complex factional conflict, a lot of events, more plot reversals than the earlier books, but also less ethics and philosophy.
I'm not sure if this is a complaint. I kind of miss the ethics and philosophy, but Diener also hasn't had much new to say for the past few books. The plot of Collision Course is quite satisfyingly twisty for a popcorn-style science fiction series. I was kept guessing about the merits of some of the factions quite late into the book, although admittedly I was in the mood for light entertainment and was not trying too hard to figure out where the book was going. I did read nearly the entire book in one sitting and stayed up until 2am to finish it, which is a solid indication that something Diener was doing worked.
I do have quibbles, though. One is that the ending is a bit unsatisfying. Like Sazo, I was getting quite annoyed at the people capturing (and recapturing) Rose and would have enjoyed somewhat more decisive consequences. Also, and here I have to be vague to avoid spoilers, I was expecting a bit more of a redemption arc for one of the players in the multi-sided conflict. The ending I did get was believable but rather sad, and I wish Diener had either chosen a different outcome (this is light happily-ever-after science fiction, after all) or wrestled more directly with the implications. There were a bit too many "wait, one more thing" ending reversals and not quite enough emotional payoff for me.
The other quibble is that Collision Course was a bit too damsel in distress for this series. Rose is pregnant, which Diener uses throughout the book as a way to raise the stakes of the plot and also make Rose more annoyed but also less capable than she was in her earlier novel. Both Sazo and Dav are in full heroic rescue mode, and while Diener still ensures Rose is primarily responsible for her own fate, there is some "military men attempt to protect the vulnerable woman" here. One of the things I like about this series is that it does not use that plot, so while the balance between Rose rescuing herself and other people rescuing her is still tilted towards Rose, I would have liked this book more if Rose were in firmer control of events.
I will mostly ignore the fact that a human and a Grih sexually reproducing makes little to no biological sense, since Star Trek did similar things routinely and it's an established genre trope. But I admit that it still annoys me a bit that the alien hunk is essentially human except that he's obsessed with Rose's singing and has pointy ears. Diener cares about Rose's pregnancy a lot more than I did, which added to my mild grumpiness at how often it came up.
Overall, this was fine. I prefer a bit more of a protagonist discovering how powerful she is by making ingenious use of the ethical dilemmas her captors have trapped themselves in, and a bit less of Rose untangling a complicated political situation by getting abducted by every player serially, but it still kept the pages turning. Any book that is sufficiently engrossing for me to read straight through is working at some level. Collision Course was highly readable, undemanding, and distracting, which is what I was looking for when I read it. I would put it about middle of pack in the series. If Rose's pregnancy is more interesting to you than it was to me, that might push it a bit higher.
If you have gotten this far in the series, you will probably enjoy this, although it does feel like Diener is running out of new things to say about this universe. That's unfortunate given the number of threads about AI sentience and rights that could still be followed, but I think tracing them properly would require more philosophical meat than Diener intends for these books. Which is why the next book I grabbed was a Culture novel.
Currently this is the final book in the Class 5 series, but there is no inherent reason why Diener couldn't write more of them.
Rating: 7 out of 10

