Two independent reviews of revision 3: both request changes
GPT-6 via Codex and Fable 5.1 read revision 3 separately, neither seeing the other's report. Both return request changes, and they converge on the same defects, which is the useful part. Scorecards on the original sixteen agree closely: Codex 6 closed, 10 partial, 0 open; Fable 7 closed, 9 partial, 0 open. "Revision 3 answers all sixteen" was an overclaim — the same overclaim GPT-6 caught in revision 2. Mostly a mechanism is stated where a fixture was asked for. Found independently by both: - The provenance envelope names an asker on paths that have none. S3 is person-less by its own definition, so §7's check cannot run for an onward S3 fetch, and gate 6b's S3 clause cannot be written. A link holder has no S2 subject either, so link sharing and derived items are incompatible as written. - A failed roster refresh keeps serving already-admitted sessions, which is the outcome §5.3's own paragraph claims to reject. - Rejecting a lower epoch does not make a restore safe: a restored home reissuing epoch numbers catches up without recovering the removals. - Anonymous link editing changes rulings that already exist elsewhere. Codex alone: §5.5 and §9 concede ruling 13 and then deny its consequences in the next sentence, which is worse than revision 2 rather than better; a source list gives no safe unit for removing one passage from a synthesis; ruling 12's rejected-alternative column mixes verified facts with an impossibility claim it does not support. Fable alone, and verified: §7.3's anonymous link editor contradicts Sheets ruling 12, "Link sharing is viewer-or-commenter, never editor", rejected alternative "Anonymous link editing", Paul, 2026-08-30. Ruling 15 took the product requirement literally without citing the ruling that already answered it — the exact failure this repository exists to prevent. No doctrine changes in this commit. Revision 4 waits on Paul's call between his 2026-08-30 ruling and his 2026-09-05 requirement.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016XuAriz559moY27sTegqpt
CODEX-FINDINGS-R3.md+239 −0FABLE-FINDINGS-R3.md+194 −0
Intent
Where do I go to get more chatgpt quota?
OK, codex is upgraded
<task-notification> <task-id>ad56aa2c22672c32a</task-id> <tool-use-id>toolu_012ZtYqMAF7v4aTWGLhUb8t6</tool-use-id> <output-file>/home/paulca/.cache/tmp/claude-1001/-home-paulca-amadan-net-oficina-suite/df6721cd-97ce-45b2-b664-3fea70beada0/tasks/ad56aa2c22672c32a.output</output-file> <status>completed</status> <summary>Agent "Fable review of revision 3" finished</summary> <note>A task-notification fires each time this agent stops with no live background children of its own. The user can send it another message and resume it, so the same task-id may notify more than once.</note> <result>Report written to `/home/paulca/amadan.net/oficina/suite/.claude/worktrees/doctrine-review/FABLE-FINDINGS-R3.md`. The doctrine was not edited. **Verdict: request changes.** **Stake.** I drafted revision 1 and recommended rulings 12–14, so I checked only their factual claims (both of ruling 12's claims about the home spec are true against trunk `2b68301`) and did not judge whether they are wise. Revision 3 is also Fable-authored, and AGENTS.md says a draft's author cannot be its reviewer; this pass should not count as §14's third pass unless Paul says so. **Sixteen findings:** 7 closed (4, 7, 9, 12, 13, 15, 16), 9 partial, 0 open. The partials are mostly where a mechanism is stated but the fixture the finding asked for is missing, plus three where the failure sequence still gets through (2, 5, 6). "Answers all sixteen" is the same overclaim GPT-6 caught in revision 2. **Top new findings (all P1, none previously reviewed):** 1. **Ruling 15's "edit" link and §7.3 contradict Sheets ruling 12** — Paul, 2026-08-30, "viewer-or-commenter, never editor", rejected alternative "anonymous link editing" — and Docs §8.2. §7.3 builds exactly that rejected actor and cites neither spec; A.2/A.3 amend neither. Paul's four states are satisfied without it: an edit link is a capability to obtain a guest grant on sign-in, which is how Docs already builds its commenter link. 2. **Provenance envelope × link viewer**: a link holder has no S2 subject, so §7's check can't run — a link on a Doc becomes a link on the Sheet it quotes, or link-sharing silently breaks. Unstated. 3. **§7 names an "asker" on S3, which has none**; gate 6b's S3 clause cannot be written. S3 itself is the custody probe and the doctrine doesn't notice. 4. **Rewind rule defeated by epoch-number reuse** after a home restore (readmission returns two writes later); and a home that loses `memberships` has no rebuild path — call 2 can't write it, no push channel — making home §10's "loses credentials, not access" false, unamended. 5. **Stale-roster rule keeps serving admitted sessions** (30-day default, sliding renewal), which is the alternative the paragraph claims to reject; it pays suite-wide S2 `UNKNOWN` for nothing. **Also:** A.1 leaves home §2's "compromised home does not cost a document" standing and misattributes it to revision 1; A.3 misses PRODUCT.md principle 3, the sentence memoria's blocker actually names; four memoria citations (decisions 13/14, gate 26, §3.2) resolve only in the unmerged `tensorx-provider` worktree; §0's retirement bound cites a retention §4.2 never states. **Worse than revision 2:** the Sheets-ruling contradiction, a wrong rule (S3 asker) where there was a gap, a lockout mode where there was lag, and a bounded §0 promise pointing at an empty section.</result> <usage><subagent_tokens>242969</subagent_tokens><tool_uses>59</tool_uses><duration_ms>739718</duration_ms></usage> </task-notification>
<task-notification> <task-id>ba9u2zxi9</task-id> <tool-use-id>toolu_01JCvTJrHt7DQ7DsigQBLkwi</tool-use-id> <output-file>/home/paulca/.cache/tmp/claude-1001/-home-paulca-amadan-net-oficina-suite/df6721cd-97ce-45b2-b664-3fea70beada0/tasks/ba9u2zxi9.output</output-file> <status>completed</status> <summary>Background command "Re-run third-pass codex review" completed (exit code 0)</summary> </task-notification>
Attributed to this commit: 10.9 g CO₂e (1230166 tokens). This is an attribution, not a measurement — usage counted from this commit's own marker forward to the next one on worktree-doctrine-review, never backward from it. A turn that produced more than one commit books all of its tokens to the last one, and a concurrent session on this branch can add to the same figure. Some of it was priced using the shared default rate, because no model-specific factor row exists yet for at least one model involved. The Carbon view has the repo total, which is never derived from this attribution.
diff --git a/CODEX-FINDINGS-R3.md b/CODEX-FINDINGS-R3.md| new file mode 100644 |
| index 0000000..f512e45 |
| --- /dev/null |
| +++ b/CODEX-FINDINGS-R3.md |
| @@ -0,0 +1,239 @@ |
| +# Findings on the suite sharing doctrine, revision 3 |
| + |
| +Reviewed by **GPT-6 (Codex), 2026-09-05**, independently of the draft and revision-3 authors. These are findings and proposed corrections, not rulings. The doctrine has not been edited. |
| + |
| +Scope: the entire doctrine at `76bdc26` (doctrine text last changed in `99a8838`), the change from `0c4f098`, commit messages, the original sixteen findings, and the local sibling sources identified below. P1 means a broken or unenforceable trust guarantee; P2 means a contract, adoption, or verification defect that needs correction before implementation. Findings describe specified behavior, not demonstrated vulnerabilities in deployed applications. |
| + |
| +## 1. The sixteen original findings |
| + |
| +“Closed” means the original failure sequence has a specified answer. It does not mean the implementation or its tests exist. A new problem in the replacement is identified separately. |
| + |
| +| Original | Status | Reason | |
| +|---|---|---| |
| +| 1. Directory writes bypass roster step-up | **Closed** | Ruling 12 and §§5.3–5.4 explicitly separate membership from call-2 hints; upsert, revoke and delayed replay cannot change the roster. The rejected-alternative argument still overclaims: R3-11. | |
| +| 2. Compromised-home bound is false | **Partial** | Ruling 13 correctly concedes impersonation, but §5.5 and §9 immediately deny its consequences; §9 now expressly applies the false bound to all three compromises. Worse in that respect: R3-1. | |
| +| 3. Writes lose source authority | **Partial** | The envelope and refusal of unverifiable sources are real changes, but its S3/link-reader checks cannot be made as specified, and passage removal lacks a safe unit: R3-4 and R3-5. | |
| +| 4. Unprotected confirmation commit and late destination check | **Closed** | §7.1 now fixes the body in bounded, expiring, single-use browser/person-bound pending state, separates receiver-origin commit, and validates the sending destination before transmission. Gate 7 retains a few fixture decisions. | |
| +| 5. Expiry and rollback do not bound revocation | **Partial** | Failed refresh and lower epochs now have rules, but existing sessions survive expiry and a restored epoch can catch up without recovering removals: R3-2 and R3-3. | |
| +| 6. Custody ignores retained copies | **Partial** | Acquisition-time custody and irrecoverable compromised copies are correctly conceded; the promised retirement bound has no target at its citation, and §0 accidentally widens its test to originals: R3-7. | |
| +| 7. Removal silently revokes guest grants | **Closed** | Gate 5 now separates removal with no independent grants from a guest retaining its granted activity. Its failed-refresh case still needs R3-2/R3-9. | |
| +| 8. S2 intersection falsely claimed to cost nothing | **Closed** | §4.3 explicitly describes Ana losing the ingested passage despite retaining her source grant. The transition should be an actual gate fixture, not only a parenthetical request. | |
| +| 9. Browser policy and middleware prevent the hand-off | **Closed** | §7.1 and A.2 name the sender CSP allowance, dedicated receipt guard, pending sign-in flow and extra POST; gate 7 traverses the real stack. | |
| +| 10. Call 8 lacks a paginated snapshot contract | **Partial** | Epoch-bound cursors and atomic publication answer mixed snapshots; the wire shape, completion marker, bounds and restart behavior remain unspecified: R3-8. | |
| +| 11. S2 lacks the source-behind case | **Closed** | §4.3 specifies loud `UNKNOWN` for an unrecognized revision. That answers the original revision-7/source-5 case; adopting it against current memoria requires an explicit reconciliation with `AHEAD`: R3-12. | |
| +| 12. Epoch claim does not pass home's claim test | **Partial** | A.1 now requests the right exception, but “can neither admit nor exclude” is inconsistent with a forced refresh that fails, and failure precedence remains unsettled: R3-9. | |
| +| 13. Leak list omits roster and activity costs | **Partial** | Roles at rest and the full-roster distribution are disclosed; activity visit/traffic costs are added, but cached activity after revocation still conflicts with the universal next-request promise: R3-10. | |
| +| 14. Amendments retain contradictions and restatements | **Partial** | Several named leftovers are covered, but Appendix A's general disclaimer conflicts with its literal replacement instructions, and new link/provenance and current-source conflicts are omitted: R3-6/R3-12. | |
| +| 15. Docs and Sheets positions are misattributed | **Partial** | The Docs qualification is now accurate and A.3 preserves Sheets' local rule, but §§2 and 10 still repeat the rejected reading and replacement: R3-12. | |
| +| 16. Citation currency misses normative changes | **Closed** | Gate 9 covers every normative change, verifies commit/revision agreement, and explains the one-revision grace; Appendix A requests both fields. | |
| + |
| +**Seven closed, nine partial, none wholly unanswered.** Several partial findings now contain useful mechanisms; acknowledgment alone is not the reason they remain partial. |
| + |
| +## 2. Findings against revision 3 |
| + |
| +### R3-1. P1 — The new compromise disclosure contradicts itself at the point of the guarantee |
| + |
| +**Where:** doctrine §5.5, lines 486–512; §6.1, lines 573–575; §9 item 4, lines 815–825; ruling 13. |
| + |
| +**What is wrong:** after conceding that the credential origin can sign in as anyone, §5.5 says a compromise of the home cannot reach an individually granted item. §9 goes further: none of the three compromises can read private/granted/link-only items, write as a person, or grant a per-item right. These statements directly contradict the new ruling. |
| + |
| +**Why:** mint an assertion for Ana, redeem it for an ordinary instance session, then read Ana's private document or exercise her actual edit/share rights. The instance correctly evaluates its own grants and authorizes the impersonated Ana. Home §5.3–§5.5 and activity design §5.1 explicitly support this sequence. A local grants join is not an independent identity check. “No trust in the home's word” in §6.1 makes the same error. |
| + |
| +The directory-only case also needs a narrower statement: adding an attacker-controlled account does not impersonate an existing person, but that account can exercise whatever ordinary write or share rights team membership/ownership actually confers. The membership record includes `owner`; compromising its writer is not inherently limited to inserting `member`. |
| + |
| +**Confidence:** high; the credential-origin counterexample is explicit in both cited contracts. |
| + |
| +**Smallest correction:** remove the universal residual bound, distinguish impersonation from rights acquired by an attacker-controlled member/owner, and make §§5.5, 6.1 and 9 cite ruling 13 consistently. A role-specific directory compromise bound must name the receiving app's role policy. No new security mechanism is required to disclose the existing exposure accurately. |
| + |
| +### R3-2. P1 — Failed refresh restores a session-length revocation tail |
| + |
| +**Where:** doctrine §5.3, lines 403–412 and 427–449; §5.4, lines 470–473; gate 5. |
| + |
| +**What is wrong:** after roster expiry, the instance keeps serving already-admitted people for their session lifetime. It nevertheless promises removal everywhere within the roster TTL. Gate 5 checks new admission and S2, leaving the existing browser session out. |
| + |
| +**Why:** admit Ana against epoch 10, remove her at epoch 11, then make call 8 unavailable through expiry. Her existing session keeps reaching team content under the explicit stale policy. Making sibling S2 return `UNKNOWN` does not stop an ordinary Docs read or memoria-owned material. Home §2.1 specifies sliding session renewal; the doctrine neither forbids renewal in this case nor defines an absolute session cutoff. “For the length of their session” is therefore not even necessarily a fixed additional bound. |
| + |
| +This is an availability choice the document can make, but it has not priced or consistently stated that choice. “Within one epoch” is still not an elapsed-time condition. Call 7 and S6 also lack an explicit stale-membership treatment. |
| + |
| +**Confidence:** high; an unexpired session alone exceeds the claimed bound, without relying on sliding renewal. |
| + |
| +**Smallest correction:** either stop using stale team standing on every protected request at a hard maximum age, preserving independently evaluable grants, or specify an absolute, nonrenewable grace and change the revocation promise to include it. Define when age starts for a multipage fetch and whether request deadlines extend the bound. Exercise an already-live session, ordinary reads, memoria-owned reads, S2, S6 and call 7 through failed refresh. Choose the security bound explicitly; cold-wake measurement alone cannot choose it. |
| + |
| +### R3-3. P1 — Rejecting a lower epoch does not make restore safe |
| + |
| +**Where:** doctrine §5.3, lines 439–445; gate 5; A.1. |
| + |
| +**What is wrong:** the receiver rejects lower numbers until the home passes a high-water mark, but no restore-safe record preserves either the mark or the membership changes it represents. |
| + |
| +**Why:** a receiver applied epoch 11, which removed Ana. Restore the home to epoch 10, which includes her. One unrelated membership change produces 11 again; two produce 12. The receiver eventually accepts a number that passes the prescribed comparison while Ana's removal remains lost. Requiring strictly greater rather than greater-or-equal merely adds one mutation to the counterexample. Restoring both receiver and home makes refresh-before-admission insufficient too: both can agree on the same obsolete roster. |
| + |
| +**Confidence:** high as a missing restore contract. An implementation with an independently durable membership journal could prevent it, but none is specified. |
| + |
| +**Smallest correction:** make roster history/restore recovery authoritative independently of the restored database, or quarantine a restored authority until membership has been reconciled through a defined recovery procedure. Preserve epoch identity across history forks; a larger counter alone is not evidence of recovery. Add both numerical catch-up and joint-restore fixtures, not only `11 → 10` rejection. Memoria §7.4's independent tombstone journal is a relevant precedent, not an already inherited roster mechanism. |
| + |
| +### R3-4. P1 — The provenance check requires an asker on paths that have none |
| + |
| +**Where:** doctrine §7, lines 615–637; §6 S3; §§4.2 and 7.3; gate 6b. |
| + |
| +**What is wrong:** every disclosure of a derived item, explicitly including an onward S3 fetch, must ask S2 whether its sources authorize the asker. S3 has no asker. An anonymous holder of a link to the derived item has none either, and §7.3 forbids using a link holder for sibling calls. |
| + |
| +**Why:** save a Sheets-derived answer into Docs, then let memoria ingest the new Doc through S3. There is no subject with which Docs can perform its required source S2. Substituting the saver caches a person's authority; inventing a member authorizes the wrong reader; skipping the check permits a newly acquired copy after a source downgrade. Making the Doc `team` does not independently settle the source's current custody or revision. |
| + |
| +Likewise, link-sharing the saved Doc does not grant the link holder access to its Sheets sources. The app cannot both promise that anyone with the URL can read this Doc and require a person-bound S2 result for every source. No safe refusal or restricted link-sharing case is stated. Team-sharing plus link-sharing still leaves this problem for the anonymous request, even if member requests work. |
| + |
| +**Confidence:** high; the incompatible signatures and requirements are explicit. Memoria §6.1 already records why adding a person to S3 was the wrong earlier fix. |
| + |
| +**Smallest correction:** define derived-item custody separately from person authorization, preserving source identities/revisions on onward acquisition and checking every source on person disclosures. Specify how a source's custody change invalidates a derived item's S1/S2/S3 eligibility. Until a no-person authorization mechanism exists, explicitly refuse unsupported derived-item S3/link disclosures or creation of such links. Do not invent an owner asker to make the call fit. Gate 6b needs a successful initial no-person acquisition as well as subsequent refusal. |
| + |
| +### R3-5. P1 — A source list cannot justify removing only one passage from a synthesis |
| + |
| +**Where:** doctrine §7, lines 615–629; gate 6b, lines 939–943; memoria §5.2 and gate 9. |
| + |
| +**What is wrong:** the envelope records only app/id/revision per source, but the outcome says the saved item “loses that passage.” Gate 6b asks for the same result across reads, exports and S3. The cited memoria contract requires withholding the whole derived artefact if any source fails. |
| + |
| +**Why:** an answer synthesized from sources A and C can express A's information in its conclusion, title or comparison with C, without quoting an identifiable A passage. A flat source list cannot locate every dependent span. Removing a quote while serving the synthesis leaves the revoked information in the output. Nor does the envelope specify how a newly edited or onward-copied Doc retains dependency coverage. |
| + |
| +There is a second output conflict: gate 6b always demands naming the app after revocation, while §4.3 permits silent `NOT_VISIBLE` and S3's custody denial must remain indistinguishable from absence. A source-specific diagnostic in that S3 denial would expose the dependency of an otherwise hidden item. |
| + |
| +**Confidence:** high for the insufficient mapping and cited whole-artefact rule; “lose that passage” is ambiguous enough that two implementers could choose opposite behavior. |
| + |
| +**Smallest correction:** make whole-artefact withholding the default when any source fails, with unchanged non-disclosure behavior at S3. If independently removable passages are wanted, first define independently authorized units and complete dependencies for each; do not infer them from quotations. Bound and validate the envelope, including transitive expansion, unknown authorities, duplicates and cycles. Gate a synthesized conclusion, title/activity output, changed revision, and an actual second write hop. The present gate performs one write with two sources, not two-hop propagation. |
| + |
| +### R3-6. P2 — Anonymous editing changes existing rulings, and actor identity is underspecified |
| + |
| +**Where:** ruling 15; doctrine §§7.2–7.3; A.1–A.3. Docs §8.2; Sheets ruling 12 and §8.3; home §5.5. |
| + |
| +**What is wrong:** §7.3 presents capability-attributed editing as preserving the existing attribution rule, but those sources explicitly require sign-in to write and mint a guest grant then. Sheets ruling 12 expressly rejects anonymous link editing. Appendix A never identifies these clauses for replacement. |
| + |
| +**Why:** a receiver following the amended sibling spec still refuses the new edit link. A receiver following §7.3 writes without the guest grant the sibling's attribution rule requires. Paul's new product requirement can justify changing that decision; the change must be recorded as such, and ruling 15 remains explicitly a proposal. |
| + |
| +The new actor also exposes an ambiguity in S8: eligibility is checked against “the item's actor,” while §7.3 attributes each revision to a link. After a link edits an S8-created Doc, does its actor become the link and permanently bar the creating sibling, or stay the sibling and misattribute the revision? The document needs distinct creation authorship and revision attribution. A link identifier in history must also be a non-secret identifier, not the bearer value; Sheets §8.3 already requires hashed token storage. |
| + |
| +**Confidence:** high for the sibling contradiction; high for the missing distinction between item creator and revision actor. |
| + |
| +**Smallest correction:** record the deliberate supersession of Docs §8.2, Sheets ruling 12/§8.3, and any affected home pending-grant text. Define immutable creator identity separately from each revision's actor and state the S8 policy after person/link edits. Add view-link write refusal, edit-link revision attribution, revocation, and mixed-actor S8 tests. Cite the existing token-storage boundary or replace it explicitly. |
| + |
| +### R3-7. P2 — Ruling 14 promises a retirement bound at a section that contains none |
| + |
| +**Where:** doctrine §0, lines 65–81; ruling 14; §4.2; §9 item 1. |
| + |
| +**What is wrong:** §0 promises retirement within one feed pull plus “its stated retention (§4.2).” Section 4.2 states neither retention nor a restore obligation. Ruling 14's requirement that retirement be “stated and timed” is therefore still unfulfilled. |
| + |
| +**Why:** memoria pulls on wake and questions, and §7.4 preserves snapshots while restorable backups reference them. A sleeping consumer or repeated failed enumeration can postpone a successful pull indefinitely. A feed-log TTL is not a cache/snapshot retirement deadline. The text must distinguish time to the next successful observation from time to retirement after that observation, including backups and the circuit breaker. The acquisition-time concession correctly limits malicious consumers, but does not specify honest retirement. |
| + |
| +There is also a new scope error: revision 2 tested what an instance held **about the others**. Revision 3 deletes that qualification and tests everything it holds. A Docs instance legitimately holds an original private Doc under ruling 15. Publishing that instance reveals content the team could never read; changing the acquisition timestamp does not cure this counterexample. |
| + |
| +**Confidence:** high; the retirement citation has no target, and the private-original counterexample follows from the new ladder. |
| + |
| +**Smallest correction:** restore the test's scope to sibling-acquired copies; distinguish originals from those copies. Cite a concrete consumer retirement/snapshot/restore policy, require its stated bounds, and explicitly disclose any unbounded delay before successful synchronization. Ruling 14 may reject push and source-held keys as complete recall mechanisms; it should not imply those alternatives have no possible effect on an honest consumer's retirement window. |
| + |
| +### R3-8. P2 — Call 8's snapshot rule is useful, but no interoperable page can yet be encoded |
| + |
| +**Where:** doctrine §5.3, lines 379–382 and 414–425; gate 5; A.1. |
| + |
| +**What is wrong:** the only wire example still contains just `epoch` and `members`. It has no continuation/completion field or cursor request parameter. No page cap, total staging bound, invalid-cursor response shape or restart action is given. “An empty response is never read as nobody is a member” also fails to distinguish a malformed/absent response from a valid completed empty snapshot. |
| + |
| +**Why:** atomic replacement solves mixed epochs only if a client can recognize completion and restart after invalidation. Two implementations can both claim to stage all pages while disagreeing about whether the first response is complete. Repeated epoch changes or a failed middle page must not extend the previous snapshot's usable age or leave unlimited staged data. |
| + |
| +The new claim that call 8 is the first response whose size the caller does not control is also inaccurate: S1 enumerates server-owned changes and call 7 has server-selected activity. That does not undermine the need to page the roster. |
| + |
| +**Confidence:** high. |
| + |
| +**Smallest correction:** provide one bounded request/response schema, explicit terminal marker, invalidation response and discard-and-restart rule. Define valid empty completion separately from fetch failure, and do not reset freshness on incomplete work. Add concurrent mutation, failed-middle-page, empty-completion and repeated-restart fixtures to gate 5. Choose the first client's constants with reasons, as the repository requires. |
| + |
| +### R3-9. P2 — Stale authority needs result precedence, and an epoch hint can cost admission |
| + |
| +**Where:** doctrine §4.3, lines 292–294; §5.3, lines 389–401 and 427–434; gates 3 and 5; A.1. |
| + |
| +**What is wrong:** stale-roster S2 is unconditionally `UNKNOWN`, whereas §4.3 and gate 3 unconditionally demand `NOT_VISIBLE` for non-custodial/deleted items. The document also says a differing epoch hint can neither admit nor exclude anybody, while requiring admission against a fresh roster after that hint. |
| + |
| +**Why:** ask about a deleted item while the roster is stale. Its nonexistence is locally determinate; an unreachable membership authority has not made it uncertain. A client needs one specified answer when both clauses apply. Returning `UNKNOWN` for the whole call can be a conservative availability choice, but it must be scoped as an exception; selectively returning it only for existing private items would violate indistinguishability. |
| + |
| +For the hint, start with a still-usable cached roster and an assertion carrying a different parseable epoch. Let the triggered call-8 fetch fail. Requiring freshness now refuses admission that the old cache would otherwise allow; accepting the old cache contradicts the fresh-roster sentence. The hint does not directly assert a role, but it can affect availability. “Exactly one request” also needs qualification once call 8 takes several pages. |
| + |
| +**Confidence:** high for the incompatible unconditional rules; the hint's availability effect depends on the failure policy that remains to be specified. |
| + |
| +**Smallest correction:** define validation and result precedence for unsupported subjects, local non-custody/nonexistence, stale membership, independent grants and revision mismatch. Retain indistinguishability in each case. Specify whether a hint invalidates an otherwise-usable copy and price that availability effect accurately. Test the combined states, including hint-triggered partial/failing refresh before the TTL. `UNKNOWN` remains a useful failure class; the defect is when it overrides a determinate denial and what the consumer is told failed. |
| + |
| +### R3-10. P2 — Activity still serves cached authorization despite the strengthened universal rule |
| + |
| +**Where:** ruling 3; doctrine §4.3, lines 278–284; §7's activity disclosure check; §9 items 5, 7 and 10; adopted activity design §7. |
| + |
| +**What is wrong:** revision 3 says authorization is never cached at any scope and that live authorization bounds the next request on every surface, explicitly including home activity. The adopted activity design permits a last-good response to render on later requests, through failed pulls until a hard maximum age. |
| + |
| +**Why:** cache a title, revoke the source or its grant, then render the home again before that maximum expires while the pull fails. The title is newly disclosed from the cache without a current check. This is not merely a browser retaining its previous page. For derived items, checking provenance when the instance first answers call 7 does not recheck the home's later render. |
| + |
| +**Confidence:** high; activity §7 expressly describes the removed-person failure case and its cache-age bound. |
| + |
| +**Smallest correction:** explicitly resolve the scope conflict: either record activity's bounded cached-disclosure exception by citation and disclose the revocation tail, or change the adopted behavior to require a current check before redisclosure. Do not claim both. Reuse activity gate 20's failed-pull/hard-maximum test, and include a derived item's source revocation. The new cost disclosure should also follow activity §2.2's per-refresh-window emission rather than imply every browser load necessarily produces an instance request. |
| + |
| +### R3-11. P2 — Ruling 12's rejected alternative mixes verified facts with an unsupported impossibility claim |
| + |
| +**Where:** status lines 21–25; ruling 12's rejected column; doctrine §5.1, lines 341–359. |
| + |
| +**What is wrong:** both requested home facts are true, but the conclusion drawn from the second is too strong. Home §6 has `kind = member | guest`, with no owner role, and includes `app` in each directory entry. Home §7 explicitly keeps owner decisions instance-side. Those facts do not prove that projecting a team-wide roster from app-scoped rows is impossible or necessarily produces app-specific standing. |
| + |
| +**Why:** projecting distinct `(team, person)` memberships can erase the app dimension and give one answer to every app. It would still suffer the owner-information and untrusted-writer defects, so it is not a defense of revision 1. It is a counterexample to one claimed reason for rejecting it. Ruling 1 alone also does not define every membership consequence; the common roster is established by rulings 4/12, and §3 expressly permits differing lone-instance rosters. |
| + |
| +The sentence “Ruling 9 made a directory row a hint” is an unqualified wrong reference: suite ruling 9 concerns writes; **home** ruling 9 concerns directory hints. |
| + |
| +**Confidence:** high for the source verification and projection counterexample. |
| + |
| +**Smallest correction:** retain the separate owner-controlled table and its two decisive reasons. Describe app scope as an aggregation/lifecycle design problem, not proof that aggregation cannot work; qualify the roster claim by shape. Name home ruling 9. Ruling 13's rejected alternative is substantively honest, although R3-1 shows its correction is not carried through. Ruling 14's alternatives are not complete recall mechanisms, as R3-7 distinguishes. Ruling 15 correctly rejects treating possession of a URL as team-wide discoverability. |
| + |
| +### R3-12. P2 — The new ladder and consuming amendments still leave incompatible contracts |
| + |
| +**Where:** doctrine §§2, 4.2, 10 and 13; Appendix A; current sibling specs. |
| + |
| +**What is wrong and why:** the following are concrete remaining adoption defects, including drift since the previous review. |
| + |
| +- **Link lifecycle:** §4.2 correctly permits indexing `team` plus a link, but §13 says a link share that a sibling can index is never built. If Ana adds a link after team ingest, following §13 would retire a still-team item; following §4.2 would retain it. Revoking just the link must not revoke team custody. Downgrading the rung while retaining the link must produce `gone`; deleting/revoking a link alone must not expose link-only item ids or capability values through S1. Gate 3 covers only static states. Also, “a link holder is never on a roster” confuses a request's authority with a person's other rights: Ana can be both a member and a link holder. |
| +- **Sheets' local consistency rule:** §2, lines 138–141, still attributes the cross-repository problem to its local same-commit rule. §10, lines 871–874, still says to replace that rule. A.3 now correctly says to keep it. The original `AGENTS.md`, lines 5–7, concerns that file and the Sheets design spec in the same repository. |
| +- **Appendix A remains operationally contradictory:** its introduction says replacements are not pasteable restatements, then A.1–A.3 say to add or replace text with quoted paraphrases. A builder cannot execute both instructions. A.4 leaves memoria §2's and §8.5's unqualified no-sibling-write clauses outside the amendment list. The new provenance requirement also needs receiving-app read/export/activity/S3 adoption, not just A.2's create route. |
| +- **Home ruling number collision:** A.1 says “Add ruling 22.” Home trunk at `2b68301` already has ruling 22 for URL-based team selection. Its §2.2 activity amendment has landed too; it is no longer a pending change to complete. Use a newly allocated ruling and the actual source baseline. |
| +- **Memoria citation branches disagree:** decisions 13/14 and the cited gate 26 exist in `tensorx-provider` at `8dfc3c9`; they are not in the supplied primary checkout. Current main at `9464a8b` instead has a five-valued S2 with `AHEAD`, explicit reconciliation, and a different gate 26. §6 cannot say the cited calls move unchanged in substance while A.4 adopts four values without addressing that current contract. This is not a recommendation to adopt `AHEAD`: main itself records unresolved problems with it. It is a requirement to pin and reconcile the actual baseline. |
| +- **Calendar needs an adoption change, not only a citation:** its substantive model is in `calendar-first-screens`, not the primary checkout's example `Note`. That model confirms there is no commenter role, but team access is represented by explicit per-person grants. A.5's instruction to add consumed rulings alone does not distinguish roster-derived team access from independent grants that survive removal, nor identify how the new sharing ladder applies to calendars/events. Otherwise gate 5 cannot test the intended removal semantics against this model. |
| + |
| +**Confidence:** high for the literal contradictions and checked source revisions. The required calendar implementation can take several forms; the missing adoption boundary is the finding. |
| + |
| +**Smallest correction:** turn Appendix A into a precise list of owning sections/gates to replace with ruling-and-commit citations, with locally owned integration changes identified separately. Resolve the link lifecycle using the rung predicate, explicitly distinguish anonymous capability requests from signed-in member requests, and add creation/revocation/downgrade/edit-after-ingest fixtures. Pin the sibling baselines, allocate the home ruling without collision, and reconcile memoria's result vocabulary. Preserve Sheets' local rule everywhere the doctrine discusses it. |
| + |
| +## 3. Verdict |
| + |
| +**Request changes.** The protected membership record, receipt/commit split, explicit acquisition-time custody, and disclosure of S2's product cost are substantive improvements. They do not yet yield a consistent implementable contract. The main blockers are the false compromise bound, session and restore revocation failures, and the provenance rules' missing no-person and whole-artefact behavior. |
| + |
| +Ruling 15's distinction between the sharing rung and a link capability is sound for custody of original items. Anonymous editing and link access to derived items require further decisions and consuming amendments. Its proposal status is correctly recorded; this review does not approve it on Paul's behalf. |
| + |
| +### Sources and verification limits |
| + |
| +All doctrine line references are to [revision 3](docs/superpowers/specs/2026-09-05-suite-sharing-doctrine.md) in this worktree. Original finding numbers refer to [CODEX-FINDINGS.md](CODEX-FINDINGS.md), which remains unchanged. |
| + |
| +| Source | Checked location and commit | |
| +|---|---| |
| +| Home design | [Home trunk design](/home/paulca/amadan.net/oficina/home/.claude/worktrees/trunk/docs/superpowers/specs/2026-08-30-home-design.md), `2b68301`. The primary checkout remains at stale `462df84`. Verified §§0, 2, 5–7 and 9, owner-role absence, app scope, sealed queue bootstrap, call-2 authority, and existing ruling 22. | |
| +| Activity | [Activity design on home trunk](/home/paulca/amadan.net/oficina/home/.claude/worktrees/trunk/docs/superpowers/specs/2026-09-05-activity-pull-design.md), `2b68301`; also located the originating worktree at `6f7e6a9`. Unlike the previous review's baseline, the design and home amendment have landed on trunk. Checked credentials, guests, response shape, cache failures and gates. | |
| +| Docs | [Docs design](/home/paulca/amadan.net/oficina/docs/docs/superpowers/specs/2026-08-30-docs-design.md), `f6cf5c2`; sharing, pending sign-in, conversion rejection, module path, router/session middleware and rastrillo v0.22.0. | |
| +| Sheets | [Sheets design](/home/paulca/amadan.net/oficina/sheets-core/docs/superpowers/specs/2026-08-30-sheets-design.md), `8ed3926`; ruling 12, §§8.2–8.3, `AGENTS.md`, `PRODUCT.md`, module path. | |
| +| Memoria original baseline | [Primary-checkout design](/home/paulca/amadan.net/oficina/memoria/docs/superpowers/specs/2026-09-03-memoria-design.md), `617eb2a`; authorization, provenance, S1–S7, retirement/restore, gates, sequencing and open defects. | |
| +| Memoria provider citations | [Provider worktree design](/home/paulca/amadan.net/oficina/memoria/.claude/worktrees/tensorx-provider/docs/superpowers/specs/2026-09-03-memoria-design.md), `8dfc3c9`; located and verified decisions 13/14, §8.4 and passage-authorization gate 26. These citations are real, but branch-specific. | |
| +| Memoria current main | [Main worktree design](/home/paulca/amadan.net/oficina/memoria/.claude/worktrees/notion-ingest/docs/superpowers/specs/2026-09-03-memoria-design.md), `9464a8b`; compared the changed S2 vocabulary, provenance, admission, reconciliation and acknowledged open defects. | |
| +| Calendar | [Calendar model](/home/paulca/amadan.net/oficina/calendar/.claude/worktrees/calendar-first-screens/internal/calendar/models.go), `f18898b`; team/personal kinds, explicit grants, owner/editor/viewer roles. Primary `ecb0df9` still has an example `Note` model. | |
| + |
| +The Docs middleware and memoria CSP claims were rechecked in local code and the installed dependencies. The previous review's numeric middleware probe was not rerun and is not presented as new test evidence. No browser flow, deployed service, contract conformance suite or persisted home membership schema was executed: the requested review is of a design and this repository has no contract module yet. No sibling files were edited and no cross-repository messages were sent. Private brainstorm attribution and discussion 33's full contents were not independently verified. |
| + |
| +## 4. Gate-by-gate assessment |
| + |
| +“Writable” below concerns whether the stated test has a definite expected result. It does not report a passing implementation. Gate 6b makes ten entries under the nine numbered gates. |
| + |
| +| Gate | Can it be written and run as stated? | Required correction or coverage | |
| +|---|---|---| |
| +| 1. Fixture conformance | **Harness yes; complete conformance not yet.** | Declare which calls each app serves; S6 belongs to Sheets and call 8 to home. Call-8 pages and provenance/S3 outcomes still need R3-4/R3-8/R3-9. Add fixtures with their first client as instructed; do not claim every app serves every call. | |
| +| 2. S2 total decoder | **Yes, as a decoder property.** | Short, duplicate, malformed, non-2xx and unsupported-subject responses have definite outcomes. Add source-forward/source-behind semantic fixtures and mixed stale-roster/non-custodial cases; total decoding does not establish correct authorization. | |
| +| 3. Custody | **Static checks mostly yes; literal fixture wording still needs correction.** | “All five” includes deleted, so “does hold a grant on them” still demands a live grant to a deleted item; its clarification only repairs the `granted` fixture. Use the same id/asker in private and deleted alternative states, with a former grant where deletion removes it. Add team-plus-link and after-ingest link/rung transitions, including Ana's retained grant. Define stale-roster precedence and derived-item custody. | |
| +| 4. No cross-team dial | **Yes.** | Correctly distinguishes an initially forbidden destination from a forbidden redirect follow-up; instrument connections per host. Check the browser form destination before rendering, with canonical host parsing and an allowed-host control. | |
| +| 5. Roster | **Not as a complete revocation gate.** | Successful refresh, retained independent grants, lower-number rejection and lone isolation can be tested. R3-2/R3-3/R3-8/R3-9 block the claimed time/failure guarantee. Add existing-session, S6/call-7 failure, failed middle page, concurrent epoch change, numerical catch-up and joint-restore cases. | |
| +| 6. Write-as-self | **Yes for the original access checks.** | Authenticated-consumer actor derivation and spoof refusal are now explicit. Add immutable creator versus revision actor behavior after person/link edits under R3-6; the current three denials do not settle it. | |
| +| 6b. Provenance survives the hop | **No, as stated.** | S3 has no asker; the envelope cannot identify safe partial redaction; universal named denial conflicts with S3 absence-hiding. Resolve R3-4/R3-5. Test successful initial access, whole-artefact dependency failure, activity/title output, changed revisions, anonymous link access, and two sequential writes. Refusal when no source authorization surface exists is independently testable. | |
| +| 7. Hand-off through middleware | **Yes for the specified receipt/commit security flow; finish the fixture parameters.** | Use the real browser CSP and receiver middleware. Explicitly choose absent/null-origin outcomes and expiry/body limits. §7.1 fixes the server-side body; ignoring an extra changed client body is safe, while the gate demands refusal—choose one wire behavior. Include expired state, concurrent replay, sign-in/session change and a successful scriptless flow. This is substantially repaired from revision 2. | |
| +| 8. Publish home database | **Yes as a seeded disclosure test against the eventual implementation.** | Owner roles are now correctly part of the expected disclosure. Exercise actual persisted data and failure paths, including bootstrap/roster writes. Preserve home's existing no-content/no-readable-address checks; a schema-column inspection or roster fixture alone does not establish them. | |
| +| 9. Citation currency | **Yes.** | Commit/revision agreement and normative-change scope are repaired. Keep the deliberate one-revision grace distinct from current conformance. Pin the consuming source baselines too, so the A.1 ruling collision and memoria branch differences are resolved before adoption. | |
diff --git a/FABLE-FINDINGS-R3.md b/FABLE-FINDINGS-R3.md| new file mode 100644 |
| index 0000000..34d5ec5 |
| --- /dev/null |
| +++ b/FABLE-FINDINGS-R3.md |
| @@ -0,0 +1,194 @@ |
| +# Findings on the suite sharing doctrine, revision 3 |
| + |
| +**Verdict: request changes.** Reviewed by Fable 5.1, 2026-09-05, against the doctrine at `HEAD` of this worktree (`76bdc26`), `CODEX-FINDINGS.md`, `CODEX-REVIEW-BRIEF.md`, `git diff 0c4f098..HEAD`, and the sibling specs on disk. The doctrine has not been edited. Findings only. |
| + |
| +## 1. My stake, and what it disqualifies me from judging |
| + |
| +I am the model that drafted revision 1, and in the consultation after the GPT-6 review I recommended what became rulings 12, 13 and 14. Revision 3 itself is also Fable-authored text, by a different session. So: |
| + |
| +- **Not independent:** whether rulings 12, 13 and 14 are the right decisions, and whether their "rejected" columns are honest. I have checked their *factual claims* against the sibling specs, because a citation is either right or wrong regardless of who recommended it, and I report where those claims fail. I have not tried to judge whether the rulings themselves are wise; a reader should discount anything approving I say about them and weight only the defects. |
| +- **Independent:** ruling 15 and §4.2, which I had never seen; §7's envelope, §7.1's split, §7.3, §5.3's three new rules, all nine gates, Appendix A's new text, and the twelve findings answered in place. None of that text is mine. |
| +- **A structural caveat** the status block should carry: `AGENTS.md` says the author of a draft cannot be its reviewer. Two of the three reviews of this document, and this one, are by the same model family that drafted it. A same-model reviewer shares the drafter's blind spots. This pass should not be counted as the "third pass" §14 waits on unless Paul decides it is. |
| + |
| +Every citation below was read at: home `trunk` worktree `2b68301` (newer than the `5a42f2d` GPT-6 read — the §2.2 amendment has since landed), activity design in the same worktree, memoria main checkout (spec at 1459 lines, 21 gates, decisions to 12) and its `tensorx-provider` worktree where noted, Docs `2026-08-30-docs-design.md` and `internal/docs/app.go`, Sheets `2026-08-30-sheets-design.md`, `PRODUCT.md`, `AGENTS.md`, calendar `calendar-first-screens` worktree, Pegamento `e7442c2`, rastrillo `v0.23.0` in the module cache. |
| + |
| +## 2. The sixteen findings |
| + |
| +"Closed" means the document now survives the failure sequence the finding described. "Partial" means the mechanism is stated but the sequence, or the fixture the finding asked for, still gets through. |
| + |
| +| # | Finding | Status | Why, in one line | |
| +|---|---|---|---| |
| +| 1 | Instance-token route around step-up | **Partial** | Own record and "call 2 cannot write membership" close the route; but gate 5 has no upsert/revoke/delayed-replay-under-instance-token fixture, which the finding asked for, and the drain-seeded first owner needs a person ref the drain cannot mint without the pepper (N6). | |
| +| 2 | Compromised-home bound false | **Partial** | Ruling 13, §5.5 and §9.4 say the right thing. But the false sentence lives in **home §2 itself** — "a compromised directory grants nothing. A compromised home costs the graph and a convenience outage. It does not cost a document." — and A.1 leaves it standing. The doctrine also misattributes: it says revision 1 widened home §2's *directory* sentence to *home*; home §2 says both, so the widening is the home spec's, not revision 1's. | |
| +| 3 | No provenance contract on writes | **Partial** | Envelope shape and the refuse-unverifiable rule are real. But the check "still authorize the *asker*" cannot run on an S3 fetch (no asker) or a link view (no roster subject), "loses that passage" is undefined once a person has edited a CRDT body, and STALE on a saved answer is unstated. N2, N3. | |
| +| 4 | Commit protocol and sender-side check | **Closed** | Receipt/commit split, body fixed server-side, single redemption, browser and person binding, destination checked before render, gate 7 through the real middleware. | |
| +| 5 | Failed refetch and rewind | **Partial** | Failed refetch has a rule, but it keeps serving admitted sessions (30-day framework default, sliding renewal), so the removed member the paragraph cites keeps access anyway (N5). The rewind rule is defeated by epoch-number reuse after a restore (N4). No time bound on the TTL, still "measured later". | |
| +| 6 | Copies retained after visibility change | **Partial** | Ruling 14 and the rewritten §0 are right in shape. But §0 promises retirement "within one feed pull plus its stated retention (§4.2)" and §4.2 states no retention; and memoria's gate 8 circuit breaker purges nothing on a wholesale purge — the exact case the finding named — so the honest instance does not retire within one pull (N7). | |
| +| 7 | Gate 5 silently offboards guests | **Closed** | "Holding no other grant" and the guest fixture. | |
| +| 8 | "Costs a correct consumer nothing" | **Partial** | Cost paragraph corrected. The transition fixture is mentioned in a parenthetical and appears in no gate. "Custody denial must dominate revision diagnostics in S2 and S6 (`STALE(cell)`, `NON_NUMERIC`)" is not addressed anywhere (N10). | |
| +| 9 | Hand-off needs middleware changes | **Closed** | §7.1's bill and A.2 match what is pinned (`form-action 'self'` at rastrillo v0.23.0 `serve.go:399`; `csrf.Protect` at Docs `app.go:412`). | |
| +| 10 | Call 8 paging | **Partial** | Epoch-bound cursor, staging, refusal and "empty is not nobody" are stated. The wire example is still `GET /roster?team=&epoch=` → `{epoch, members}` with no cursor, cap or completion field, and gate 5 has no concurrent-change or failed-middle-page fixture. | |
| +| 11 | Source-behind revision | **Partial** | `UNKNOWN` is the right value and A.4 carries it. No forward/backward revision fixture in §11, which the finding asked for. | |
| +| 12 | Epoch claim and home §5.4 | **Closed** | Own exception, argued from "the instance decides nothing from it", recorded in A.1. | |
| +| 13 | Leak list omissions | **Closed** | §9 items 8–10, gate 8 rewritten. | |
| +| 14 | Amendments leave contradictions | **Partial** | A.2's shape sentence, A.4's §11/fixtures/decision 7 are fixed. A.3 still misses Sheets `PRODUCT.md` **principle 3** (line 170: "Never design a flow that implies data can move to another instance"), which is the sentence memoria §13's blocker names — so A.4's "close the blocker against A.1 to A.3" cannot close it. A.1 misses home §2, §2.1 and §10 (N6). | |
| +| 15 | Two positions misattributed | **Closed** | Docs §11.2 read correctly as "ships customer documents to a third party"; Sheets `AGENTS.md` kept. | |
| +| 16 | Citation currency | **Closed** | Any normative change bumps; revision checked against commit. | |
| + |
| +Closed 7, partial 9, open 0. The status block's "Revision 3 answers all sixteen" is the same kind of claim GPT-6 flagged in revision 2's "no new machinery": true of the citations, not of the failure sequences. |
| + |
| +## 3. New findings, by severity |
| + |
| +P1: a trust boundary or promised property is broken, or a normative rule cannot be built as stated. P2: a contract, adoption or verification defect. P3: accuracy. |
| + |
| +### N1. P1 — Ruling 15's "edit" link and §7.3 contradict a Paul ruling in Sheets and Docs §8.2, and cite neither |
| + |
| +**What is wrong.** Sheets §1 ruling 12: *"Link sharing is viewer-or-commenter, never editor"*, rejected alternative *"Anonymous link editing"*, **Paul, 2026-08-30**. Sheets §8.3: an anonymous editor "would write unattributed rows into version history". Docs §8.2: *"Link shares are a per-document capability, viewer or commenter, never editor. Anything that writes is attributed, and attribution is what mints membership."* Doctrine ruling 15 makes a link "view or edit", and §7.3 builds the actor Sheets rejected by name — *"the honest actor is the link capability itself"* — and calls it a satisfaction of ruling 9. §7.3 cites neither spec; A.2 and A.3 amend neither §8.2 nor §8.3. |
| + |
| +**Why it matters.** This is not a drift between restatements; it is a new ruling overturning a settled one without saying so, in the document whose one rule is that a ruling lives once. The moment Docs adopts A.2, Docs §8.2 and suite §7.3 disagree and gate 9 has nothing to say about it. It also weakens ruling 9: "a write names its real actor" becomes "a write names a bearer token", which is what ruling 9's rejected column calls a write capability without an identity. |
| + |
| +**The product requirement does not need it.** "Anyone with the link can edit" is already how Docs builds its commenter link: the link is a capability to *obtain* a grant — the holder signs in, attribution mints a guest member, and from then on they are on the `granted` rung with a person ref. That gives Paul all four product states, keeps every write attributed to a person, keeps S2's asker a roster subject with no special case, and deletes §7.3 and leak item 11's "the app cannot name them" — because it can, after the first write. |
| + |
| +**Confidence:** high that the contradiction is real and uncited. High that the sign-in-mints-guest shape satisfies the requirement; whether Paul wants anonymous editing anyway is his call, in which case ruling 15 must name Sheets ruling 12 as overturned and A.3 must amend it. |
| + |
| +**Smallest correction.** Ruling 15: "view, or edit after sign-in — an edit link is a capability to obtain a guest grant (Docs §8.2, Sheets §8.3), never an anonymous actor." Delete §7.3. Leak item 11 loses "or writes". |
| + |
| +### N2. P1 — The provenance envelope has no rule for a viewer who is not a roster subject, which makes a link on a Doc a link on the Sheet it quotes |
| + |
| +**What is wrong.** §7: on every disclosure path the receiver "checks that the sources still authorize the asker, through S2 to each app of record". A link holder has no asker subject (§3, §7.3). So for a Doc carrying an envelope, viewed through a link, the check cannot be made — and the doctrine says nothing about what happens then. |
| + |
| +**Why.** Ana saves a memoria answer quoting a team-visible Sheet into a Doc, then link-shares the Doc to a contractor. If Docs shows the Doc, the contractor reads Sheets content nobody granted; the link has laundered the cell through one hop, which is the exact thing §4.3's transitivity rule forbids. If Docs refuses, link-sharing a Doc containing any saved answer silently stops working, and nothing says so. Guests are half-covered by accident: S2 to Sheets for a Docs-only guest returns `NOT_VISIBLE`, so the passage is withheld — but the doctrine should say that too, because it is a product surprise ("my guest cannot see the table I pasted"). |
| + |
| +**Confidence:** high. |
| + |
| +**Smallest correction.** One rule in §7: an item carrying an envelope discloses envelope-derived passages only to an asker every source can be asked about; to anyone else — link holders, and under N1 any un-signed-in visitor — those passages are withheld loudly and the rest of the item renders. One fixture in gate 6b: link view of the item from gate 6b's own scenario, expect the passage withheld. |
| + |
| +### N3. P1 — §7's check cannot run on an S3 fetch, so gate 6b cannot be written as stated |
| + |
| +**What is wrong.** §7 lists "an onward S3 fetch" among the disclosure paths that check "the asker". S3 carries no person (§6, memoria §6.1). Gate 6b asserts "its S3 answer … lose[s] that passage and name[s] the app" — S3 answers a body or a 404 (memoria §6.1) and has no representation for "withheld loudly, app named". And there is no person-less call by which B can ask A whether a source is still team-visible. |
| + |
| +**Why.** §11's first line: a gate that cannot be written as stated is a spec bug. This one cannot. Worse, the thing that *would* work is already in the contract and unnamed: S3 itself is the custody probe — B fetches `(id, revision)` from A; 200 means team-visible, 404 means not. |
| + |
| +**Confidence:** high. |
| + |
| +**Smallest correction.** In §7, split the disclosure paths by what they carry: per-person paths (read, export, activity) check S2 for the asker; the custody path (S3) serves envelope-derived passages only for sources B has probed team-visible at the app of record, and strips the rest silently — S3 is custody-only and must not become loud, or gate 3's "404, never 403" gains a third status. Gate 6b's "revoke the source in A" becomes two fixtures: "take the source below the `team` rung" (S3 loses it) and "revoke the asker's grant while the source stays `team`" (read and export lose it; S3 does not). |
| + |
| +Two adjacent gaps in the same rule, both P2 on their own: **what "loses that passage" means once Ana has edited the saved answer** — a CRDT body has no separable passage after the first edit, so either the saved answer is an immutable quoted block that is withheld as a unit, or provenance attaches to the whole item and the whole Doc is withheld, or the rule stops at a person's deliberate act; the doctrine must choose. And **what `STALE` does to a saved answer**: under memoria §4.1 any edit to the Sheet makes the saved revision stale, memoria regenerates but Docs cannot, so a saved answer decays on the source's first edit; say so, or say Docs treats `STALE` as `VISIBLE`-with-a-notice, which is a different rule from memoria's. |
| + |
| +### N4. P1 — The rewind rule is defeated by epoch-number reuse, and a home that loses `memberships` has no rebuild path |
| + |
| +**What is wrong.** §5.3: an instance refuses an epoch below the one it holds "until the home passes its own high-water mark". The home does not know the high-water mark — it was in the backup it lost. Sequence: instance holds 11; home restored at 10; owner adds someone → home is at 11 with a *different* set; the instance sees an equal epoch and, per §5.3, does not refetch; the next write → 12 → accepted, and everyone removed between old-10 and old-11 is readmitted. Finding 5's sequence, delayed by two writes. |
| + |
| +**Second half.** Home §10: *"Losing this database loses credentials, not access. The directory rebuilds as instances re-upsert."* Under ruling 12 the roster does not rebuild — call 2 cannot write membership, no channel runs home→instance, and instances hold the only copies. A home that loses `memberships` loses every team's roster suite-wide, and with no owner in the table nobody can write it. A.1 does not amend §10's sentence, and no recovery is written. |
| + |
| +**Confidence:** high on the collision; medium on the fix shape. |
| + |
| +**Smallest correction.** Epoch is `(generation, counter)`, the generation minted at each home restore; an instance seeing a generation it has not seen treats the home as unavailable until an operator verb re-seeds `memberships` and marks the generation trusted. Write the re-seed into home gate 8's restore drill (each instance's call-8 copy is a candidate source, which is a reason to keep those copies rather than treat them as disposable). Amend home §10 in A.1. |
| + |
| +### N5. P1 — The stale-roster rule pays availability for a property it does not buy |
| + |
| +**What is wrong.** §5.3: past the TTL with no successful fetch, the instance "keeps serving people it has already admitted for the length of their session" — then says the alternative it rejected is "an unreachable home lets a removed member keep their access for as long as the outage lasts". Those are the same thing for anyone already signed in. Instance sessions are rastrillo's 30-day default (memoria §13 says so of memoria; nothing in Docs or Sheets overrides it) and home §2.1 asks for *sliding* renewal, so "the length of their session" is unbounded during an outage. §5.4's promise — removed "within one epoch, and on an instance that admits nobody, within the roster TTL" — has an exception the stale rule creates and does not name. |
| + |
| +**What the rule does cost:** during any home outage longer than the TTL, every instance answers `UNKNOWN` on S2, so memoria withholds every sibling passage for every member for the outage, and no one new signs in — which the home outage already prevents (home §2.1), so that half buys nothing either. |
| + |
| +**Confidence:** high. |
| + |
| +**Smallest correction.** Either refuse team-standing-based requests for *all* sessions past the TTL (which is what "costs availability on purpose" already claims), or state that existing sessions are bounded by the instance session TTL, put a number on that TTL in the contract module with its reason, and write the exception into §5.4. Either way the cost paragraph should stop claiming the rejected alternative is different from the chosen one. |
| + |
| +### N6. P2 — Ruling 12 makes the home hold and enforce a person-level entitlement, and A.1 does not amend the sentences that forbid it |
| + |
| +**What is wrong.** Both factual claims in ruling 12 are true against trunk `2b68301`: home §6 says "`kind` is member or guest", §10's `directory` table is `person ref, app, team sqid, host, kind`, and §7's sentence is quoted accurately (from the fast-path paragraph). But the new table's *writer* rule — "written only by an owner" — is the home deciding "may this person write the roster", and home ruling 19 says the home answers "never 'may this person'", home §7 says "It never forms an opinion about whether a person is entitled to anything", and home §2.2's "what you may *do* is the instance's business" is the stated ground for home ruling 15 rejecting a per-team 2FA floor. §5.2's "is this person on this team is a fact about its records" does not cover "may this person add a member". A.1 amends §7's "never learns" sentence and nothing else in that argument. |
| + |
| +Also unamended by A.1, each now false or stale: |
| + |
| +- Home §2 bullet 1 (finding 2's sentence; see the table). |
| +- Home §2.1 "Losing it costs a convenience, not access — for the directory": under §5.3, a home outage past the TTL now costs access at every instance. |
| +- Home §10 "loses credentials, not access" (N4). |
| +- "Complete ruling 18's pending change of *never renders* to *never stores*" — landed at `2b68301`; A.1 asks for a change that is done. |
| +- §5.3 says call-2 and call-5 responses carry the roster epoch; A.1 only adds the assertion claim and call 8. |
| +- The seeded first owner arrives as a **sealed address** (home §7); `memberships` keys on a person ref; minting a person stub needs the blind index and therefore the pepper (home ruling 4: the home hashes). The drain runs outside the home process (§7). Who hashes is unstated. |
| +- "Move *step-up for instances* to built-when" — home §14's row is an instance-side `RequireFresh` round trip; the roster write is a directory-origin flow. Defensible since the directory obtains sessions like a consumer (§4), but A.1 should say that is the reading. |
| + |
| +**Confidence:** high on every item; they are literal. |
| + |
| +**Smallest correction.** A.1 lists ruling 19's second half, §7's "never forms an opinion", §2's bullet 1, §2.1's line, and §10's sentence as amended, states who hashes the seeded owner's address, and drops the already-landed item. |
| + |
| +### N7. P2 — §0's retirement promise cites a retention that is stated nowhere and is false for memoria's wholesale case |
| + |
| +**What is wrong.** §0: an honest instance retires "within one feed pull plus its stated retention (§4.2)". §4.2 states no retention; S1's per-consumer TTL is the *feed's* retention, not the consumer's purge delay. Ruling 14: "what it must *retire* is stated and timed" — neither. And memoria gate 8: "a wholesale `NOT_VISIBLE` or 404 response states an anomaly and purges nothing"; §5.1's enumeration diff "deletes nothing on a timeout … or partial page". A team folder made private produces a wholesale `gone` in one pull; whether the breaker fires on `gone` rows is unstated, and if it does the honest instance retires nothing — the case finding 6 named explicitly. |
| + |
| +**Confidence:** medium-high; it turns on memoria's breaker semantics, which the doctrine adopts by citation. |
| + |
| +**Smallest correction.** §4.2 names the bound (one S1 pull plus a purge delay with its reason in the module). A sentence that `gone` rows are applied even when wholesale — the breaker is for S2/S3 anomalies, not for the feed — or the promise in §0 shrinks to what the breaker allows. |
| + |
| +### N8. P2 — The ladder's `team` predicate has no rung for "team minus exclusions", which Sheets already has |
| + |
| +**What is wrong.** §4.2's predicate is "readable by every roster member by virtue of team standing alone". Sheets §4.5's join is "rows this team can see, plus rows granted to me individually, **minus rows I have been removed from**". A team-visible sheet with one member excluded is readable by every member but one. Under the predicate as written it is not `team`, so custody excludes it and the whole team loses it in memoria because one person was removed; or Sheets' predicate function calls it `team` and the exclusion is enforced by S2 — which is what the two-rule design intends, and is what the doctrine should say. Same question for calendar, whose team calendar is "a grant everyone holds" (§2), which reads as `granted` under the table. |
| + |
| +**Confidence:** high that it is unstated; the intended answer is clear. |
| + |
| +**Smallest correction.** Predicate: "team standing alone suffices for a member who has not been individually excluded; exclusions are S2's business, not custody's". A.5 says calendar's `Kind = team` maps to the `team` rung. |
| + |
| +### N9. P2 — Link changes and the feed are unstated |
| + |
| +The brief asked. Under ruling 15 the coherent answer is that a link created or revoked on a `team` item is invisible to S1 — not `gone`, not a revision — and a link on any other rung was never announced. The doctrine does not say it, and the leak is real if an app bumps `touched_at` or `revision` on link creation: S1 carries no visibility flag by design, and a metadata bump on link creation is "this team item was just link-shared" through the side door. One sentence in §4.2; one assertion in gate 3 (create and revoke a link on the `team` fixture, expect no feed row). |
| + |
| +### N10. P2 — S6's diagnostic values can reopen the existence distinction (finding 8's second half) |
| + |
| +S6 returns `STALE(cell)`, `NON_NUMERIC(cell)`, `MIXED_UNITS` (memoria §6.1). §6's S6 row says "the custody intersection, as S2" but nothing says `NOT_VISIBLE` dominates every other value, and gate 3 covers only S2. A cell in a `private` sheet answering `NON_NUMERIC` tells a sibling the sheet exists. One sentence in §4.3; one S6 fixture in gate 3. |
| + |
| +### N11. P2 — Four memoria citations resolve only in an unmerged worktree |
| + |
| +"memoria decision 13, Paul, 2026-09-05" (§8), "Decisions 13 and 14 stand" (A.4), "memoria §8.4, gate 26" (§6's S2 row), and leak item 7's "memoria §3.2" rendered-page entry all exist in `memoria/.claude/worktrees/tensorx-provider` and not on memoria's main checkout, which has 21 gates and decisions to 12. The citations are accurate to that worktree — gate 26 is "every passage id in a model prompt is one S2 returned `VISIBLE` for in this same request" — but the doctrine presents them as memoria's spec. Gate 9 checks app→doctrine currency; nothing checks doctrine→app. Smallest: a sources table like `CODEX-FINDINGS.md`'s, naming the commit read per sibling and marking these as pending merge. |
| + |
| +### N12. P2 — Gates that still cannot be written as stated |
| + |
| +- **Gate 5** "after one epoch" still has no observation condition (GPT-6's words, unchanged). Writable as "after the instance's next call-8, driven by a differing claim on the fake clock". No fixture for finding 1's instance-token replay, finding 10's failed middle page, or finding 8's transition. |
| +- **Gate 6b**: N3. |
| +- **Gate 7** "the absent and `null` origin cases decided explicitly" is not an assertion; say refused. |
| +- **§7.3 has no gate at all** (moot under N1). |
| +- **§11's preamble** says gates live in the contract module; gates 5, 8 and 9 cannot — 8 is a home-repo database test, 9 is a script over five repos. Say which gates are fixtures and which are app-side obligations. |
| + |
| +### N13. P3 — `UNKNOWN` now has four meanings and no reason code |
| + |
| +Unsupported subject kind (§3, whole call), sibling past deadline (§6.3), source-behind revision (§4.3, per item), stale roster (§5.3, scope unstated). The consumer's honest move differs — re-ingest, retry, nothing. An additive `reason` on the wire. And say stale-roster `UNKNOWN` is whole-call: per-item, a stale instance would answer `NOT_VISIBLE` for private and deleted items and `UNKNOWN` for team ones, and gate 3's byte-for-byte promise should hold during staleness too. |
| + |
| +### N14. P3 — Small mis-citations, mostly carried from revision 2 |
| + |
| +- §7.1: "Home call 6, whose shape this borrows, carries two protections (home §5.6)". §5.6 is the sign-in redirect protocol; call 6 is §8. The protections are real, the section is wrong. |
| +- §6.3: "a consumer pre-warms on its own wake (memoria §6.5, activity design §6)". Memoria §6.5 does; activity §6 has a minimum pull interval and no pre-warm. |
| +- §5.6: "Docs has none yet". Docs §8.2 has viewer and commenter for links, and §7.4 comments. |
| +- Ruling 13's rejected column, on home §2: see finding 2. |
| + |
| +## 4. Verdict |
| + |
| +**Request changes.** N1 through N5 are each a trust-boundary or build-as-stated defect in text no reviewer has seen, and N1 contradicts a Paul ruling in a sibling repo without naming it. Nine of the sixteen prior findings are partial, mostly where a mechanism is stated and the fixture the finding asked for is not. |
| + |
| +Ruling 15 in particular should not go to Paul as written: the sign-in-mints-guest shape satisfies his four states and needs no new actor, and he ruled against anonymous editing on 2026-08-30. If he wants to reverse that, the row must say so. |
| + |
| +## 5. Worse than revision 2 |
| + |
| +1. **A new contradiction with a settled ruling.** Revision 2 had no link rung and was consistent with Sheets ruling 12 and Docs §8.2. Revision 3's §7.3 builds the alternative that ruling rejected by name, and the document whose one rule is "cite, never restate" does not cite it (N1). |
| +2. **A wrong rule where there was a gap.** Revision 2 was silent on provenance across a write; revision 3 states a rule that names an asker on a person-less call and lists disclosure paths one of which cannot perform it (N3). Under §10, A.2 will carry that rule into Docs as a citation, so it propagates rather than drifts. |
| +3. **A lockout mode where there was lag.** Revision 2's stale roster was lag. Revision 3's is refusal below a high-water mark the home cannot observe, exited by a condition number reuse satisfies falsely (N4), plus suite-wide `UNKNOWN` on S2 during any outage past the TTL for a property the same paragraph gives back (N5). |
| +4. **A promise in §0 with a citation to nothing.** Revision 2's §0 was instantaneous and false. Revision 3's is bounded by "its stated retention (§4.2)", and §4.2 states none (N7). A false absolute is at least legible; a bounded promise pointing at an empty section reads as kept. |
| +5. **The same overclaim GPT-6 caught, one revision later.** "Revision 3 answers all sixteen" in the status block, §12 step 0, §14 and the README, where nine are partial. Revision 2 said "no new machinery"; the doctrine now records that as a defect and repeats its shape. |
| + |
| +Nothing in revision 3 is worse than revision 2 on the twelve findings answered in place except where noted above; the hand-off (§7.1), the epoch claim (§5.3), the leak list (§9) and the Docs §11.2 reading (§8) are clean improvements. |
| + |
| +--- |
| + |
| +### Appendix — gates, refreshed |
| + |
| +| Gate | Writable as stated? | |
| +|---|---| |
| +| 1 Fixture conformance | Yes; call 8's paged shape and S8's write shape still need golden fixtures before it means anything. | |
| +| 2 S2 total decoder | Yes. | |
| +| 3 Custody per rung | Yes for S3 and S2; missing S6 (N10), the link-change no-feed-row assertion (N9), and finding 8's transition. | |
| +| 4 No cross-team dial | Yes. The hand-off destination check is a different code path (form render, not the client); fine to share a gate, say so. | |
| +| 5 Roster | Not yet: "after one epoch" needs an observation; no instance-token replay, no failed-middle-page, no existing-session case for the stale rule (N5), no generation-change case (N4). | |
| +| 6 Write-as-self | Yes. | |
| +| 6b Provenance | No: the S3 clause (N3); no link-view case (N2); "revoke" ambiguous between rung change and grant change. | |
| +| 7 Hand-off | Yes, once "decided explicitly" becomes "refused". | |
| +| 8 Publish the database | Yes, in the home repo, not the contract module. | |
| +| 9 Citation currency | Yes for the arithmetic and commit check; "any normative change" is a judgment the script cannot make, which is fine if the doctrine says a reviewer makes it. | |