12748 Commits
Author SHA1 Message Date
4cc3332bd7 chore(sqlite): bump hanzoai/sqlite v0.2.4 → v0.3.2, drop modernc from the graph (#18)
s3's SQLite filer already imports github.com/hanzoai/sqlite on main. v0.3.2 is
self-contained (vendored pure-Go engine), so modernc.org/{sqlite,libc,memory,
mathutil} are no longer needed and are dropped from go.mod (verified: go build ./...
stays green, cgo + nocgo, without them). csqlite + sqlcipher (v0.3.2's cgo backend)
enter as indirect.

modernc removal is done via go mod edit rather than go mod tidy: a pre-existing,
unrelated go.sum re-tag drift on github.com/luxfi/pq@v1.0.3 blocks full-graph ops
on this branch's base (origin/main) — out of scope for the sqlite migration.

Co-authored-by: hanzo-dev <dev@hanzo.ai>
2026-07-18 09:15:14 -07:00
Hanzo Dev 5d49337743 fix(s3api): bound gateway startup filer reads so an unresponsive filer can't hang :8333
Red flagged NewCircuitBreaker's unbounded context.Background() filer read as a latent
CrashLoopBackOff: on a K8s cold/co-restart the s3 gateway dials the filer Service (TCP
accepted by kube endpoints) before the filer answers RPCs, the unbounded read blocks
~4min, :8333 never binds, liveness kills the pod. Confirmed via goroutine dump; the fix
is a bounded context (zap-proto muxConn.CallContext honors ctx.Done()).

The startup path has THREE reads of this anti-pattern, all of which block :8333 — fixing
only the circuit breaker leaves the gateway hanging at the first one:
- command/s3.go GetFilerConfiguration: REQUIRED read, already in a for{}+Sleep(1s) retry
  loop, but the unbounded ctx defeats the retry (first call hangs forever). Bound each
  attempt (10s) so the retry loop actually retries until the filer answers.
- s3api/s3api_circuit_breaker.go: OPTIONAL read. Bound (10s); the existing fail-open path
  (circuit breaker disabled) runs on deadline.
- s3api/bucket_metadata.go BucketRegistry.init: OPTIONAL warm-up whose error path was
  glog.Fatal (itself a CrashLoop trigger). Bound (10s) + warn-and-proceed instead of
  Fatal; the registry warms lazily via GetBucketMetadata -> LoadBucketMetadataFromFiler.

Empirically verified on a local single-node cluster: the bounded ctx is honored
(muxConn.CallContext returns "context deadline exceeded" at 10s), :8333 binds (~10s vs an
indefinite hang before), and a SigV4 create-bucket / PUT / GET (byte-identical) / DELETE
round-trip succeeds. GOWORK=off go build ./s3/... = 0; s3api bucket registry/metadata
tests pass. Keeps the fail-open intent; only bounds the wait.
2026-07-17 23:08:44 -07:00
zandGitHub 98c3134b6f Merge: drop gRPC/build cruft (macOS artifact + unused deps + stale doc)
Remove a 32MB macOS Mach-O binary junk-committed at repo root, 2 unused
indirect deps, and correct the stale gRPC section in LLM.md. Zero Go source
change. Red-verified: grpc-free ZAP stubs kept load-bearing, grpc//indirect
structural to the GCP client family, full-tag build green, go-sdk retained.
2026-07-17 22:33:55 -07:00
Hanzo Dev cecd33914f chore(deps): go mod tidy — drop two unused indirect deps, mark sqlite indirect
go mod tidy (GOWORK=off) removes go.mod/go.sum entries no longer referenced by
any package, under any build tag:
- github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1 — unimported (grep all .go = 0)
- github.com/luxfi/container v0.0.4 — unimported (grep all .go = 0)
- modernc.org/sqlite marked // indirect (pulled transitively via hanzoai/sqlite;
  no direct import remains)

Default build and full-tag build (elastic gocdk sqlite ydb tarantool tikv rclone)
both green. go.sum: the checksums for the two dropped modules are removed.

NOTE: github.com/hanzos3/go-sdk is deliberately NOT dropped — `go mod why` shows
it is a required transitive dep of github.com/luxfi/zapdb (the filer zapdb
metadata store) via s3/filer/luxdb; tidy keeps it.
2026-07-17 21:56:49 -07:00
Hanzo Dev 714db20c0f chore(cruft): drop committed macOS build artifact; correct stale gRPC status in LLM.md
- remove stress: a 32MB Mach-O arm64 (macOS) binary committed to the repo root,
  unreferenced by any build/CI/script — an accidentally-committed build artifact.
- LLM.md: the gRPC-rip section listed volume RPC, raft, cert hot-reload and the
  core dial/server as still grpc-bound; all were since ported to ZAP. The main
  module now has zero google.golang.org/grpc imports (grep -rl google.golang.org/grpc s3/ = 0).
  Record the true residual: google.golang.org/grpc // indirect is pulled only by
  the optional Google Cloud client family (kms/pubsub/storage apiv*), which are
  grpc-transport SDKs never dialed in a no-GCP deployment; zeroing it is a
  CTO-gated GCP-surface rip, not an RPC-transport change.
2026-07-17 21:16:55 -07:00
Hanzo Dev f4ec1896c3 chore(notice): pin SeaweedFS provenance and deviations; sweep product branding 2026-07-13 16:05:26 -07:00
037e7efdb4 fix(sqlite): use hanzoai/sqlite (the one driver), drop direct modernc import (#15)
* fix(sqlite): use hanzoai/sqlite (the one driver), drop direct modernc import

* fix(sqlite): use hanzoai/sqlite (the one driver), drop direct modernc import

---------

Co-authored-by: Hanzo AI <ai@hanzo.ai>
2026-07-10 02:23:01 -07:00
zeekayandClaude Opus 4.8 ea34a5b2e2 fix(deps): repair vanished pins / go.sum drift ( core-bump@latest age@v1.6.0) + build green
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
v2026.4.0
2026-06-30 14:40:55 -07:00
z c7627d0568 docs(brand): add hero banner 2026-06-28 20:08:15 -07:00
z 9d04c0eb0a chore(brand): dynamic hero banner 2026-06-28 20:08:14 -07:00
596c633aaf ci: self-contained multi-arch docker-build (fix 'workflow was not found') (#14)
The public s3 repo called a reusable workflow in the PRIVATE hanzoai/.github repo
(uses: hanzoai/.github/.github/workflows/docker-build.yml@main). GitHub forbids a
public repo from calling a private repo's reusable workflow — it resolves as
'workflow was not found', so every docker-build failed at 0s (not a runner or YAML
issue; the shared file and org access were both fine).

Replace with a self-contained build that:
- pushes to ghcr.io/hanzoai/s3 with GITHUB_TOKEN (no custom registry secret, no
  cross-repo reusable dependency),
- builds linux/amd64 + linux/arm64 (was amd64-only) via buildx/QEMU — the Dockerfile
  is pure-Go (CGO_ENABLED=0) so it cross-builds cleanly,
- runs on the self-hosted amd64 runner (evo).

Co-authored-by: Hanzo AI <ai@hanzo.ai>
2026-06-26 14:31:56 -07:00
b70cf438ac deps: drop seaweedfs-org deps — fork goexif + go-fuse to hanzoai (#13)
* deps: drop seaweedfs-org deps — fork goexif + go-fuse to hanzoai

Replaces the last external github.com/seaweedfs/* import paths with Hanzo forks:
- github.com/seaweedfs/goexif v1.0.3 -> github.com/hanzoai/goexif v1.0.4
- github.com/seaweedfs/go-fuse/v2 v2.9.3 -> github.com/hanzoai/go-fuse/v2 v2.9.4
46 .go files repointed (1 goexif + 45 go-fuse sites); go.mod/go.sum updated; LLM.md
notes no seaweedfs-org import paths remain. The forks are full module-path renames
(zero seaweedfs residue), Apache-2.0 attribution retained in each fork's LICENSE.

Verified: go build ./s3 -> exit 0, binary runs (Hanzo S3 4.34). go mod tidy clean
(GOPRIVATE=github.com/hanzoai/*). With this, 'seaweedfs' is gone from s3's deps.

* docs: correct fork license identities (red review)

goexif is BSD-2-Clause (Robert Carlsen), go-fuse is BSD-3-Clause (Go-FUSE
Authors) — not Apache-2.0, and neither fork has a NOTICE. The s3 codebase's
own Apache-2.0 + NOTICE (crediting SeaweedFS) is separate.

---------

Co-authored-by: Hanzo AI <ai@hanzo.ai>
2026-06-26 13:31:21 -07:00
3cb9b321c8 fix: correct seaweedfs->hanzo rename artifacts + drop legacy minio + datastore cross-link (#12)
* fix: correct crude seaweedfs->hanzo rename artifacts + drop legacy minio

- s3 update: GitHubLatestRelease("hanzo","hanzo") -> ("hanzoai","s3"); the
  blunt rename pointed updates at a nonexistent repo (help text already said
  hanzoai/s3). Now 's3 update' pulls real Hanzo S3 releases. (go build clean.)
- LLM.md: fix upstream attribution (was github.com/hanzo/hanzo) to credit the real
  SeaweedFS upstream, matching NOTICE; correct 'renamed from weed'; note goexif +
  go-fuse are the only external deps still under the seaweedfs org.
- LLM.md: add S-Chain section cross-linking datastore (OLAP) + the S-Chain storage
  role (reverse of hanzoai/datastore's link), proven-vs-direction scoped.
- drop legacy docker/compose/local-minio-gateway-compose.yml (unreferenced MinIO-
  gateway demo).

main is already ZAP-native + internally renamed; these are residual-artifact fixes.

* fix: correct seaweedfs->hanzo rename artifacts + datastore cross-link

- s3 update: GitHubLatestRelease("hanzo","hanzo") -> ("hanzoai","s3") so updates
  pull real Hanzo S3 releases (help text already said hanzoai/s3). go build clean.
- LLM.md: correct upstream attribution to SeaweedFS (matches NOTICE); note goexif +
  go-fuse are the only remaining seaweedfs-org deps; add S-Chain datastore cross-link.

---------

Co-authored-by: Hanzo AI <ai@hanzo.ai>
2026-06-26 12:49:52 -07:00
zeekay 3081d9d638 ZAP-final: drive gRPC to 0 in all s3 code; fix dead go-bip39 via luxfi fork
Completes the ZAP-native migration on main's leaderless base (schain
pinned-writer is canonical — NO consensus engine introduced). Every
non-test s3 package is now gRPC-free (`google.golang.org/grpc` importers:
16 -> 0); all gRPC-importing test files converted too, so the root module
has ZERO direct grpc importers.

Source (ported from feat/grpc-final's grpc-free versions onto main, which
do NOT touch the leaderless rewrite):
- pb/grpc_client_server.go: dialoption param thread, ZAP pools only.
- mq/broker/*: status.Errorf(codes.X) -> fmt.Errorf("X: ...").
- server/volume_grpc_admin.go: keeps the v2026.3.1 authz-bypass fix
  (fail-closed over peerless ZAP) + grpc-free.
- server/volume_grpc_erasure_coding.go, server/common.go (request_id),
  svc/master/stream_server.go (drop grpc.ServerStream embed),
  wdclient/masterclient.go, operation/assign_file_id.go (string-match
  classification).
- security/tls.go (drop LoadServerTLS/advancedtls/SNIStripping),
  security/tls_reload.go + certreload/certreload.go (native mtime/size
  keypair watcher, no grpc certprovider/pemfile),
  util/http/client/http_client.go.

command/master.go: kept main's leaderless schain coordinator; stripped
only the vestigial reflection-only gRPC server (no master RPC rode it).

Tests: codes/status -> fmt/strings; grpc.ServerStream/metadata mocks ->
grpc-free seams (Send/Recv/Context); integration tests dial ZAP
(transport.Dial + pb.NewZapFilerClient / master.New(...ToMasterZapAddress)).
volume_grpc_admin_zap_authz_test.go still PASSES and still asserts the
admin bypass is CLOSED. Deleted tls_sni_test.go (tested removed SNIStripping).

go-bip39: upstream github.com/tyler-smith/go-bip39 repo is deleted (fetch
fails under GOPROXY=direct), breaking `go mod tidy`. Redirect to the luxfi
fork via an in-tree drop-in module (third_party/go-bip39) under the original
path delegating to github.com/luxfi/go-bip39 v1.1.2 — a plain replace is
impossible (the fork renamed its module path and self-imports
.../wordlists, "used for two different module paths"). `go mod tidy` now
succeeds.

go.mod: google.golang.org/grpc/security/advancedtls DROPPED; grpc demoted
direct -> // indirect. grpc now survives ONLY as a transitive of Google
Cloud SDKs (cloud.google.com/go/{kms,storage,pubsub}) used by the GCP
KMS / GCS storage / Pub/Sub integrations — external API-client transport,
not s3 internal RPC. Fully removing it would mean ripping out all GCP
cloud support (out of scope).
2026-06-25 18:25:47 -07:00
zeekay 8ac2c5465e Delete raft: leaderless native coordination via schain pinned-writer
Removes hashicorp/raft entirely from the S3 master — the last consensus that
wasn't native Lux. Replaces the leader-election + serialized-writer FSM with a
leaderless topology.Coordinator interface:
- AllocateVolumeId / NextFileId / topology read-write, no IsLeader gate, no election.
- LocalCoordinator: single-node dev/test impl (keeps the suite green, standalone
  master works).
- schainCoordinator: production backend — delegates allocation to the schain
  storage VM's owner-gated, ML-DSA-verified AllocateTx (luxfi/chains, the native
  pinned-writer over lux/consensus). Fails CLOSED until the schain endpoint is
  wired (ErrSchainNotWired) — never silently single-writer in prod.

Deleted: raft_hashicorp.go, raft_server.go, raft_server_handlers.go, raft_common.go,
master_grpc_server_raft.go, consensus_server.go (+ tests), the cluster_raft_* shell
cmds, masterNewRaft.html. Dropped hashicorp/raft + raft-boltdb from go.mod. Removed
IsLeader gating from master_server, assign/volume/collection/admin handlers,
meta_aggregator, kafka coordinator, telemetry, UI.

Assign hot-path no longer requires being leader — any master serves; allocation is
serialized by the Coordinator (pinned writer), not an elected leader. Build exit 0;
server/topology/command/mq/admin suites all green.

VERIFY: hashicorp/raft in prod=0, go.mod=0; remaining 'isLeader' hits are
explanatory comments + the filer meta_aggregator's own aggregation flag (not master
raft).
2026-06-25 16:44:57 -07:00
zeekay 4b7a29022f HOTFIX v2026.3.1: close volume admin authz bypass over ZAP (Red CRITICAL) + broker mTLS key + ReceiveFile no-op
Red review of released v2026.3.0 found a CRITICAL deploy-gating authz bypass I
introduced in dcd09e8b4:
- [CRITICAL] checkGrpcAdminAuth returned nil (ALLOW) on no gRPC peer — but the ZAP
  backend always dispatches with context.Background() (peerless) and the guard is
  always non-nil, so the IP whitelist was bypassed on 100% of ZAP admin RPCs. On
  plaintext ZAP with a configured whitelist, ANY unauthenticated caller could
  DeleteCollection/AllocateVolume/VolumeDelete. FIX: fail closed — allow on no-peer
  ONLY when the whitelist is empty (IsWhiteListed("")==true, allow-all/dev); deny
  when a whitelist is configured (IP can't be evaluated over ZAP; use the PQ-mTLS
  allowed_commonNames CN gate instead). Red's TestZapAdminAuthBypassesWhitelist
  flips FAIL→PASS; control + EC e2e stay green.
- [HIGH] kafka gateway dialed the broker with grpc.mq while the broker server +
  canonical client use grpc.msg_broker — an mTLS rollout would sever kafka↔broker.
  Unified on grpc.msg_broker.
- [LOW] ReceiveFile zero-Send CloseSend opened a doomed empty-oneof stream (server
  'unknown message type'); now a clean no-op, CloseAndRecv handles the nil stream.
Keeps Red's regression tests.
v2026.3.1
2026-06-25 14:27:26 -07:00
zeekay 60f2aa33e7 Merge branch 'feat/zapdb-final' 2026-06-25 13:30:31 -07:00
zeekay 24d2b0c361 Merge branch 'feat/zapdb-integrated' into feat/zapdb-final 2026-06-25 13:27:57 -07:00
zeekay 81968f0bbf Merge zap/engine-rip: full gRPC→ZAP rip (master/volume/mq/filer/object), svc/ rename, PQ transport
All internal S3 service transport is now native ZAP (github.com/zap-proto/go v1.8.1):
- master/volume/mq/filer/object servers retired gRPC, serve over transport.ListenStream(TLS)
- PQ X-Wing (X25519MLKEM768) by construction; per-service ZAP client pools
- svc/{master,volume,mq,filer,object} packages (Pike-style)
- Red-verified (4 HIGH + MEDIUM fixed); EC e2e green; raft is the only remaining gRPC
  server (slated for leaderless pinned-writer replacement, not migration)
Suite: green (1 known-flaky perf test).
v2026.3.0
2026-06-25 13:26:47 -07:00
zeekay e35086399d volume: fix ReceiveFile oneof drop — open client-stream lazily on first Send
The ReceiveFile client-streaming adapter opened the wire stream with an
empty ReceiveFileRequestInput{} (Data=0, oneof-unset) as the init frame,
on the false assumption the server would "drain it without acting." But
serverStream.Recv replays the init frame as the server's FIRST Recv, so
the production handler's oneof switch (server/volume_grpc_copy.go) saw a
request with no variant set and hit its default → "unknown message type",
breaking EC shard distribution.

Root cause: s3/svc/volume/client.go ReceiveFile + receiveFileClientStream
— a protocol contract mismatch with serverStream.Recv (wire), not a
codec/offset bug. The wire layer was always correct (its own roundtrip
test opens with the real Info as init).

Fix: defer the wire OpenStream until the first Send, using that frame as
the init payload — so the real info frame leads the stream, exactly like
every server-streaming RPC rides its first message as init. No empty
opener. CloseSend opens a (genuinely empty) stream only if nothing was
ever sent, keeping the method total.

No generated files touched — fix is entirely in the hand-written adapter.

Verify:
- new focused unit test s3/svc/volume/receivefile_oneof_test.go drives the
  exact caller path (ReceiveFile→Send(Info)→Send(content)→CloseAndRecv)
  against a strict server mirroring the production handler's default;
  FAILS before, PASSES after.
- e2e TestEcEncodeJulorLayoutConverges: PASS (51.2s), 17 shards distributed.
2026-06-25 12:46:24 -07:00
zeekay dcd09e8b48 volume: admin authz over ZAP = transport mTLS, not gRPC peer IP whitelist
The volume admin gate (checkGrpcAdminAuth) read the caller IP via gRPC
peer.FromContext and denied on 'no peer info' — but over the native ZAP mesh there
is no gRPC peer, so every admin RPC (AllocateVolume, DeleteCollection, EC ops...)
was denied, breaking EC shard distribution. Over ZAP the caller is authenticated
at the TRANSPORT by PQ-mTLS (pb.ServerTLSConfig requires+verifies the client cert
CN and fails closed without a CA), so the IP whitelist is a gRPC-era fallback that
can't apply. Treat absence of a gRPC peer as the ZAP path → transport mTLS is the
authorization boundary. Also fixes the e2e test's stale *grpc.ClientConn slice type.
(Exposed by TestEcEncodeJulorLayoutConverges; a separate ReceiveFile streaming-oneof
bug remains, handed off.)
2026-06-25 12:40:38 -07:00
zeekay f5796da5a5 bump luxfi/database v1.19.3; drop pebbledb shim (factory provides it now)
leveldb + pebbledb are build-tag-only via luxfi/database's factory; zapdb is
the always-in native default. No s3-side registration slop.
2026-06-25 12:38:57 -07:00
zeekay b42807bea0 rename <svc>zap → svc/<name>: drop compound names, nest service adapters (Pike)
masterzap→svc/master, volumezap→svc/volume, mqzap→svc/mq, filerzap→svc/filer,
zapsvc→svc/object. Simple one-word packages nested under s3/svc/, parallel to
s3/wire/<name>; the zap suffix was redundant (ZAP is the only transport) and
compound. Dual-import collisions (s3/mq, s3/filer domain pkgs) aliased filersvc/
mqsvc in the few files that need both. Bare-name-vs-var clash (master param vs
master pkg) fixed by renaming the param to masterAddr. Swept test/ stragglers +
an e2e test's stale *grpc.ClientConn→transport.Conn. Suite green (66 ok).
2026-06-25 12:24:22 -07:00
zeekay 2126dcc2eb security: ServerTLSConfig fails closed on cert-without-CA (Red MEDIUM)
Red found that a mesh component with grpc.<c>.cert/.key set but grpc.ca empty
silently served one-way TLS — a server cert presented, ANY client accepted, no
mutual auth (mTLS downgrade). Internal ZAP services are mTLS-only, so refuse to
serve: glog.Fatalf with an actionable message instead of dropping client-cert
verification. Same for an unreadable CA. Applies uniformly to master/volume/mq/
filer (one shared pb.ServerTLSConfig). Green: pb, security, command.
2026-06-25 11:40:15 -07:00
zeekay be8cb85656 integrate: master gRPC→ZAP rip (architecture B), retire master_zap_bridge
Merge worktree-agent-aee73f310721c9a9e: adopt the masterzap package (server.go/
server_rpc.go/stream_server.go — 21 unary + 3 bidi over ZAP) as the master server
adapter, matching filerzap/volumezap/mqzap (one way). DELETE s3/server/master_zap_bridge.go
+ master_zap_stream.go (architecture A: s3server.NewMasterZapBackend) per owner decision.
command/master.go + master_follower.go serve the master over transport.ListenStream/
ListenStreamTLS; WithMasterClient pooled via masterPool. Red HIGH fixes included
(assign retry-over-ZAP string classifier; KeepConnected/SendHeartbeat abandon-path
CloseSend). Consumers (filer_discovery, coordinator_registry, volume_metrics) routed
through pb.WithMasterClient. de-grpc'd master_pb gets a stdlib UnimplementedHanzoServer;
volume Query gets an Unimplemented stub (volume_grpc_query.go) replacing the retired embed.

Reconciled against main's WIP + the volume/mq integrations: pb-local ClientTLSConfig/
ServerTLSConfig (no pb<->security cycle), pb.DialOption type throughout.

GATES: zero gRPC server registrations (master/volume/mq/filer all retired); no conflict
markers; no pb->security import cycle. Suite: 50 pkgs ok; 1 known-flaky perf-timing test
(TestConcurrencyIneffectiveOnStreamBottleneck) passes 3/3 in isolation.
2026-06-25 11:37:03 -07:00
zeekay bfa03f1a54 integrate: all-zapdb storage onto wire-rip HEAD 2026-06-25 11:27:18 -07:00
zeekay dfbd5d6a5d consolidate: all persistent storage on zapdb via luxfi/database; fix sqlite self-containment 2026-06-25 11:17:04 -07:00
zeekay 9b06c332ad Merge branch 'feat/zapdb-storage' into feat/zapdb-all
# Conflicts:
#	go.mod
2026-06-25 11:10:55 -07:00
zeekay db7ecc9747 Merge branch 'feat/luxdb-store' into feat/zapdb-all
# Conflicts:
#	docker/filer.toml
#	go.mod
#	go.sum
#	k8s/charts/s3/values.yaml
#	s3/command/scaffold/filer.toml
#	s3/filer/leveldb/leveldb_store_test.go
#	s3/filer/leveldb/object_size_metric_test.go
#	s3/filer/luxdb/luxdb_store_test.go
#	s3/filer/luxdb/object_size_metric_test.go
#	s3/filer/zapdb/object_size_metric_test.go
#	s3/filer/zapdb/zapdb_store_test.go
#	s3/mount/meta_cache/meta_cache.go
#	s3/server/filer_server.go
2026-06-25 11:09:57 -07:00
zeekay 870349ab20 storage: convert volume needle-map + chunk cache to zapdb via luxfi/database
Eliminate direct goleveldb use from the on-disk volume needle-map index and
the on-disk chunk cache, routing both through luxfi/database with the
ZAP-native zapdb backend (factory.New("zapdb", ...)), matching the proven
filer luxdb store. The needle-id -> (offset,size) byte layout, the watermark
batched-write semantics, and the rebuild-from-.idx recovery path are
preserved byte-for-byte, so existing .ldb directories keep working.

- needle_map_leveldb.go: LevelDbNeedleMap now holds a database.Database.
  Get/Put/Delete, watermark get/set, generate-from-idx, increment loading,
  and lazy load/unload all reimplemented over database.Database. BadgerDB
  (zapdb) auto-recovers on open, subsuming leveldb RecoverFile. Freshness is
  now determined by the db dir's newest file mtime vs the .idx (uncertainty
  rebuilds — always safe).
- recordCount made atomic.Uint64. It is bumped on every Put/Delete which run
  under a shared RLock (lazy path) or no lock (resident path); the prior plain
  uint64 was a latent data race. Add() gives each writer a consistent count.
- needle_map.go / needle_map_memory.go: drop *opt.Options from the
  TempNeedleMapper.UpdateNeedleMap surface (goleveldb-specific, meaningless to
  zapdb which self-tunes).
- volume_loading.go: collapse the small/medium/large NeedleMapLevelDb cases
  into one zapdb-backed map; remove the goleveldb open-file-cache consts.
- chunk_cache_on_disk.go: open the cache needle map without leveldb opts.
- Tests: port the stale-watermark rebuild + concurrency tests off goleveldb;
  add round-trip (256 ids, exact offset/size), batch+reopen-persistence tests.
  Functional needle-map tests pass under -race.

Left untouched: needle_map/memdb.go (in-memory MemDb) — it is an in-memory
sort buffer, not on-disk embedded KV, and its DescendingVisit needs reverse
iteration that database.Iterator (forward-only) cannot provide. It is now the
sole direct goleveldb importer in s3. No bbolt exists in s3.

luxfi/database v1.19.0 and luxfi/log v1.4.3 promoted indirect -> direct.
2026-06-25 11:00:47 -07:00
zeekay 5ddcac82b0 integrate: mq broker gRPC→ZAP rip (architecture B, Red-verified)
Merge worktree-agent-aef6acb034ce75a0b: mqzap server adapter (14 unary + 7
streaming), command/mq_broker.go serves over ZAP (gRPC HanzoMessaging retired),
WithBrokerGrpcClient flipped to brokerPool, kafka broker client + follower legs
migrated, Red HIGH mTLS-downgrade fix. Reconciled against main's WIP:
- broker dialer unified into pb.DialBrokerZapAddr (exported, mirrors DialMasterZapAddr);
  deleted mqzap/dial.go and pointed both follower legs (broker_grpc_sub, local_partition)
  at it — fixes the pb<->mqzap<->security import cycle the same way master avoids it.
- ClientTLSConfig/ServerTLSConfig calls retargeted security.X -> pb.X (main relocated
  them into pb). DialOption type aligned to pb.DialOption.
Green: mqzap, all mq/*, wire/mq_broker, pb.
2026-06-25 11:00:14 -07:00
zeekay 6502fb3157 integrate: volume gRPC→ZAP rip (architecture B, Red-verified)
Merge worktree-agent-a6f8baf78d5e1a844: volumezap server adapter (37 unary + 11
streaming), command/volume.go serves over ZAP (gRPC VolumeServer retired),
WithVolumeServerClient flipped to volumePool, wire/volume_server Context()+
embedMessage Red fixes. Reconciled against main's WIP: aligned dialVolumeZapAddr +
WithVolumeServerClient to main's pb-local ClientTLSConfig/DialOption/pb.ServerTLSConfig
(main relocated TLS config into pb to break the pb<->security cycle). Green: pb,
volumezap, operation, storage, topology, command.
2026-06-25 10:54:53 -07:00
zeekay e1e705e565 rip gRPC from 5 services: gRPC-free interfaces over ZAP, deadline-honoring calls
filer, master, iam, plugin and worker no longer use google.golang.org/grpc on
the client path.

- gRPC-free client interfaces: the generated *_grpc.pb.go client interfaces drop
  "opts ...grpc.CallOption" (no caller ever passed one) and their streaming
  methods return the shared seam types in s3/pb/rpc (ServerStream[T] /
  BidiStream[Req,Resp]) instead of grpc.ServerStreamingClient/BidiStreamingClient.
  The gRPC server scaffolding (Unimplemented*Server, Register*Server, ServiceDesc,
  handler trampolines) is deleted; servers serve over the ZAP wire Dispatch.
- The ZAP adapters (filerzap/masterzap/...) implement the gRPC-free interfaces;
  grpc.DialOption becomes pb.DialOption (the dial is the ZAP transport).
- Unary calls honor context deadlines: the wire client threads ctx to
  transport.Conn.CallContext (v1.8.1), so a call to an unresponsive peer aborts
  on the caller's deadline instead of blocking forever.
- Error semantics: the filer tags each failure with its code name ("NotFound: …",
  "Internal: …") in the message, which crosses the ZAP wire and is classified by
  mount/error_classifier.go — replacing grpc status/codes.
- master ZAP listener port: grpcPort+10000 could exceed 65535; made overflow-safe.
- test doubles updated to the gRPC-free interfaces (0 tests skipped).
- dead cmd/s3-db and cmd/s3-sql (postgres-wire / SQL-engine entry points whose
  backends were already ripped) deleted; finished the backend-rip import cleanup.

go build ./... green; go test ./s3/... green (heavy stream benches run under
their existing -short gates).

Still on gRPC (next wave): volume_server + mq (reverted — servers/adapters not
ready), the remaining ~23 plumbing files, and the go.mod dependency itself.
2026-06-25 06:39:01 -07:00
zeekay 1934d78dac checkpoint: in-tree WIP (master_zap_bridge rip + filer/mount/consumer changes)
Preserving the working-tree WIP as a recoverable checkpoint before integrating the
parallel agent rips (master/volume/mq). This is architecture A for the master rip
(s3server.NewMasterZapBackend in master_zap_bridge.go); builds clean. Volume + mq
not ripped here. Recoverable: revert this commit to restore the prior HEAD.
2026-06-25 01:24:30 -07:00
zeekay 5c43e23c87 wire/volume_server: fix embedMessage empty-message null-collapse (red MEDIUM)
Red found embedMessage was the PRE-FIX template: it copied the sub-buffer
verbatim (header included) and returned base+rootOff. For a present-but-empty
nested message (zero-field, e.g. QueryRequest InputSerialization.ParquetInput{},
buffer header-only with rootOff==HeaderSize==len) that offset landed one past the
copied region -> out of bounds -> Object.IsNull() -> the variant was silently
DROPPED on the wire. Same defect class the filer wire already fixed
(child[HeaderSize:] copy, not verbatim).

Fix:
- copy only the payload region sub[HeaderSize:] and return base+(rootOff-HeaderSize)
  — the filer's fix; all internal field-relative pointers shift by the same
  HeaderSize so deeper nested objects/lists/strings stay valid.
- AND preserve present-but-empty presence: WriteBytes(empty) returns 0 (which the
  filer fix would also read back as null), so for an empty body we write one
  aligned anchor byte, giving the size-0 object (which reads no fields) a non-null,
  in-bounds root. Presence survives instead of collapsing.

Red's TestQuery_InputSerializationVariants/parquet (was FAIL: ParquetInput->nil)
now PASSES; csv/json still pass; the 43-field FetchAndWriteNeedle RemoteConf graph
and the VolumeServerStatus nested float32 graph still round-trip faithfully.
Added wire-level TestEmbedEmptyMessagePresenceParquet +
TestEmbedNonEmptyMessageStillFaithful to lock both branches in.

NOTE: helpers_zap.go is generated (DO NOT EDIT). The proto->zap codegen MUST carry
this embedMessage form on regen — same standing requirement recorded for the
other generated hand-fixes in this migration (embedMessage whole-segment copy,
Dispatch err-in-body). Flag upstream zap-proto/go: a builder-native empty-embedded
encoding (StartObject(0) yielding a referenceable root) would remove the anchor-
byte workaround.
2026-06-25 01:17:38 -07:00
zeekay da39fc2bbf volumezap: thread per-stream Context() through streaming adapters (red HIGH)
Red found the streaming server-stream adapters handed the engine
context.Background() instead of a context cancelled on client conn-drop — a
goroutine leak for any handler that gates an idle wait on stream.Context().Done()
(and lost request-scoped cancellation on the checkGrpcAdminAuth(stream.Context())
streaming-admin paths).

Root cause: wire/volume_server.serverStream exposed no Context(), unlike the
filer template (filerstream gives every server-stream type a Context() ->
transport.Stream.Context(), the v1.6.2 cancel-on-disconnect fix).

Fix mirrors filerstream exactly:
- serverStream.Context() -> s.Context() (transport per-stream ctx, cancelled on
  stream end OR peer conn-drop).
- each of the 11 *ServerStream types gets Context() delegating to z.Context().
- the volumezap Send/Recv adapters return out.Context()/in.Context() and drop the
  ctx=context.Background() field entirely.

Red's TestVolumeTailSender_ContextCancelOnConnDrop (was a 3s-timeout LEAK) now
PASSES: the handler blocked on stream.Context().Done() releases on client conn
drop. This also gives the streaming admin-auth paths a real cancellable context
(red fix-priority #3, satisfied by this change).
2026-06-25 01:17:24 -07:00
zeekay c90b015226 filer: metadata store over luxfi/database (backend zapdb default; pebble/leveldb selectable), drop leveldb 2026-06-25 01:05:30 -07:00
zeekay 144309a7f7 mq: gate broker->follower replication dials on mTLS (Red HIGH fix)
Red found the two follower-replication legs (SubscribeFollowMe in broker_grpc_sub.go,
PublishFollowMe in local_partition.go) regressed from pb.GrpcDial(...,
security.LoadClientTLS(grpc.msg_broker)) to unconditional plaintext transport.Dial —
a silent mTLS downgrade (vs a PQ-mTLS follower listener: handshake fails, replication
breaks; vs plaintext: payloads in cleartext). Add mqzap.DialBroker — the SAME gate as
pb.dialBrokerZapAddr / kafka.dialBrokerZap (PQ-TLS when grpc.msg_broker certs, else
plaintext) — and route both legs through it. Also drop the now-dead grpc.DialOption
param from MaybeConnectToFollowers (gating moved to viper), removing grpc from
local_partition.go entirely. Keeps Red's red_vectors_test.go (6 round-trip proofs).
2026-06-25 00:59:56 -07:00
zeekay 7fe0cecd91 pb: dial volume server over ZAP (volumePool), flip WithVolumeServerClient
WithVolumeServerClient now reuses one pooled ZAP transport.Conn per volume
address (transport.NewPool over dialVolumeZapAddr — PQ-TLS via transport.DialTLS +
PQTLSConfig when grpc.volume certs are set, else plaintext) and runs fn with
volumezap.New(conn). Signature is unchanged, so all ~40 consumers (operation,
shell, storage, topology, server replication/EC paths) migrate to ZAP through
this single seam — no call-site edits. Mirrors the proven filerPool.
2026-06-25 00:48:16 -07:00
zeekay b13aaeb84f volume: serve over ZAP transport, retire gRPC VolumeServer registration
startGrpcService now serves the volume server over transport.ListenStream /
ListenStreamTLS (PQ X-Wing mTLS when grpc.volume.cert/.key is set, plaintext
otherwise) via volumezap.NewServerBackend + vsw.Dispatch/StreamHandler — the same
listener carries the 37 unary + 11 streaming RPCs. The gRPC path is gone:
volume_server_pb.RegisterVolumeServerServer, reflection.Register,
pb.NewGrpcServer, pb.ServeGrpcOnLocalSocket, and the grpc/reflection imports all
removed. shutdown closes the *transport.Server (Close, not GracefulStop).
2026-06-25 00:48:16 -07:00
zeekay 941b21f6f5 volumezap: server backend over wire/volume_server (37 unary + 11 streaming)
Adapt the gRPC-shaped volume_server_pb.VolumeServerServer to the generated
vsw.VolumeServerStore so the whole volume server answers over the canonical
github.com/zap-proto/go transport — the volume analogue of filerzap.NewServerBackend.

- server.go: 37 unary methods, one hop each way (Wrap req buffer -> pb -> engine
  -> pb -> New resp buffer).
- stream_server.go: 11 streaming methods (10 server-stream via Send-adapters
  embedding grpc.ServerStream for the unused interface methods; 1 client-stream
  ReceiveFile via Recv/SendAndClose).
- server_rpc.go / server_convert.go: per-RPC + leaf converters, the exact inverse
  of rpc.go/convert.go (request decode, response encode).
- server_roundtrip_test.go: proto-shaped fake served over real TCP ListenStream,
  reached by the volumezap client — unary scalar, unary nested/repeated/oneof,
  server-stream, and client-stream all proven over ZAP. No protobuf framing,
  no gRPC transport.
2026-06-25 00:47:58 -07:00
zeekay 02e25efbc2 mqzap: prove server adapter end-to-end over ZAP
fakeEngine implements mq_pb.HanzoMessagingServer; served via mq_brokerwire.Serve
through the real NewServerBackend/NewStreamServer and dialed with mqzap.New. Covers
unary (FindBrokerLeader/ConfigureTopic with retention+assignments/FetchMessage/
GetPartitionRangeInfo), bidi PublishMessage + SubscribeMessage (oneof resp), and
server-stream GetUnflushedMessages. All green.
2026-06-25 00:45:50 -07:00
zeekay 8eba19dbd7 mq: migrate broker consumers off gRPC to ZAP
- broker SubscribeMessage: dial the follower broker over transport.Dial and open
  the SubscribeFollowMe client-stream via OpenStream(...Ordinal), forwarding Ack/
  Close as zero-copy wire frames (mirrors PublishFollowMe in local_partition.go);
  drops pb.GrpcDial + mq_pb.NewHanzoMessagingClient.
- kafka integration BrokerClient: replace grpc.DialContext + NewHanzoMessagingClient
  with dialBrokerZap (PQ-TLS/plaintext) + mqzap.New; conn is now transport.Conn.
2026-06-25 00:45:50 -07:00
zeekay 499b8ae8a6 pb: flip WithBrokerGrpcClient to ZAP via brokerPool
dialBrokerZapAddr (PQ-TLS when grpc.msg_broker.cert/.key, else plaintext) + a
transport.NewPool, mirroring filerPool. WithBrokerGrpcClient now pools one ZAP
conn per broker address and runs fn with mqzap.New(conn) — the broker fully cut
over so its address IS the ZAP endpoint (no port offset). DialOption now inert.
2026-06-25 00:45:39 -07:00
zeekay bcccff7ed0 command/mq_broker: serve broker over ZAP, retire gRPC HanzoMessaging registration
Replaces both pb.RegisterHanzoMessagingServer sites with transport.ListenStream /
ListenStreamTLS over mq_brokerwire.Dispatch(mqzap.NewServerBackend) +
mqzap.NewStreamServer. PQ-secured mTLS (X25519MLKEM768) when grpc.msg_broker.cert/.key
is set, plaintext otherwise — same gate the gRPC broker enforced, no downgrade.
Main + localhost listeners; blocks until interrupt closes every ZAP listener.
2026-06-25 00:45:39 -07:00
zeekay 233a120d3f mqzap: server adapter — wrap mq_pb.HanzoMessagingServer onto wire/mq_broker Backend
NewServerBackend (14 unary) + NewStreamServer (7 streaming) adapt the existing
broker engine to the generated mq_brokerwire.Broker/StreamBroker, mirroring the
proven filerzap template. server_convert.go owns the request-view->*mq_pb and
*mq_pb-response->ResponseInput direction; stream_server_convert.go the streaming
mirror; both reuse the leaf converters in convert.go (added partitionOffsetFromWire,
brokerStatsFromView, publisher/subscriber/range ToWire). Zero protobuf on the wire.
2026-06-25 00:45:10 -07:00
zeekay efbc4f6f41 zapsvc: drop PQTLSConfig wrap — transport DialTLS/ListenTLS are PQ by construction (v1.8.1) 2026-06-25 00:20:47 -07:00
zeekay 72bd0b20df build: restore green ./... after backend/postgres rip + v1.7.0 migration
Three stragglers left the tree red:
- cmd/s3-db and cmd/s3-sql were the PostgreSQL-wire and SQL-engine entry
  points; their backing packages (s3/server/postgres, s3/query/engine) were
  ripped in 5b7369380, leaving the commands importing nothing. Deleted.
- s3/server/filer_server.go and s3/command/imports.go still imported the 20
  non-SQLite filer backends deleted in 448e751f1. Dropped the dead imports.
- test/plugin_workers/framework.go passed *transport.Stream where v1.7.0 made
  Stream an interface (transport.Stream). Fixed the handler signature.

go build ./... now exits 0.
2026-06-25 00:02:06 -07:00
zeekay 6baee5d0e3 masterzap: decode the 5 repeated heartbeat fields it dropped
HeartbeatReqFromWire decoded Volumes/EcShards/LocationUuids/MaxVolumeCounts
but silently omitted NewVolumes, DeletedVolumes, NewEcShards, DeletedEcShards
and DiskTags — which the encode side writes and the wire view exposes. That is
the volume->master incremental topology-churn channel, so a wired adapter would
leave the master blind to incremental volume/EC-shard adds and deletes.

Add the five decode blocks (reusing ecShardInfoFromView; new volumeShortInfoFromView
and diskTagFromView), and a round-trip test that pins all five — the prior
TestSendHeartbeatBidi only exercised Ip/Port/Id.
2026-06-25 00:01:50 -07:00
zeekay 448e751f1e rip: 20 non-SQLite filer backends — SQLite-only (native ZAP all, no postgres/mysql/mongo/etc.)
Deleted filer backends arangodb/cassandra(2)/etcd/hbase/leveldb2/leveldb3/
mongodb/mysql(2)/postgres(2)/redis(1,2,3)/tarantool/tikv/ydb/elastic and their
blank imports in command/imports.go + server/filer_server.go. Kept sqlite (the
only selectable metadata store) + abstract_sql (sqlite base) + leveldb (FUSE
mount meta_cache uses it directly, internal — not a backend choice). Per:
SQLite-only scoped per tenant.
2026-06-24 23:44:12 -07:00