oficina / meet Public

docs: slice 1 strings for copy review; AGENTS.md notes

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Paul Campbell pushed by paul@keymail.dev 82cbc1c87c2f6eb597357cbf0aee416fb7d43856 parent 47c19f3
2 files changed, +114 −0
  • AGENTS.md +9 −0
  • docs/superpowers/copy/2026-09-08-slice-1-strings.md +105 −0

CI passed — run details

diff --git a/AGENTS.md b/AGENTS.md
index 2f1e946..6bd07ef 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -19,6 +19,15 @@ mechanically.
takes that one screen over, by existence.
- `gen/` — generated when manifests are used; never edit. Regenerate
with `rastrillo generate`.
+- `internal/meet/seal/` — the app's only encryption surface. A title
+ is sealed by the store and opened by the store; no handler holds a
+ plaintext title it did not get from `store.title`. An outsider's
+ address is stored only as a keyed fingerprint.
+- `internal/meet/store.go` — every database access. `standing.go` is
+ the entry authority (spec §2.3), computed per request, never stored.
+- Sign-in: `auth.go` is Docs' shape with the pending-join exception of
+ spec §3.2 and Slides' same-answer wrapper. Every answer from
+ `POST /signin` is `303 /signin?sent=1`.
## Rules the family holds hard
diff --git a/docs/superpowers/copy/2026-09-08-slice-1-strings.md b/docs/superpowers/copy/2026-09-08-slice-1-strings.md
new file mode 100644
index 0000000..b5c2373
--- /dev/null
+++ b/docs/superpowers/copy/2026-09-08-slice-1-strings.md
@@ -0,0 +1,105 @@
+# Slice 1 copy list
+
+Drafts, pending copy review per spec §10; the review is one sitting
+for the slice before merge.
+
+## Sign in (`/signin`)
+
+| String | Where |
+| --- | --- |
+| Sign in | `templates/signin.html`, `title` block |
+| Sign in to Meet | `templates/signin.html`, `content` block, page-header Title |
+| If that address can sign in here, a link is on its way. Open it on this device to continue. | `templates/signin.html`, `content` block, sent notice |
+| Email address | `templates/signin.html`, `content` block, field Label |
+| Send me a sign-in link | `templates/signin.html`, `content` block, submit button |
+| That does not look like an email address. | `auth.go`, `signin` (`err=address`) |
+| Too many sign-in attempts just now. Wait a few minutes and try again. | `auth.go`, `signin` (`err=rate`) |
+| That sign-in link has expired. Ask for a new one. | `auth.go`, `signin` (`err=expired`) |
+| Sign-in did not work. Try again. | `auth.go`, `signin` (default `err`) |
+
+## Welcome (`/welcome`)
+
+| String | Where |
+| --- | --- |
+| Signed in | `templates/welcome.html`, `title` block |
+| You're signed in | `templates/welcome.html`, `content` block, page-header Title |
+| You're signed in as {{.Email}}. This team's Meet has no meetings for you. If someone sent you a meeting link, open it again now. | `templates/welcome.html`, `content` block |
+| Sign out | `templates/welcome.html`, `content` block, submit button |
+
+## Meetings list (`/`)
+
+| String | Where |
+| --- | --- |
+| Meetings | `templates/index.html`, `title` block and page-header Title |
+| New meeting | `templates/index.html`, `content` block, `h2` |
+| Title | `templates/index.html`, `content` block, field Label |
+| Starts (%s), or leave blank to start now | `templates/index.html`, `content` block, field Label (`%s` is the instance zone, e.g. "Europe/Dublin") |
+| Enter the start as a date and time, or leave it blank to start now. | `handlers_meetings.go`, `parseStart` |
+| Give the meeting a title. | `handlers_meetings.go`, `createMeeting` |
+| Keep the title under 200 characters. | `handlers_meetings.go`, `createMeeting` |
+| Create meeting | `templates/index.html`, `content` block, submit button |
+| Upcoming | `templates/index.html`, `content` block, `h2` |
+| No meetings yet. Make one above and share its link. | `templates/index.html`, `content` block, empty-state Body |
+| Starts {{.Starts}} | `templates/index.html`, `content` block, upcoming row (when the meeting has a start time) |
+| Starts now | `templates/index.html`, `content` block, upcoming row (when the meeting has no start time) |
+| · no live link | `templates/index.html`, `content` block, upcoming row (when the meeting's link was revoked and not replaced) |
+| Replace the link | `templates/index.html`, `content` block, upcoming row action link |
+| End | `templates/index.html`, `content` block, upcoming row action link |
+| Ended meetings ({{len .Ended}}) | `templates/index.html`, `content` block, `details summary` |
+| Ended | `templates/index.html`, `content` block, ended row |
+
+## Link shown once (`/meetings`, `/meetings/{sqid}/links`)
+
+| String | Where |
+| --- | --- |
+| Your meeting link | `templates/link_once.html`, `title` block |
+| Meetings | `templates/link_once.html`, `content` block, back-nav Label |
+| {{.Title}} | `templates/link_once.html`, `content` block, page-header Title (the meeting's own title) |
+| Starts {{.Starts}}. | `templates/link_once.html`, `content` block (when the meeting has a start time) |
+| The old link has stopped working. | `templates/link_once.html`, `content` block (only when the link was replaced) |
+| This is the only time this link is shown. Copy it now and send it to the people you are meeting. | `templates/link_once.html`, `content` block |
+| Meeting link | `templates/link_once.html`, `content` block, link input aria-label |
+| Go to the meeting | `templates/link_once.html`, `content` block, link button |
+
+## Confirm: replace the link (`/meetings/{sqid}/links/replace`)
+
+| String | Where |
+| --- | --- |
+| Replace the link? | `handlers_meetings.go`, `confirmReplaceLink` (rendered as `title` block and page-header Title via `templates/confirm.html`) |
+| Meetings | `templates/confirm.html`, `content` block, back-nav Label |
+| Everyone holding the current link for "{{title}}" will get a not-found page. You will see the new link once. | `handlers_meetings.go`, `confirmReplaceLink` (rendered as the confirm Body) |
+| Replace the link | `handlers_meetings.go`, `confirmReplaceLink` (confirm-form Label) |
+| Cancel | `templates/confirm.html`, `content` block, confirm-form CancelLabel |
+
+## Confirm: end the meeting (`/meetings/{sqid}/end` GET)
+
+| String | Where |
+| --- | --- |
+| End the meeting? | `handlers_meetings.go`, `confirmEnd` (rendered as `title` block and page-header Title via `templates/confirm.html`) |
+| Meetings | `templates/confirm.html`, `content` block, back-nav Label |
+| "{{title}}" will close for everyone and its link will stop working. | `handlers_meetings.go`, `confirmEnd` (rendered as the confirm Body) |
+| End the meeting | `handlers_meetings.go`, `confirmEnd` (confirm-form Label) |
+| Cancel | `templates/confirm.html`, `content` block, confirm-form CancelLabel |
+
+## Holding page (`/m/{sqid}/join`)
+
+| String | Where |
+| --- | --- |
+| {{.Title}} | `templates/join.html`, `title` block and page-header Title (the meeting's own title) |
+| Meetings | `templates/join.html`, `content` block, back-nav Label (members only) |
+| Starts {{.Starts}}. | `templates/join.html`, `content` block (when the meeting has a start time) |
+| You are {{.Name}}, joining as a {{.Standing}}. | `templates/join.html`, `content` block (`{{.Standing}}` is "member" or "guest", from `standing.go`, `Standing.String`) |
+| This team's Meet has no relay yet. Calls usually connect only between people on the same network. | `templates/join.html`, `content` block (the floor notice; shown only when no relay is configured) |
+| The call itself is the next slice of this app. When it lands, this page will show your camera preview, device pickers and a join button, and needs JavaScript for that part only; everything else here works without it. | `templates/join.html`, `content` block |
+| End the meeting | `templates/join.html`, `content` block, member-only link |
+
+## Error page (`/errors`, and any handler's `ErrorPage`)
+
+`templates/errors.html` now renders rastrillo's shared `error-page`
+partial (`{{template "error-page" dict "Status" .Status "Ref" .Ref}}`).
+The status, body sentence, and link labels it renders are rastrillo's
+copy, not Meet's, so they are not listed here.
+
+| String | Where |
+| --- | --- |
+| Something went wrong | `templates/errors.html`, `title` block (the browser tab title; the partial does not override it) |