fix(worker): private multi-sheet ACL inheritance via meta:parent - #850
Conversation
…nce and multi-sheet import
CI stop (Phase 2) — no deployPer owner instruction: anything red → stop before cutover. No re-run for green, no threshold changes, no production deploy. Checks so far
E2E failure
After Sheet1 is visible, Add never produced the expected Likely contract drift vs the guarded Add Sheet path from Job: https://github.com/audreyt/ethercalc/actions/runs/31488270045/job/93768911037 Phases 3–4 (atomic cutover / verify) not started. |
CI complete — still stopped (e2e red)Full check table for run 31488270045:
Overall CI conclusion: failure (sole blocker is e2e). E2E (unchanged)
Not startedNo merge, no production deploy, no threshold changes, no re-run for green. |
…eet contract
The old multi-toc-csv spec waited for POST /_/{room} with text/csv — the
direct parent-TOC write that 170eaa4 deleted because it minted unmarked
public children under private parents. That was contract drift, not a
defect: the test pinned the vulnerable transport.
Replace (not relax) the transport wait with POST /_/={room}/sheet
(application/json, 201 + authoritative {sheet}). Keep the user-visible
cold-seed / add / rename / delete / reload outcomes intact. Explicitly
assert that Add Sheet no longer emits the legacy parent CSV POST.
Strengthen on the seam this change is about: under a real private parent
(authWorkerBase + virtual authenticator), the created child denies
anonymous HTTP read (403) and reports isPrivate/canRead:false via
/_/{child}/access — proof the child carries meta:parent. An unmarked
child would stay public under authorize().
Local: build:assets + full packages/e2e chromium suite 51/51 green.
e2e contract updated — replaced, not relaxedPushed What changed in
|
CI complete — all greenFull check table for head
e2e contract note (why this is not a weakened test)The previous red was the old assertion waiting for Still held (no merge/deploy by this agent)
Awaiting owner direction on merge/cutover. |
Cutover complete — atomic 100%Phase 1 — merge
Phase 2 — versions
Phase 3 — live verify (ethercalc.net)
Edge purge: not needed. Worker code + Workers Assets ride the version; guarded route was live immediately (no DO skew window observed). What this cutover cannot prove from outsidePrivate-child anonymous denial is covered by unit tests, the six-inversion pass, and the real-passkey Playwright case on CI — not by an unauthenticated production probe (creating a private parent requires a real session). No claim of live private-child coverage beyond public-path verification above. Held
|
Summary
Private multi-sheet workbook children inherit access from their parent RoomDO through immutable
meta:parent(derive-at-authz), not stamped ACL copies. RoomDO remains the sole authz boundary (AGENTS.md decision #14); parented children resolve via a trusted parent hop.Why not stamp
Cross-DO ACL copies have no atomic multi-DO transaction, leave partial-failure children, and require N-way rewrite/reconciliation on every parent ACL change. Derive is race-free and needs no reconciliation.
What shipped
meta:parent/meta:nextChildIndexstorage keys (@ethercalc/shared)POST /_/={room}/sheetfor Add Sheet / cold seede2e contract (this push)
packages/e2e/tests/multi-toc-csv.spec.tspreviously waited forPOST /_/{room}withtext/csv— the vulnerable direct parent-TOC write that170eaa4deleted. That was contract drift, not a defect: the test pinned the path we set out to remove.Replaced, not relaxed:
POST /_/={room}/sheet(application/json→ 201 + authoritative{sheet})text/csvPOST{isPrivate:true,canRead:false,canWrite:false}provesmeta:parent(unmarked child would stay public)Local proof before push:
vp run build:assets+ fullpackages/e2echromium 51/51 green.Evidence held
/Users/au/ethercalc-acl-repair-recovery-20260811.tgz/Users/au/w/ethercalc-acl-six-inversion-evidence.txtCutover constraint
Atomic 100% deploy only — new
/_do/*child/parent protocol endpoints cannot be gradually ramped (PROD_UPGRADE_PLAN.md §4.3). No merge/deploy until CI is fully green.Test plan
build:assets