Skip to content

Pre-launch FS hardening + WHITEOUT deletion (depth→1024, redirect/contentHash specs, per-name whiteout)#37

Merged
JamesCarnley merged 45 commits into
mainfrom
claude/fs-deletion-and-prelaunch-hardening
Jun 26, 2026
Merged

Pre-launch FS hardening + WHITEOUT deletion (depth→1024, redirect/contentHash specs, per-name whiteout)#37
JamesCarnley merged 45 commits into
mainfrom
claude/fs-deletion-and-prelaunch-hardening

Conversation

@JamesCarnley

Copy link
Copy Markdown
Member

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_DEPTH 32 → 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.
  • REDIRECT read-time resolution spec (ADR-0063, 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.
  • contentHash self-describing encoding (ADR-0064, specs/10): canonical sha2-256 multibase-multihash so a file's EFS contentHash shares its IPFS CID digest. Gates durable file-metadata seeding.
  • Workflows + audit: canonical move/rename/delete workflows (specs/04) and docs/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):

  • Per-name whiteout of inherited content (file and folder): lets a lens hide content published by a lower lens (e.g. a system default) that it cannot revoke. Solves "I deleted it but still see it" when the file falls through from a lower lens.
  • One delete verb: 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).
  • Folder re-add fix: whiteout a folder then re-assert your own of the same name → un-hidden (the positive-override now recognizes a folder visibility-TAG, not just a file PIN).
  • Out of scope (deliberately): opaque-directory ("show only mine here") — dropped, no concrete use case, re-adds additively if needed. DATA-whiteout — not a unionfs concept (overlayfs has no inode-level whiteout).

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

  • Full hardhat suite: 646 passing, 0 failing (post-merge with latest main).
  • 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.
  • WHITEOUT reviewed by a 3-lens adversarial pass (viewer-sovereignty, storage/upgrade-safety/additivity, gas/DoS/single-pass) — zero P0/P1/P2.

Notes for the reviewer

  • This branch was merged with 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).
  • ADRs were renumbered 0058/0059/0060 → 0062/0063/0064 to avoid the collision with main's freshly-merged 0058–0061.
  • Reads as two logical parts by commit group: pre-launch hardening (depth + specs) and WHITEOUT.

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.

JamesCarnley and others added 12 commits June 20, 2026 23:26
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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/hardhat/contracts/EFSRouter.sol
Comment thread packages/hardhat/contracts/EFSFileView.sol Outdated
Comment thread packages/hardhat/deploy/08_whiteout.ts

@JamesCarnley JamesCarnley left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[gpt-5-codex · review]

Same-account advisory review: BLOCKING

Base/head: main@cec2436550b590402d35dffc46fa7ec2e921acf5da4faca0.
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:

  1. 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/04 rule that deep links into a whited path 404.
  2. Existing native P2 thread confirmed: plain EFSFileView phase-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.
  3. 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.
  4. Live CI P1: deploy-pin-check is failing on the current head. The job reports deployedContracts.ts drifted from the committed version; the branch adds/wires WhiteoutResolver, but the committed app artifact was not regenerated.
  5. Docs/release P2s remain: ADR-0055’s new status line conflicts with the ADR body; redirect taxonomy still says sameAs/supersededBy are followed even though ADR-0063/specs/09 make symlink the only followed kind; workflow/overview prose still says contentHash is keccak256 instead of canonical sha2-256 multibase-multihash; workflow/indexing prose still says MAX_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.
  6. Release-test P2: DeploySafe.fork.test.ts still asserts Object.keys(result.proxies).lengthOf(6) while RESOLVERS now 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.

Comment thread packages/hardhat/contracts/EFSFileView.sol Outdated
Comment thread docs/adr/0055-whiteout-cross-lens-negative-mask.md Outdated
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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/hardhat/contracts/EFSRouter.sol
Comment thread packages/hardhat/deploy/08_whiteout.ts Outdated
JamesCarnley and others added 2 commits June 22, 2026 02:50
…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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/hardhat/contracts/EFSRouter.sol Outdated
…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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread specs/10-file-metadata-encoding.md
Comment thread packages/hardhat/contracts/EFSIndexer.sol Outdated
JamesCarnley and others added 3 commits June 22, 2026 04:36
…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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/hardhat/contracts/EFSFileView.sol
Comment thread packages/hardhat/deploy-lib/schemas.ts
…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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/hardhat/contracts/WhiteoutResolver.sol
…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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread specs/04-Core-Workflows.md Outdated
Comment thread specs/09-redirect-resolution.md
…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 JamesCarnley left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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 37 and GraphQL reviewThreads agree).
  • Merge state: CLEAN, MERGEABLE, not draft.
  • Checks: ci, contract-tests, and deploy-pin-check all succeeded.

Local verification on the detached PR-head worktree passed:

  • git diff --check origin/main...HEAD
  • yarn docs:check
  • yarn hardhat:lint --max-warnings=0
  • yarn hardhat:check-types
  • yarn 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/skipped
  • yarn next:lint --max-warnings=0
  • yarn next:check-types
  • yarn workspace @se-2/nextjs test — 99 passing

From this review pass, PR #37 is merge-ready from the review/check/verification perspective.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/hardhat/contracts/EFSIndexer.sol
Comment thread packages/hardhat/contracts/EFSIndexer.sol

@JamesCarnley JamesCarnley left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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.md still documents MAX_ANCHOR_DEPTH = 32 for 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 as onAttest, including upward propagation, while this PR intentionally changed index() / 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 JamesCarnley left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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 37 and GraphQL reviewThreads agree).
  • Merge state: CLEAN, MERGEABLE, not draft.
  • Checks: ci, contract-tests, and deploy-pin-check all succeeded.

Focused local verification on the detached PR-head worktree passed:

  • git diff --check origin/main...HEAD
  • yarn docs:check
  • yarn 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.

claude added 2 commits June 23, 2026 18:45
…-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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/hardhat/deploy-lib/schemas.ts
… 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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread specs/04-Core-Workflows.md Outdated
…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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/hardhat/contracts/WhiteoutResolver.sol
…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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/hardhat/contracts/EFSRouter.sol
…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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/hardhat/contracts/EFSFileView.sol
…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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/hardhat/deploy-lib/views.ts Outdated
…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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/hardhat/contracts/EFSFileView.sol
Comment thread packages/hardhat/deploy-lib/schemas.ts
… 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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/hardhat/contracts/EFSFileView.sol
…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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/hardhat/deploy-lib/schemas.ts
claude added 2 commits June 23, 2026 20:41
…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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/hardhat/contracts/EFSFileView.sol Outdated
…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>
@JamesCarnley
JamesCarnley merged commit c6b4075 into main Jun 26, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants