chore: replace em dashes with hyphens, add no-em-dash rule to CLAUDE.md

This commit is contained in:
2026-09-10 09:18:58 +00:00
parent 759d36e85d
commit 059949674d
31 changed files with 65 additions and 61 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"time"
)
// SendLicense delivers the blob inline. It is signed public data, not a secret
// SendLicense delivers the blob inline. It is signed public data, not a secret -
// it is useless on any instance other than the one it names.
func (s Sender) SendLicense(to, instanceName, blob string) error {
return s.sendTemplate(to, "", "license", struct {
+1 -1
View File
@@ -90,7 +90,7 @@ func normaliseText(s string) string {
}
// funcs are shared by both template flavours. They exist so that a message
// template never formats a date or builds a structure itself two templates
// template never formats a date or builds a structure itself - two templates
// formatting the same date two ways is exactly the drift this package removes.
var funcs = map[string]any{
// dict builds a map for the layout's helper templates, which take more
+3 -3
View File
@@ -3,7 +3,7 @@
// It owns three things that used to exist in three copies: the SMTP
// conversation (including the 465-implicit-TLS case that net/smtp gets wrong),
// the RFC 5322 envelope, and the rendered look of a Vantage email. Callers see
// only typed Send* methods nobody outside this package builds a subject line,
// only typed Send* methods - nobody outside this package builds a subject line,
// a MIME part or a colour.
package mail
@@ -24,7 +24,7 @@ import (
// timeout bounds the whole SMTP conversation. Without it a mail server that
// accepts the connection and then stalls holds an HTTP request open until the
// client gives up and admin's signup rollback runs on that request's context.
// client gives up - and admin's signup rollback runs on that request's context.
const timeout = 15 * time.Second
// Sender is a configured SMTP destination. It is a value, not a singleton:
@@ -92,7 +92,7 @@ func (s Sender) sendTemplate(to, replyTo, name string, data any) error {
// Port 465 is implicit TLS: the server expects a TLS handshake immediately, so
// the connection is wrapped BEFORE any SMTP is spoken. Every other port gets
// plaintext then STARTTLS if offered. net/smtp.SendMail only does the latter,
// which is why it fails against a 465 mail server that bug silently stopped
// which is why it fails against a 465 mail server - that bug silently stopped
// every admin email from being delivered once already.
func (s Sender) send(m message) error {
if !s.Enabled() {
+1 -1
View File
@@ -3,5 +3,5 @@
{{template "lead" (printf "You have been invited to join %s on Vantage." .AccountName)}}
{{template "p" "Set your own password and finish joining:"}}
{{template "button" (dict "label" "Set password and join" "url" .Link)}}
{{template "p" "This link expires in 24 hours. If you were not expecting this, ignore it nothing happens until you open the link."}}
{{template "p" "This link expires in 24 hours. If you were not expecting this, ignore it - nothing happens until you open the link."}}
{{end}}
+1 -1
View File
@@ -4,5 +4,5 @@
{{template "lead" (printf "You have been invited to join %s on Vantage." .AccountName)}}
{{template "p" "Set your own password and finish joining:"}}
{{template "button" (dict "label" "Set password and join" "url" .Link)}}
{{template "p" "This link expires in 24 hours. If you were not expecting this, ignore it nothing happens until you open the link."}}
{{template "p" "This link expires in 24 hours. If you were not expecting this, ignore it - nothing happens until you open the link."}}
{{end}}
+3 -3
View File
@@ -3,7 +3,7 @@
Every colour in the email system lives in this file and nowhere else, in the
same way no component in web/, site/ or adminsite/ carries a hex. The values
are web/app/globals.css's tokens an email is read before the recipient
are web/app/globals.css's tokens - an email is read before the recipient
clicks through to the control plane, so the two should not look like
different products. They are written as literal hex here because email
clients support neither var() nor a reliable prefers-color-scheme, so the
@@ -18,7 +18,7 @@
--ink-3 #71879f --well #04101f
Layout is tables and inline styles throughout, which is not a stylistic
choice it is the only thing Outlook renders predictably.
choice - it is the only thing Outlook renders predictably.
A message file overrides "title", "pill" and "body"; the empty defaults below
exist so that a message needing no pill does not have to define one.
@@ -57,7 +57,7 @@
</p>
{{- end -}}
{{- /* well shows machine output a licence blob, an install ID. Mirrors
{{- /* well shows machine output - a licence blob, an install ID. Mirrors
web/'s --well surface, the floor beneath the ground. */ -}}
{{- define "well" -}}
<pre style="margin:0 0 20px;padding:14px;background:#04101f;border:1px solid #1e3855;border-radius:4px;color:#9fb3ca;font-family:ui-monospace,'Cascadia Mono','SF Mono',Menlo,Consolas,monospace;font-size:12px;line-height:1.5;white-space:pre-wrap;word-break:break-all;">{{.}}</pre>
+1 -1
View File
@@ -1,7 +1,7 @@
{{- /*
The plain-text counterpart of layout.html.tmpl.
It defines the same helper names p, lead, button, well, note, rows, chip
It defines the same helper names - p, lead, button, well, note, rows, chip -
so a message's txt file reads as the same document as its html one, and a
helper added on one side is obvious by its absence on the other.
+1 -1
View File
@@ -3,5 +3,5 @@
{{template "lead" (printf "Your licence for %s is below." .InstanceName)}}
{{template "p" "Paste it into Settings → Licence on your Vantage install:"}}
{{template "well" .Blob}}
{{template "p" "The licence is signed public data, not a secret it is useless on any instance other than the one it names."}}
{{template "p" "The licence is signed public data, not a secret - it is useless on any instance other than the one it names."}}
{{end}}
+1 -1
View File
@@ -4,5 +4,5 @@
{{template "lead" (printf "Your licence for %s is below." .InstanceName)}}
{{template "p" "Paste it into Settings > Licence on your Vantage install:"}}
{{template "well" .Blob}}
{{template "p" "The licence is signed public data, not a secret it is useless on any instance other than the one it names."}}
{{template "p" "The licence is signed public data, not a secret - it is useless on any instance other than the one it names."}}
{{end}}
+1 -1
View File
@@ -2,5 +2,5 @@
{{define "title"}}{{.InstanceName}} is renewed{{end}}
{{define "body"}}
{{template "lead" (printf "Your Free licence for %s now runs until %s." .InstanceName (date .Expires))}}
{{template "p" "Nothing else changes your servers, agents and monitors carry on as they were."}}
{{template "p" "Nothing else changes - your servers, agents and monitors carry on as they were."}}
{{end}}
+1 -1
View File
@@ -3,5 +3,5 @@
{{define "title"}}{{.InstanceName}} is renewed{{end}}
{{define "body"}}
{{template "lead" (printf "Your Free licence for %s now runs until %s." .InstanceName (date .Expires))}}
{{template "p" "Nothing else changes your servers, agents and monitors carry on as they were."}}
{{template "p" "Nothing else changes - your servers, agents and monitors carry on as they were."}}
{{end}}
+1 -1
View File
@@ -3,5 +3,5 @@
{{template "lead" "Confirm this address to finish setting up your Vantage account."}}
{{template "button" (dict "label" "Confirm email address" "url" .Link)}}
{{template "p" (printf "The link works once and expires in %d hours." .TTLHours)}}
{{template "p" "If you did not request this, ignore this email nothing happens until the link is opened."}}
{{template "p" "If you did not request this, ignore this email - nothing happens until the link is opened."}}
{{end}}
+1 -1
View File
@@ -4,5 +4,5 @@
{{template "lead" "Confirm this address to finish setting up your Vantage account."}}
{{template "button" (dict "label" "Confirm email address" "url" .Link)}}
{{template "p" (printf "The link works once and expires in %d hours." .TTLHours)}}
{{template "p" "If you did not request this, ignore this email nothing happens until the link is opened."}}
{{template "p" "If you did not request this, ignore this email - nothing happens until the link is opened."}}
{{end}}
+1 -1
View File
@@ -6,7 +6,7 @@
(dict "k" "Instance" "v" .InstanceName)
(dict "k" "New findings" "v" .Count))}}
{{range .Rows}}
{{if .FixedIn}}{{template "well" (printf "%s (%s) %s on %s, fixed in %s" .CVEID .Severity .PackageName .ServerName .FixedIn)}}{{else}}{{template "well" (printf "%s (%s) %s on %s, no fix published" .CVEID .Severity .PackageName .ServerName)}}{{end}}
{{if .FixedIn}}{{template "well" (printf "%s (%s) - %s on %s, fixed in %s" .CVEID .Severity .PackageName .ServerName .FixedIn)}}{{else}}{{template "well" (printf "%s (%s) - %s on %s, no fix published" .CVEID .Severity .PackageName .ServerName)}}{{end}}
{{end}}
{{if .More}}{{template "p" (printf "…and %d more." .More)}}{{end}}
{{template "note" (printf "Scanned against a vulnerability database pulled %s ago." .DBAge)}}
+1 -1
View File
@@ -4,7 +4,7 @@
{{define "body"}}
{{template "lead" .Summary}}
{{range .Rows}}- {{.CVEID}} ({{.Severity}}) {{.PackageName}} on {{.ServerName}}{{if .FixedIn}}, fixed in {{.FixedIn}}{{else}}, no fix published{{end}}
{{range .Rows}}- {{.CVEID}} ({{.Severity}}) - {{.PackageName}} on {{.ServerName}}{{if .FixedIn}}, fixed in {{.FixedIn}}{{else}}, no fix published{{end}}
{{end}}
{{if .More}}...and {{.More}} more.{{end}}
+2 -2
View File
@@ -10,7 +10,7 @@ type VulnDigestRow struct {
PackageName string
ServerName string
// FixedIn empty means no vendor fix has been published, which the template
// says explicitly rather than leaving blank it is a real state, not
// says explicitly rather than leaving blank - it is a real state, not
// missing data.
FixedIn string
}
@@ -23,7 +23,7 @@ type VulnDigestRow struct {
type VulnDigest struct {
InstanceName string
// Count is every newly opened finding in the batch, which may exceed
// len(Rows) Rows is capped and More carries the remainder.
// len(Rows) - Rows is capped and More carries the remainder.
Count int
TopSeverity string
Summary string