Skip to content

Scaffold the EFS SDK monorepo#1

Open
JamesCarnley wants to merge 141 commits into
mainfrom
chore/scaffold
Open

Scaffold the EFS SDK monorepo#1
JamesCarnley wants to merge 141 commits into
mainfrom
chore/scaffold

Conversation

@JamesCarnley

Copy link
Copy Markdown
Member

Initial scaffold of the EFS SDK monorepo, set up from best-practice research + multiple expert-subagent review passes.

What's here

  • pnpm + Turborepo + Changesets workspace, two independently-versioned packages:
    • @efs/sdk — TypeScript SDK (tsup dual ESM/CJS, viem-native, vitest)
    • @efs/solidity — compile-in Solidity library (Foundry, ships .sol source)
  • ADR system mirrored from the contracts repo but lighter (MADR-style, no freeze ceremony): ADR-0001 layout, 0002 viem-only, 0003 compile-in Solidity.
  • Top-level docs (README, CONTRIBUTING, AGENTS.md), CI, scaffolded public API shapes reflecting the planning design (identity seam, static-vs-dynamic refs).

Verified

  • TS: build (dual ESM/CJS + types), typecheck, test (2 passing), lint — all green.
  • Solidity: wired for forge build/test/fmt, CI-verified.

Notes for review

  • npm scope is @efs (org needs claiming on npm before first publish; one-line revert to @efs-project if taken).
  • Method bodies are stubs (NotImplemented) — this is structure + decisions, not implementation.
  • Cross-cutting design stays in the planning vault (sdk-architecture.md); ADRs here implement slices of it.

🤖 Generated with Claude Code

JamesCarnley and others added 4 commits June 10, 2026 17:33
pnpm + Turborepo + Changesets workspace with two packages:
- @efs-project/sdk      — TypeScript SDK (tsup dual ESM/CJS, viem-native, vitest)
- @efs-project/solidity — compile-in Solidity library (Foundry, ships .sol source)

Includes the ADR system (mirrored from contracts, lighter — ADR-0001 layout,
0002 viem-only, 0003 compile-in Solidity), top-level docs (README, CONTRIBUTING,
AGENTS.md), CI, and scaffolded public API shapes reflecting the planning design
(identity seam, static-vs-dynamic refs). TS build/typecheck/test/lint verified
green; Solidity is CI-verified (forge not local).

Best-practice review applied (changeset config, publishConfig, forge-std CI
install, .nvmrc/engines).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
- Rename npm scope @efs-project/* -> @efs/* (scope confirmed unpublished;
  GitHub org stays efs-project). Pending `npm org create efs` before publish.
- ADR system: cut the contracts-inherited Etched/Durable/Ephemeral "permanence
  framing" section + the cargo-culted `Permanence:` template field (validation
  flagged as residual freeze-rigor); fold the one real point (published npm API
  is the only near-permanent surface) into Discipline.
- Add the missing procedural bits agents need: next-number mechanic, an
  ADR-worthiness threshold ("a choice with alternatives worth preserving"), and
  a worked boundary example (vault design -> SDK ADR slice).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Establishes the three-layer doc model so nothing duplicates: specs (how it
works now) vs ADRs (why we chose it) vs planning vault (cross-cutting design).
Seeds specs/overview.md (the SDK model at a glance) and wires it into AGENTS.md
as start-here reading.

Co-authored-by: Claude Opus 4.8 <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: c8e5a19b20

ℹ️ 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 .github/workflows/ci.yml Outdated
- BLOCKER fix: .github/workflows/ci.yml still used @efs-project/sdk (the rename
  grep missed .yml) — would have failed every CI run. Now @efs/sdk.
- Add release.yml using npm Trusted Publishing (OIDC) — no stored NPM_TOKEN,
  provenance automatic. ADR-0004 records the decision (OIDC over long-lived
  token) + the one-time per-package trusted-publisher setup.
- Mark docs/api row "(later)"; bump recommended-next ADR numbers.

Co-authored-by: Claude Opus 4.8 <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: 7994df5334

ℹ️ 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 .github/workflows/release.yml Outdated
JamesCarnley and others added 3 commits June 10, 2026 19:55
- Solidity job failed: `forge install --no-commit` flag was removed in current
  Foundry. Clone forge-std (test-only dep) via git instead — version-stable.
- Changeset job failed: no changeset on the PR. Add an empty changeset (the
  designed no-release escape hatch) for the scaffold.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
- CI: minimal `permissions: contents: read`, cancel-in-progress concurrency,
  `timeout-minutes` on all jobs, pin forge-std to v1.9.4 (no master drift).
- Release: pin global npm to @11; explicit `publishConfig.provenance: true` on
  both packages (belt-and-suspenders around the changesets/pnpm publish path).
- ADR-0004 reconciled with the explicit-provenance choice.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
forge fmt --check was the last red CI job. Reformatted EFSLib/EFSWriter to
Foundry style (verified locally with forge 1.7.1), simplified the stub
signatures to unnamed params/returns so there are no unused-variable warnings,
and removed the unreachable emit in _efsPinFile. Build + test pass locally.

Co-authored-by: Claude Opus 4.8 <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: eadb898eab

ℹ️ 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/sdk/src/index.ts Outdated
JamesCarnley and others added 3 commits June 10, 2026 21:25
- P1: release workflow ran `pnpm build` (turbo) which builds @efs/solidity via
  `forge build`, but never installs Foundry → release job would fail on main.
  Scope the release build to @efs/sdk only; the Solidity package publishes .sol
  source and needs no build artifact (CI compile-checks it per-PR).
- P2: remove the hardcoded `version = '0.0.0'` export — it would go stale after
  the first Changesets bump. Re-add derived from the manifest when implementing.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
… deployer

The SDK ships a maintained chainId -> {addresses, schema UIDs} registry and
resolves EFS by chain (with a custom-deployment override). It deploys nothing;
integration tests fork a registry chain (anvil --fork-url) like the contracts
repo, rather than reimplementing EFS's CREATE3/proxy deploy. Reflected in the
overview spec.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
- DX-7/ENG-14: lower Solidity pragma floor ^0.8.28 -> ^0.8.26 so the library
  is compilable alongside the contracts repo (pinned 0.8.26). Real compat bug.
- DX-11: fix wrong ADR pointer in index.ts (cited ADR-0004 = OIDC publishing
  for the error model; now points at "Recommended next").
- DX-10: repoint READMEs from the private planning vault to the public in-repo
  docs/specs/overview.md as the primary "how it works" reference.

Larger API-shape findings (resume/onProgress in pinFile, fetch+verify, resolvedBy,
branded UIDs, pagination iterator, deployments codegen) tracked for the beta-slice spec.

Co-authored-by: Claude Opus 4.8 <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: d1e88d32fa

ℹ️ 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 .github/workflows/ci.yml
Comment thread packages/solidity/package.json
JamesCarnley and others added 4 commits June 10, 2026 22:26
First functional-slice plan for @efs/sdk: write/read real files with the API
shapes frozen correctly before publish. Grounded in the freeze-branch contracts
(contentHash now lives as a lens-scoped PROPERTY string; no chain deployed but a
local fork exists) and two review passes.

Adversarial review caught: (1) the spec/scaffold drifted to a FLAT API but the
validated design is NAMESPACED (efs.fs.write) — realigned, surfaced as Decision F;
(2) content verification is trust-relative not absolute (attacker can attest a
contentHash under their own lens) — honest semantics baked in; (3) honest click
count (~3 with metadata, not 2); richer WriteReceipt/preview; per-step idempotent
resume; pinned local-fork artifact boundary; declared the large-file/update/delete
seams. Decisions A/C/D/E/F surfaced for James.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…pping

- P1: the "Changeset present" gate would block Changesets' own Version Packages
  PR (it consumes the changeset files). Skip the gate for head_ref
  changeset-release/main so the version PR can pass and publish.
- P2: `pnpm test` / `pnpm --filter @efs/solidity test` failed on a clean checkout
  (forge-std absent, lib/ gitignored). Add a `setup` script + prebuild/pretest
  hooks that bootstrap forge-std, and DRY the CI solidity job to run the package
  scripts so CI and a contributor's local run are identical.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…odule

Decision A closed after two expert passes: contentHash is a bare SHA-256 digest
(lowercase hex, sha256sum-identical); the PROPERTY key is the algorithm tag — no
multihash/CID/keccak (its future-proofing is illusory; the IPFS-CID rationale is
false). Built it (it's pure, chain-independent):

- src/content/hash.ts: hashContent() + trust-relative verifyContent()
  (matches-author/mismatch/no-claim; no-claim != success; malformed claim guarded)
- tests against known SHA-256 vectors; exported from index.ts
- ADR-0006 + docs/specs/content-hash.md (incl. fetch-safety: lens-scoped mirrors,
  size-cap streaming, ignore transport Content-Type)
- updated beta-slice (Decision A done) + overview + ADR index (next: 0007/0008)

Verified by subagent (impl correct, vectors confirmed, cross-docs consistent: GO).

Co-authored-by: Claude Opus 4.8 <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: 39653f6167

ℹ️ 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 .github/workflows/release.yml Outdated
JamesCarnley and others added 3 commits June 10, 2026 23:28
changesets/action with `publish: pnpm release` would publish the unpublished
0.0.0 scaffold packages on the first no-changeset main run — premature, and the
@efs org doesn't exist yet. Drop the `publish:` input so the action only manages
the Version Packages PR and never publishes. Re-enable at launch with a one-line
`with: { publish: pnpm release }` (documented inline + in ADR-0004).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…rors

Realign to the namespaced client (Decision F): efs.fs.* / efs.lenses.* /
efs.eas.* / efs.raw.*. Built the foundational, chain-independent layers:

- eas/: viem-native EAS layer (vendored ABIs, SchemaEncoder, attest/multiAttest
  builders, UID re-derivation) — no ethers/eas-sdk (ADR-0002). 15 tests.
- lenses/: opaque Lens, lens()/identity()/resolveLens; throws MaxLensesExceeded
  rather than truncating (review S2); ENS resolution; MAX_LENSES=20.
- chain/: deployments registry + resolveDeployment + construct-time integrity
  gate (checks view/router bytecode, review S1) (ADR-0005).
- errors/: typed EfsError tree (NotImplemented/LensRequired/MaxLensesExceeded/
  SchemaMismatch/DeploymentNotFound).
- types/: branded DataUID, DataRef vs PathRef, WriteReceipt/ReadResult/EfsFile.
- fs.* verbs are NotImplemented stubs with their final signatures.

format script now runs `biome check --write` (organizes imports too, matching CI).
tsc/test(24)/build/lint all green.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Integration review (GO) flagged two:
- B1/B2: fs.* stubs were async-typed but threw synchronously — `.catch()`/
  `.rejects`/`for await` would misbehave. Make them reject / throw-on-iterate so
  the async contract is locked before fs.* is implemented; tests use `.rejects`.
- S1: assertDeploymentIntegrity only checks bytecode presence — softened the
  doc to say so (sanity gate, not "is the right EFS contract"); the real trust
  gate (schema-UID match) is noted as landing with the read layer.

EAS layer, lenses, deployments, errors all verified by the review. tsc/test(24)/
build/lint green.

Co-authored-by: Claude Opus 4.8 <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: 5e92a8d0f0

ℹ️ 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/sdk/README.md Outdated
The quickstart still used the pre-F flat API (efs.read/efs.pinFile); the client
is namespaced (efs.fs.read/write/fetch). Updated to the accurate shape — read
returns a ref + resolvedBy, fetch gets verified bytes — and added a status note
that fs.* verbs are the target shape (currently NotImplemented).

Co-authored-by: Claude Opus 4.8 <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: 145e590697

ℹ️ 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/sdk/src/eas/attest.ts Outdated
JamesCarnley and others added 2 commits June 10, 2026 23:53
…ex P2)

buildAttest/buildMultiAttest returned no tx-level `value`, so a non-zero
per-attestation resolver value would revert (no ETH sent). Compute and include
`value` on the ContractCall: buildAttest forwards data.value; buildMultiAttest
sums every entry across all requests. Added tests (26 total).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
From the 3-agent foundation review. The additive-now/breaking-later items:
- Type-level write gating: createEfsClient overloads return EfsReadClient (no
  write verbs) without a walletClient, EfsClient with one (viem's read/write
  split). Runtime WalletRequired backstop.
- EfsError -> viem-BaseError-grade: shortMessage, open-union `code`, cause,
  walk(). Added WalletRequired/CursorInvalid/PartialBatchFailure.
- Named, exported option/return types (ReadOptions/ListOptions/FetchOptions/
  WriteOptions) — no inline literals; param renamed `as` -> `lens`.
- Pagination seam: Page<T> + EfsList<T> (AsyncIterable + .page()).
- Batch seam: efs.batch() + BatchReceipt/OperationResult/WriteMechanism;
  fs.write documented as sugar over it.
- Wallet-agnostic seam (your point): EfsReader/EfsWriter aliases instead of raw
  viem types in the public config, so widening to an ethers adapter later is
  non-breaking. viem-core stays; any wallet already works via EIP-1193.
- FileStat (was Stat), branded steps[].uid, dropped root `export *`.

Deferred (additive, non-breaking later): full graph/props/lists/sorts namespace
skeleton — designed in a dedicated pass. tsc/test(27)/build/lint green.

Co-authored-by: Claude Opus 4.8 <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: 4017c175b9

ℹ️ 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/sdk/README.md Outdated
Renamed the read option `as` -> `lens` in the hardening batch; the README
quickstart still showed `{ as: ... }`. Fixed.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…t chain drift

Three more drift windows in a multi-step write: writeFileTier1 now re-asserts the chain
before its planning reads (parent/visibility/transport) so a wrong-chain UID can't enter
the plan; submitLayeredTier1 re-asserts before each receipt wait (inside the wait try) so a
post-send drift surfaces as outcome-unknown carrying the txHash, not a false partial
failure; storeOnchain re-asserts before each deploy's receipt wait so a drift fails closed
with WrongChain instead of a misleading no-address abort. Updates/adds regressions.

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: e9adb0f964

ℹ️ 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/sdk/src/writes/overview.ts
Comment thread packages/sdk/src/writes/mirrors.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.

Re-reviewed latest head e9adb0f.

The newest write-guard commits look good: standalone planning reads are guarded before they feed plans, file-write planning reads are guarded before parent/tag/transport reads, and receipt waits are guarded after broadcast while preserving the outcome-unknown recovery shape. Local verification passed on this head: git diff --check origin/main...HEAD, pnpm --filter @efs/sdk typecheck, pnpm --filter @efs/sdk test (563 passed, 3 skipped), pnpm --filter @efs/sdk build, pnpm lint, and pnpm --filter @efs/solidity test (53 passed). GitHub CI is green and merge state is clean.

One non-blocking coverage note: lists.remove(entryUID, { listUID }) now guards the advisory config read, but I only see tests for the existing append-only/list-not-found/revocable behavior, not the new WrongChain/no-read/no-revoke case. I would not block on that because the path is advisory and the revoke itself is already chain-guarded.

The merge-blocking release/docs issue is still present: .changeset/escape-hatches-raw-eas-decode.md and packages/sdk/src/raw/contracts.ts still say efs.raw.* instances re-resolve deployment lazily so chain changes are reflected. Current code and the later raw-surface changeset describe the actual contract: raw instances are bound to construction-chain deployment addresses and fail closed with WrongChain on live chain drift. Please update those stale docs before merge so the release notes/source docs do not promise raw chain-switch re-resolution.

JamesCarnley and others added 4 commits June 23, 2026 00:51
… chain drift

setOverview now re-asserts the chain before the /tags/system resolution (its UID becomes the
Overview marker TAG, baked into the plan before writeFileTier1's own re-assert); mirrors.add
re-asserts before resolveMirrorTransport's on-chain /transports fallback, reusing the submit
context. Completes the standalone-write planning-read sweep (mirrors.add was the one missed).
Adds regressions for both.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ADR-0014/0015)

Additive foundational scaffolding, no behavior change. Adds the ReadSource interface +
capabilities, the ViemReadSource live adapter (chain-as-data) and snapshot/indexer stubs,
the TrustDescriptor provenance shape, and reserved fetch/verifier client-config slots that
throw NotImplemented rather than silently no-op. Two ADRs capture the decisions (pluggable
read source + chain-as-data; read-trust provenance / Fork 1 = inline hybrid). The rename,
read-path wiring, trust stamping, and chainless construction are the gated behavioral phases.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The additive ReadSource scaffolding (viem/snapshot/indexer adapters + config guards) put the
gzipped bundle at 36.02 kB, 21 B over the 36 kB budget (the types are erased; the adapters are
real runtime). Raise to 38 kB — headroom for this slice plus the upcoming read-path wiring/trust
phases — consistent with the prior surface-growth bumps (10 → 36 kB). Revisit size after launch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e budget 69 kB

Two independent expert reviews of the trust field names converged. Reshape the reserved
TrustDescriptor (ADR-0015) from a flat { source, existence, revocation, asOf } record to a
discriminated union on `freshness` ('current' | 'as-of' | 'stale'): the dangerous state is
now spelled `stale` and can't hide behind a reassuring `existence:'confirmed'`, incoherent
combinations are unrepresentable, and asOf exists only on the 'as-of' variant. `source`
literals reconciled with ReadSourceCapabilities.kind ('cache' → 'snapshot'); the 'live' value
collision (a source AND a revocation value) removed; the require→requireTrust sugar option
moved onto the same freshness lattice (default 'as-of'). ADR-0015 updated with the review.
Bundle budget raised to 69 kB (loose pre-launch headroom). Reserved type, no behavior change.

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: 040b374b73

ℹ️ 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/sdk/src/index.ts Outdated
…rift (TOCTOU)

liveDeployment() resolves the deployment at time T, but the read engines' readContract/getCode
run at T+1; a provider that drifts in between used the resolved chain's addresses on the new
chain. readContext now hands the engines a chainGuardedPublicClient pinned to the resolved
deployment.chainId, re-asserting live==resolved before each read (fail closed, WrongChain).
The guard proxy now covers getCode too (web3:// reads); getEnsAddress stays unguarded (ENS is
cross-chain). Adds a TOCTOU regression (eth_chainId reports seeded chain at resolve, drifts at read).

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.

Re-reviewed latest head dd5de95.

Local verification passed on this head: git diff --check origin/main...HEAD, pnpm --filter @efs/sdk typecheck, pnpm --filter @efs/sdk test (573 passed, 3 skipped), pnpm --filter @efs/sdk build, pnpm lint, and pnpm --filter @efs/solidity test (53 passed). GitHub CI is green and merge state is clean.

The newest write-planning guards look good: setOverview and mirrors.add now guard before the planning reads that feed their plans, and the tests cover the important no-read/no-submit ordering. I did not find a code blocker there.

I do still see merge-blocking docs/API-truth issues:

  1. The prior raw docs/release-note blocker remains. .changeset/escape-hatches-raw-eas-decode.md and packages/sdk/src/raw/contracts.ts still say raw contract instances re-resolve deployment lazily so chain changes are reflected. Current code and the later raw-surface changeset describe the real contract: raw instances are bound to construction-chain deployment addresses and fail closed with WrongChain on live-chain drift.

  2. docs/adr/0015-read-trust-provenance.md reads like the trust field lands now: it says EfsFile, FileInfo, and ReadResult carry required trust, and that reads stamp { freshness:'current', source:'live' }. But the current types do not include trust; the changeset and TrustDescriptor comment correctly describe it as reserved for a later behavioral slice. Please soften the ADR language so it does not claim current result shapes already include trust.

  3. docs/adr/0014-pluggable-read-source-and-chain-as-data.md says chainless clients work / the chainless-client rejection is superseded, but createEfsClient still rejects chainless ViemConfig.publicClient at construction. viemReadSource(client, { chainId }) supports chain-as-data, but it is not wired into createEfsClient yet. Please make the ADR match this phase.

  4. snapshotReadSource advertises supportsGetCode / supportsEns from snap.code / snap.ens, but getCode currently returns undefined and getEnsAddress is absent even when ENS data is present. Either implement those optional lookups or advertise the capabilities as false until the stub can actually serve them.

Once those docs/capability-truth issues are corrected, the verified code paths look very close.

@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.

Re-reviewed latest head 0fc48eb.

The new read-path TOCTOU guard looks good: readContext now resolves the live deployment, then gives the read engines a public client guarded against that resolved deployment.chainId; the guard also covers getCode for web3:// reads while leaving ENS unguarded as documented. Local verification passed on this head: git diff --check origin/main...HEAD, pnpm --filter @efs/sdk typecheck, pnpm --filter @efs/sdk test (574 passed, 3 skipped), pnpm --filter @efs/sdk build, pnpm lint, and pnpm --filter @efs/solidity test (53 passed). GitHub CI is green and merge state is clean.

The merge-blocking docs/capability issues from the previous review still appear unresolved:

  1. .changeset/escape-hatches-raw-eas-decode.md and packages/sdk/src/raw/contracts.ts still claim raw contract instances re-resolve deployment lazily so chain changes are reflected, while the actual contract is fail-closed WrongChain on live-chain drift.
  2. docs/adr/0015-read-trust-provenance.md still reads as though EfsFile, FileInfo, and ReadResult already carry required trust, but this PR only reserves TrustDescriptor; current result types do not include trust yet.
  3. docs/adr/0014-pluggable-read-source-and-chain-as-data.md still says chainless clients work / the chainless-client rejection is superseded, but createEfsClient still rejects chainless ViemConfig.publicClient; only viemReadSource(client, { chainId }) supports chain-as-data today.
  4. snapshotReadSource still advertises supportsGetCode / supportsEns based on supplied snapshot data, but the stub does not actually serve those lookups (getCode returns undefined; getEnsAddress is absent).

Code-path hardening continues to look solid; the remaining blockers are docs/release/capability truth issues that would mislead callers if this merged as-is.

@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: 0fc48eb632

ℹ️ 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/sdk/src/mirror/fetch.ts
Comment thread packages/sdk/src/writes/submit.ts Outdated
Comment thread packages/sdk/src/index.ts
…mespace read TOCTOU

fetchVerified (public) now rejects non-finite/non-positive maxBytes (NaN slips the `>` cap
checks, Infinity disables the ceiling). submitLayeredTier1 swallows a throwing onLayer/onProgress
callback so a reporting bug can't abort the remaining irreversible layers (partial write).
The standalone namespaces (graph.tags/pins, props, mirrors) now route their reads through a
chainGuardedPublicClient pinned to the resolved deployment chain — closing the same
resolve-then-read TOCTOU just fixed in readContext (optional dep; falls back unguarded in tests).
Adds 7 regressions.

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: 5d44417a23

ℹ️ 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/sdk/src/writes/props.ts Outdated
Comment thread packages/sdk/src/reads/lists.ts
… ADDR width

props.list previously guarded only the anchor-page read — the per-anchor getAttestation used
the unguarded publicClient and the value reads went through readContext() (a second
liveDeployment resolution). A mid-list chain switch decoded chain-A anchors against chain B.
All props.list reads now route through the guarded client pinned to the single resolved
deployment. Separately, lists.has now rejects a non-20-byte ADDR-mode target (a 32-byte UID
colliding on its trailing 20 bytes returned a false true), mirroring validateAddTarget.
Adds regressions; updates the props.list tests to a single production-faithful read client.

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.

Reviewed current head 5d44417a23 in a clean detached worktree. CI is green and local verification passed (git diff --check origin/main...HEAD, pnpm --filter @efs/sdk typecheck, pnpm --filter @efs/sdk test, pnpm --filter @efs/sdk build, pnpm lint, pnpm --filter @efs/solidity test). Still not merge-ready; these blockers remain:

  1. props.list still escapes the new pinned-chain read guard. It resolves dep and creates guarded pc, but the anchor-name decode pass still reads with unguarded deps.publicClient (packages/sdk/src/writes/props.ts:191) and the value pass calls deps.readContext() (packages/sdk/src/writes/props.ts:203), which can re-resolve a different live chain mid-method. A provider switch after the first guarded page read can still mix chains or avoid the intended WrongChain fail-closed behavior. Please keep the later reads pinned to the same dep/guarded client and add a direct props.list regression; the new test name mentions props but currently exercises only mirrors.list.

  2. ADR-0015 still promises required read-trust fields that the public API does not carry. The ADR says EfsFile, FileInfo, and ReadResult carry required trust: TrustDescriptor plus requireTrust/StaleTrust sugar gating, but the current exported types omit trust (packages/sdk/src/types.ts:543, :749, :773) and returned files are built without it. Either land the behavioral slice now or revise the ADR/changeset language so PR #1 honestly reserves the shape instead of claiming it is present.

  3. ADR-0014 still says chainless createEfsClient works in PR #1, but createEfsClient continues to throw InvalidArgument when publicClient.chain?.id is absent (packages/sdk/src/index.ts:633), and the tests assert that rejection. Please make the docs match the shipped behavior, or actually route read-only chainless clients through the viemReadSource(client, { chainId }) path.

  4. The raw-contract docs and release note still overclaim live chain rebinding. packages/sdk/src/raw/contracts.ts and .changeset/escape-hatches-raw-eas-decode.md say lazy raw access reflects a chain change, while the implementation is construction-chain bound and guarded to fail closed with WrongChain on live-chain drift. The docs should say that exactly.

  5. snapshotReadSource still advertises capabilities it does not implement. With snap.code, it sets supportsGetCode: true but getCode always returns undefined; with snap.ens, it sets supportsEns: true but installs no getEnsAddress. Because ReadSourceCapabilities are meant to be branch-before-call flags, these need to be honest (implement the map lookups or advertise false until the stub is real).

  6. Minor docs drift: .changeset/foundational-read-source-scaffolding.md still describes the old TrustDescriptor shape as source/existence/revocation; the exported type is now the freshness discriminated union.

@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.

Re-reviewed current head 4363d015b6b71d4dc1b0b106c156c51b38601ec1 in a clean detached worktree.

The newest code fixes look good:

  • The previous props.list TOCTOU blocker is addressed. props.list now resolves one deployment, derives one guarded read client, and uses that same pinned client for anchor enumeration, anchor-name getAttestation, and per-key value reads. Focused subagent review found no issue in this slice.
  • The new lists.has ADDR-width validation also looks correct. The false-positive was real for 32-byte values that already matched the right-aligned address membership key; valid 20-byte addresses remain accepted. Focused subagent review found no issue in this slice.

Fresh verification passed on this head:

  • git diff --check origin/main...HEAD
  • pnpm --filter @efs/sdk typecheck
  • pnpm --filter @efs/sdk test (583 passed, 3 skipped)
  • pnpm --filter @efs/sdk build
  • pnpm lint
  • pnpm --filter @efs/solidity test (53 passed)

GitHub CI is green, merge state is clean, and there are no unresolved review threads. This head is still not merge-ready because the remaining docs/capability-truth blockers from the previous review are still current:

  1. ADR-0015 still reads as though EfsFile, FileInfo, and ReadResult already carry required trust: TrustDescriptor plus requireTrust/StaleTrust gating, but the current exported result types do not include trust yet. Please make the ADR/changeset language explicit that this PR reserves the shape rather than shipping the behavioral result fields.

  2. ADR-0014 still says chainless createEfsClient works / the chainless-client rejection is superseded in PR #1, while createEfsClient still rejects a chainless ViemConfig.publicClient. viemReadSource(client, { chainId }) supports chain-as-data, but that is not wired through createEfsClient yet. Please make the ADR match this phase.

  3. The raw-contract docs/release note still overclaim live chain rebinding. .changeset/escape-hatches-raw-eas-decode.md, packages/sdk/src/raw/contracts.ts, and the matching packages/sdk/src/index.ts comments still say raw instances re-resolve deployment lazily so chain changes are reflected. The actual contract is construction-chain-bound raw instances guarded with WrongChain on live-chain drift. Please update the stale wording.

  4. snapshotReadSource still advertises capabilities it does not implement. With snap.code, it sets supportsGetCode: true but getCode returns undefined; with snap.ens, it sets supportsEns: true but no getEnsAddress is installed. Since these are branch-before-call capability flags, either implement those lookups or advertise false until the stub can serve them.

  5. Minor release-note drift: .changeset/foundational-read-source-scaffolding.md still describes the old TrustDescriptor shape as source/existence/revocation; the exported type is now the freshness discriminated union.

@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: 4363d015b6

ℹ️ 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/sdk/src/reads/fetch.ts Outdated
Comment thread packages/sdk/src/reads/attestations.ts Outdated
… attestationsFor

fetchRef clamped the fetch cap to the declared size; for a size-0 file that clamped to 0, which
fetchVerified rejects as a non-positive cap — empty files failed. The clamp now applies only for
positive declared sizes (empty bodies verify vs the empty-SHA-256 under the default cap).
attestationsFor now flattens the top-level ref.uid/dataUID/anchorUID that HasSourceUIDs accepts
(was only the sourceUIDs bag), so DirEntry/DataRef DTOs hydrate instead of returning {}. Adds 2 regressions.

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: 16bf2c92fa

ℹ️ 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/sdk/src/index.ts Outdated
verifyDeployment resolved the deployment from the live chain but probed getCode + schema
readContract via the unguarded publicClient; a post-resolution chain switch verified the
resolved chain's addresses against the new chain. It now probes through a
chainGuardedPublicClient pinned to the resolved dep.chainId (the guard already covers both
readContract and getCode). Adds a TOCTOU regression.

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.

Re-reviewed current head e1d1de67be7541ae0827c6df9b37c9b25c787993 in a clean detached worktree.

The two newest code commits look good:

  • 16bf2c92 fixes empty-file reads (size attested 0) without weakening the positive fetch cap behavior, and attestationsFor now hydrates DTOs that carry only top-level dataUID / anchorUID / ref.uid. Focused review found no issue.
  • e1d1de6 fixes efs.raw.verifyDeployment() TOCTOU by resolving the deployment once and probing through a client guarded to that resolved chain. Deployment overrides still flow through the same resolver, and the new drift regression covers the intended WrongChain fail-closed path. Focused review found no issue.

Fresh verification passed on this head:

  • git diff --check origin/main...HEAD
  • pnpm --filter @efs/sdk typecheck
  • pnpm --filter @efs/sdk test (586 passed, 3 skipped)
  • pnpm --filter @efs/sdk build
  • pnpm lint
  • pnpm --filter @efs/solidity test (53 passed)

GitHub CI is green, merge state is clean, and there are no unresolved review threads. Still not merge-ready because the docs/capability-truth blockers remain in the current tree:

  1. ADR-0015 still reads as though EfsFile, FileInfo, and ReadResult already carry required trust: TrustDescriptor plus requireTrust/StaleTrust gating, but current exported result types do not include trust yet. Please make the ADR/changeset language explicit that this PR reserves the shape rather than shipping those behavioral fields.

  2. ADR-0014 still says chainless createEfsClient works / the chainless-client rejection is superseded in PR #1, while createEfsClient still rejects a chainless ViemConfig.publicClient. viemReadSource(client, { chainId }) supports chain-as-data, but that is not wired through createEfsClient yet. Please make the ADR match this phase.

  3. The raw-contract docs/release note still overclaim live chain rebinding. .changeset/escape-hatches-raw-eas-decode.md, packages/sdk/src/raw/contracts.ts, and matching comments in packages/sdk/src/index.ts still say raw instances re-resolve deployment lazily so chain changes are reflected. The actual contract is construction-chain-bound raw instances guarded with WrongChain on live-chain drift. Please update the stale wording.

  4. snapshotReadSource still advertises capabilities it does not implement. With snap.code, it sets supportsGetCode: true but getCode returns undefined; with snap.ens, it sets supportsEns: true but no getEnsAddress is installed. Since these are branch-before-call capability flags, either implement those lookups or advertise false until the stub can serve them.

  5. Minor release-note drift: .changeset/foundational-read-source-scaffolding.md still describes the old TrustDescriptor shape as source/existence/revocation; the exported type is now the freshness discriminated union.

@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: e1d1de67be

ℹ️ 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/sdk/src/writes/submit.ts Outdated
Comment thread packages/sdk/src/reads/attestations.ts
…scape hydration

submitLayeredTier1's pre-send chain guard now folds a drift into WriteNotSentError
(carrying the landed-UID map + WrongChain cause) ONCE an earlier layer has landed — a true
partial write — while a first/only-layer drift still escapes as raw WrongChain.
attestationsForUIDs now re-throws a systemic WrongChain rejection instead of swallowing it to
undefined (which looked like genuine absence); per-UID degradation still maps to undefined.
Updates the per-layer guard test to the partial-error contract; adds a hydration regression.

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: 95c8c956db

ℹ️ 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/sdk/src/writes/submit.ts Outdated
Comment thread packages/sdk/src/writes/detect.ts
…ity cache per connector

submitLayeredTier1 now builds the layer refs before the cancellation check and, once an
earlier layer has landed, folds an abort into WriteNotSentError (landed map + AbortError
cause) instead of letting a raw AbortError escape and drop the partial-write context; a
first-layer abort still escapes raw. detectAccount's profile cache is now scoped by the
connector (wallet client) via a WeakMap, since getCapabilities (gasless/batch) is
connector-dependent — a connector switch no longer reuses a stale capability profile.
Adds 4 regressions.

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.

Re-reviewed current head 87e4ca84f166b201dab0c573ba65925cb53e8058.

The newest fixes look good: the mid-write abort path now preserves partial-write recovery context, and the wallet-scoped capability cache avoids cross-connector reuse. I also had two focused subagent passes check those slices independently, and both came back clean.

Local verification passed on the current head:

  • git diff --check origin/main...HEAD
  • pnpm --filter @efs/sdk typecheck
  • pnpm --filter @efs/sdk test (591 passed, 3 skipped)
  • pnpm --filter @efs/sdk build
  • pnpm lint
  • pnpm --filter @efs/solidity test (53 passed)

GitHub status is also green right now, with clean merge state and no unresolved review threads. I still do not think this PR is merge-ready yet, because these blockers remain:

  1. expand: ["attestations.schema"] / withSchema can still swallow systemic chain drift. attestationFor() calls schemaRecordFor(), and schemaRecordFor() catches every getSchema() failure and returns undefined. That means a WrongChain raised while hydrating schema data fulfills as an attestation missing schemaRecord, so the new rejection scan in attestationsForUIDs() never sees it. Please let systemic WrongChain escape from schemaRecordFor() while preserving ordinary per-schema degradation if that is intentional. Relevant area: packages/sdk/src/reads/attestations.ts:81-107.

  2. ADR-0015 still says EfsFile, FileInfo, and ReadResult carry required trust descriptors and documents requireTrust / StaleTrust, but the current public SDK types do not expose that contract yet. The docs are ahead of the implementation.

  3. ADR-0014 still says chainless SDK construction lands in PR #1 and that rejecting chainless ViemConfig.publicClient was superseded, but createEfsClient() still rejects chainless public clients. Either the behavior or the ADR needs to change before merge.

  4. The raw contract escape-hatch docs/release note still claim raw instances re-resolve deployment info and reflect wallet chain changes, while the implementation is construction-chain-bound and reports WrongChain on drift. That mismatch will mislead downstream callers.

  5. snapshotReadSource() still advertises supportsGetCode / supportsEns from snapshot contents even though getCode() returns undefined and no ENS resolver is installed. Capability metadata should describe callable behavior, not stored snapshot presence.

  6. .changeset/foundational-read-source-scaffolding.md still describes the old TrustDescriptor shape as source / existence / revocation, but the exported SDK type uses the current freshness union shape.

Once those are corrected, the current write-path fixes themselves look ready from my pass.

@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: 87e4ca84f1

ℹ️ 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/sdk/src/reads/redirects.ts
Comment thread packages/sdk/src/index.ts
…spaces on read clients

followRedirectChain no longer throws RedirectHopLimit when the chain terminates exactly at the
cap — it does a final terminal check on the last hop's destination, failing closed only if a
genuine further followable hop (or a cycle) exists. EfsReadClient now carries read-only views of
graph/props/mirrors/redirects (Pick-derived TagsReadNs/PinsReadNs/PropsReadNs/MirrorsReadNs/
RedirectsReadNs + EfsGraphReadNs), so the lens-scoped read verbs are type-reachable on a
no-wallet client without a cast; mutators stay gated to EfsClient. Adds 2 regressions.

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.

Re-reviewed current head 5e6d64dfaad90e65e29c783d139f7884840ec333.

The newest commit looks good. The redirect hop-cap fix now accepts a chain that terminates exactly at the cap while still failing closed on a genuine extra followable hop/cycle, and the read-only client type now exposes only the wallet-free read namespaces. I checked those locally and had two focused subagent passes review the same delta; both came back clean.

Local verification on this head passed:

  • git diff --check origin/main...HEAD
  • pnpm --filter @efs/sdk typecheck
  • pnpm --filter @efs/sdk test -- redirects.test.ts index.test.ts (45 passed)
  • pnpm --filter @efs/sdk test (593 passed, 3 skipped)
  • pnpm --filter @efs/sdk build
  • pnpm lint
  • pnpm --filter @efs/solidity test (53 passed)

GitHub CI is green, merge state is clean, and there are no unresolved review threads. I still do not think this PR is merge-ready, because the previous merge blockers remain on this head:

  1. expand: ["attestations.schema"] / withSchema can still swallow systemic chain drift. schemaRecordFor() catches every getSchema() failure and returns undefined, so a WrongChain during schema hydration fulfills as an attestation missing schemaRecord instead of escaping as a systemic failure. Relevant area: packages/sdk/src/reads/attestations.ts:81-107.

  2. ADR-0015 still says EfsFile, FileInfo, and ReadResult carry required trust descriptors plus requireTrust / StaleTrust, but the current exported SDK surface does not implement that contract.

  3. ADR-0014 still says chainless SDK construction lands in PR #1 and that the chainless ViemConfig.publicClient rejection was superseded, while createEfsClient() still rejects chainless public clients.

  4. The raw contract escape-hatch docs/release note still claim raw instances re-resolve deployment info and reflect wallet/provider chain changes, while the implementation is construction-chain-bound and reports WrongChain on drift.

  5. snapshotReadSource() still advertises supportsGetCode / supportsEns from snapshot contents even though getCode() returns undefined and no ENS resolver is installed.

  6. .changeset/foundational-read-source-scaffolding.md still describes the old TrustDescriptor shape (source / existence / revocation) instead of the exported freshness union shape.

So: the latest addressed areas are verified, but these blockers still need one more pass before merge.

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.

1 participant