Skeleton generator: service-address line renders raw English in DE — stale @hoganlovells.com match (needs rebrand-domain decision) #158
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Surfaced by hopper during t-paliad-368 S7 (2026-07-06).
Symptom
In
scripts/gen-hl-skeleton-template/main.go, theexampleRulesentry for the recitals service-address line matches on:but the current HLC Patents Style
.dotm(inmAi/patentstyle,word/HLC Patents Style.dotm) now authors that line asupc-hub@hlc.compost-rebrand. Because the match text is stale, the rule never fires, so the whole paragraph — including its DE/EN branching — is inert: the DE_firm-skeleton.docxrenders the line as raw, untranslated English (Electronic address for service: upc-hub@hlc.com) instead of the GermanZustellungsanschrift: ….This is a bigger effect than "the domain is stale": the DE localisation of the entire service-address line is currently dead.
(Note: the sibling
user.emailrule had the same stale-domain match —[name.lastname]@hoganlovells.com— and was fixed to@hlc.comin S7 (commit5e1a67f) becauseuser.emailwasn't landing at all without it. This ticket is the remaining twin, left untouched pending the domain decision below.)Why it wasn't fixed in S7
m's standing instruction during S7 was to leave the service hub email alone. The fix is trivial mechanically (update the
exampleRulesmatch textupc-hub@hoganlovells.com→upc-hub@hlc.com, mirroring theuser.emailfix) — but it hinges on a firm decision:Needs from m
upc-hub@hlc.com? The.dotmalready authors it that way, which strongly implies yes — but confirm before baking it into the generated skeleton that ships on court filings.Zustellungsanschrift:translation), regenerate the two skeletons intomAi/patentstyleword/Paliad/HLC/, and verify the DE skeleton renders the German label.Scope
scripts/gen-hl-skeleton-template/main.go(oneexampleRulesentry)_firm-skeleton.docx+_skeleton.en.docxinmAi/patentstyleLow priority; isolated to the service-address recitals line. The rest of t-368 (letterhead sender + court recipient address auto-fill) is shipped and live.
Fixed, plus a second inert rule this ticket did not know about. Not closing — m closes.
Commits
6efc14c— the fix and the detector8492f90— merge-path assertione7dbb2c— the regenerated skeletons, branchmai/diesel/skeleton-158-regen, not mergedBranch
mai/diesel/m-paliad-158-a-stale. CI runs 668 and 671 green.1. Still stale — confirmed from two sources
Both the patentstyle source
word/HLC Patents Style.dotmand paliad's own published copy (frontend/public/patentsstyle/HLC-Patents-Style.dotm, v0.260728-0005) author:So the domain question this ticket parked is answered by the template itself, and by m's 2026-07-27 canonical-domain ruling. No new decision was needed.
2. A second rule was dead the same way
The detector found it: the letterhead date rule matched
14 April 2026; the template says1 July 2026. So{{today.long_de}}/{{today.long_en}}never landed either.This is visible in the artifact that is live right now. The shipped
_firm-skeleton.docx(built 2026-07-06) prints the literal22 June 2026where the filing date belongs — that was the template's example date on the day of that build, and the rule was already stale then. Every skeleton pulled since carries a fixed June date.Nobody had reported it. That is the point of the ticket, not a side note.
3. What was actually built
The two literals are the small part.
buildSkeletonnow fails withinertRuleErrornaming every rule that matched no paragraph, andrules_fire_test.goholds the same line in CI against the copy of the template published in this repo — the publish commit is the earliest moment paliad can know the authored text moved, so that is where the check fires.TestInertRuleIsReportedis the negative control: it pins the service-address rule back to the retired domain and requires the checker to name that rule. Watched fail, watched pass.Both stale rules now match on shape, not on a literal another repo owns. The service-address rule captures the address out of the template and carries it into the translated label, so paliad no longer restates a firm address it does not author, and the same domain change cannot make the rule inert again. The date matches a date.
scripts/was in no test scope at all — notmake test, notci-test-gate.sh. The check would never have run in CI. Added to both, the same gappkg/had.4. Sweep, per the ticket's question
Every rule in
exampleRulesmatches a literal patentstyle owns — that is what the table is. So the answer is not a shortlist of risky rules; it is that the whole table is exposed and the detector is what covers it. Two were dead, both now found and both re-expressed as shape matches. The rest currently fire.5. Regeneration
Regenerated both skeletons from the current source
.dotmon a patentstyle branch, not merged — shipping them is paliad/head's call.Measured before committing:
HLCpat-Base,HLCpat-Footnote,HLCpat-FootnoteChar); no renames, no removals. All 9HLCpatkeys inpkg/docforge/stylemapstill exist.{{key}}; the regeneration emits<<key>>, what the renderer emits today. Both are recognised.HasMergePlaceholdersand render against a full sample variable set with zero orphan placeholders. DE showsZustellungsanschrift: upc-hub@hlc.comand a real date; EN keeps the English label.Most of this was already shipped — the render check was not
Commit: https://mgit.msbls.de/m/paliad/commit/1649852 (branch
mai/jason/issue-158-service-address)No patentstyle commit from me: none was needed. Both halves of the fix landed on 2026-07-29, before this task was written.
6efc14c— paliad maine7dbb2c—mAi/patentstylemain,word/Paliad/HLC/And
6efc14cwent further than this task asks for. Rather than swapping the literal@hoganlovells.com→@hlc.com, it made the match a regex that captures the address, so the generator no longer restates a firm address it does not author and the same domain change cannot make the rule inert again. It also addedinertRuleError, which fails the build for any rule matching no paragraph, and pulledscripts/into the test scope — which had been in no gate at all.Verified on the shipped artifacts, not from the log. Unzipped both skeletons and read the paragraph back:
What was genuinely open
The check this task named: "Assert the German label is present, not merely that the rule fired."
Three tests guard this generator and none of them looks at what a rule wrote.
TestExampleRulesAllFireAgainstReferenceTemplateproves a rule matched;TestInertRuleIsReportedis its negative control;TestReferenceTemplateServiceAddressIsCanonicalreads the template, not the output.Measured, not assumed: replacing
de: "Zustellungsanschrift: $1"with the English text leaves all three green. The German half of the branch can be deleted outright and the package notices nothing — #158's outcome reached from the other side, with the rule firing the whole time.TestTranslatedRulesProduceTranslatedOutputcloses it, generalised past the one line reported here. Four rules carry a DE/EN branch —In Sachen,vertreten durch, the service address, andtoday.long_de/long_en— and each language's skeleton must contain that rule's text for that language. Placeholders run through the generator's ownrenderPlaceholders, so the check cannot drift from the{{key}}→<<key>>contract it asserts on.One design note worth reading. The first draft selected rules to check by comparing their two languages (
de != en). That made it blind to exactly the defect it exists for: collapsing a translation removes the rule from the selection, so all four mutations stayed green. It is now pinned by match text — the one part of a rule a lost translation does not touch. A guard must not take its subject from the field the defect changes. Caught by running the mutations, not by reading the test.Mutation matrix, each green on the old three and red on the new one:
In Sachen→ Englishvertreten durch→ EnglishThe enumeration
No
exampleRulesentry in any of the threegen-*scripts still matches a@hoganlovells.comaddress. Zero.But there is a third instance of the same family outside
exampleRules, and it bites.scripts/seed-example-projectsheldmatthias.siebels@hoganlovells.comas aconstand lookedauth.usersup by exact email. Prod carries exactly one matching row:So the lookup found nothing and every seeded example project silently got
created_by = NULL— over anote:line, not an error. Same shape as the two generator rules: a firm-domain literal in a place that has no reason to hold one. Fixed by shape rather than by literal, mirroring6efc14c: the local part stays in code, the domain comes fromemaildomain.Canonical().Everything else matching
hoganlovellsin the tree is deliberate alias handling (internal/emaildomain, the sign-in whitelist,cmd/canonicalize-emails) or prose.Gate
scripts/ci-test-gate.shgreen under-raceover./internal/... ./cmd/... ./pkg/... ./scripts/...(vet clean, 0 new failures, 0 tolerated).check-gofmt.shrc=0.bun test441 pass.bun run buildclean. No migration. Harness only — prod was read, never written.Unrelated, for whoever touches it next:
bun run buildregeneratesfrontend/src/i18n-keys.tsone line smaller on current main —deadlines.adjusted.vacationhas no literal any more. Pre-existing drift, left out of this commit deliberately.Not closing — that is m's call.