carlos / platform Public

settings-2 task 1: internal/updatewords, the draft strings for the settings plans

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 75aae424966f7e462d9e7e213fbd0c060c429d6d parent 8d33cef
3 files changed, +142 −0
  • internal/updatewords/words.go +50 −0
  • internal/updatewords/words_authorize.go +46 −0
  • internal/updatewords/words_test.go +46 −0
diff --git a/internal/updatewords/words.go b/internal/updatewords/words.go
new file mode 100644
index 000000000..7f9d5d576
--- /dev/null
+++ b/internal/updatewords/words.go
@@ -0,0 +1,50 @@
+// Package updatewords holds every member-facing string the instance update
+// settings plans add (plans 2 to 5), as drafts with an ID and a context. The
+// copy review (plan 5, Task 1) exports All(), Paul rewrites them, and the
+// approved text replaces each Text; a test then pins them to the approved
+// record. Code reads a string only through Text, so a reviewed string has one
+// home. Each plan adds its own words_*.go file, so parallel branches never
+// edit the same lines.
+package updatewords
+
+import (
+ "fmt"
+ "sort"
+)
+
+// Draft is one string: Context says where it appears and what it does, for
+// the reviewer who cannot see the screen.
+type Draft struct{ ID, Text, Context string }
+
+var drafts = map[string]Draft{}
+
+// add registers drafts from a file's init. A duplicate ID is a programming
+// error and panics at start-up, never at the moment a member reads it.
+func add(ds ...Draft) {
+ for _, d := range ds {
+ if _, dup := drafts[d.ID]; dup {
+ panic(fmt.Sprintf("updatewords: duplicate id %s", d.ID))
+ }
+ drafts[d.ID] = d
+ }
+}
+
+// Text is the string for id. An unknown id panics: it can only be a typo in
+// code, which the package's tests catch.
+func Text(id string) string {
+ d, ok := drafts[id]
+ if !ok {
+ panic(fmt.Sprintf("updatewords: unknown id %s", id))
+ }
+ return d.Text
+}
+
+// All is every draft, sorted by ID.
+func All() []Draft {
+ out := make([]Draft, 0, len(drafts))
+ for _, d := range drafts {
+ out = append(out, d)
+ }
+ sort.Slice(out, func(i, j int) bool { return out[i].ID < out[j].ID })
+ return out
+}
diff --git a/internal/updatewords/words_authorize.go b/internal/updatewords/words_authorize.go
new file mode 100644
index 000000000..e1daacab9
--- /dev/null
+++ b/internal/updatewords/words_authorize.go
@@ -0,0 +1,46 @@
+package updatewords
+
+func init() {
+ // TODO-COPY: drafts awaiting Paul's copy review (copy-review/strings.json).
+ add(
+ Draft{ID: "settings.evidence.no-record",
+ Text: "no promotion record: authorize it or pick a newer build",
+ Context: "Why a pin, an install request or a recovery onto an older build was refused: the build was promoted before promotion records existed, or never promoted. Shown in carlos instances list, on the instance page, and returned by the console when a pin is set."},
+ Draft{ID: "settings.authorize.intro",
+ Text: "Authorize %s %s with this manifest:",
+ Context: "First line of carlos releases authorize, above the digests. App and version."},
+ Draft{ID: "settings.authorize.manifest-row",
+ Text: " manifest %s",
+ Context: "The manifest's sha256, the one digest the signed record will carry."},
+ Draft{ID: "settings.authorize.artifact-row",
+ Text: " %s %s",
+ Context: "One line per file of the build: its platform (or site) and its sha256, so the person can check them against what they built."},
+ Draft{ID: "settings.authorize.prompt",
+ Text: "Sign a promotion record for exactly these bytes? Type yes to continue: ",
+ Context: "Asked after the digests. Anything but yes signs nothing. --yes skips it."},
+ Draft{ID: "settings.authorize.done",
+ Text: "authorized %s %s: it can now be pinned and recovered on any box",
+ Context: "Printed after a record is signed. App and version."},
+ Draft{ID: "settings.authorize.already",
+ Text: "%s %s already has a promotion record for these bytes; nothing to sign",
+ Context: "Printed when the build already has a record with the same digest."},
+ Draft{ID: "settings.authorize.aborted",
+ Text: "nothing signed",
+ Context: "Printed when the person did not type yes."},
+ Draft{ID: "settings.authorize.changed",
+ Text: "the manifest of %s changed since it was shown. Nothing was signed. Run the command again",
+ Context: "Returned when someone reshipped the version name between showing the digests and the confirmation. %s is the version."},
+ Draft{ID: "settings.authorize.root-only",
+ Text: "authorizing a build needs the deployment's root key. A scoped key cannot do it",
+ Context: "Returned by carlos releases authorize against a bucket directly with a scoped CARLOS_RELEASE_KEY."},
+ Draft{ID: "settings.authorize.not-shipped",
+ Text: "%s has not been shipped, or its manifest cannot be read",
+ Context: "Returned when the version named does not exist. %s is the version."},
+ Draft{ID: "settings.authorize.no-key",
+ Text: "this console has no release key, so it cannot sign a promotion record",
+ Context: "Returned by the console's authorize door when the console was started without the deployment's release key. Shown by carlos releases authorize."},
+ Draft{ID: "settings.authorize.write-failed",
+ Text: "could not write the promotion record. Nothing was signed. Try again",
+ Context: "Returned by the console's authorize door when the bucket refused the record write. Shown by carlos releases authorize."},
+ )
+}
diff --git a/internal/updatewords/words_test.go b/internal/updatewords/words_test.go
new file mode 100644
index 000000000..0d452269e
--- /dev/null
+++ b/internal/updatewords/words_test.go
@@ -0,0 +1,46 @@
+package updatewords
+
+import (
+ "sort"
+ "strings"
+ "testing"
+)
+
+func TestDraftsAreWellFormed(t *testing.T) {
+ all := All()
+ if len(all) == 0 {
+ t.Fatal("no drafts registered")
+ }
+ if !sort.SliceIsSorted(all, func(i, j int) bool { return all[i].ID < all[j].ID }) {
+ t.Fatal("All is not sorted by ID")
+ }
+ for _, d := range all {
+ if !strings.HasPrefix(d.ID, "settings.") || d.Text == "" || d.Context == "" {
+ t.Errorf("%q: every draft needs a settings.* ID, a text and a context", d.ID)
+ }
+ if strings.ContainsRune(d.Text, '—') {
+ t.Errorf("%s: no em dashes in member-facing text", d.ID)
+ }
+ if Text(d.ID) != d.Text {
+ t.Errorf("%s: Text disagrees with All", d.ID)
+ }
+ }
+}
+
+func TestUnknownIDPanics(t *testing.T) {
+ defer func() {
+ if recover() == nil {
+ t.Fatal("an unknown ID did not panic")
+ }
+ }()
+ Text("settings.no.such.string")
+}
+
+func TestDuplicateIDPanics(t *testing.T) {
+ defer func() {
+ if recover() == nil {
+ t.Fatal("a duplicate ID did not panic")
+ }
+ }()
+ add(Draft{ID: "settings.authorize.done", Text: "x", Context: "y"})
+}