Skip to content

release: v0.2.0 - #267

Merged
allamiro merged 2 commits into
mainfrom
release/v0.2.0
Aug 6, 2026
Merged

release: v0.2.0#267
allamiro merged 2 commits into
mainfrom
release/v0.2.0

Conversation

@allamiro

@allamiro allamiro commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Bumps the workspace to 0.2.0. The release workflow cross-checks the tag against this value, so it must land before the tag is pushed.

What this release is

v0.1.0 shipped verified promotion as a quorum-proven floor. Everything since closes the ways that floor could be computed from unsound inputs, or acted on in ways that lost acknowledged data.

PR What it closes
#258 Replicas record which fencing epoch wrote each stretch of their log, and can be asked for it. Two replicas reporting offset 90 are no longer indistinguishable when only one holds the same record there.
#259 A diverged replica is truncated instead of stranded — bounded so it can never discard acknowledged records.
#262 Replicas are fenced and read in one round trip, and a replica that could not be fenced does not count toward the quorum. An offset now either comes from a log that has been stopped, or it does not come at all.
#263 A replica reconciles against the candidate while fenced, so it agrees before it answers. Closed #261.
#266 Committed high-water marks stop being droppable — and that mark is the bound that stops truncation from discarding acknowledged records.

Each of those closes a demonstrated path to losing or corrupting acknowledged data, and each is exercised by the live-chaos suite rather than by unit tests alone.

Release notes themselves also improved (#260): the body now carries a real changelog with linked issues and PRs instead of install boilerplate, which moved to docs/RELEASE_VERIFICATION.md.

What is NOT closed

Stating this here rather than leaving it to be discovered.

#240 stays open for the Raft §5.4.1/§5.4.2 question: whether the fence plus the acknowledged-records bound fully substitute for an election restriction, given metadata grants the lease with no log-completeness condition on the candidate. My attempt at a new-epoch marker (#265) was withdrawn — it could not be encoded (the protocol rejects zero-record replica appends) and, more importantly, it did not close the hazard I wrote it for. The full analysis is on #265 and #240.

The signed leadership-transition record is also outstanding, and wants #255's segment transfer first so it can name the segments either side of a transition.

Also here

The changelog generator learned to linkify references inside a compound trailer like (#240, closes #261) — that was leaving the single unlinked number in an otherwise fully linked changelog.

Verification

Workspace tests, clippy -D warnings, fmt clean. The generator is shellcheck-clean and its output for this range was checked against the real repository.

Once this merges: git tag -a v0.2.0 -m "v0.2.0" && git push origin v0.2.0.


Summary by cubic

Prepare the v0.2.0 release by bumping the workspace and crate versions and hardening the release-notes generator so it links issue references correctly without touching non-references. This must merge before tagging so the workflow can validate the tag.

  • Dependencies

    • Set workspace to 0.2.0 and bump all vtop-* crates to 0.2.0.
  • Bug Fixes

    • Linkify issue numbers in compound trailers and all non-closing references with BSD/GNU sed compatibility; anchor matches to standalone #N so URLs and existing links aren’t rewritten.
    • Only clean trailers when edits occurred to avoid mangling titles (e.g., stripping trailing (), fixing x, )).

Written for commit 7c5c1e0. Summary will update on new commits.

Review in cubic

Bumps the workspace to 0.2.0. The release workflow cross-checks the tag
against this value, so it has to land before the tag is pushed.

WHAT THIS RELEASE IS. v0.1.0 shipped verified promotion as a quorum-proven
floor. Everything since closes the ways that floor could be computed from
unsound inputs, or acted on in ways that lost acknowledged data:

  #258  replicas record which fencing epoch wrote each stretch of their log,
        and can be asked for it — two replicas reporting offset 90 are no
        longer indistinguishable when only one of them holds the same record
        there.
  #259  a diverged replica is truncated instead of stranded, bounded so it can
        never discard acknowledged records.
  #262  replicas are fenced and read in ONE round trip, and a replica that
        could not be fenced does not count toward the quorum — an offset now
        either comes from a log that has been stopped, or it does not come.
  #263  a replica reconciles against the candidate WHILE fenced, so it agrees
        before it answers. Closed #261, where a diverged replica acked a new
        leader's writes as duplicates and could be counted toward a quorum for
        bytes it did not hold.
  #266  committed high-water marks stop being droppable. They were sent on a
        try_send whose result was discarded, so a loaded follower silently
        stopped learning what had been acknowledged — and that mark is the
        bound that stops truncation from discarding acknowledged records.

Also improves the release notes themselves (#260): the body carries a real
changelog with linked issues and pull requests instead of install boilerplate,
which now lives in docs/RELEASE_VERIFICATION.md.

WHAT IS NOT CLOSED, stated plainly rather than left to be discovered. #240
remains open for the Raft §5.4.1/§5.4.2 question: whether the fence plus the
acknowledged-records bound fully substitute for an election restriction, given
metadata grants the lease with no log-completeness condition on the candidate.
An attempt at a new-epoch marker (#265) was withdrawn — it could not be
encoded, and it did not close the hazard it was written for. The signed
leadership-transition record is also outstanding, and wants #255's segment
transfer first so it can name the segments either side of a transition.

The changelog generator also learned to linkify references inside a compound
trailer like "(#240, closes #261)", which was leaving the one unlinked number
in an otherwise fully linked changelog.
@cursor

cursor Bot commented Aug 6, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All reported issues were addressed across 3 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread scripts/release-notes.sh Outdated
Comment thread scripts/release-notes.sh Outdated
…eferences

Two review findings, both real.

THE LINKIFIER MATCHED ANY `#digits`. Widening it from `(#N)` to a bare `#N` —
so a compound trailer like "(#240, closes #261)" would link — also made it
rewrite the fragment in a URL (`.../page#123`) and nest a link inside one a
title already carried. Now anchored to a standalone reference: start of line,
a space, or an opening paren before the `#`. Two sed passes rather than a BRE
alternation, which is a GNU extension BSD sed does not accept.

THE TRAILER TIDY RAN UNCONDITIONALLY. `s/ *()$//` and friends exist to clean
up a trailer this code just edited, but they were applied to every subject —
so a title ending in `foo()` became `foo`, and one containing `x, )` became
`x)`. Now gated on whether a strip actually happened.

Both verified against the cases they describe rather than reasoned about: a
URL fragment, a pre-existing markdown link, a standalone reference, and one at
line start. Real output for the v0.1.0..HEAD range is unchanged.
@allamiro

allamiro commented Aug 6, 2026

Copy link
Copy Markdown
Owner Author

Both fixed in 7c5c1e0, and both were real.

The linkifier matched any #digits

Correct. I widened it from (#N) to a bare #N so a compound trailer like (#240, closes #261) would link, and did not think about what else that now matched. A URL fragment (.../page#123) got rewritten mid-URL, and a title already carrying a markdown link got a nested one.

Anchored to a standalone reference now — start of line, a space, or an opening paren before the #. Two sed passes rather than a BRE alternation, since \| is a GNU extension and this has to behave the same under BSD sed when run locally.

The trailer tidy ran unconditionally

Also correct, and I checked it rather than taking it on faith:

$ printf 'a title ending in foo()\na title with x, ) inside\n' | sed 's/ *()$//; s/(, /(/; s/, )/)/'
a title ending in foo
a title with x) inside

Both mangled, exactly as described. Those substitutions exist to clean up a trailer this code has just edited, so they are now gated on whether a strip actually happened.

Verification

Checked against the cases rather than reasoned about:

input output
fix docs at https://example.com/page#123 now unchanged
see [#5](https://x/5) for context unchanged
relates to #240 and (#255) both linked
#77 was the cause linked

Real output for the v0.1.0..HEAD range is identical to before the fix, so this is a robustness change rather than a behaviour one for this release. shellcheck clean.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

2 issues found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="scripts/release-notes.sh">

<violation number="1" location="scripts/release-notes.sh:106">
P2: A title can still be corrupted when it both closes an issue and contains ordinary `(, ` or `, )` text: stripping the closing trailer makes `trailer_edited=1`, then the unanchored tidy substitutions rewrite the rest of the title. Scope these substitutions to the edited trailing trailer so cleanup cannot alter unrelated subject text.</violation>

<violation number="2" location="scripts/release-notes.sh:121">
P2: Titles containing an existing Markdown link whose label includes an issue reference are rendered with nested links because the space/parenthesis anchor still matches inside the label; protect existing Markdown links or otherwise skip references inside link spans before linkifying.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread scripts/release-notes.sh
# `foo()`, or containing a trailing-comma expression — for a cleanup
# that had nothing to do with them.
if [ "$trailer_edited" = 1 ]; then
subject=$(printf '%s' "$subject" | sed 's/ *()$//; s/(, /(/; s/, )/)/')

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: A title can still be corrupted when it both closes an issue and contains ordinary (, or , ) text: stripping the closing trailer makes trailer_edited=1, then the unanchored tidy substitutions rewrite the rest of the title. Scope these substitutions to the edited trailing trailer so cleanup cannot alter unrelated subject text.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/release-notes.sh, line 106:

<comment>A title can still be corrupted when it both closes an issue and contains ordinary `(, ` or `, )` text: stripping the closing trailer makes `trailer_edited=1`, then the unanchored tidy substitutions rewrite the rest of the title. Scope these substitutions to the edited trailing trailer so cleanup cannot alter unrelated subject text.</comment>

<file context>
@@ -81,30 +81,45 @@ for number in $pulls; do
+        # `foo()`, or containing a trailing-comma expression — for a cleanup
+        # that had nothing to do with them.
+        if [ "$trailer_edited" = 1 ]; then
+            subject=$(printf '%s' "$subject" | sed 's/ *()$//; s/(, /(/; s/, )/)/')
+        fi
     fi
</file context>

Comment thread scripts/release-notes.sh
url="https://github.com/${repo}/issues"
subject=$(printf '%s' "$subject" |
sed "s|(#\([0-9][0-9]*\))|([#\1](https://github.com/${repo}/issues/\1))|g")
sed "s|\([ (]\)#\([0-9][0-9]*\)|\1[#\2](${url}/\2)|g" |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Titles containing an existing Markdown link whose label includes an issue reference are rendered with nested links because the space/parenthesis anchor still matches inside the label; protect existing Markdown links or otherwise skip references inside link spans before linkifying.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/release-notes.sh, line 121:

<comment>Titles containing an existing Markdown link whose label includes an issue reference are rendered with nested links because the space/parenthesis anchor still matches inside the label; protect existing Markdown links or otherwise skip references inside link spans before linkifying.</comment>

<file context>
@@ -81,30 +81,45 @@ for number in $pulls; do
+    url="https://github.com/${repo}/issues"
     subject=$(printf '%s' "$subject" |
-        sed "s|#\([0-9][0-9]*\)|[#\1](https://github.com/${repo}/issues/\1)|g")
+        sed "s|\([ (]\)#\([0-9][0-9]*\)|\1[#\2](${url}/\2)|g" |
+        sed "s|^#\([0-9][0-9]*\)|[#\1](${url}/\1)|")
 
</file context>

@allamiro
allamiro merged commit 3242360 into main Aug 6, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

broker: a diverged replica ACKs the new leader's writes as duplicates

1 participant