~bigbes/tarantool-etcd · issues

skfac6scnbakdj9s1gi73nvdbrc1k3jr · 113 rows

idcontent_hashtitledescriptiondesignacceptance_criterianotesstatuspriorityissue_typeassigneeestimated_minutescreated_atcreated_byownerupdated_atclosed_atclosed_by_sessionexternal_refspec_idcompaction_levelcompacted_atcompacted_at_commitoriginal_sizesenderephemeralwisp_typepinnedis_templatemol_typework_typesource_systemmetadatasource_repoclose_reasonevent_kindactortargetpayloadawait_typeawait_idtimeout_nswaitershook_beadrole_beadagent_statelast_activityrole_typerigdue_atdefer_untilno_historystarted_atis_blocked
tarantool-etcd-axsa0c9a9219a53e6fa60ca977b86cbde3b627bc6e616f64b0c292af4d186b91633Learner: rafthttp peer transport over nghttp2Implement etcd's rafthttp peer transport so the cluster can stream the raft log to us. Endpoints (HTTP/2, port 2380): /raft (pipeline POST), /raft/stream/message/<local-id> and /raft/stream/msgapp/<local-id> (long-lived streams), /raft/snapshot (snapshot receive, separate phase). Must: open/maintain streams to each peer, receive MsgApp/MsgHeartbeat/MsgSnap, send MsgAppResp/MsgHeartbeatResp back, do etcd peer version negotiation (X-Etcd-Cluster-ID, X-Server-Version, X-Raft-To/From headers). Reuse lib/nghttp2 for HTTP/2 framing. Raw message bodies are gogoproto-encoded raftpb.Message — decode lives in the proto-decode phase; this phase just moves bytes + manages stream lifecycle.rafthttp reference in etcd/server/etcdserver/api/rafthttp/. Header contract is strict — mismatched cluster-id/version closes the stream.open2taskNULLNULL2026-05-20T06:45:14ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:37ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL1
tarantool-etcd-b08e3928051dd644ec2d3c70348320e479a23d4e425c4f5776f5a2cbbfc3d571607Phase 5g — Auth/Cluster/Maintenance/Lock/Election option coveragePer-option density on the remaining v3 services. Low priority — each surface is small and the existing files already cover the canonical paths; spot-fill only what option coverage actually reveals. Run after Phase 5f.Spot-fill tests added where an unaddressed option diverges between cells; documented as a known gap otherwise.Source: docs/TODO.md "Open / Conformance matrix — Phase 5 option coverage".open3taskNULLNULL2026-05-19T13:34:10ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:37ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL1
tarantool-etcd-bdfbfc4038d48324b7c9fc5e533914f732797d0d1bb9a7f9d09560a51dc7cce0722gRPC server reflectionRoadmap P1. Implement the gRPC reflection service (grpc.reflection.v1alpha / v1) so tools like grpcurl and etcdctl-adjacent tooling can discover services/methods without local .proto files. Serve the descriptors from the codegen-emitted schema tables.Roadmap-only item; not tracked before.open1featureNULLNULL2026-05-20T06:55:23ZEugene Blikhbigbes@gmail.com2026-05-20T06:55:23ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-bg44f65298830b799a0aa90d2dadbcb7f92f52d144db8dc119673c85221d1f7ffbaiproto-verify: etcd_role_list vs Auth.RoleListAdd Lua testkit verification for etcd_role_list (mirrors gRPC Auth.RoleList). Successful path: assert response shape matches the gRPC response message after MsgPack round-trip. Error path: at least one error case asserting {code, message} matches app/etcd/errors.lua catalog. Exercise at least one non-default option if applicable. Goes in test/iproto_parity_test.lua under group iproto/parity/auth. Call shape: local resp = etcd_role_list(req).Verification-only. Wrapper exists at app/etcd/api.lua. Epic tarantool-etcd-w8q.open3taskNULLNULL2026-05-19T14:54:14ZEugene Blikhbigbes@gmail.com2026-05-19T14:54:14ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-bol6e7729d0a88e476af22e1b9544083fc6358ea78739d3f4496e69e263f342d93fiproto-verify: etcd_role_add vs Auth.RoleAddAdd Lua testkit verification for etcd_role_add (mirrors gRPC Auth.RoleAdd). Successful path: assert response shape matches the gRPC response message after MsgPack round-trip. Error path: at least one error case asserting {code, message} matches app/etcd/errors.lua catalog. Exercise at least one non-default option if applicable. Goes in test/iproto_parity_test.lua under group iproto/parity/auth. Call shape: local resp = etcd_role_add(req).Verification-only. Wrapper exists at app/etcd/api.lua. Epic tarantool-etcd-w8q.open3taskNULLNULL2026-05-19T14:54:12ZEugene Blikhbigbes@gmail.com2026-05-19T14:54:12ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-boq78f7ab0f980e3e418ac85b10e54290632eb565a339b43e58c52e1512d179539aLearner: raft state machine (follower/learner subset)Minimal raft state machine for a non-voting learner. Track currentTerm, commitIndex, lastApplied, and the membership ConfState. Handle: MsgApp (append entries, advance commit), MsgHeartbeat (advance commit, reply), MsgSnap (hand to snapshot phase). Explicitly DROP/reject MsgVote/MsgPreVote and never campaign or transition to candidate/leader (learners can't vote or be elected). Apply ConfChange entries to track membership (including our own promotion away from learner -> would flip behavior, out of v1 scope). No proposal path. This is the brain that decides which entries are committed and ready to apply; the apply loop is a separate phase.We are NOT reimplementing etcd's full raft — only the receive/commit/apply path a learner needs. Election, log compaction-on-leader, ReadIndex coordination all out of scope.open2taskNULLNULL2026-05-20T06:45:15ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:37ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL1
tarantool-etcd-bq8384f622c395002fdc1fa6c43c9005f80116e1c4c08c9aed8828a8671b4293a6biproto-verify: etcd_lease_revoke vs Lease.LeaseRevokeAdd Lua testkit verification for etcd_lease_revoke (mirrors gRPC Lease.LeaseRevoke). Successful path: assert response shape matches the gRPC response message after MsgPack round-trip. Error path: at least one error case asserting {code, message} matches app/etcd/errors.lua catalog. Exercise at least one non-default option if applicable. Goes in test/iproto_parity_test.lua under group iproto/parity/lease. Call shape: local resp = etcd_lease_revoke(req).Verification-only. Wrapper exists at app/etcd/api.lua. Epic tarantool-etcd-w8q.open3taskNULLNULL2026-05-19T14:53:59ZEugene Blikhbigbes@gmail.com2026-05-19T14:53:59ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-buq9370d11c13a9d704f0b6e3f0241d2513428257a7e3278aacfed07ddb5818c965Drop stale TODO-item-14 comment in app/etcd/json.luaapp/etcd/json.lua:621 has a stale comment: "/v3/election/observe — gated on TODO item 14". TODO item 14 closed in docs/TODO.md (the Election Observe broadcast is implemented; STREAM_HANDLERS at line 427 includes /v3/election/observe). The comment is now misleading; rewrite it to describe what the fallback branch actually catches (a streaming PATH without a handler registered) and remove the historical reference.Comment at app/etcd/json.lua:621 no longer references TODO item 14 or implies /v3/election/observe is unimplemented.Backlog. Found while auditing TODOs for the bd port on 2026-05-19.open4taskNULLNULL2026-05-19T13:34:52ZEugene Blikhbigbes@gmail.com2026-05-19T13:34:52ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-cc708a9119b866b0edcef671ef29415ba1d060bc828197979f54344268411b4c784Conformance: bump etcd backend from 3.6 to 3.7tests/conformance/go.mod pins go.etcd.io/etcd/{api,client/pkg,client,server,tests}/v3 at v3.6.0, so every 'etcd' conformance cell measures us against 3.6 behavior. etcd 3.7 is now released and is what new deployments will run. Bump the pins to v3.7.0 and fix whatever the suite surfaces. Known-relevant 3.7 changes that touch the harness rather than our server: - clientv3 no longer honors the deprecated grpc.WithBlock dial option (client creation is non-blocking) — harness/dial.go may rely on dial-blocking for readiness. - Go 1.26.4 build requirement. - Protobuf overhaul: golang/protobuf + gogo/protobuf -> google.golang.org/protobuf, plus grpc-middleware v2. May move types the suite imports. - v2 discovery/request/client packages removed (we never used them). - embed.Etcd surface may have shifted; experimental flags were all removed in favor of Kubernetes-style feature gates. Any behavior divergence this uncovers gets its own issue + a knownGaps entry, not a silent skip.cd tests/conformance && go test -count=1 ./... green against both backends on both wires with v3.7.0 pins; each new divergence has an issue and a gaps.go entry referenced from docs/TODO.md.open2taskNULLNULL2026-07-17T11:30:04ZEugene Blikhbigbes@gmail.com2026-07-17T11:30:04ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-cnjed489cb32430e8d6cd2ea3b91464291e41a9c603992a7c8baf680dd56c313931[epic] Raft-learner replica — join an etcd cluster as a non-voting memberAttach this server to a real etcd cluster as a Raft *learner* (non-voting member), receiving the replicated log over etcd's internal peer protocol (rafthttp) and applying it into our etcd_* spaces. Unlike the Watch-mirror route (tarantool-etcd-7ey), a learner is in the cluster's membership view (MemberList shows it), sees auth/lease/cluster/alarm state in the log automatically, and avoids the Watch compaction-resync gap. Cost is ~60-70% of full-member work, NOT 20%: the election state machine, proposal path, leader responsibilities, and snapshot *send* drop off, but the rafthttp transport, log applier, and snapshot *receive* (bbolt parse) all remain. We track etcd-INTERNAL protos (raftpb.Message, etcdserverpb.InternalRaftRequest) — stable-ish but not a public contract; release cadence binds to upstream etcd versions. Decision context (chat 2026-05-20): user explicitly chose the learner path over the Watch mirror. This epic is the alternative to 7ey, not a child of it. Phasing is learner-first and bottom-up: config -> transport -> proto decode -> state machine -> apply loop -> snapshot receive -> durability -> membership handshake -> conformance. Split into child issues below.Surface map: peer endpoints /raft, /raft/stream/message/<id>, /raft/stream/msgapp/<id>, /raft/snapshot on port 2380. Reuses our nghttp2 HTTP/2 layer for the transport and our pure-Lua pb engine for the gogoproto schemas. Easiest correctness oracle: tests/conformance harness can SpawnEtcd then MemberAddAsLearner us.open2featureNULLNULL2026-05-20T06:39:59ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:36ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-cpp51598282012a458cd2be1c01fc8c7326fd8c8624f667d400c44e1d56412c5f5bC-runtime + C-compile-time protobuf path (3-5x speedup)Roadmap P1. The pure-Lua / pb protobuf encode/decode is a hot path; a C runtime (and compile-time generated codecs) for protobuf is expected to bring 3-5x throughput, approaching Go-level. Scope: evaluate/extend the pb engine with a C backend, generate per-message C codecs at compile time, wire into the decode/encode boundary. Interacts with the JIT-disabled-after-box.cfg reality on this build.Roadmap-only item; not tracked before.open1featureNULLNULL2026-05-20T06:55:24ZEugene Blikhbigbes@gmail.com2026-05-20T06:55:24ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-cz54624dbf6ad6bf8e90df4dfb60839daf2c9b81d1490c3dccf619f343a0eef92fciproto-verify: etcd_maintenance_move_leader vs Maintenance.MoveLeaderAdd Lua testkit verification for etcd_maintenance_move_leader (mirrors gRPC etcdserverpb.Maintenance.MoveLeader). Same test pattern as verify-only tasks: positive path plus at least one error path, response shape matches gRPC, error codes from app/etcd/errors.lua. For UNIMPLEMENTED-by-design endpoints (Cluster.MemberAdd/Remove/Update/Promote), assert the wrapper returns the canonical UNIMPLEMENTED error consistent with gRPC rather than skipping. Goes in test/iproto_parity_test.lua under group iproto/parity/maintenance.Epic tarantool-etcd-w8q. Blocked on the matching impl issue.open3taskNULLNULL2026-05-19T14:54:42ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:37ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL1
tarantool-etcd-dkr36433e1a02770d7b48365cfd48bf7f0f3db1f7e2f287b723f41083bd7ff61377Alternative transports for gRPCRoadmap P2 (later). Support gRPC over transports other than the current nghttp2/TCP path (e.g. unix sockets, or alternate HTTP/2 stacks). Exploratory; depends on the http2-rock extraction landing first.Roadmap-only item; not tracked before.open2featureNULLNULL2026-05-20T06:55:26ZEugene Blikhbigbes@gmail.com2026-05-20T06:55:26ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-dmtc018e2fea002b9ae10b51cd9b69a7fc6e4137e1abddda5894b9874aea50df95fiproto-verify: etcd_election_resign vs Election.ResignAdd Lua testkit verification for etcd_election_resign (mirrors gRPC v3electionpb.Election.Resign). Same test pattern as verify-only tasks: positive path plus at least one error path, response shape matches gRPC, error codes from app/etcd/errors.lua. For UNIMPLEMENTED-by-design endpoints (Cluster.MemberAdd/Remove/Update/Promote), assert the wrapper returns the canonical UNIMPLEMENTED error consistent with gRPC rather than skipping. Goes in test/iproto_parity_test.lua under group iproto/parity/election.Epic tarantool-etcd-w8q. Blocked on the matching impl issue.open3taskNULLNULL2026-05-19T14:54:53ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:37ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL1
tarantool-etcd-g1a94cc76ee0c10feae7cdcc327b843bb2cd907d8b2e7190c64ce7f199385cb4caaiproto-impl: etcd_member_list vs Cluster.MemberListWrap the existing handler cluster.member_list (already invoked by gRPC/JSON via defs.lua route etcdserverpb.Cluster.MemberList) as a Lua global etcd_member_list callable via iproto CALL. Mechanical change in app/etcd/api.lua: add rawset(_G, 'etcd_member_list', wrap('cluster', 'member_list')) under the appropriate service block; append 'etcd_member_list' to the funcs table so box.schema.func.create plus guest grant runs at role apply; document the wrapper in the module-level LDoc comment. If Cluster.MemberList returns UNIMPLEMENTED today, the wrapper still gets added so the iproto caller observes the same UNIMPLEMENTED error gRPC would return. Election.Observe is server-streaming over gRPC; iproto has no stream primitive, so propose a polling shape (observe_create/_pull/_cancel) mirroring the Watch precedent at api.lua:81-83.etcd_member_list is callable from net.box:call('etcd_member_list', {req}) with no Lua error before handler dispatch. Successful request shape produces same successful response shape as gRPC. box.schema.func.create plus guest grant idempotent on role re-apply.Epic tarantool-etcd-w8q. Handler at app/etcd/cluster.lua.open3taskNULLNULL2026-05-19T14:54:25ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:36ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-gz4ce1604ad8990ae56710064076900a30bc028c5a592327c484f437c820d40360ciproto-verify: etcd_put vs KV.PutAdd Lua testkit verification for etcd_put (mirrors gRPC KV.Put). Successful path: assert response shape matches the gRPC response message after MsgPack round-trip. Error path: at least one error case asserting {code, message} matches app/etcd/errors.lua catalog. Exercise at least one non-default option if applicable. Goes in test/iproto_parity_test.lua under group iproto/parity/kv. Call shape: local resp = etcd_put(req).Verification-only. Wrapper exists at app/etcd/api.lua. Epic tarantool-etcd-w8q.open3taskNULLNULL2026-05-19T14:53:53ZEugene Blikhbigbes@gmail.com2026-05-19T14:53:53ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-h8r864b7efe5edb39f6670b5bb0ca34accb55dcf6beba77a46d7fd987280df09847iproto-verify: etcd_election_observe vs Election.ObserveAdd Lua testkit verification for etcd_election_observe (mirrors gRPC v3electionpb.Election.Observe). Same test pattern as verify-only tasks: positive path plus at least one error path, response shape matches gRPC, error codes from app/etcd/errors.lua. For UNIMPLEMENTED-by-design endpoints (Cluster.MemberAdd/Remove/Update/Promote), assert the wrapper returns the canonical UNIMPLEMENTED error consistent with gRPC rather than skipping. Goes in test/iproto_parity_test.lua under group iproto/parity/election.Epic tarantool-etcd-w8q. Blocked on the matching impl issue.open3taskNULLNULL2026-05-19T14:54:51ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:37ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL1
tarantool-etcd-hcoa75a35cc4e55aca16758bcde37bde3575cc73d8106697aa8e8274c5013dfdb31iproto-impl: etcd_election_observe vs Election.ObserveWrap the existing handler election.observe (already invoked by gRPC/JSON via defs.lua route v3electionpb.Election.Observe) as a Lua global etcd_election_observe callable via iproto CALL. Mechanical change in app/etcd/api.lua: add rawset(_G, 'etcd_election_observe', wrap('election', 'observe')) under the appropriate service block; append 'etcd_election_observe' to the funcs table so box.schema.func.create plus guest grant runs at role apply; document the wrapper in the module-level LDoc comment. If Election.Observe returns UNIMPLEMENTED today, the wrapper still gets added so the iproto caller observes the same UNIMPLEMENTED error gRPC would return. Election.Observe is server-streaming over gRPC; iproto has no stream primitive, so propose a polling shape (observe_create/_pull/_cancel) mirroring the Watch precedent at api.lua:81-83.etcd_election_observe is callable from net.box:call('etcd_election_observe', {req}) with no Lua error before handler dispatch. Successful request shape produces same successful response shape as gRPC. box.schema.func.create plus guest grant idempotent on role re-apply.Epic tarantool-etcd-w8q. Handler at app/etcd/election.lua.open3taskNULLNULL2026-05-19T14:54:50ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:36ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-hlx629cacff048485b7bfdb7696ef646a8c092fc87f720e2f43caae3e2bfd8170aeReplica route: watch-tail live syncAfter bootstrap, open a clientv3 Watch from the bootstrap watermark+1 over the whole keyspace and apply every event (PUT/DELETE) into the etcd_* spaces, advancing the local synced watermark per event header. Must handle: - Progress notifications (WithProgressNotify) to advance the watermark even when idle, and detect staleness. - ErrCompacted (code 11): upstream compacted past our position -> trigger a re-bootstrap (tarantool-etcd child) then resume. - Reconnect/backoff on upstream Unavailable; resume from last applied revision. - Ordering: apply events in revision order; the local revision counter tracks upstream mod_revision (see revision-alignment child). This is the steady-state engine of mirror mode.ErrCompacted=11 and progress-notify semantics are the ones we already understand from conformance work (see clientv3 quirks memory).open2taskNULLNULL2026-05-20T06:17:55ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:37ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL1
tarantool-etcd-huo96dcd8d31ebf9f5f56da997ac7d459e417b024ed5bd339a4a5c33c469b4e96c1etcd /metrics compatibility — match upstream Prometheus metric names + endpointExpose a Prometheus /metrics endpoint whose metric names, label sets, and types match upstream etcd's, so existing etcd Grafana dashboards, recording rules, and alerts work unchanged against tarantool-etcd. This is the compatibility layer on top of the underlying metrics integration (tarantool-etcd-unw): map our collected operational stats onto etcd's canonical series — e.g. etcd_server_has_leader, etcd_server_leader_changes_seen_total, etcd_mvcc_db_total_size_in_bytes, etcd_server_proposals_committed_total, grpc_server_handled_total{grpc_method,grpc_code}, etcd_network_peer_round_trip_time_seconds, etcd_debugging_mvcc_keys_total, etc. Scope to nail down: which series are meaningful for a Tarantool backend vs which must be emitted as constants/stubs to satisfy dashboards, the /metrics text-format exposition path (does it ride the JSON gateway or a dedicated listener), and a conformance check that scrapes both real etcd and tarantool-etcd and diffs the metric name/label surface.etcd 3.7 metric surface additions (from the 3.7.0 announcement) — fold into the name/label diff, and note that the diff must be taken against a 3.7 scrape once tarantool-etcd-cc7 bumps the conformance backend off 3.6: - etcd_server_request_duration_seconds (new, non-debugging — likely dashboard-relevant) - etcd_debugging_server_watch_send_loop_watch_stream_duration_seconds - etcd_debugging_server_watch_send_loop_watch_stream_duration_per_event_seconds - etcd_debugging_server_watch_send_loop_control_stream_duration_seconds - etcd_debugging_server_watch_send_loop_progress_duration_seconds The four watch send-loop series are etcd_debugging_* and describe upstream's internal watch send loop, which our watch.lua (fiber.cond + kv_history catch-up) has no structural analogue for — candidates for the 'stub or omit' bucket rather than the 'map' bucket.open2featureNULLNULL2026-05-20T19:08:45ZEugene Blikhbigbes@gmail.com2026-07-17T11:31:01ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL1
tarantool-etcd-hx983339a7afd9423290ef9d2cd3efe2cd40957688e945103b127b1b1bbb8e52b4aiproto-impl: etcd_member_remove vs Cluster.MemberRemoveWrap the existing handler cluster.member_remove (already invoked by gRPC/JSON via defs.lua route etcdserverpb.Cluster.MemberRemove) as a Lua global etcd_member_remove callable via iproto CALL. Mechanical change in app/etcd/api.lua: add rawset(_G, 'etcd_member_remove', wrap('cluster', 'member_remove')) under the appropriate service block; append 'etcd_member_remove' to the funcs table so box.schema.func.create plus guest grant runs at role apply; document the wrapper in the module-level LDoc comment. If Cluster.MemberRemove returns UNIMPLEMENTED today, the wrapper still gets added so the iproto caller observes the same UNIMPLEMENTED error gRPC would return. Election.Observe is server-streaming over gRPC; iproto has no stream primitive, so propose a polling shape (observe_create/_pull/_cancel) mirroring the Watch precedent at api.lua:81-83.etcd_member_remove is callable from net.box:call('etcd_member_remove', {req}) with no Lua error before handler dispatch. Successful request shape produces same successful response shape as gRPC. box.schema.func.create plus guest grant idempotent on role re-apply.Epic tarantool-etcd-w8q. Handler at app/etcd/cluster.lua.open3taskNULLNULL2026-05-19T14:54:21ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:36ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-iij291c145ebcd3fb5899f03f83ed0a7ad011df3459d5a8ed30498483aef3cd726fiproto-verify: etcd_lock vs Lock.LockAdd Lua testkit verification for etcd_lock (mirrors gRPC Lock.Lock). Successful path: assert response shape matches the gRPC response message after MsgPack round-trip. Error path: at least one error case asserting {code, message} matches app/etcd/errors.lua catalog. Exercise at least one non-default option if applicable. Goes in test/iproto_parity_test.lua under group iproto/parity/lock. Call shape: local resp = etcd_lock(req).Verification-only. Wrapper exists at app/etcd/api.lua. Epic tarantool-etcd-w8q.open3taskNULLNULL2026-05-19T14:54:17ZEugene Blikhbigbes@gmail.com2026-05-19T14:54:17ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-iz4362238cde2d5629a32ed5166d55ec1085d0b4eb2cc0715b0eab59a0ab734967fiproto-verify: etcd_role_grant_permission vs Auth.RoleGrantPermissionAdd Lua testkit verification for etcd_role_grant_permission (mirrors gRPC Auth.RoleGrantPermission). Successful path: assert response shape matches the gRPC response message after MsgPack round-trip. Error path: at least one error case asserting {code, message} matches app/etcd/errors.lua catalog. Exercise at least one non-default option if applicable. Goes in test/iproto_parity_test.lua under group iproto/parity/auth. Call shape: local resp = etcd_role_grant_permission(req).Verification-only. Wrapper exists at app/etcd/api.lua. Epic tarantool-etcd-w8q.open3taskNULLNULL2026-05-19T14:54:15ZEugene Blikhbigbes@gmail.com2026-05-19T14:54:15ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-j1cd72af58dd67917cd0d6f45c09ebc8410746a5a5fa3ce0f2fc547a0845aa4d6da/debug/pprof/heap — pprof-shape converter on top of /debug/memprof/debug/memprof ships the raw Tarantool memprof binary trace. Open work: a pprof-shape converter — pure-Lua parser for the memprof binary, aggregate events by allocation site, emit a four-dimension perftools.profiles.Profile (alloc_objects/count, alloc_space/bytes, inuse_objects/count, inuse_space/bytes — Go heap profile shape). Implementation sketch: 1. Pure-Lua parser for the memprof binary format (header magic + tagged event stream: alloc / realloc / free / symtab). Reference is tools/memprof.lua + tools/utils/binreader.lua in upstream tarantool/tarantool (not bundled with the homebrew binary). 2. Aggregate into (stack_key → {alloc_objs, alloc_bytes, inuse_objs, inuse_bytes}) with inuse_* from correlating alloc events against later free events inside the same window. Stack keys are the (chunkname, line) chain from symtab events. 3. Encode via lib/protobuf/encoder.lua + lib/pprof/defs.lua — schema already supports multi-sample-type profiles, declare four sample_type entries. 4. New endpoint /debug/pprof/heap?seconds=N on the JSON gateway. Same shape as /debug/pprof/profile (600 s cap, 503 on memprof-unavailable). Existing /debug/memprof stays for raw-trace use cases.Known frictions: - misc.memprof.available == false on Apple Silicon (same arm64 constraint as the JIT — see reference_apple_silicon_no_jit). start() returns true but stop() says "profiler is disabled" and writes nothing. /debug/memprof already detects this and 503s; pprof-heap should do the same. Linux/x86_64 unaffected. - inuse_* is "alive at end-of-window", not "alive right now" — long-lived objects allocated before the window started never appear. Document this; Go heap profile has the same caveat. - Writing the binary parser without ground-truth output is the main risk — develop on a Linux box where memprof actually fires, validate against tools/memprof.lua textual report.1. /debug/pprof/heap?seconds=N returns valid pprof-shaped protobuf, parseable by `go tool pprof`. 2. On Apple Silicon, returns 503 with clear "memprof unavailable on arm64" message. 3. Round-trip tests in test/pprof_test.lua (same shape as the cpu profile tests).Source: docs/TODO.md "Open / Pprof-shape /debug/pprof/heap". Referenced from app/etcd/debug.lua:16, lib/pprof/memprof.lua:12.open3featureNULLNULL2026-05-19T13:34:30ZEugene Blikhbigbes@gmail.com2026-05-19T13:34:30ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-jg3a13319c39a4bdd813b6d85a5f391773719f4b5f9a43692850e00e8bb4928a25cReplica route: config block + role plumbingAdd the role config surface for replica mode and validate/apply it. New block under app.roles.etcd, e.g.: replica: enabled: false mode: mirror # mirror (read-only) | proxy (forward writes) upstream_endpoints: ['http://etcd-a:2379', ...] username: '' # optional auth to upstream password: '' tls: {...} Wire validate/apply/stop in app/roles/etcd.lua: when replica.enabled, the local store must refuse normal write registration and instead start the sync fiber (other child issues). Validate that mode is one of mirror|proxy and endpoints is non-empty. No sync logic here — just config parsing, validation, and the on/off switch the other phases hang off of.Mirrors the existing grpc/json/cmux config block validation in app/roles/etcd.lua.open2taskNULLNULL2026-05-20T06:17:54ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:36ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-kbc3b334f8edc7b7d1335eb359e0d4f364dd8acf1cbb760567eb695a1b7e940b54fConformance test: gRPC Watch on a follower replicatests/conformance/replicaset_smoke_test.go covers ReadReplicatesToFollowers (Range on each follower after a leader Put) but nothing exercises a Watch stream *pinned to a follower endpoint* while mutations happen on the leader. The Lua integration test (test/grpc_integration_test.lua:547) explicitly punts: "True replicaset behaviors (watch deliveries across nodes ...) need a real Raft cluster and live in the Go harness." Watch on a follower has its own moving parts that Range does not: - the watcher fiber lives on the follower - kv_history rows arrive via replication (relay → applier), not via the local mutation - the box.on_commit broadcast must fire on the applier path (see memory feedback_tarantool_trigger_broadcast — broadcast from on_commit, not on_replace, so the woken reader sees committed state on the follower side too) Without this test, a regression in the follower-side watch wake-up would slip through the rs3 suite.- Reuse mustDial(t, []string{followerEndpoint}) from existing rs3 tests — same dial pattern as ReadReplicatesToFollowers. - Use a short context.WithTimeout (5 s wall, 2 s wait-for-event) — replication lag on the local rs3 harness is sub-ms. - Use harness.UniqueKey(t) for key isolation. - Skip on non-rs3 backend (the single-node tarantool backend has no follower). - Mirror the synchronous "wait for created chunk" pattern jsonclient/watch already uses, even on the gRPC client — avoids the race where the Put commits before the Watch is registered.1. New test in tests/conformance/replicaset_smoke_test.go that: a. Spawns the rs3 backend, identifies leader + followers via rs.LeaderEndpoint / rs.Endpoints. b. Opens a Watch stream pinned to each follower endpoint (one subtest per follower). c. Issues a Put on the leader. d. Asserts the follower-side watcher receives the PUT event within a short deadline (≤2 s on a quiet box). e. Asserts the event header.revision matches the leader-side Put response revision. 2. Additional subtest: range watch ("/rs_smoke/watch/", "\0") on a follower receives multiple events in revision order when the leader issues several Puts. 3. Optional subtest: prev_kv populated correctly on the follower-side event when WithPrevKV is requested. 4. Suite stays green with CONFORMANCE_BACKEND=tarantool_rs3 go test -count=1 -run TestReplicasetSmoke -v.Source: gap surfaced while porting docs/TODO.md to bd on 2026-05-19. Cross-refs: tests/conformance/replicaset_smoke_test.go ReadReplicatesToFollowers (line ~160), test/grpc_integration_test.lua:547 comment about which behaviors live where, memory feedback_tarantool_trigger_broadcast.open2taskNULLNULL2026-05-19T14:11:02ZEugene Blikhbigbes@gmail.com2026-05-19T14:11:02ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-lac9b0811dbe3090da92e2f2c059b263cbef43e1721b4418917747dcf3102a20f60Phase 5e — Lease option coveragePer-option density on Lease RPCs. Canonical paths are already covered; what is missing is option coverage in the {tarantool, etcd} × {grpc, json} matrix. Smallest remaining surface — should be the warm-up before Phase 5f. Likely tests: - TestLeaseGrantWithExplicitID - TestLeaseGrantTTLBoundaries (TTL=0 / negative / very-large) - TestLeaseTimeToLiveAttachedKeys - TestLeaseRevokeRevokesAttachedKeys (each attached key disappears + watcher sees DELETE at the revoke revision) - TestLeaseKeepAliveOnceTTLZero (cross-wire — jsonclient-internal case already pinned) Sub-phases 5a-c each surfaced one Lua-side divergence — expect at least one more here.Each listed test ported, runs on all four cells, passes (or is documented as a known gap in tests/conformance/harness/gaps.go cross-referenced from docs/TODO.md).Source: docs/TODO.md "Open / Conformance matrix — Phase 5 option coverage".open2taskNULLNULL2026-05-19T13:34:01ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:36ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-lkoa9f5b3fdb1d8c955ea9817c5961cd2fd334733f9495cfcea8dc728d5d59c5badRoute writes to current master (write-forwarding on followers)Followers currently reject writes with ER_READONLY → gRPC UNAVAILABLE, and clientv3 does NOT fail over endpoints on Unavailable (see memory feedback_clientv3_error_assertions). Clients must pin to the leader, which breaks endpoint-agnostic client setups (AutoSyncInterval, DNS round-robin, k8s Service). Implement write-forwarding inside the role: when a follower receives a mutating RPC (Put / DeleteRange / Txn-with-writes / LeaseGrant / LeaseRevoke / LeaseKeepAlive / Compact / Auth* / Lock / Campaign / Resign / Proclaim), proxy it to the current Raft leader via experimental.connpool + a setuid stored Lua function (same pattern as MaintenanceMoveLeader, see project_cross_node_promote memory). Reads stay local per replicaset.read_pref (already implemented).- Reuse the connpool helper introduced for MaintenanceMoveLeader (tests/conformance/harness/tarantool_rs_server.go:475 area). - Trigger forwarding inside grpc.lua make_handler before dispatching the write — cheaper than wrapping every kv/lease/txn module. - box.info.election.leader gives the leader id; map id→advertise URL via advertise.lua (already used for MemberList clientURLs). - Streaming RPCs (Watch, LeaseKeepAlive, Election Observe) are subtler — defer or handle separately; first cut should be unary-only.1. Mutating RPC on a follower in tarantool_rs3 backend succeeds (matches the leader-equivalent response shape, including header.revision monotonicity). 2. No regression in existing rs3 conformance subtests. 3. New conformance subtest TestWriteForwardingOnFollower covers Put/Txn/LeaseGrant from a follower endpoint. 4. If the leader is unknown (election in progress), return ErrGRPCNoLeader as today.Discussed in chat 2026-05-19 as the only multi-master option that preserves etcd contract. Memory refs: project_cross_node_promote, feedback_clientv3_error_assertions.open2featureNULLNULL2026-05-19T13:33:55ZEugene Blikhbigbes@gmail.com2026-05-19T13:33:55ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-m0w1e497e0d597a35ddd55d2b06dbb53bee3d2af9ede56d5397f2267151a481b309iproto-verify: etcd_unlock vs Lock.UnlockAdd Lua testkit verification for etcd_unlock (mirrors gRPC Lock.Unlock). Successful path: assert response shape matches the gRPC response message after MsgPack round-trip. Error path: at least one error case asserting {code, message} matches app/etcd/errors.lua catalog. Exercise at least one non-default option if applicable. Goes in test/iproto_parity_test.lua under group iproto/parity/lock. Call shape: local resp = etcd_unlock(req).Verification-only. Wrapper exists at app/etcd/api.lua. Epic tarantool-etcd-w8q.open3taskNULLNULL2026-05-19T14:54:18ZEugene Blikhbigbes@gmail.com2026-05-19T14:54:18ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-m1nc9126753270e756137235fe87d06b79c038f9607c12502bc9e772f6f2ff6cf6ciproto-impl: etcd_election_leader vs Election.LeaderWrap the existing handler election.leader (already invoked by gRPC/JSON via defs.lua route v3electionpb.Election.Leader) as a Lua global etcd_election_leader callable via iproto CALL. Mechanical change in app/etcd/api.lua: add rawset(_G, 'etcd_election_leader', wrap('election', 'leader')) under the appropriate service block; append 'etcd_election_leader' to the funcs table so box.schema.func.create plus guest grant runs at role apply; document the wrapper in the module-level LDoc comment. If Election.Leader returns UNIMPLEMENTED today, the wrapper still gets added so the iproto caller observes the same UNIMPLEMENTED error gRPC would return. Election.Observe is server-streaming over gRPC; iproto has no stream primitive, so propose a polling shape (observe_create/_pull/_cancel) mirroring the Watch precedent at api.lua:81-83.etcd_election_leader is callable from net.box:call('etcd_election_leader', {req}) with no Lua error before handler dispatch. Successful request shape produces same successful response shape as gRPC. box.schema.func.create plus guest grant idempotent on role re-apply.Epic tarantool-etcd-w8q. Handler at app/etcd/election.lua.open3taskNULLNULL2026-05-19T14:54:48ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:36ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-mah9a466a5136be87beabd361f6098012ee8e2ee48bd3ccb1250ca93018108ada6fUnix socket listener for gRPC + JSON (etcd 3.7)etcd 3.7 adds Unix socket endpoints — local communication without a TCP port, aimed at development and edge devices. We bind TCP only: the role's grpc.listen / json.listen are host:port, and there is no unix path handling in app/roles/etcd.lua, app/etcd/grpc.lua, or lib/cmux.lua. For a Tarantool-embedded etcd this is more than parity: a co-located Tarantool EE instance reading its centralized config from us over a unix socket skips the loopback stack and needs no port allocated or firewalled. Scope: accept a unix:// (or unix/:) listen URI in the role config, bind an AF_UNIX socket, and confirm the cmux HTTP/2-preface peek and the PeekSock replay work unchanged over it (they should — cmux only needs a stream socket).Tarantool's socket.tcp_server has a unix-socket sibling; confirm which API the nghttp2 server layer can accept a listening socket from. Decide the socket file lifecycle: stale-file removal on bind, permissions, and unlink on role stop.Role boots with a unix listen path; grpc + JSON both serve over it; cmux multiplexes both on one unix socket; a conformance or Lua test dials it; socket file is cleaned up on stop.open3featureNULLNULL2026-07-17T11:30:46ZEugene Blikhbigbes@gmail.com2026-07-17T11:30:46ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-mo5dbe7e65616d159fdbd81f97f8b988209daa63549799f00a9436da023cecace05iproto-verify: etcd_member_list vs Cluster.MemberListAdd Lua testkit verification for etcd_member_list (mirrors gRPC etcdserverpb.Cluster.MemberList). Same test pattern as verify-only tasks: positive path plus at least one error path, response shape matches gRPC, error codes from app/etcd/errors.lua. For UNIMPLEMENTED-by-design endpoints (Cluster.MemberAdd/Remove/Update/Promote), assert the wrapper returns the canonical UNIMPLEMENTED error consistent with gRPC rather than skipping. Goes in test/iproto_parity_test.lua under group iproto/parity/cluster.Epic tarantool-etcd-w8q. Blocked on the matching impl issue.open3taskNULLNULL2026-05-19T14:54:26ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:37ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL1
tarantool-etcd-nbsd8c32e3fb95d9e7bc7827a04bdbe8af747dd5df724c8d1b56f20654f307d2157TLS support on gRPC + JSON wiresRoadmap P0 blocker. etcd clients expect TLS on the client port (and the JSON/HTTP gateway). Implement TLS termination for both the gRPC/HTTP-2 (nghttp2) listener and the JSON-over-HTTP/1.1 gateway, including cmux'd single-port mode. Scope: server cert/key config, optional client-cert auth (--client-cert-auth equivalent), wiring through the role config (grpc.tls / json.tls blocks).Roadmap-only item; no TLS issue existed in beads.open0featureNULLNULL2026-05-20T06:55:22ZEugene Blikhbigbes@gmail.com2026-05-20T06:55:22ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-ns020b6fc12f33291102415f4213204ede198952347fae1b7e670b587ba2f267a73iproto-verify: etcd_maintenance_defragment vs Maintenance.DefragmentAdd Lua testkit verification for etcd_maintenance_defragment (mirrors gRPC etcdserverpb.Maintenance.Defragment). Same test pattern as verify-only tasks: positive path plus at least one error path, response shape matches gRPC, error codes from app/etcd/errors.lua. For UNIMPLEMENTED-by-design endpoints (Cluster.MemberAdd/Remove/Update/Promote), assert the wrapper returns the canonical UNIMPLEMENTED error consistent with gRPC rather than skipping. Goes in test/iproto_parity_test.lua under group iproto/parity/maintenance.Epic tarantool-etcd-w8q. Blocked on the matching impl issue.open3taskNULLNULL2026-05-19T14:54:35ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:37ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL1
tarantool-etcd-nwl3f54509527d06071750dbdddfdcafe415133385b9549ce08b80b06cc16f9d6cfiproto-verify: etcd_user_revoke_role vs Auth.UserRevokeRoleAdd Lua testkit verification for etcd_user_revoke_role (mirrors gRPC Auth.UserRevokeRole). Successful path: assert response shape matches the gRPC response message after MsgPack round-trip. Error path: at least one error case asserting {code, message} matches app/etcd/errors.lua catalog. Exercise at least one non-default option if applicable. Goes in test/iproto_parity_test.lua under group iproto/parity/auth. Call shape: local resp = etcd_user_revoke_role(req).Verification-only. Wrapper exists at app/etcd/api.lua. Epic tarantool-etcd-w8q.open3taskNULLNULL2026-05-19T14:54:11ZEugene Blikhbigbes@gmail.com2026-05-19T14:54:11ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-ovob02eee9877621d78af7f66286e7ff63fc6564aac6beeca0cb795fe667217cb17Learner: durable applied_index (WAL-equivalent for restart)Persist enough raft state (currentTerm/HardState, applied_index, ConfState) so a restart resumes from the last applied entry instead of replaying from zero or forcing a full snapshot. Store in a dedicated space (e.g. etcd_raft_meta) written in the same transaction as each applied entry. On boot in learner mode: read last applied_index, reconnect transport, and request entries after it (or a snapshot if the leader has compacted past it). Tarantool's own WAL gives us durability of the *space writes*; this issue is specifically the raft bookkeeping that lets us re-attach to the cluster correctly.etcd stores this as raft WAL + snapshot metadata; we collapse it to a meta space since Tarantool's WAL already durably persists the applied data.open2taskNULLNULL2026-05-20T06:45:17ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:37ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL1
tarantool-etcd-ovtdb6cf24009cca490a9e5a89f705f27d73388ddfcc3513448452e373522faeeb5iproto-verify: etcd_member_remove vs Cluster.MemberRemoveAdd Lua testkit verification for etcd_member_remove (mirrors gRPC etcdserverpb.Cluster.MemberRemove). Same test pattern as verify-only tasks: positive path plus at least one error path, response shape matches gRPC, error codes from app/etcd/errors.lua. For UNIMPLEMENTED-by-design endpoints (Cluster.MemberAdd/Remove/Update/Promote), assert the wrapper returns the canonical UNIMPLEMENTED error consistent with gRPC rather than skipping. Goes in test/iproto_parity_test.lua under group iproto/parity/cluster.Epic tarantool-etcd-w8q. Blocked on the matching impl issue.open3taskNULLNULL2026-05-19T14:54:21ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:37ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL1
tarantool-etcd-ozm88152e03bc9011e822aa42ffc9212e11e04a9788bd5d40d5312f3e47da59657ciproto-verify: etcd_user_list vs Auth.UserListAdd Lua testkit verification for etcd_user_list (mirrors gRPC Auth.UserList). Successful path: assert response shape matches the gRPC response message after MsgPack round-trip. Error path: at least one error case asserting {code, message} matches app/etcd/errors.lua catalog. Exercise at least one non-default option if applicable. Goes in test/iproto_parity_test.lua under group iproto/parity/auth. Call shape: local resp = etcd_user_list(req).Verification-only. Wrapper exists at app/etcd/api.lua. Epic tarantool-etcd-w8q.open3taskNULLNULL2026-05-19T14:54:09ZEugene Blikhbigbes@gmail.com2026-05-19T14:54:09ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-p3sd7ab326ea50217052ff7528067d9bda449d1d177009210c5b6dc67df52f33a52iproto-verify: etcd_election_leader vs Election.LeaderAdd Lua testkit verification for etcd_election_leader (mirrors gRPC v3electionpb.Election.Leader). Same test pattern as verify-only tasks: positive path plus at least one error path, response shape matches gRPC, error codes from app/etcd/errors.lua. For UNIMPLEMENTED-by-design endpoints (Cluster.MemberAdd/Remove/Update/Promote), assert the wrapper returns the canonical UNIMPLEMENTED error consistent with gRPC rather than skipping. Goes in test/iproto_parity_test.lua under group iproto/parity/election.Epic tarantool-etcd-w8q. Blocked on the matching impl issue.open3taskNULLNULL2026-05-19T14:54:48ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:37ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL1
tarantool-etcd-q5f722c317df5aebe05f32f99bf226d4b916604f1518089bea768b2ed206866ecd3Learner: snapshot receive (bbolt parse + bucket translation)Handle /raft/snapshot. When we fall too far behind (or on first join), the leader ships a bbolt DB file dump, NOT raft entries. Two options: (a) parse the bbolt file and translate etcd's buckets — key (the mvcc keyspace), meta (consistent_index, scheduledCompactRev, finishedCompactRev), lease, auth/authUsers/authRoles, members/members_removed, cluster, alarm — into our etcd_* spaces; or (b) refuse snapshots and bootstrap via clientv3 Range/Watch instead, accepting that the cluster MAY force a snapshot mid-stream if we lag past its compaction window (it eventually will). Recommend (a) for a true learner. Needs a minimal bbolt page/leaf reader in Lua or via FFI. This is the phase most likely to surprise — it bypasses the raft proto entirely.bbolt format: page-based B+tree, freelist, meta pages with txid. Bucket values for mvcc keys are mvccpb.KeyValue protobufs keyed by revision{main,sub}. This is the single biggest sub-effort in the epic.open2taskNULLNULL2026-05-20T06:45:16ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:37ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL1
tarantool-etcd-rzh26beb784e16ef7c22030f27a08fe4e55b5e0453b6cd19af9df1ffd97a8bb3235iproto-impl: etcd_maintenance_status vs Maintenance.StatusWrap the existing handler maintenance.status (already invoked by gRPC/JSON via defs.lua route etcdserverpb.Maintenance.Status) as a Lua global etcd_maintenance_status callable via iproto CALL. Mechanical change in app/etcd/api.lua: add rawset(_G, 'etcd_maintenance_status', wrap('maintenance', 'status')) under the appropriate service block; append 'etcd_maintenance_status' to the funcs table so box.schema.func.create plus guest grant runs at role apply; document the wrapper in the module-level LDoc comment. If Maintenance.Status returns UNIMPLEMENTED today, the wrapper still gets added so the iproto caller observes the same UNIMPLEMENTED error gRPC would return. Election.Observe is server-streaming over gRPC; iproto has no stream primitive, so propose a polling shape (observe_create/_pull/_cancel) mirroring the Watch precedent at api.lua:81-83.etcd_maintenance_status is callable from net.box:call('etcd_maintenance_status', {req}) with no Lua error before handler dispatch. Successful request shape produces same successful response shape as gRPC. box.schema.func.create plus guest grant idempotent on role re-apply.Epic tarantool-etcd-w8q. Handler at app/etcd/maintenance.lua.open3taskNULLNULL2026-05-19T14:54:32ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:36ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-rzr3973dcbaf27d8ffaf25bdad2afcfcbfeb9e6deb07cd8ecf62c5a6446247c3468nghttp2 unary send-path rewrite — close parallel KVGet gap, drop jit.offParallel KVGet on tarantool is ~70% slower than etcd at GOMAXPROCS=6 (12 688 ops/s vs 21 900 ops/s; p95 970 µs vs 405 µs — docs/BENCH.md "Linux x86_64 — KVGet matrix, 2026-05-15"). Root cause: per-Connection IO mutex in lib/nghttp2/grpc.lua (Connection:_locked) — nghttp2 sessions are not reentrant, so every fiber's submit_response + send_all + sock:write serializes. Etcd has no such constraint. Fix: pre-build HEADERS + DATA + trailers in pure Lua, skip nghttp2's C→Lua data-source callback on the unary send path, recover ~10–20% throughput lost to jit.off + drop the JIT pin entirely.See memory project_nghttp2_send_callback_rewrite for the plan. Pre-frame DATA in Lua, avoid re-entering nghttp2 mid-send. Touch points: - lib/nghttp2/grpc.lua (Connection, _locked, send_response) - lib/nghttp2/ffi.lua (data-source callback signature) - M.recv/M.send/M.send_all/M.send_data currently pinned jit.off — un-pin once the callback re-entry is gone (memory feedback_nghttp2_session_not_reentrant explains the original panic).1. BenchmarkKVGetParallel/point closes the gap to within ~10% of etcd at GOMAXPROCS=6. 2. p95 latency under parallel load drops below 600 µs. 3. No bad-callback panics across 10 verbose runs (the regression test from commit d0fa396). 4. jit.off removed from M.recv/M.send/M.send_all/M.send_data.Sources: docs/BENCH.md "Linux x86_64" + memory notes project_nghttp2_send_callback_rewrite, feedback_nghttp2_session_not_reentrant, feedback_nghttp2_dual_connection.open2taskNULLNULL2026-05-19T13:34:42ZEugene Blikhbigbes@gmail.com2026-05-19T13:34:42ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-rzs63c2e0e3f3c883b2db5734e851457a1f568e3a1ebb871de515f13411bd7ecbd9iproto-impl: etcd_member_update vs Cluster.MemberUpdateWrap the existing handler cluster.member_update (already invoked by gRPC/JSON via defs.lua route etcdserverpb.Cluster.MemberUpdate) as a Lua global etcd_member_update callable via iproto CALL. Mechanical change in app/etcd/api.lua: add rawset(_G, 'etcd_member_update', wrap('cluster', 'member_update')) under the appropriate service block; append 'etcd_member_update' to the funcs table so box.schema.func.create plus guest grant runs at role apply; document the wrapper in the module-level LDoc comment. If Cluster.MemberUpdate returns UNIMPLEMENTED today, the wrapper still gets added so the iproto caller observes the same UNIMPLEMENTED error gRPC would return. Election.Observe is server-streaming over gRPC; iproto has no stream primitive, so propose a polling shape (observe_create/_pull/_cancel) mirroring the Watch precedent at api.lua:81-83.etcd_member_update is callable from net.box:call('etcd_member_update', {req}) with no Lua error before handler dispatch. Successful request shape produces same successful response shape as gRPC. box.schema.func.create plus guest grant idempotent on role re-apply.Epic tarantool-etcd-w8q. Handler at app/etcd/cluster.lua.open3taskNULLNULL2026-05-19T14:54:23ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:36ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-sdtce9fb24507b45a493bd9ffc4a4ab22edafe46b9e41a95b2813bb6b2016b0ccc8iproto-verify: etcd_auth_status vs Auth.AuthStatusAdd Lua testkit verification for etcd_auth_status (mirrors gRPC Auth.AuthStatus). Successful path: assert response shape matches the gRPC response message after MsgPack round-trip. Error path: at least one error case asserting {code, message} matches app/etcd/errors.lua catalog. Exercise at least one non-default option if applicable. Goes in test/iproto_parity_test.lua under group iproto/parity/auth. Call shape: local resp = etcd_auth_status(req).Verification-only. Wrapper exists at app/etcd/api.lua. Epic tarantool-etcd-w8q.open3taskNULLNULL2026-05-19T14:54:04ZEugene Blikhbigbes@gmail.com2026-05-19T14:54:04ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-sir5cc0da191ba98b3f835cc3fcdc3e3f5ed44926cb471cb6df204b16f644957871JWT auth-token mode (--auth-token=jwt) — we only have simple tokensetcd supports two auth-token modes: simple (an opaque token in a server-side table) and jwt (a signed, self-contained token the server verifies with a key, no server-side session state). etcd 3.7 leans further on JWT — 'clients may now set the JWT directly, offering more flexibility in authentication options.' We implement simple-token only: Auth.Authenticate mints an opaque token stored in the etcd_tokens space (truncated on auth disable, app/etcd/auth.lua). There is no JWT handling anywhere in app/etcd/. A client configured against a JWT-mode etcd, or one presenting a pre-issued JWT, gets rejected by us. This also matters for our own topology: simple tokens are server-local session state, so under a replicaset a token minted on one node is not honored by another unless etcd_tokens replicates and stays consistent. JWT is stateless and sidesteps that entirely. Scope: an auth.token config block selecting simple|jwt, JWT sign/verify (RS256 + HS256 at minimum) over the etcd claim set (username, revision), key material from config, and acceptance of a client-supplied JWT on both wires.Needs a JWT implementation in Lua — check what Tarantool ships (digest for HMAC/SHA, crypto for RSA) before pulling a dependency. Note digest.base64_encode MIME-wraps at 76 chars by default; JWT needs {nowrap = true} and URL-safe alphabet.Server boots in jwt mode; a token minted by Authenticate verifies on a different replicaset node without shared session state; a conformance cell runs the auth suite in jwt mode against both backends; simple mode stays the default and unchanged.open2featureNULLNULL2026-07-17T11:30:45ZEugene Blikhbigbes@gmail.com2026-07-17T11:30:45ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-sqve03dd24141b120acf0cc989ed396918ed61284c9962f1c036f30a262a51d39e6iproto-impl: etcd_election_proclaim vs Election.ProclaimWrap the existing handler election.proclaim (already invoked by gRPC/JSON via defs.lua route v3electionpb.Election.Proclaim) as a Lua global etcd_election_proclaim callable via iproto CALL. Mechanical change in app/etcd/api.lua: add rawset(_G, 'etcd_election_proclaim', wrap('election', 'proclaim')) under the appropriate service block; append 'etcd_election_proclaim' to the funcs table so box.schema.func.create plus guest grant runs at role apply; document the wrapper in the module-level LDoc comment. If Election.Proclaim returns UNIMPLEMENTED today, the wrapper still gets added so the iproto caller observes the same UNIMPLEMENTED error gRPC would return. Election.Observe is server-streaming over gRPC; iproto has no stream primitive, so propose a polling shape (observe_create/_pull/_cancel) mirroring the Watch precedent at api.lua:81-83.etcd_election_proclaim is callable from net.box:call('etcd_election_proclaim', {req}) with no Lua error before handler dispatch. Successful request shape produces same successful response shape as gRPC. box.schema.func.create plus guest grant idempotent on role re-apply.Epic tarantool-etcd-w8q. Handler at app/etcd/election.lua.open3taskNULLNULL2026-05-19T14:54:46ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:36ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-sy6ff088cd8c36175c942b8e80aa7a1bfa3bdaa64bf92a9ff46f8c736505ea0b302iproto-verify: etcd_watch_pull vs Watch.Watch-pullAdd Lua testkit verification for etcd_watch_pull (mirrors gRPC Watch.Watch-pull). Successful path: assert response shape matches the gRPC response message after MsgPack round-trip. Error path: at least one error case asserting {code, message} matches app/etcd/errors.lua catalog. Exercise at least one non-default option if applicable. Goes in test/iproto_parity_test.lua under group iproto/parity/watch. Call shape: local resp = etcd_watch_pull(req).Verification-only. Wrapper exists at app/etcd/api.lua. Epic tarantool-etcd-w8q.open3taskNULLNULL2026-05-19T14:53:57ZEugene Blikhbigbes@gmail.com2026-05-19T14:53:57ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-tf04410402a2773378d989b3453c6d566e9ab0eb85ec6a8ba9eb21801b478e96d73iproto-impl: etcd_maintenance_hash_kv vs Maintenance.HashKVWrap the existing handler maintenance.hash_kv (already invoked by gRPC/JSON via defs.lua route etcdserverpb.Maintenance.HashKV) as a Lua global etcd_maintenance_hash_kv callable via iproto CALL. Mechanical change in app/etcd/api.lua: add rawset(_G, 'etcd_maintenance_hash_kv', wrap('maintenance', 'hash_kv')) under the appropriate service block; append 'etcd_maintenance_hash_kv' to the funcs table so box.schema.func.create plus guest grant runs at role apply; document the wrapper in the module-level LDoc comment. If Maintenance.HashKV returns UNIMPLEMENTED today, the wrapper still gets added so the iproto caller observes the same UNIMPLEMENTED error gRPC would return. Election.Observe is server-streaming over gRPC; iproto has no stream primitive, so propose a polling shape (observe_create/_pull/_cancel) mirroring the Watch precedent at api.lua:81-83.etcd_maintenance_hash_kv is callable from net.box:call('etcd_maintenance_hash_kv', {req}) with no Lua error before handler dispatch. Successful request shape produces same successful response shape as gRPC. box.schema.func.create plus guest grant idempotent on role re-apply.Epic tarantool-etcd-w8q. Handler at app/etcd/maintenance.lua.open3taskNULLNULL2026-05-19T14:54:39ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:36ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-tt663510fbc9abb4568f1a181ec6515e1edededff7dbb3a0cf8e1f67e62b24c780dReplica route: lease / auth state mirroring (scope v1 vs later)KV is the v1 target; this issue scopes how non-KV state behaves in replica mode and what (if anything) v1 mirrors. Questions: - Leases: do we mirror upstream lease grants/TTLs/expiry so locally-served keys show correct lease attachment, or pass-through lease ops to upstream? At minimum the lease_id on replicated kvs must round-trip; full lease lifecycle mirroring may be later. - Auth: mirror upstream users/roles/permissions, or run replica reads unauthenticated/locally-authed? Decide whether auth is enforced on the replica or delegated. - Watch served to local clients: our Watch subsystem already reconstructs from kv_history, which the tail populates — confirm local watchers work transparently once KV sync lands. Output: a documented v1 scope (likely 'KV + lease_id round-trip only; auth+full-lease+ deferred') appended to docs/TODO.md, plus any follow-up issues.Likely mostly a scoping/decision issue that spawns concrete follow-ups; keep v1 KV-only.open2taskNULLNULL2026-05-20T06:17:57ZEugene Blikhbigbes@gmail.com2026-05-20T06:17:57ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL0
tarantool-etcd-uee9e6ca4342149c79eee16a063f881ae3eb1683b9de5774eae58d2b37bfc8bcb9bReplica route: bootstrap snapshot importOn entering replica mode, pull the full upstream keyspace once and load it into our etcd_* spaces, recording the upstream revision the snapshot was taken at (the Watch tail starts from here). Approach: a clientv3-style Range over the whole keyspace ([\\x00, \\x00) with WithRange/WithFromKey) reading at a single revision (use the header.revision from the first Range, or RangeRequest with revision pinned + paging via WithLimit + WithMinModRev/last-key continuation). Persist each kv with its create_revision/mod_revision/version/lease intact. Alternatively consume Maintenance.Snapshot if/when interop lands (tarantool-etcd-16d) — but Range is the dependency-free path for v1. Output: etcd_* spaces populated, and the 'synced through revision R' watermark persisted for the tail phase to resume from.Must preserve upstream create_revision/mod_revision/version exactly — feeds revision-alignment. Page large keyspaces to avoid one giant Range.open2taskNULLNULL2026-05-20T06:17:54ZEugene Blikhbigbes@gmail.com2026-07-17T14:27:37ZNULLNULL0NULLNULLNULL000<binary>0NULLNULLNULL0NULL1