oficina / memoria Public

Answer the review (Claude Fable 5.1); estilo 846b397

- estilo's busy.js now holds only a submit with a spinner showing
  (rastrillo discussion 51), so script submits no longer stall.
- Scripts that submit on the visitor's behalf pass the form's button, so
  it shows the spinner (Calendar quick-add, Sheets file drop).
- Slides' presenter Next/Previous/Blackout opt out (data-busy="false"):
  a live talk wants those instant. Memoria's old vendoring tool no longer
  writes rastrillo.js, which would bring the old busy rule back.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paul Campbell pushed by paul@keymail.dev 807986c308b5d4c762d771181850ffd80dc99bd9 parent c5e0a57
4 files changed, +16 −6
  • go.mod +1 −1
  • go.sum +2 −0
  • internal/memoria/static/busy.js +7 −2
  • tools/vendorassets/main.go +6 −3

CI passed — run details

CI log
=== vet ===
go vet ./...
go: downloading amadan.net/oficina/estilo.git v0.0.0-20260929165053-846b39772f3c
=== fmt ===
=== test ===
go test ./...
?   	amadan.net/oficina/memoria/cmd/memoria	[no test files]
ok  	amadan.net/oficina/memoria/internal/memoria	3.393s
ok  	amadan.net/oficina/memoria/internal/memoria/chunk	(cached)
ok  	amadan.net/oficina/memoria/internal/memoria/fact	(cached)
?   	amadan.net/oficina/memoria/internal/memoria/icons	[no test files]
ok  	amadan.net/oficina/memoria/internal/memoria/index	(cached)
ok  	amadan.net/oficina/memoria/internal/memoria/notion	(cached)
ok  	amadan.net/oficina/memoria/internal/memoria/provider	(cached)
ok  	amadan.net/oficina/memoria/internal/memoria/query	(cached)
ok  	amadan.net/oficina/memoria/internal/memoria/seal	(cached)
ok  	amadan.net/oficina/memoria/internal/memoria/sibling	(cached)
ok  	amadan.net/oficina/memoria/internal/memoriatest	1.656s
?   	amadan.net/oficina/memoria/scripts/writeestilo	[no test files]
?   	amadan.net/oficina/memoria/tools/bench	[no test files]
?   	amadan.net/oficina/memoria/tools/drive	[no test files]
?   	amadan.net/oficina/memoria/tools/seed	[no test files]
?   	amadan.net/oficina/memoria/tools/vendorassets	[no test files]
=== migration-check ===
go run github.com/carlosframework/rastrillo/cmd/rastrillo migration check
rastrillo migration check: models and migrations agree
diff --git a/go.mod b/go.mod
index 965f625..6998b6e 100644
--- a/go.mod
+++ b/go.mod
@@ -5,7 +5,7 @@ go 1.26
toolchain go1.26.5
require (
- amadan.net/oficina/estilo.git v0.0.0-20260929095838-0994675f496e
+ amadan.net/oficina/estilo.git v0.0.0-20260929165053-846b39772f3c
amadan.net/oficina/home/connect v0.0.0-20260910000424-5b8d8410775f
amadan.net/oficina/home/handoff v0.0.0-20260908102137-481d2d57f489
amadan.net/oficina/suite v0.0.0-20260905215529-60b01a8a0d6d
diff --git a/go.sum b/go.sum
index 0d46593..df349a7 100644
--- a/go.sum
+++ b/go.sum
@@ -6,6 +6,8 @@ amadan.net/oficina/estilo.git v0.0.0-20260929095046-d0664ee49914 h1:V0AyxXYCxqGZ
amadan.net/oficina/estilo.git v0.0.0-20260929095046-d0664ee49914/go.mod h1:4u0jNBtIdMLOsJyrScfqoEuYDJF7BBM3qM9YWbzt6aw=
amadan.net/oficina/estilo.git v0.0.0-20260929095838-0994675f496e h1:LTSmIWUS8RjPb6m94Ynf7moyFYeBXr08rdOr3nmNqvg=
amadan.net/oficina/estilo.git v0.0.0-20260929095838-0994675f496e/go.mod h1:4u0jNBtIdMLOsJyrScfqoEuYDJF7BBM3qM9YWbzt6aw=
+amadan.net/oficina/estilo.git v0.0.0-20260929165053-846b39772f3c h1:YYocIz3r3b4oIA0K/58JkSsmyTOCzMT/2GaW/MFbbPo=
+amadan.net/oficina/estilo.git v0.0.0-20260929165053-846b39772f3c/go.mod h1:4u0jNBtIdMLOsJyrScfqoEuYDJF7BBM3qM9YWbzt6aw=
amadan.net/oficina/home/connect v0.0.0-20260910000424-5b8d8410775f h1:lkw3tjzHfZxe74pNfo+tGDz4mkZLg+D6R+FTkmsym6M=
amadan.net/oficina/home/connect v0.0.0-20260910000424-5b8d8410775f/go.mod h1:YroavXe43Wietec+po8mtSk4a9Bir2h31Q3iAf4MWxI=
amadan.net/oficina/home/handoff v0.0.0-20260908102137-481d2d57f489 h1:RPKtyry/71i06o8L+gjAaUyexbmG56kO1YPs601URAM=
diff --git a/internal/memoria/static/busy.js b/internal/memoria/static/busy.js
index 5d0a9f8..550a843 100644
--- a/internal/memoria/static/busy.js
+++ b/internal/memoria/static/busy.js
@@ -166,7 +166,7 @@
// back); so does the guard's own refusal of a second submit. Only a
// submit nobody else stopped is held, and only if the busy rule armed
// it (aria-busy on the form: not opted out, not a dialog, not a new
- // window).
+ // window) and a button is showing the spinner.
var held = new WeakSet(); // submit events this listener cancelled
var pending = new Map(); // form -> timer, for a hold still running
var releasing = null; // the form whose held submit is going now
@@ -175,9 +175,14 @@
if (!form || form.tagName !== "FORM") return;
if (form === releasing) { releasing = null; return; }
if (e.defaultPrevented || form.getAttribute("aria-busy") !== "true") return;
+ // Only a submit with a spinner to show is held: the hold is for the
+ // spinner. A script's requestSubmit() with no submitter, or a button
+ // that opted out, has nothing on screen to keep up, and holding it
+ // would only be a silent 650ms stall. The form is still guarded.
+ var btn = e.submitter || null;
+ if (!btn || btn.getAttribute("aria-busy") !== "true") return;
e.preventDefault();
held.add(e);
- var btn = e.submitter || null;
pending.set(form, setTimeout(function () { release(form, btn); }, HOLD_MS));
});
diff --git a/tools/vendorassets/main.go b/tools/vendorassets/main.go
index 053590e..ca17873 100644
--- a/tools/vendorassets/main.go
+++ b/tools/vendorassets/main.go
@@ -2,6 +2,10 @@
// This is what `rastrillo doctor --fix` does; the CLI installed on this
// machine predates v0.22.0 and has no doctor, so we do it from the
// linked library instead — which is the same source the pin test reads.
+//
+// Not rastrillo.js: that file comes from estilo's busy package, via
+// scripts/writeestilo, without the old busy rule. The one in this library
+// still has it, and the two rules together cancel every submit.
package main
import (
@@ -15,9 +19,8 @@ import (
func main() {
dir := filepath.Join("internal", "memoria", "static")
for name, body := range map[string][]byte{
- "tokens.css": ui.TokensCSS(),
- "rastrillo.js": ui.ShimJS(),
- "select.js": ui.SelectJS(),
+ "tokens.css": ui.TokensCSS(),
+ "select.js": ui.SelectJS(),
} {
if err := os.WriteFile(filepath.Join(dir, name), body, 0o644); err != nil {
log.Fatalf("write %s: %v", name, err)