Submission generator — unified auto-naming scheme (date · initiator · …) + customizable #155
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?
Request (m, 2026-05-28 00:37)
Shape
<date> <initiator> <…>— date leads, then the initiator (party filing? lawyer drafting? case reference?), then the rest.Today's state
Auto-naming logic likely lives in
internal/services/submission_draft_service.goorsubmission_base_service.go(whatever fills the default title on a freshly-created draft). Quick audit needed to confirm current pattern and where the format string lives.Decisions to lock before implementing (worth a quick m grilling)
YYYY-MM-DD(sortable, ISO) orDD.MM.YYYY(German conventional)?·/—/-/_?{{.Date}} {{.Initiator}} {{.Caseref}}) — flexible but lawyer-unfriendly%date% %initiator% %caseref%) — friendlier, less powerAcceptance (high level)
<date> <initiator>per m's briefNOT
This is already built. Both asks shipped in t-paliad-352 and t-paliad-356 (slices 2–5); the issue simply has no comment saying so. No code was written for this pass — there is no commit link because there is nothing to commit, and adding a third generator would have been the wrong move.
1. One engine, not two disagreeing generators
This was the thing worth checking, and the answer is the opposite of what was expected.
pkg/nomencomposes names from ordered segments (variable, separator, wrapping, and a per-segment missing-value policy).internal/services/namegen.goregisters exactly two artifacts:submission_draft_title—date · client · forum · opponent · keyworddate · keyword · (case_number)They do not disagree about how a name is built: both render through the same engine, with the same precedence — user override → firm override → system default. There is no second generator to unify.
2. Customizable in two of the three places; per-template is genuinely absent
GET/PUT/DELETE /api/me/name-compositionsplus a livePOST …/preview. Stored inpaliad.users.name_compositions./api/admin/name-compositionsbehind the admin gate, backed bypaliad.firm_name_compositions.firm_name_compositionsis keyed by artifact, not by template, so per-template would be a third scope rather than a row in the existing table.One line worth having before deciding anything:
firm_name_compositionshas zero rows after two months. A surface that is built, reachable and never used is a different finding from one that was never wired — it may mean nobody needs a firm default, rather than that it is missing.3. Date first, and it has held since 2026-06-02
Measured on prod: 33 drafts — 20 date-first, 13 starting
Entwurf N. The cut is clean. EveryEntwurf Ndraft was created between 2026-05-25 and 2026-06-01; every draft from 2026-06-02 onwards is date-first. The 13 are legacy rows, not a live gap. One user has a personal override.The decision that needs you first
The two artifacts disagree about a missing value, and the filename is the one that got it right.
case_numberusesPlaceholder("TBD"), so a missing docket renders visibly as(TBD).Omit— a missing client, forum or opponent vanishes along with its separator.So a project with no opponent renders
2026-05-31 Bayer AG ./. UPC. That looks like a complete, deliberate name — and it looks identical whether the opponent is genuinely not recorded yet or exists and failed to resolve. Nothing distinguishes the two.The engine already implements
PlaceholderandLiteral, and the filename artifact already uses one. This is a policy choice, not a missing capability. It changes every future draft title, so it is being left exactly as it is until you decide.Two smaller ones, if you are deciding anyway
"The initiator" has three readings and only one is wired.
clientsegment, the root ancestor of the project tree. Note this is not "the party filing": we file only when we act for the proactive party, whichproject.our_sidecarries.user.display_nameexists in the submission variable bag — a different catalog — so it would need adding.case_number, not in the title catalog.All three are reachable, two need a catalog entry, and they produce visibly different names.
Whether the firm-wide surface should carry a default at all, given the zero rows above.
Not closing — only m closes issues.
Gemessen, nicht geraten — und das meiste war schon da
Branch
mai/hades/issue-155-naming, zwei Commits:docs/findings-submission-naming-155-2026-07-30.mdDie drei Fragen aus dem Issue, beantwortet aus dem Code
1. Wie viele Stellen erzeugen einen Namen? Ein Trichter, zwei Artefakte.
Drei HTTP-Pfade liefern ein
.docxaus. Alle drei rufensubmissionDownloadFilename. Es gibt keinen zweiten Generator zu vereinheitlichen.Der Entwurfstitel ist ein zweiter Name für eine zweite Sache. Beide laufen über dieselbe Engine (
pkg/nomen).2. Was ist der "Initiator"? Schon entschieden — das Identitäts-Trio.
Geliefert mit t-paliad-352:
<Datum> <Mandant> ./. <Forum> ./. <Gegner>. Das ist genau das Trio, das du selbst genannt hast ("CLIENTNAME / UPC / OPPONENTNAME").Gemessener Render, Systemvorgabe, nichts aufgelöst:
Eckige Klammern — die Familie spricht schon die Konvention aus #162.
3. Wo gehört "anpassbar" hin? Schon gebaut, auf vier Ebenen.
paliad.firm_name_compositionspasst — es ist die Firmen-Ebene einer Kette, die es bereits gibt. Kein zweiter Mechanismus nötig:composer_meta.name_overridesusers.name_compositions(mig 160)/einstellungen, Token-Feld + Palette + Live-Vorschaufirm_name_compositions(mig 162)/api/admin/name-compositions, Admin-gateddocs/plans/prd-filename-generator-2026-06-01.mdist die Antwort auf dieses Issue. Alle fünf Slices sind gelandet.Was wirklich gefehlt hat
Der
.docx-Dateiname konnte den Initiator gar nicht benennen.Sein Katalog kannte nur
date,keyword,case_number. Die Engine hat das gewünschte Schema schlicht abgelehnt:Eine Firma konnte also die Einstellungsseite öffnen, die genau dafür gebaut wurde, und
<Datum> <Mandant> ./. <Gegner>trotzdem nicht auf den Dateinamen legen.Was der Branch ändert
clientim Titel etwas anderes hieße als im Dateinamen, könnte eine Konvention nicht über beide tragen.Artifact.ExtraMissing. Jede Variable, die ein Artefakt anbietet, braucht eine Antwort auf "und wenn sie leer ist" — nicht nur die, die seine Vorgabe zufällig benutzt. Sonst würde ein einkomponierterclientstill verschwinden: ein Dateiname, der sich perfekt liest und die Partei nicht enthält, nach der er benannt ist.Markiert wird mit dem
TBDdieses Artefakts, nicht mit dem eckigen Label des Titels. Das Label ist sprachabhängig, und eine gespeicherte Komposition darf keine Sprache in die Renders der anderen einfrieren — genau der Fehler, den dieses Artefakt schon einmal hatte ("Az. folgt" im englischen UI).Die Einstellungsseite brauchte keine Änderung
Die Palette wird aus dem Katalog gebaut, die Reihenfolge kannte alle sechs Variablen schon, und die Vorschau liefert bereits Beispielwerte für Mandant/Forum/Gegner. Die drei Chips erscheinen von selbst. Das Design hat das vorgesehen — es fehlte nur der Katalog-Eintrag.
Eine Frage bleibt für dich
Soll die Vorgabe für den Dateinamen künftig mit dem Initiator führen?
Heute, und auch nach diesem Branch:
Möglich, seit das Vokabular existiert:
Ich habe das nicht entschieden, aus zwei Gründen:
Wer es will, kann es heute schon firmenweit unter
/adminsetzen, ohne Deploy. Das ist das Argument, die Vorgabe zu lassen. Deine Antwort entscheidet, ob das so bleibt.Nicht gemacht
Geprüft
Harness auf Port 15489.
scripts/ci-test-gate.shgrün (0 known-failing toleriert),make check-gofmtsauber, 426 Frontend-Tests,go vetsauber,-racegrün. Branch nicht hinterorigin/main. Keine Migration nötig.Ein Befund am Rande: vier Tests benutzten
clientbzw.opponentals ihr Beispiel für eine unbekannte Variable — weil sie fehlten. Zwei davon laufen nur gegen die Live-DB und wären ohne den vollen Gate nicht aufgefallen. Sie benutzen jetzt ein Unsinnswort, und ein positiver Fall prüft, dass das Trio gültig ist.m's Antwort (2026-07-30): Vorgabe bleibt, Firmen wählen es selbst
Der Standard-Dateiname ändert sich nicht. Wer den Initiator auf der Datei will, stellt ihn firmenweit unter
/adminein.m's Gründe waren die beiden aus der Frage: der Name des Gegners reist über Betreffzeilen und Anhangslisten, und ein Aktenordner trüge sonst zwei Konventionen nebeneinander.
Damit ist der gebaute Teil die ganze Lieferung, nicht die Hälfte. Vorher bot die Einstellungsseite eine Anpassung an, die die Engine ablehnte —
Validategabnomen: unknown variable: clientzurück, eine Firma konnte den Initiator also konfigurieren und trotzdem nicht bekommen. Das Opt-in funktioniert jetzt, und kein vorhandener Dateiname ändert sich.Erstes Branch merged nach main:
bf3dd6f.Nachtrag für die nächste Person in
pkg/nomenEin Negativ-Test, dessen Fixture "etwas, das es nicht gibt" ist, hört auf zu testen, sobald es das gibt — und zwar still.
Vier Tests hier benutzten
clientbzw.opponentals ihr Beispiel für eine unbekannte Variable, gerade weil diese Schlüssel im Dateinamen-Katalog fehlten. Als die Schlüssel dazukamen, prüften alle vier nichts mehr: die Behauptung lautet "das wird abgelehnt", und ein jetzt gültiger Wert wird eben nicht abgelehnt.Zwei der vier laufen nur gegen eine Live-Datenbank.
go test -shortblieb grün; nur der volle Gate hat es gemeldet.Das Fixture heisst jetzt
unknownNameVar(internal/services/name_composition_spec_test.go) und trägt die Regel: es muss ein Unsinnswort bleiben, nie eine echte Variable, die zufällig gerade in einem Katalog fehlt. Wer ein Vokabular erweitert, sucht die Tests nach den hinzugefügten Wörtern ab.Folge-Commit:
mai/hades/issue-155-followup— nur Tests und Doku, keine Verhaltensänderung. Gate grün (0 known-failing toleriert),check-gofmtsauber, 441 Frontend-Tests.Die vollständige Messung samt m's Entscheidung steht in
docs/findings-submission-naming-155-2026-07-30.md.