Pre-launch FS hardening + WHITEOUT deletion (depth→1024, redirect/contentHash specs, per-name whiteout)#37
Conversation
The 32-level anchor-depth cap was anomalously low: no modern filesystem imposes an explicit directory-depth cap (depth is bounded emergently by path length — Linux PATH_MAX ~2048 levels, Windows long-path ~16k), so 32 wrongly rejected deep trees EFS must be able to mirror. Raise to 1024 (~90x the deepest tree ever observed; gas stays trivial and self-paid). The cap keeps its depth-counter form because that is what actually bounds the ancestor-chain walks (a path-byte cap would not). Free-until-burn: MAX_ANCHOR_DEPTH is a constant in EFSIndexer impl bytecode behind the upgradeable proxy, so the change orphans nothing. Also decide AGAINST an anchor-name length cap (ADR-0058): not needed for correctness (calldata + O(len) validation self-limits absurd names), lens-scoping removes the public grief surface, and truncation is a client concern (ADR-0056 principle). A generous 8192-byte backstop stays available. - EFSIndexer.sol: MAX_ANCHOR_DEPTH 32 -> 1024 (+ reasoning/gas-math comment) - ADR-0058 (new) supersedes ADR-0021; README index + ADR-0021 status updated - docs/FS_OPERATIONS_AUDIT.md (new): full rename/move/delete/symlink/hardlink/ paths capability audit + 3-tier change model (free-forever / until-burn / only-now); concludes zero frozen-field changes needed - FUTURE_WORK.md: resolve the name-length-cap item (decided against) - Tests read MAX_ANCHOR_DEPTH from the contract so they never go stale; value-lock at 1024 + positive deep-tree (40) regression; full build-to-cap revert proof gated behind RUN_SLOW_TESTS=true (1025 anchors ~60s) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…S workflows, redirect follower (all DRAFT/Proposed)
Drafts the items that must be pinned before durable Sepolia data is seeded
(plus the canonical FS workflows). All marked DRAFT / Status: Proposed —
pending maintainer sign-off on the SPICY decisions noted in each.
Specs / ADRs (plans):
- specs/09-redirect-resolution.md + ADR-0059 (Proposed): REDIRECT read-time
resolution — kind-following, D_MAX=8 (ceiling 32), visited-set cycle-stop,
lowest-UID-in-SCC canonicalization, lens precedence, dangling contract,
the WHITEOUT negative-terminal reservation + seeding ban, conformance vectors.
- specs/10-file-metadata-encoding.md + ADR-0060 (Proposed): self-describing
contentHash/size/cid encoding (multibase-multihash + CID), closed reserved-key
registry, conformance vectors.
- specs/04-Core-Workflows.md: canonical move (8a), rename (8b), folder move/
rename (8c), delete (8d) workflows + caveats (8e: cross-attester hardlink
mirror footgun, ghost-folder sticky flag).
- README indexes (adr + specs) updated for 0059/0060/09/10.
Code (additive, redeployable view — NOT frozen, safe to revise):
- EFSFileView.resolveRedirect(source, lenses, maxHops, aliasResolver): bounded
lens-scoped redirect/symlink follower; enum RedirectStatus {Resolved, Dangling,
CycleStopped, DepthExceeded, Suppressed(reserved for WHITEOUT)}.
- AliasResolver: additive ERC-7201 activeRedirectBySource index + getActiveRedirect
getter (the upgradeable advisory reverse index ADR-0050 anticipated; pre-burn-safe
append, but storage on a frozen-proxy — SPICY, needs layout review before burn).
- test/RedirectResolution.test.ts: 23 passing (12 conformance vectors).
Gate: compile clean, docs:check consistent, eslint + check-types clean,
redirect test 23 passing, affected suites (AliasResolver/EFSFileView) 59 passing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…A-256 James ratified three decisions (2026-06-20); fold them into the now-Accepted ADR-0059/ADR-0060 + specs/09/10 + the redirect follower code. #1 Versioning (path=newest, UID=exact): the redirect follower now auto-follows ONLY symlink (kind=2). supersededBy (1)/sameAs (0)/reserved (3+) are non-followed terminals — a version chain is a discoverable on-chain breadcrumb, not auto- navigation. "Newest" comes from the publisher re-pointing the path's placement; a fixed UID/link never silently advances (preserves no-silent-revision). #3 D_MAX default 8 -> 16 (hard ceiling stays 32): covers long real chains; gas trivial. #4 contentHash canonical = sha2-256 (multihash code 0x12, f1220<64-hex>), so a file's EFS contentHash shares its IPFS CID digest (one hash, not two). Keep the self-describing multibase-multihash format; keccak-256 demoted to optional alternate. (keccak stays only for the unrelated PROPERTY value-interning hash.) - EFSFileView.resolveRedirect: follow symlink only; _REDIRECT_D_MAX 8->16 - specs/09 + ADR-0059 -> Accepted; rules, vectors, algorithm updated - specs/10 + ADR-0060 -> Accepted; sha2-256 canonical + recomputed vectors - test/RedirectResolution.test.ts: 26 passing (supersededBy terminal; 16-cap boundary) - README indexes: drop "Proposed" on the four flipped entries Gate: compile clean, RedirectResolution 26 passing, docs:check consistent, lint clean. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Permanence-tier: Durable
Cross-lens negative-mask schema per ADR-0055 (lens-local delete of inherited content). Implementation complete and compiling; dedicated conformance test suite + full verification still pending (next commit). - WhiteoutResolver.sol (new): empty schema, ANCHOR-only refUID (v1), ERC-7201, two-structure storage (append-only discovery list + active-marker map), write guards (SourceNotAnchor/OrphanAnchor/ZeroRef/BadPayload/HasExpiration/ NotRevocable), readers getChildrenWhitedOut/Count + isWhitedOut. Read-side only (no kernel writes). - schemas.ts: WHITEOUT 10th schema (additive post-freeze) + WhiteoutResolver (7th). - EFSFileView: whiteout predicate in plain + filtered directory listings. - EFSRouter: negative-terminal in the lens scan. - deploy/08_whiteout.ts + deploy-lib wiring + verify-gate getter. - Test helpers updated for the new ctor args. ANCHOR-only v1; opaque-directory + DATA-whiteout deferred (additive). Per ADR-0055. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Permanence-tier: Durable
Completes the WIP from the prior commit. WhiteoutResolver + EFSFileView predicate + EFSRouter negative-terminal verified against all 10 ADR-0055 conformance vectors; no implementation bugs found. - test/Whiteout.test.ts (new, 21 tests): per-name hide, lens-scoped below/above, same-lens override, revoke un-hides, idempotent/no-op-safe, cross-lens unaffected, re-whiteout last-writer-wins, all 7 write-guard rejections (ZeroRef/BadPayload/NotRevocable/HasExpiration/SourceNotAnchor x4 / OrphanAnchor / WrongSchema), router negative-terminal (404, no fall-through, revoke restores). - EFSFileViewFiltered.test.ts: reformat the testable-deploy ctor call (3rd whiteout arg pushed it over the prettier width gate) — format only. Verification: compile clean; Whiteout 21, EFSFileView 15, EFSFileViewFiltered 24, RedirectResolution 26, EFSTransports 44, EFSDataModel.e2e 50 all passing; lint clean; docs:check consistent. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Tested-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Permanence-tier: Durable
…d coverage) Three-lens adversarial review (viewer-sovereignty, storage/upgrade, gas/DoS) returned zero P0/P1/P2. Addressed the P3 polish: - getFilesAtPath now applies the whiteout negative-terminal (was asymmetric with the router's _findDataAtPath — a viewer could see DATA via the view that the router would 404). Same precedence: positive PIN before whiteout, lens order; getParent SLOAD guarded on whiteoutResolver != 0. Adds getParent to EFSFileView's IEFSIndexer interface. CONSUMER-VISIBLE behavior change on a Durable surface (intentional, per ADR-0055 readdir+resolution parity). - Filtered-listing whiteout coverage: the filtered walker had zero whiteout tests (deployed with ZeroAddress). Added drop-from-filtered + both-tag- exclusion-and-whiteout-skip-once (no double-decrement / cursor corruption). - AGENT-NOTEs: onRevoke typing-skip safety (anchors immutable); folder same-lens override fires only for DATA-PIN files (opaque-directory deferred per ADR-0055). Whiteout 25, EFSFileViewFiltered 24, EFSFileView 15, e2e+transports 94 passing; lint clean; docs:check consistent. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Reviewed-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Tested-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Permanence-tier: Durable
…etion Extends per-name whiteout to the full overlayfs/unionfs model. - WHITEOUT_OPAQUE sibling schema (fieldString "bool opaque" — distinct UID; empty would collide with per-name's self-derived UID), same WhiteoutResolver: activeOpaque + append-only opaqueDirs storage, guards (OpaqueTargetNotFolder requires refUID = generic folder), isOpaque reader, 2nd self-UID in initialize. - EFSFileView: opaqueIdx cut-line computed once per page, folded into the listing predicate (single-pass preserved); folder re-add fix (positive terminal now = file PIN OR folder visibility-TAG via _one(lens), no EdgeResolver change); resolution predicate stays PIN-only (correct overlayfs lookup semantics). - EFSRouter: full-unionfs (2-B) — per-segment opaque cut 404s a deep link into a suppressed subtree; per-name terminal kept. - Two USER verbs documented (specs/04): delete(path) auto-selects the marker (overlayfs-style, never makes the user choose) + makeExclusive(folder) = opaque curation act. delete-means-gone enforced across listing AND resolution. DATA-whiteout explicitly out-of-scope (not a unionfs concept). - Deploy: 11th schema (additive post-freeze, frozen 9 untouched); verify asserts both self-UIDs. Golden vectors pin both WHITEOUT UIDs. - Also fixed pre-existing breakage from the WIP commit (router 6-arg deploy, check-types in safePlan/08_whiteout/simulate-freeze-set, =9 freeze-count asserts). Whiteout 54 passing; full suite 676 passing 0 failing; lint + check-types + docs clean. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Tested-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Permanence-tier: Durable
Opaque-directory review returned zero P0/P1/P2; addressing the P3 polish. - 3 new conformance vectors (Whiteout.test.ts, now 57 passing): higher-lens whiteout of the opaque-lens's own child wins; two-opaque-lens stack → highest-precedence opaque is the cut; router intermediate-segment opaque cut 404s a deep link through a below-cut subfolder. - orchestrate.ts: per-schema smoke log "10/10" → dynamic SCHEMAS.length (was stale at 11 schemas). - EFSFileView.sol: fix _suppressedInOpaqueWalk NatSpec referencing a nonexistent _isItemWhitedOutForListing (it IS the listing predicate; resolution twin is _isItemWhitedOutForResolution). - FUTURE_WORK: note two optional hardenings (MAX_PATH_SEGMENTS defense-in-depth on the router walk; paged getOpaqueDirs reader) — not built. No behavior change beyond the two stale-string fixes. Whiteout 57 passing; lint + docs:check clean. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Reviewed-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Tested-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Permanence-tier: Durable
Decision: the on-chain redirect follower is deferred (built when redirects are actually used); its rules stay pinned (needed before any durable REDIRECT seeding) and may be refined at implementation time. - EFSFileView: remove resolveRedirect + RedirectStatus/RedirectResolution + IAliasResolverForFileView + follower-only helpers. All WHITEOUT code + getParent (used by whiteout) kept. - AliasResolver: remove activeRedirectBySource + getActiveRedirect + their onAttest/onRevoke writes -> back to ZERO storage change vs main (drops the only frozen-proxy storage change). - Delete test/RedirectResolution.test.ts. - specs/09 + ADR-0059 kept (Status: Accepted — rules pinned), reframed as "implementation DEFERRED; these are the rules the future follower must satisfy." Grep: zero dangling references in any .sol/.ts/deploy/artifact. Whiteout 57 passing; regression 214 passing; lint + check-types + docs:check clean. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Permanence-tier: Durable
Decision: opaque-directory whiteout has no concrete use case. Removed; re-adds additively later if a real "show only mine in this folder" need appears. The complete per-name deletion model stays (this is what real use needs): revoke (own content -> genuine not-found) + per-name whiteout (inherited content, file OR folder) + the folder re-add override fix + client-cascade docs. - WhiteoutResolver: remove WHITEOUT_OPAQUE schema/storage/guards/readers; back to single per-name schema. - EFSFileView: _suppressedInOpaqueWalk -> _isItemWhitedOutForListing (per-name + folder re-add fix; opaque cut removed); _isItemWhitedOutForResolution unchanged. - EFSRouter: remove per-segment opaque cut; per-name terminal kept. - deploy/schemas/verify/golden-vectors: back to 10 schemas (frozen 9 + WHITEOUT). - specs/04: one delete verb (auto-marker-select + last-child folder cascade); specs/02 WHITEOUT row only; ADR-0055 status note (per-name done, opaque deferred); FUTURE_WORK records opaque as deferred. Grep: zero opaque refs in code/tests. Whiteout 27 passing; regression 225 passing; lint + check-types + docs:check clean. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Permanence-tier: Durable
Main claimed 0058-0061 for router/web3/multichain work. Renumber this branch's ADRs to the next free numbers: 0062 (raise MAX_ANCHOR_DEPTH), 0063 (REDIRECT read-time resolution), 0064 (contentHash self-describing encoding). Files renamed via git mv; all references updated (specs 09/10, README indexes, ADR-0021 status, EFSIndexer comment, depth tests, FS audit, FUTURE_WORK). docs:check clean. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…chor-depth # Conflicts: # docs/adr/README.md
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 50b590402d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
JamesCarnley
left a comment
There was a problem hiding this comment.
[gpt-5-codex · review]
Same-account advisory review: BLOCKING
Base/head: main@cec24365 → 50b590402d35dffc46fa7ec2e921acf5da4faca0.
Reviewers/personas run: protocol/spec/ADR, Solidity/security, router/deletion semantics, FileView pagination/perf, deploy/CI/release, tests/coverage, coordinator adversarial pass.
Preflight: PR description and Agents involved read; repo guidance/spec docs read; native review threads refreshed via yarn pr:intake 37 and GitHub review-thread state. Duplicate policy: do not duplicate existing native threads; add only distinct new inline findings.
Blocking findings:
- Existing native P1 thread confirmed: router path traversal only applies WHITEOUT at the final target, so a deep link can bypass a whited-out ancestor folder. That contradicts the new
specs/04rule that deep links into a whited path 404. - Existing native P2 thread confirmed: plain
EFSFileViewphase-1 listing can scan an unbounded tail of whited-out direct file anchors because the new whiteout skip consumes no result slot and the plain walker lacks the filtered walker’s file-scan budget. - New inline P2: listing positive override accepts a same-lens TAG on file anchors, so a whited-out file can reappear in directory listings while router/getFilesAtPath still return it as deleted.
- Live CI P1:
deploy-pin-checkis failing on the current head. The job reportsdeployedContracts.ts drifted from the committed version; the branch adds/wiresWhiteoutResolver, but the committed app artifact was not regenerated. - Docs/release P2s remain: ADR-0055’s new status line conflicts with the ADR body; redirect taxonomy still says
sameAs/supersededByare followed even though ADR-0063/specs/09 make symlink the only followed kind; workflow/overview prose still sayscontentHashiskeccak256instead of canonicalsha2-256multibase-multihash; workflow/indexing prose still saysMAX_ANCHOR_DEPTH = 32; Safe/deployment docs still describe 6 resolvers / 9 schemas / register×9 even though the code now plans WHITEOUT as resolver/schema 7/10. - Release-test P2:
DeploySafe.fork.test.tsstill assertsObject.keys(result.proxies).lengthOf(6)whileRESOLVERSnow has 7 entries; the normal CI suite does not exercise that fork rehearsal.
One nuance: I did not add a duplicate deploy-order thread. The existing 08_whiteout.ts thread still needs a dev reply, but one deploy reviewer found the legacy scripts are currently inert through legacySuperseded; if that thread is stale, reply/push back natively and resolve it after the reviewer agrees. The red deploy-pin-check is the concrete release blocker either way.
Verification I ran locally on the detached PR-head worktree:
git diff --check origin/main...HEAD— passed.yarn docs:check— passed.yarn hardhat:lint --max-warnings=0— passed.yarn workspace @se-2/hardhat test test/Whiteout.test.ts test/EFSRouter.test.ts test/EFSFileView.test.ts test/EFSFileViewFiltered.test.ts— passed, 133 tests.yarn hardhat:check-types— passed after TypeChain generation from the test compile.
GitHub checks refreshed at review time: ci passed, contract-tests passed, deploy-pin-check failed. The PR should not merge until the unresolved native threads are fixed/replied-to, deployedContracts.ts is regenerated so the pin check is green, and the stale docs/fork rehearsal proof are updated or explicitly deferred with maintainer sign-off.
P1 (router deep-link 404): the per-name whiteout terminal ran only on the final path segment, so a deep link into a whited-out folder still served a lower lens's child (specs/04 requires a 404). The effective lens stack is now hoisted to request() and a per-segment whiteout terminal (_isSegmentWhitedOut, PIN-only positive + whiteout negative, same precedence) runs after each resolved segment before descending. Guarded on whiteoutResolver != 0. +test. P2 (plain listing scan budget): plain phase-1 getDirectoryPageBySchemaAndAddressList skipped whited-out files without a _FILE_SCAN_BUDGET_PER_CALL guard (the filtered walker has one), so a dir with many hidden direct files could scan the whole remaining source in one call. Mirrored the budgeted walk + opaque-cursor continuation. +test. P2 (deploy ordering): 08_whiteout now tags "WhiteoutResolver"; 02_fileview and 03_router declare it a dependency so it deploys before the views (was running after -> views wired ZeroAddress whiteout). Latent today (legacy scripts inert; the orchestrated CreateX path already wires it correctly) but structurally fixed. Verified: compile clean; Whiteout (incl. deep-link-404 + budget vectors), EFSRouter 67, EFSTransports 44 passing; lint + check-types + docs:check clean. (3 pre-existing heavyweight-seed/E2E timeouts are environmental — reproduce on the clean baseline, don't touch the changed paths.) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Tested-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Permanence-tier: Durable
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2892e88d74
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ted addrs) deploy-pin-check failed because this PR adds WhiteoutResolver and changes EFSIndexer/EFSFileView/EFSRouter bytecode, so the committed pinned-fork artifact was stale. Regenerated via `yarn fork && yarn deploy` at FORK_BLOCK=10691000 (ADR-0037 pin): adds the WhiteoutResolver block and updates the view addresses (EFSFileView/EFSRouter/ListReader) that shift when the new resolver enters the deploy nonce sequence. 31337 fork block only; the 11155111 Sepolia block is preserved (per-chain merge, ADR-0061). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…not nonce+1 The nonce+1 proxy-address prediction is only correct on a first run where both the impl and proxy deploy txs are sent. On a retry where hardhat-deploy reuses an unchanged WhiteoutResolverImpl (no tx, newlyDeployed=false), the proxy is not at nonce+1, so the predicted address — and the schema UID derived from it — is wrong, and the self-UID gate aborts (non-idempotent local deploy). Now the UID is computed from whiteoutResolver.target after the deploy/reuse decision; the self-UID gate is the cross-check. (Script is currently inert behind legacySuperseded, so this is latent — but correct for reactivation.) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: abd307d62d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…t traversal The per-segment whiteout 404 check used a PIN-only positive terminal, so a lens that whiteouts an inherited folder /dir and then RE-ADDS it (uploading /dir/own.txt emits a folder visibility TAG, not a placement PIN) still had every deep link through /dir 404'd — even though listings correctly show the re-added folder. Now the per-segment check fires only on INTERMEDIATE (non-leaf) segments and its positive terminal is PIN OR folder visibility-TAG (definition=dataSchema, via _one(lens) + hasActiveTagFromAny) — byte-for-byte the EFSFileView listing predicate. The leaf DATA lookup stays PIN-only in _findDataAtPath (a folder TAG must not un-gate a direct file read). Overlayfs nuance encoded + tested: after owner whiteouts+re-adds /dir, a lower-lens child it did NOT individually whiteout (/dir/child.txt) correctly resolves (200) — directory whiteout exposes lower children not individually whited; and a directly-whited leaf still 404s (leaf gate intact, asserted). Whiteout 30, EFSRouter 67 passing; lint + check-types + docs:check clean. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Tested-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Permanence-tier: Durable
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 03602d64ce
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…4 depth cap This PR added specs/10 (canonical sha2-256 multihash contentHash, ADR-0064) and raised MAX_ANCHOR_DEPTH to 1024 (ADR-0062), but the authoritative upload workflow in specs/04 still told clients to compute bare keccak256 for contentHash and to bound the ancestor visibility-TAG walk at MAX_ANCHOR_DEPTH=32 (ADR-0021). Since specs are authoritative and PROPERTY values are non-revocable, a conformant client would permanently mint non-canonical hashes and would stop emitting visibility TAGs above level 32 (deeper folders invisible in lens listings). Fixed both: - contentHash steps (workflows 1, 2, + overview upload flow) now specify the canonical sha2-256 multibase-base16 multihash (f1220…) per specs/10/ADR-0064. - the visibility-walk bound now references MAX_ANCHOR_DEPTH=1024 (ADR-0062) and tells clients to read EFSIndexer.MAX_ANCHOR_DEPTH() rather than hardcode. docs:check clean. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Main merged ADR-0062 (EFS Devnet chain id 26001993, PR #30 family). Renumber this branch's depth ADR 0062 -> 0065; keep 0063 (redirect) / 0064 (contentHash), which remain free on main. Files + all refs updated; docs:check clean. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…chor-depth # Conflicts: # docs/FUTURE_WORK.md # docs/adr/README.md
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 139dfde84c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…y phase Addresses two P2 review findings on the WHITEOUT branch (PR #37). Finding 1 — viewer-sovereignty hole (EFSFileView): the attester-scoped, schema-agnostic getDirectoryPageByAddressList returned the raw indexer page with no whiteout filter, so a child whited out by a higher-precedence lens still surfaced through this exposed API even though the schema-aware listings suppress it. Filter the fixed page in place with the same _isItemWhitedOutForListing predicate (positive terminal = file PIN OR folder visibility-TAG keyed on DATA_SCHEMA_UID, matching standard browsing). The indexer's own source cursor is unaffected by how many items we drop, so pagination stays correct. Zero-cost when the whiteout resolver is unset. Finding 2 — additive post-freeze deploy (deploy-lib): appending WhiteoutResolver to the core resolver set made the Safe machinery expect it in Batch 1, but detectDeployPhase keyed Phase 0 only on EFSIndexer. In the real Sepolia path (nine-schema core already live, only WHITEOUT missing) the flow then threw in buildDeploysFromOnchain because no code existed at the predicted WhiteoutResolver address. Add a dedicated additive step: detectMissingResolvers finds resolvers with no on-chain code while the core is live; buildAdditivePlan deploys ONLY those proxies (born Safe-owned) and registers ONLY their schemas; execute + propose paths branch to it before the core ceremony. detectDeployPhase is now additive-aware (a schema whose resolver proxy is absent no longer masquerades as a fresh Phase-1 owe), so a complete core resolves to Phase 3. Detection is impl-free and gated on a live indexer, so the fresh-deploy path is unchanged and a non-additive resume deploys no impls (FIX B preserved). Also un-rot two DeploySafe.fork assertions that hardcoded the pre-WHITEOUT resolver count (6 / 8 legs) — bound to RESOLVERS.length so future additive resolvers don't break them. Verified (Sepolia fork): DeploySafe.fork 7/7, DeploySafeAdditive.fork 4/4 (incl. live-core-adds-only-WHITEOUT end-to-end + propose A1→A2 walk), Whiteout 31/31 (incl. the new address-list bypass vector), EFSFileView / Filtered / Router suites green; lint + check-types clean. Permanence-tier: Durable Refs: ADR-0055, specs/04-Core-Workflows.md Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 52dc78dc01
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ile ADR-0055 status Addresses two more P2 review threads on PR #37. EFSFileView listing/resolution consistency: _isItemWhitedOutForListing's positive terminal accepted a folder-visibility TAG (the folder re-add fix) on ANY anchor, including a file anchor. A lens could whiteout a lower-lens file.txt then attach a TAG (definition = DATA_SCHEMA_UID) on that same file anchor to un-hide it in directory listings, while getFilesAtPath and the router stayed PIN-gated and still returned it deleted — a viewer-facing inconsistency. Gate the TAG branch to GENERIC FOLDER anchors (forSchema == 0, the same discriminator _buildFileSystemItems uses for isFolder), decoded once per item. A file anchor's only positive re-assertion is now its placement PIN, matching resolution. The folder re-add fix (vector 14) is unchanged — folders still re-add via their visibility TAG. New vector 17 proves a same-lens TAG on a whited-out FILE anchor does NOT un-hide it, in both listing views, with getFilesAtPath agreeing it's deleted. ADR-0055 status reconciliation: the prior in-line "IMPLEMENTED" status note contradicted the Decision/Required-semantics body (which still lists refUID = ANCHOR or DATA and calls opaque-directory "required"). Rewrote the Status line — the ADR's one sanctioned mutable slot per docs/adr/README.md — as a clean amendment: shipped scope is per-name ANCHOR-only; the DATA- refUID variant is dropped and opaque-directory deferred (neither shipped); the body is preserved unedited as the original design vision; specs/02 and specs/04 are authoritative for shipped behavior. The Decision / Consequences / Alternatives sections (the immutable historical record) are untouched. The narrowing itself was ratified earlier this session. Verified: Whiteout 32/32 (incl. vector 17), EFSFileView / Filtered / Router 106/106, compile clean, lint + hardhat:check-types + docs:check green. Permanence-tier: Durable Refs: ADR-0055 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: af31aef431
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…y with symlink-only following Two spec-consistency P2s on PR #37 (both doc-only, reconciling specs to already-ratified decisions). specs/04 (move/rename/folder-move): workflows 8a/8b/8c still told clients that moving INHERITED content "cannot suppress the old source" and degrades to "also place at the new path" — stale now that this PR ships WHITEOUT (workflow 8f). A client following the old text would re-pin at the destination and leave the old path visible. Updated the inherited-content paths: own content revokes the source PIN (Step 4); inherited content attests a per-name WHITEOUT on the source anchor instead (lens-local, ADR-0055 / 8f). Folder move whiteouts old descendant anchors + the emptied old folder via the 8f cascade. specs/02 (REDIRECT taxonomy): the kind table still said sameAs/supersededBy are "Followed at read time" and symlink "Followed one hop", contradicting the ratified symlink-only-following rule (ADR-0063 / specs/09). An SDK implementing from specs/02 could auto-follow supersededBy and silently revise a fixed DATA link. Reconciled: symlink is the ONLY auto-followed kind (a D_MAX-bounded, cycle-safe walk); sameAs (canonicalization-only) and supersededBy (version breadcrumb, "latest" reached via the path's placement PIN) are non-followed terminals. Pointed the section at specs/09 as authoritative for follow rules. Permanence-tier: Durable Refs: ADR-0055, ADR-0063, specs/09-redirect-resolution.md Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…live P2 follow-up on PR #37 (companion to the specs/09 §10 fix). ADR-0067's Decision items 6-7 still framed WHITEOUT as future-only and scoped the sentinel-seeding ban to "Until the WHITEOUT schema exists" — which now ships in this PR, so a reader could treat the ban as expired and mint reserved REDIRECT/TAG/PIN/DATA tombstones as durable suppression facts. Amended: item 6 — WHITEOUT is a live, separate schema whose negative terminal is applied by the router/file view, never produced by this redirect follower (the `Suppressed-reserved` slot is defined-but-never-returned because suppression lives elsewhere, not because it's unbuilt). Item 7 — the seeding ban is PERMANENT and does not expire; suppression comes only from the WHITEOUT schema; sentinels stay banned forever (the category-error cost is identical before/after WHITEOUT ships). Related-line tag updated to match. Consistent with specs/09 §7/§10 and ADR-0055. Permanence-tier: Durable Refs: ADR-0067, ADR-0055, specs/09-redirect-resolution.md Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
JamesCarnley
left a comment
There was a problem hiding this comment.
[gpt-5-codex · final re-review]
Re-reviewed current head 59e847664a75466a1da53fb7242cccd541067073 after the latest fixes. I found no new blocking findings and did not add duplicate inline threads.
Current live GitHub state:
- Native review threads: 26 total, 0 unresolved (
yarn pr:intake 37and GraphQL reviewThreads agree). - Merge state:
CLEAN,MERGEABLE, not draft. - Checks:
ci,contract-tests, anddeploy-pin-checkall succeeded.
Local verification on the detached PR-head worktree passed:
git diff --check origin/main...HEADyarn docs:checkyarn hardhat:lint --max-warnings=0yarn hardhat:check-typesyarn workspace @se-2/hardhat test test/Whiteout.test.ts test/EFSRouter.test.ts test/EFSFileView.test.ts test/EFSFileViewFiltered.test.ts test/EFSIndexer.index.test.ts test/SchemaGoldenVectors.test.ts test/DeploySafe.fork.test.ts test/DeploySafeAdditive.fork.test.ts test/EFSDataModel.e2e.test.ts test/EFSTransports.test.ts— 293 passing, 13 fork-only pending/skippedyarn next:lint --max-warnings=0yarn next:check-typesyarn workspace @se-2/nextjs test— 99 passing
From this review pass, PR #37 is merge-ready from the review/check/verification perspective.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 59e847664a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
JamesCarnley
left a comment
There was a problem hiding this comment.
[gpt-5-codex · follow-up re-review]
Superseding my immediately previous merge-ready comment: the automated connector review that landed after it opened two new P2 native threads, and I verified both are valid.
Current blockers:
specs/03-Onchain-Indexing-Strategy.mdstill documentsMAX_ANCHOR_DEPTH = 32for the upward propagation walk, while the live contract/ADR-0068 now set the cap to 256.- The same spec still says public
index(bytes32)runs the same global indexing logic asonAttest, including upward propagation, while this PR intentionally changedindex()/indexBatch()to discovery-only with no schema-blind folder-presence propagation per ADR-0066.
Checks are green and my local code verification remains clean, but review state is no longer clean because native GitHub has 2 unresolved threads needing a dev reply/fix. PR #37 should not merge until those spec updates land or the threads are explicitly resolved with maintainer agreement.
Two spec-sync P2s on PR #37 — specs/03 (authoritative for kernel/indexing behavior) lagged the contract changes this PR made. - §"_containsAttestations Propagation Behaviour": MAX_ANCHOR_DEPTH stated 32; updated to 256 (ADR-0068), with the write-side gas rationale and the 32→1024→256 history so spec readers / launch review use the live cap. - §"Public Index API": described index()/indexBatch() as running the same global indexing as onAttest "including upward propagation". Updated to DISCOVERY-ONLY (ADR-0066): index() makes any attestation findable (schema/ attester/sent/received/referencing + the schema-scoped _containsSchemaAttestations fact) but does NOT propagate schema-blind folder presence (_containsAttestations/_childrenByAttester) — that is owned by real placement (PIN/TAG via propagateContains, anchor creation). Prevents a resolver/client from relying on permissionless index() to populate folder presence, which the code intentionally no longer does. Permanence-tier: Durable Refs: ADR-0066, ADR-0068 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
JamesCarnley
left a comment
There was a problem hiding this comment.
[gpt-5-codex · final re-review]
Re-reviewed current head 9d28399f42d1bbdc2c33b692225ebe62b821e520 after the specs/03 fix. I found no new blocking findings and did not add duplicate inline threads.
Current live GitHub state:
- Native review threads: 28 total, 0 unresolved (
yarn pr:intake 37and GraphQL reviewThreads agree). - Merge state:
CLEAN,MERGEABLE, not draft. - Checks:
ci,contract-tests, anddeploy-pin-checkall succeeded.
Focused local verification on the detached PR-head worktree passed:
git diff --check origin/main...HEADyarn docs:checkyarn workspace @se-2/hardhat test test/EFSIndexer.index.test.ts test/EFSTransports.test.ts— 73 passing, 1 slow depth-cap pending/skipped
Earlier full-head verification for this review cycle also passed on the same PR series before the specs-only follow-up: hardhat lint/typecheck, next lint/typecheck/tests, and the broader WHITEOUT/router/file-view/deploy-focused suite. From this current pass, PR #37 is merge-ready from the review/check/verification perspective.
…-max-anchor-depth Conflicts resolved: - deploy-lib/orchestrate.ts (smoke comment): kept main's post-seal-retry explanation (smoke runs on every path; seal() fires before smoke, so alreadySealed != smoke-complete) and corrected the schema count 9 → 10 (this branch's perSchemaSmoke attests WHITEOUT too, ADR-0055). - nextjs/contracts/deployedContracts.ts: generated file — took this branch's copy as the base; regenerated from a fresh deploy of the merged contracts in the follow-up so it matches both main's PR #40 and this branch's EFSIndexer/WhiteoutResolver/view changes. Verified post-merge: hardhat suite 654 passing, DeploySafe.fork + DeploySafeAdditive.fork 12 passing, lint + hardhat:check-types + next:check-types green. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Regenerated against a fresh fork deploy of the merged contract set (main's PR #40 post-seal-retry + this branch's EFSIndexer/WhiteoutResolver/view changes). Only the 3 redeployable, stateless view addresses shifted — EFSFileView, EFSRouter, ListReader — because the merged deploy nonce sequence changed; they are baked into no schema UID. The kernel, resolvers, SystemAccount, and every schema-UID-bound contract kept their deterministic CREATE3 addresses, and all 9 frozen schema UIDs are unchanged. deploy-pin-check now matches a fresh deploy. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3e5f084a09
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… schema) P2 on PR #37. Adding WHITEOUT to the deployed schema/resolver set means the operator runbooks must include its resolver proxy + ProxyAdmin in the burn ceremony, but docs/DEPLOYMENT.md and docs/SEPOLIA_FREEZE_TABLE.md still described 9 schemas / 6 resolvers / 7 ProxyAdmins — so a burn following them would renounce 7 ProxyAdmins and leave WhiteoutResolver's outside the immutability ceremony (a live schema's resolver still Safe-upgradeable). Fix (without rewriting the signed 9-schema freeze, which is historical and did register exactly nine): - SEPOLIA_FREEZE_TABLE.md: added a "WHITEOUT — additive 10th schema (post-freeze, ADR-0055)" section with its own one-row sign-off (resolver proxy + UID filled at the additive deploy), and noted WhiteoutResolver is NOT OwnableUpgradeable (only its ProxyAdmin is renounced). Burn checklist (a) now reads 7 ProxyAdmins without WHITEOUT / 8 once it is deployed, and lists WhiteoutResolver among the no-contract-owner resolvers. - DEPLOYMENT.md §0: added the additive-WHITEOUT bullet (7th resolver proxy / 8th CREATE3 contract / 8th ProxyAdmin when present, via the additive deploy path). Burn paragraph updated to 7-or-8 proxies and adds WhiteoutResolver to the initialize()-only (no-renounce) resolver list. Permanence-tier: Durable Refs: ADR-0055, ADR-0048 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 52d4583eca
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…not revoke P2 on PR #37. The delete workflow said "own placement → revoke → genuine not-found", but that only holds when nothing is inherited beneath the path. When your PIN/TAG OVERRIDES a lower lens (e.g. you shadowed system's file), revoking your own edge removes the positive terminal and first-attester-wins falls THROUGH to the lower lens — the file reappears (revert-to-inherited), not deleted. A client following the old text would resurface a deleted override from below. Fixed §8f delete(path) to be three-way and distinguish intents: - own placement, nothing underneath → revoke (genuine not-found); - own placement SHADOWING a lower lens → revoke AND whiteout (both required: a bare revoke reverts to inherited; a whiteout without revoke loses to your own active PIN via same-lens positive-before-whiteout); - inherited only → whiteout directly. Added a revertToInherited(path) = revoke-only sibling so "remove my version" isn't conflated with "this shouldn't exist here." Corrected the lens-local bullet and added a shadowing caveat to the §8d revoke primitive. Permanence-tier: Durable Refs: ADR-0055, ADR-0031 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 02bd5e45d1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…n-delete P2 on PR #37. The documented un-delete path is eas.revoke(WHITEOUT_SCHEMA, whiteoutUID), but WhiteoutResolver only exposed isWhitedOut (bool) and getChildrenWhitedOut (child anchors) — so a reloaded client that knows the (parent, attester, child) slot could not recover the active WHITEOUT UID without off-chain event-log replay. Worse after a re-whiteout: revoking a stale UID intentionally no-ops (vector 8), so the client needs the CURRENT UID specifically. Added an additive view getActiveWhiteout that returns the live UID for a slot (or 0). Pure read of the existing activeWhiteout storage — no storage change, no schema-UID change (the WHITEOUT UID keys on the unchanged proxy address); free-until-burn, and WhiteoutResolver isn't deployed on real Sepolia yet so it ships in the initial deploy. New vector 19: 0 when none → live UID after attest → NEW UID after re-whiteout → 0 after revoking the getter's UID. specs/04 §8f un-delete now points at the getter. Regenerated deployedContracts.ts (WhiteoutResolver ABI gains the getter; addresses unchanged). Whiteout 34/34; lint/check-types/docs:check green. Permanence-tier: Durable Refs: ADR-0055 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 720c3b726e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ent 0) P2 on PR #37. Schema/Attestation containers seed currentParent from a root *alias anchor* and start the path walk at startIdx=1, so the per-segment deep-link whiteout terminal never checked segment 0 (the alias). A viewer who whited out a schema/attestation alias anchor at root could still have a deep link `/0x<uid>/child.txt` descend THROUGH the whited alias and serve lower-lens content — the exact bypass the per-segment fix closed for ordinary folders. Apply the same `_isSegmentWhitedOut(root, aliasUID, effLenses)` terminal on the alias seed before the loop, when an alias was actually used (a raw-UID seed is not a tree anchor) AND there are deeper segments (so the alias is an intermediate folder — the bare-alias leaf stays PIN-gated via _findDataAtPath, matching the loop's leaf rule). Returns the same 404 as the per-segment terminal. EFSRouter is a stateless redeployable view; internal-only change, no ABI/address change, deployedContracts unchanged. New Whiteout vector (in the vector-10 router stack): a deep link through a whited-out schema-alias anchor 404s for [owner, alice] (no fall-through) and serves 200 for the control lens [alice]; un-whited control is 200. Router suite 67/67; Whiteout 35/35; lint/check-types/docs:check green. Permanence-tier: Durable Refs: ADR-0055, ADR-0033 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 509b5a3155
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…cost guard) P2 on PR #37 — a regression from the folder-vs-file gate (vector 17 fix). _isItemWhitedOutForListing decoded the child anchor via eas.getAttestation UNCONDITIONALLY to classify folder-vs-file, so every listing candidate paid an extra external EAS read whenever whiteout was wired — even on ordinary pages with no active whiteouts — and kept entries were decoded AGAIN in _buildFileSystemItems. That ~doubles per-item EAS reads on large listings, violating the specs/02 WHITEOUT "no per-item doubling" read-cost invariant. The only way this predicate drops an item is an active whiteout on it (positives merely override a whiteout). So scan the lens stack for ANY whiteout FIRST — O(1)-class WhiteoutResolver mapping reads, no getAttestation — and return false early when none. The folder-classification decode now runs only for an item that actually carries a whiteout (rare). Ordinary no-whiteout pages pay ZERO extra EAS reads; the single decode for kept items stays in _buildFileSystemItems. Internal-only change to a stateless view — no ABI/address change, deployedContracts unchanged. Verified: vectors 13-19 (folder re-add, file-anchor gate, budget scan, the address-list + getFilesAtPath terminals) + EFSFileView/Filtered suites all green (74 passing); the pre-pass preserves the precedence/override semantics. Permanence-tier: Durable Refs: ADR-0055, specs/02-Data-Models-and-Schemas.md Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 69ac0b99ef
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…n-chain P2 on PR #37. deployViews wired EFSFileView/EFSRouter to whiteoutDep.address whenever the named deployment record existed. But in the Safe-native ADDITIVE PROPOSE flow, 00_efs_core.ts saves the PREDICTED WhiteoutResolver record before the Safe batch deploys it — so on an older core where only WHITEOUT is missing, the record exists but the address is code-less. The views would then be wired to a non-contract address, and every isWhitedOut() call reverts, breaking listings/resolution until the views are redeployed. Extended the existing ZeroAddress fallback with a getCode guard: pass the WhiteoutResolver address only when it actually has code; otherwise ZeroAddress (whiteout disabled), exactly like an older pre-WHITEOUT core. Once the additive deploy lands, re-running efs-views rewires the views (redeployIfArgsChanged sees whiteoutAddr change 0 → real). The fresh-deploy path is unchanged (WhiteoutResolver has code → real address): verified a full pinned-fork deploy wires the views to the live resolver at their committed addresses and regenerates deployedContracts.ts byte-identical (pin holds). lint + check-types green. Permanence-tier: Durable Refs: ADR-0055, ADR-0048 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0e364d6843
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… overview Two P2s on PR #37. EFSFileView (cursor bypass): getFilesAtPath's per-lens whiteout terminal only fires for lenses at index >= the opaque cursor. A caller could pass a fabricated/stale `abi.encode(k)` cursor that resumes PAST a whiteout-terminal lens — e.g. stack [owner(PIN), bob(whiteout), alice(PIN)] with cursor=2 skips bob and returns alice's DATA, while the cursorless router would 404. Added a skipped-prefix guard: before honoring a nonzero cursor, re-scan [0, cursor) and if any skipped lens whites out the anchor with no own positive PIN (a negative terminal), return the terminal empty page. A legitimate forward cursor never points past a terminal (the walk sets attesterIdx=length on the first one), so this only trips on a fabricated cursor. New vector 20. specs/overview.md (required-read, was stale at 9 schemas / no WhiteoutResolver): added the WHITEOUT row (additive 10th, post-freeze) to the schema table with a note that the freeze set is the nine above; added WhiteoutResolver to the core-contracts table; and added the WHITEOUT negative-terminal to the read flow (deep link into a whited path 404s). Internal-only view change (no ABI/address change, deployedContracts unchanged). Whiteout 36/36, EFSFileView/Router 82/82; lint/check-types/docs:check green. Permanence-tier: Durable Refs: ADR-0055, specs/overview.md Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3e377e0aa2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ited out P2 on PR #37 — the listing analogue of the per-segment router terminal. The directory-listing entrypoints filtered whited CHILDREN under parentAnchor but never checked whether parentAnchor ITSELF is a negative terminal under its own parent. So when a higher lens whited out /dir (lower lens has /dir/child.txt), EFSFileView still listed /dir's children even though EFSRouter now 404s the deep link /dir/child.txt — a listing-vs-resolution inconsistency a caller hits by listing the known /dir anchor. Added `_isListedFolderWhitedOut(folderAnchor, attesters)` — the listing analogue of EFSRouter._isSegmentWhitedOut: evaluates _isItemWhitedOutForListing (PIN OR folder visibility-TAG re-add positive) with (getParent(folderAnchor), folderAnchor). Preflight all three lens-scoped entrypoints (getDirectoryPageBySchemaAndAddressList, getDirectoryPageFiltered, getDirectoryPageByAddressList) → empty page when the listed folder is whited for the viewer (and not re-added). Root/address-root (no parent) can't be whited (OrphanAnchor guard) → no-op; short-circuits when whiteout disabled. New vector 21: a higher-lens whiteout on /dir makes all three entrypoints return empty for [owner, alice]; the control lens [alice] (excludes owner) still lists the child. Internal-only view change — no ABI/address change, deployedContracts unchanged. Whiteout 37/37, view/router suites 143/143; lint/ check-types green. Permanence-tier: Durable Refs: ADR-0055 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 82be7dbc50
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…WHITEOUT) P2 on PR #37. Adding WhiteoutResolver makes RESOLVERS.length 7, so orchestrate() returns 7 resolver proxies and result.deploys is 8 (7 resolvers + SystemAccount). The pinned-fork ceremony tests still asserted the old counts, failing any MAINNET_FORKING_ENABLED run before exercising the ceremony: - Deploy.fork.test.ts: Object.keys(result.proxies) expected 6 → now bound to RESOLVERS.length; title updated (7 proxies / 10 schemas / 10 smokes). - BurnToImmutable.fork.test.ts: result.deploys expected 7 → now RESOLVERS.length + 1 (resolvers + SystemAccount); imported RESOLVERS; refreshed the 7→8 ProxyAdmin prose in titles/comments. The burn loops already iterate result.deploys dynamically, and the contract-owner renounce stays 3 (EFSIndexer/MirrorResolver/SystemAccount) — WhiteoutResolver is not OwnableUpgradeable, so only its ProxyAdmin is renounced. Verified on the pinned fork: Deploy.fork 2/2, BurnToImmutable.fork 4/4 (the burn now renounces 8 ProxyAdmins + 3 contract owners → every owner == 0). Test-only; no contract change. lint/check-types green. Permanence-tier: Durable Refs: ADR-0055, ADR-0048 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 70a3eea86e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…aSchemaUID P2 on PR #37 — a follow-on to the parent-folder terminal added last round. `_isListedFolderWhitedOut` hard-coded `dataSchemaUID` as the folder visibility-TAG definition, but the per-item walker uses the listing's `anchorSchema`. So a folder whited out and then re-added under a NON-DATA schema (`TAG(definition=anchorSchema, refUID=folder)` — e.g. a LIST/custom container) was still treated as whited: the parent terminal suppressed the whole page before the per-item walker could honor the schema-correct re-add positive — inconsistent with the walker right below it. Threaded the visibility-TAG definition through `_isListedFolderWhitedOut` and the three lens-scoped entrypoints: the two schema-aware listings pass `anchorSchema`; the schema-agnostic `getDirectoryPageByAddressList` passes `DATA_SCHEMA_UID` (standard browsing, matching its per-item filter). The PIN- positive arg stays `dataSchemaUID` (file placement is always DATA-schema; a folder has no DATA PIN). DATA-schema behavior is unchanged (vector 21 still passes). New vector 22: a folder re-added under a non-DATA schema is recognized by the parent terminal (lists its child) — would return empty under the old hard-coded def. Internal-only view change (helper is `internal`; external signatures unchanged) — no ABI/address change, deployedContracts unchanged. Whiteout 38/38; lint/check-types green. Permanence-tier: Durable Refs: ADR-0055, ADR-0038 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Pre-launch filesystem hardening + a complete deletion primitive (unionfs-style whiteout), done while the schemas are still pre-launch and changeable.
Pre-launch hardening (no frozen-field changes):
MAX_ANCHOR_DEPTH32 → 1024 (ADR-0062, supersedes ADR-0021). 32 was anomalously low — no real filesystem caps directory depth; it's bounded emergently by path length. Free-until-burn proxy upgrade; orphans nothing.specs/09): symlink-only following (supersededBy is a non-followed terminal — path = newest, UID = exact, preserving "no silent revision"), D_MAX=16/ceiling 32, cycle-stop, lens precedence, the WHITEOUT negative-terminal reservation + seeding ban. The on-chain follower code is deferred (built when redirects are actually seeded); the rules are pinned now because they gate durable REDIRECT seeding.specs/10): canonical sha2-256 multibase-multihash so a file's EFS contentHash shares its IPFS CID digest. Gates durable file-metadata seeding.specs/04) anddocs/FS_OPERATIONS_AUDIT.md(rename/move/delete/symlink/hardlink/paths capability map + the 3-tier "what's still changeable" model).WHITEOUT — cross-lens deletion (new additive schema):
systemdefault) that it cannot revoke. Solves "I deleted it but still see it" when the file falls through from a lower lens.deleteverb: revoke your own placement → genuine not-found (no 0-byte sentinel); per-name whiteout for inherited content; the client cascades a folder whiteout when the deleted item was the last visible child. Lens-local and structurally viewer-sovereign — you can never globally delete content you don't own (correct for a union/shared filesystem).Why
Two gaps surfaced from a filesystem-operations audit: (1) deletion of inherited content was impossible (you can't revoke another lens's attestation), so a user "deleting" a system default still saw it fall through — confusing and broken; (2) the 32-level depth cap would reject deep archival/mirror trees that every real OS holds. Both are best fixed now, pre-launch, while changeable. The redirect/contentHash specs must be pinned before any durable data is seeded (non-revocable / permanent once written).
Permanence tier
Durable (devnet contracts, pre-mainnet) with one Etched-bound element: the WHITEOUT schema field string at registration. The 9 frozen schemas are untouched; depth is a free-until-burn proxy upgrade; WHITEOUT is an additive 10th schema (orphans nothing, same path as SORT_INFO). Deploying requires a Safe proxy-upgrade (EFSIndexer for depth; EFSFileView/EFSRouter redeploy) + WHITEOUT schema registration — a later step, James-gated.
Specs / ADRs touched
New: ADR-0062 (depth), ADR-0063 (REDIRECT resolution), ADR-0064 (contentHash encoding),
specs/09-redirect-resolution.md,specs/10-file-metadata-encoding.md,docs/FS_OPERATIONS_AUDIT.md. Updated: ADR-0021 (Status → superseded by 0062), ADR-0055 (Status note: per-name whiteout implemented, opaque-directory deferred),specs/02,specs/04, READMEs,docs/FUTURE_WORK.md.Test plan
test/Whiteout.test.ts: per-name file + folder whiteout, folder re-add override, revoke un-hides, lens-scoping (viewer excluding the lens unaffected), all write-guard rejections, router negative-terminal (404, no fall-through).yarn lint(warnings-as-errors),yarn check-types,yarn docs:check— all clean.Notes for the reviewer
origin/main(not rebased) to resolve the router/web3/multichain integration in one clean pass; the EFSRouter auto-merge (main's serving hardening + this branch's whiteout terminal) was verified by the router/whiteout/fileview suites (133 passing).Agents involved
Claude Opus 4.8 (1M context) — FS-operations audit (7-agent fan-out), WHITEOUT brainstorm → dev → 3-lens adversarial review, and the integration. Acting via James's account.