Repository navigation
fix(client): authenticate inline publication receipts; regrade the append gates - #555
Merged
Merged
Conversation
…receipt After any failed PublishInlineArtifact request the client read the operation row and returned a succeeded row as this publication's result. It checked only the row's kind and operation id and reported the result as not replayed. Reusing an operation id for other bytes therefore returned the earlier publication's receipt as a success while the path kept the earlier body. A create-only claim refused at admission also tried to abort an operation that was never admitted and reported a NotFound abort failure. The client now observes the row once and accepts a succeeded row only when its receipt records this publication: the same target, revision, logical size and body digest, and the generation its claim implies. That receipt is returned as a replay, so an exact retry still converges after a lost response or after an owner restart, which refuses the epoch-bound identity. A receipt of other inputs leaves the server's error unchanged. A missing row means nothing was admitted, so the refusal is returned without an abort; a running row of this publication is aborted as before. The scripted transport now refuses a reused identity with other inputs, a create-only claim on an existing path and an unknown operation as the engine does, and can lose inline responses or refuse an inline replay after an epoch change. Signed-off-by: wchwawa <wch19961116@gmail.com>
…ation Since the fused and inline publication paths landed, a small append commits in one PublishInlineArtifact request and a one-batch body in the Prepare/Finish pair. The append gates still armed their faults on the stepwise requests, so the identity gate's response-loss cases waited for a request that never came and the operations gate could not quarantine. Each faulted fixture now declares the publication shape it needs and fails as a shape mismatch, not as a missed fault, when the command sends another one. Fixtures that need objects use a body past the inline bound; inline variants cover the one-request commit boundary. The identity gate's lost-admission retry follows the product contract: once cleanup proves the lost attempt cannot publish, the same logical id completes once on the current head. The gates read the pinned Holt version from Cargo.lock. Signed-off-by: wchwawa <wch19961116@gmail.com>
This was referenced Oct 21, 2026
Merged
feichai0017
pushed a commit
to feichai0017/NoKV
that referenced
this pull request
Oct 29, 2026
Bump crates/nokv and crates/nokv-python to 0.12.1, together with the workspace dependencies and the build identity test, for the inline receipt fix in NoKV-Lab#555. The wire protocol (nokv.workspace.rpc.v14) and the metadata format (System format 14) are unchanged, so 0.12.1 and 0.12.0 clients, CLIs, and owners interoperate. The Python SDK install notes use 0.12.1 and describe the 0.12 line. The LoopX Stage 2A install example still pinned the 0.11.1 wheel, which the stack script refuses next to a 0.12 owner; it now names 0.12.1. Signed-off-by: wchwawa <wch19961116@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related Issue
Relates to #551
Relates to #552
Two follow-ups to the inline publication path that #552 merged: one client
defect it introduced, and the append acceptance gates it left unable to fire
their faults.
Summary
Inline receipts are authenticated before they are returned. For a body
of at most 16 KiB, a publication that reused an operation id with other
inputs returned the original publication's receipt as a success
(
replayed: false, the first body's digest), and the second body was neverwritten. A body above the bound already failed with "publish operation id was
reused with different immutable inputs". On an inline error the client now
reads the durable operation row once:
replayed, only when the row records exactlythis publication: operation id, target, revision, size, body digest, and the
generation its claim implies;
The append gates fault the requests a publication actually sends. A
small append now commits in one
PublishInlineArtifactrequest and aone-batch body in the fused Prepare/Finish pair. The identity, operations,
and product gates still armed their faults on stepwise requests, so their
response-loss cases waited for a request that never came. Each faulted
fixture now:
rather than a missed fault when the command sends another one;
Inline variants cover the one-request commit boundary. The identity gate's
lost-admission retry now follows the product contract
(
append-product-spec.md, recovery timelines): once cleanup proves the lostattempt cannot publish, the same logical id completes once on the current
head. The gates read the pinned Holt version from
Cargo.lock.Commits:
fix(client): authenticate an inline publication before returning its receipttest(workbench): regrade the append gates for inline and fused publicationScope
path returns, and the gates that exercise it.
object-store, agent interface, or docs change is mixed in.
maintenance task this PR resolves.
without a removal condition (none added).
Change Size And Review
+835 / -117 (952 lines).
current-head pusher approved the exact current head commit. Not
applicable: under 5,000 lines.
Code Contract (Code Changes Only)
docs/development/code_contract.md: the receiptcheck is in
nokv-client/src/artifact.rs, beside the inline path.names (
InlinePublicationRow,observe_inline_publication,records_inline_publication).errors.rs(none added).(none added).
lifetime, snapshot/commit/event retention, GC epochs, and fail-closed
recovery boundaries. Not applicable: no metadata change.
Claims and Evidence
planned capabilities. Not applicable: no user-facing documentation change.
authentication or authorization (no security claims).
Validation
Command and result: with Rust 1.99.1,
cargo fmt --all -- --checkis clean,and
cargo clippy --workspace --all-targets -- -D warningspasses, as do thefeature clippy runs from
rust.yml.cargo test -p nokv-clientpasses.Four new tests fail before the fix and pass after it:
an_inline_identity_reused_for_other_inputs_is_refused_without_a_stale_receiptan_inline_publication_whose_response_was_lost_returns_its_receipt_as_a_replayan_inline_retry_refused_across_owner_epochs_recovers_its_own_receiptan_inline_create_refused_at_admission_does_not_abort_an_absent_operationA live probe of the defect on
d4ada8d441returned the first body'sreceipt for the reused id. After the fix it returns
RequestReplayMismatch, including after an owner restart.Command and result: the three append gates pass on this code against etcd
3.7.1 and the pinned RustFS image:
append_identity_recovery_gate.py --mode qualified --scenario all: 9/9PASS in 175 s.
--mode baselinestill reproduces the legacy duplicateappend.
append_operations_acceptance_gate.py: 4/4 PASS in 238 s.append_product_acceptance_gate.py --append-activity-lease-ms 1000 --scenarios <19 native cases>: 19/19 PASS, in each of 3 consecutive runs.On the same binary, the pre-change gates time out or report the cases NOT
QUALIFIED.
Not run (with reason):
legacy_wire_rejectedandlegacy_format_rejectedneed a frozen pre-stack binary (
--legacy-nokv-bin), which this host does nothave. These gates are not part of
rust.yml.Contributor Sign-off
Signed-off-bytrailer.