build: the mail cleanup runs on the final words, not only a model's reply

A stray placeholder or a lost link was only fixed when a model wrote
the mail, so a words file that already carried one kept it through
every later build. The pass now runs once on the finished
aggregates.yaml words, covering --words, --words-from and the model
alike; the football club's three mails lose the `{chain}` they were
shipped with.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Bendik Aagaard Lynghaug
2026-09-24 20:28:27 +02:00
co-authored by Claude Opus 5
parent 0a02b4db1a
commit c6d0701639
4 changed files with 17 additions and 12 deletions
+2 -2
View File
@@ -29,8 +29,8 @@ mails went from 33 to 40 words to 16 to 19 on one pass and 21 to 27
on the next, LIX from 30 to 39 to 29 to 40. The site here carries the
second pass; its approved mail reads "{child} har fått plass på laget
for sitt årskull. Faktura for treningsavgiften kommer, og plassen er
klar når den er betalt." with a stray `{chain}` the model left at the
end, which renders as the record id. On the vel the same prompt
klar når den er betalt." The stray `{chain}` the model left at the end of each is gone: the
cleanup now runs on the final words, whatever wrote them. On the vel the same prompt
evened six mails out at 17 to 24 words with both links kept. A first
version of this note quoted a mail that did not exist and copied the
vel's aggregates over the club's; both corrected here.
@@ -55,19 +55,19 @@ aggregates:
betalt:
event: betalt
mail:
body: Betalingen er registrert, og plassen på laget er sikret. Trenerne tar kontakt før oppstart. Har du spørsmål, bare svar på denne mailen. {chain}
body: Betalingen er registrert, og plassen på laget er sikret. Trenerne tar kontakt før oppstart. Har du spørsmål, bare svar på denne mailen.
subject: Betalt - plassen er sikret
to: submitter
godkjent:
event: godkjent
mail:
body: '{child} har fått plass på laget for sitt årskull. Faktura for treningsavgiften kommer, og plassen er klar når den er betalt. {chain}'
body: '{child} har fått plass på laget for sitt årskull. Faktura for treningsavgiften kommer, og plassen er klar når den er betalt.'
subject: Godkjent - plass på laget
to: submitter
open:
event: received
mail:
body: Innmeldingen er mottatt, og trenerne ser på den nå. Du hører fra oss så snart plassen er avklart. {chain}
body: Innmeldingen er mottatt, og trenerne ser på den nå. Du hører fra oss så snart plassen er avklart.
subject: Innmeldingen er mottatt
to: submitter
trukket:
@@ -2,15 +2,15 @@
"aggregates.yaml": {
"innmeldinger": {
"betalt": {
"body": "Betalingen er registrert, og plassen på laget er sikret. Trenerne tar kontakt før oppstart. Har du spørsmål, bare svar på denne mailen. {chain}",
"body": "Betalingen er registrert, og plassen på laget er sikret. Trenerne tar kontakt før oppstart. Har du spørsmål, bare svar på denne mailen.",
"subject": "Betalt - plassen er sikret"
},
"godkjent": {
"body": "{child} har fått plass på laget for sitt årskull. Faktura for treningsavgiften kommer, og plassen er klar når den er betalt. {chain}",
"body": "{child} har fått plass på laget for sitt årskull. Faktura for treningsavgiften kommer, og plassen er klar når den er betalt.",
"subject": "Godkjent - plass på laget"
},
"open": {
"body": "Innmeldingen er mottatt, og trenerne ser på den nå. Du hører fra oss så snart plassen er avklart. {chain}",
"body": "Innmeldingen er mottatt, og trenerne ser på den nå. Du hører fra oss så snart plassen er avklart.",
"subject": "Innmeldingen er mottatt"
}
}
+9 -4
View File
@@ -1620,10 +1620,7 @@ pub fn run(argv: &[String]) -> anyhow::Result<()> {
std::fs::write(out.join(format!("llm/{:02}-{}.md", n + 1, path.replace('/', "_"))), format!("{prompt}\n\n=== REPLY ===\n{reply}"))?;
match first_object(&reply) {
Some(given) => {
let mut merged = merge_words(fallback, &given);
if path == "aggregates.yaml" {
keep_links(fallback, &mut merged);
}
let merged = merge_words(fallback, &given);
match wrong_language(&plan.language, &given) {
Some(found) => eprintln!("words: {path} - the reply reads as {found} for a {} plan, keeping the words it had", plan.language),
None => {
@@ -1636,6 +1633,14 @@ pub fn run(argv: &[String]) -> anyhow::Result<()> {
}
}
}
// Last, whatever the words came from - a model, an overrides file,
// a lift from a live repo: a mail keeps the link to the sender's
// own move, and a placeholder left loose in its prose goes.
if let Some(mails) = words.get("aggregates.yaml").cloned() {
let mut mails = mails;
keep_links(&fallback_words(&plan)["aggregates.yaml"], &mut mails);
words.insert("aggregates.yaml".to_string(), mails);
}
write_repo(&out, render(&plan, &words)?)?;
// The words as used, so the next rebuild can start from them.
std::fs::write(out.join("words.json"), serde_json::to_string_pretty(&words)?)?;