oficina / suite Public

Draft Forms intake and Sheets projection boundary

Paul Campbell pushed by paul@keymail.dev 1bb8bfdb0cbf5012ffb0c157f315725b507fa603 parent 1ac4323
1 file changed, +137 −0
  • docs/superpowers/specs/2026-09-08-forms-intake-boundary.md +137 −0

CI passed — run details

CI log
=== gate ===
ok  	amadan.net/oficina/suite	0.007s
ok  	amadan.net/oficina/suite/conformance	0.004s
diff --git a/docs/superpowers/specs/2026-09-08-forms-intake-boundary.md b/docs/superpowers/specs/2026-09-08-forms-intake-boundary.md
new file mode 100644
index 0000000..17f691a
--- /dev/null
+++ b/docs/superpowers/specs/2026-09-08-forms-intake-boundary.md
@@ -0,0 +1,137 @@
+# Forms intake and Sheets projection: candidate scope
+
+Status: internal execution proposal, not an approved design or a new ruling.
+Author: /root/sheets_track, Codex, 2026-09-08. Independent review pending.
+Scope: overnight queue item 15. No application implementation or repo creation.
+
+## Evidence and ownership
+
+Read suite main 1ac4323a7317a2bf4def3829896d9895a6ddc464 and
+plan/overnight-readiness queue item 15. There is no Forms specification in
+that main tree. No Forms checkout was found in the local Oficina workspace;
+`amadan discuss list oficina/forms` returned not found. That response does not
+establish global absence or exclude a differently named/private repository.
+Root knows no alternate app. Suite discussion 5 records no Forms implementation
+owner. This branch owns only boundary discovery and this proposal.
+
+Sheets main 4aea8f4 has an authenticated editor cell POST at
+`internal/sheets/app.go:233`; `handlers_grid.go:98` requires a person and
+SheetEditor. Its request names arbitrary row/column coordinates. It is not a
+submission-only capability. The approved isolated atomic/watermark candidate
+d35cf94 improves multi-cell atomicity and freshness; it supplies neither durable
+response identity nor append deduplication. Workbook tabs d8fc99f and all-worksheet
+import proposal 55e98af remain separate review candidates, not shipped APIs.
+
+Binding dependencies are citations, not new summaries: suite doctrine at
+1ac4323, rulings 8, 9 and 15, §§4.2–4.3 and §§7–7.3; Sheets design
+2026-08-30 at 4aea8f4, §§4 and 8–9. Any intake actor outside those contracts
+needs an attributed upstream decision. Anonymous/public write authority is not
+inferred from the phrase Forms, a URL token, or the overnight authorization.
+
+## Placement choices to review
+
+A. A Forms area inside the team's Sheets instance. Intake and destination can
+share a transaction and the current content sealer. This avoids a new service
+credential and cross-app provenance protocol, but requires a distinct response
+store and submission authorization; respondents must never receive SheetEditor.
+The same-app choice must specify visibility independently of the linked workbook.
+It must not silently make every response readable by the workbook's audience.
+
+B. A distinct Forms app with its own durable response store and a separately
+authorized Sheets projection. This fits a standalone product, but adds deployment,
+identity, custody, export/deletion and S8 receiving-side integration work. Current
+Sheets editor APIs and suite S1–S3 module are not that implementation. Do not
+simulate it by retaining a person's session or posting as the form creator.
+
+Recommendation for review: evaluate A as the first viable delivery shape, with a
+response-store boundary that can later migrate explicitly; choose B only with an
+owned receiving-side contract. Neither choice is a settled product decision here.
+
+## First substantive implementation candidate after design review
+
+Deliver durable signed-in submission intake with a fixed published schema and a
+recoverable owner-authorized projection into a designated response tab. First
+slice is backend only; authoring, publishing, respondents and response management
+need subsequent reviewed UI and Estilo adoption before product readiness.
+
+Proposed model: form ID, immutable published schema revision, stable field IDs,
+response ID, attributed submitter, acceptance time, sealed typed answers, and a
+projection receipt keyed by response ID and destination. Field labels are content;
+never use their spelling as IDs. Do not store raw answers in logs or receipt keys.
+Draft/schema editing and published-schema switching must be explicit operations.
+
+Accept only the exact published revision, known fields, allowed types and bounded
+sizes; server validation is authoritative. A stale revision must not be silently
+coerced. Store answers as values: formula-looking strings must not enter Sheets'
+formula parser. A string beginning with = stays literal through projection and
+export. Required/choice/length checks belong to the published revision.
+
+Acceptance means the sealed response and its projection work record are committed
+durably. Projected means the receiver committed the complete row and an idempotency
+receipt together. Those states are distinct. A client retry after an ambiguous
+response must return the same receipt for the same response identity and payload;
+a different payload under that identity must fail. Specify the key's scope and
+retention before implementation; do not expire it earlier than retries can recur.
+
+Use stable destination tab/column IDs and a mapping revision. Never select a row
+by reading the last visible row then independently writing cells. Concurrent
+submissions must allocate distinct rows in the receiver's transaction. A lost
+acknowledgment after commit must not append again. Destination/schema drift,
+removed columns, lost grants or deleted destinations leave the durable response
+available to its authorized custodian and projection pending/failed; do not drop
+answers, remap by position, or turn failure into apparent success.
+
+For choice B, projection must meet the cited cross-app write/provenance contract;
+that includes receiver-side authorization and all disclosure paths, not just an
+HTTP bearer accepted by an editor route. For A, authorization checks must cover
+intake and each projection attempt rather than relying on form creation time.
+
+## Decisions and prerequisites the design must close
+
+- Who may author, publish, submit, read responses and export? Define whether a
+ signed-in guest may submit without reading prior responses, and whether that
+ grant exposes any form/team metadata. Preserve existing actor rulings.
+- Who owns response custody? Choose explicit initial visibility, sharing changes,
+ respondent access, and whether linking a workbook changes any authority.
+- Define closed-form behavior, submission limits, per-principal and per-form
+ abuse budgets, body bounds, and durable retry behavior. Numeric limits need
+ reasons and deployment evidence; client IP cannot be assumed trustworthy.
+- Specify exports with field IDs/revisions and typed values; decide spreadsheet
+ formula-injection behavior without silently corrupting canonical answers.
+- Define response deletion versus removing a projected row, form deletion,
+ retention and backup limits, detached copies and revocation behavior. There is
+ no implied automatic purge policy. An unavailable projection cannot authorize
+ deleting the canonical response. No notification should carry answer contents
+ until recipients and disclosure rules are designed.
+- Home assertion/roster integration is needed for suite identity; local admitted
+ accounts can support a scoped development fixture, not a claimed team rollout.
+ New app placement additionally needs owned provisioning, keys, backup/restore,
+ exact process version, CI and a reviewed isolated canary.
+- Tabs and atomic writes help the destination UX/store, but their completion does
+ not settle intake authority or imply a usable Forms product. No dependency on
+ Meet/media is identified for this slice.
+
+## Required acceptance evidence
+
+1. Real HTTP submit/list/export tests across two principals and two forms:
+ respondent cannot enumerate/read prior answers or change destination cells;
+ foreign/removed/expired authority fails without existence disclosure.
+2. Crash/ambiguous-ack tests at both transaction boundaries; retry one accepted
+ response after process reopen, observe exactly one sealed response and row.
+ Concurrent submissions each preserve a complete distinct row.
+3. Force validation failure in the final field: no partial answer/row/event.
+ Mutate receiver deduplication off and require the ambiguous-ack test to fail.
+4. Publish a schema change while an old page submits; no answer misassignment.
+ Rename/reorder/remove mapped columns; no positional remapping or dropped data.
+5. Literal formula-looking text, Unicode, multiline and choice values survive
+ stored response, projection and export with explicit type expectations.
+6. Revoke destination permission after intake; no write, canonical response
+ retained, no false success. Close the form and verify the chosen retry policy.
+7. Plaintext scan of DB/WAL/log fixtures, restore with correct/wrong keys, old
+ binary compatibility where rollback is claimed, and actual process SHA.
+8. Mutation checks must remove real validation/authorization/idempotency controls,
+ not only change expected errors. No missing-route 404 test is fidelity proof.
+
+No current passing test or live Forms workflow is claimed. This proposal is the
+reviewable next slice; implementing anonymous access or a cross-app editor bridge
+before closing these boundaries would invent policy rather than enact the queue.