Bolt quote improvements - #9044

Merged
rustyrussell merged 21 commits into
ElementsProject:masterfrom
rustyrussell:bolt-quote-improvements
Apr 30, 2026
Merged

Bolt quote improvements#9044
rustyrussell merged 21 commits into
ElementsProject:masterfrom
rustyrussell:bolt-quote-improvements

Conversation

@rustyrussell

@rustyrussellrustyrussell commented Apr 10, 2026

Copy link
Copy Markdown
Collaborator

One incredibly valuable thing about Core Lightning is we include, and enforce BOLT checks. This PR takes it to the next level:

  1. Improve our tooling, so we can cover Rust, C and Python files, and get stricter with enforcement:
    1. ... at the beginning means "follows the previous quote"
    2. ... elsewhere means "skip something, but now won't skip over sections.
    3. Any comment starting with BOLT causes a complaint, ensuring we catch typos.
  2. Fix up our tests and other files we now cover, to make them up-to-date.
  3. Add make check-requirements-coverage to show what Requirement sections we don't quote
  4. Include the bulk of them, including writing some new code where we were missing minor things

Greater coverage puts us in a much stronger position when we update to the latest BOLT version at the beginning of a release cycle.

Changelog-None: Users will never see it. Their loss!

@rustyrussellrustyrussell added this to the 26.06 milestone Apr 10, 2026
@rustyrussell
rustyrussellforce-pushed the bolt-quote-improvements branch 4 times, most recently from 24ab569 to 3d50f97CompareApril 13, 2026 04:37
@ddustin

Copy link
Copy Markdown
Collaborator

I think I've seen this CI error before, some kind of flake around askrene?

**BROKEN** plugin-cln-xpay: askrene-age failed with {"code":-32601,"message":"Unknown command 'askrene-age'"}

@ddustin

Copy link
Copy Markdown
Collaborator

Pretty cool what Claude can do. Managing BOLT reference is apropos for a large language model 🫡

Update BOLT quotes in test and library Python files to match current BOLT
text: punctuation (periods to semicolons), capitalization (Lightning on
Bitcoin mainnet), fix field ordering in invoice breakdowns, add ... to skip
features fields and SHA256 hex details, correct backtick-quoting of field
names, and remove incorrect BOLT #7 label from a plain comment.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…ker.
We're going to get stricter, so "/* BOLT #N to-local output */" or "/* BOLT11 ... */"
will upset it.
Also remove a stray bare blank line in a BOLT comment block.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…_final_cltv_expiry_delta.
The BOLT #7 was updated to use the new default 18 as min_final_cltv_expiry_delta, so
update our quote and test, and fix other textual spec changes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Some of these are malformed (thus were unchecked!), some are from the
stricter interpretation of `...` which won't cross section boundaries.
Several BOLT quotes had drifted from the current spec text:
- connectd/queries.c: BOLT #7 uses 'full_information' not 'complete';
remove a second quote that referenced query_channel_range but was
actually wrong (that requirement is for query_short_channel_ids).
- lightningd/dual_open_control.c: channel reserve is 1% rounded down
(not just 1%); witness weight check now says SHOULD broadcast rather
than MUST fail; RBF quotes simplified to match actual BOLT wording.
- openingd/openingd.c: 'The sending node' became 'The sender';
invalid signature response now says MUST send warning/error not just
MUST fail the channel.
- openingd/dualopend.c: same invalid-signature quote as openingd.c.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mose of these are from the stricter `...` which won't cross section
boundaries. The listoffers_done doesn't actually need the ellipsis at
all.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Textual updates: the tests are actually correct. The invoice.c change
is to cross a section boundary.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
The Python tool (copied from lnprototest) handles multiple comment styles.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Splits BOLT files into per-section chunks so wildcards can't inadvertently
cross section headers, supports `...`-at-start semantics, and adds make-style `-k`
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…ics.
The new check_quotes.py tool will treat `...` at the start of a quote as
"immediately follows previous quote in BOLT text". To prepare for that,
we change existing quotes which used leading `...` to mean "skip some
text": split them into two consecutive BOLT comments (the second starting
with `...` to use the existing wildcard match), and add explicit `*...`
markers between consecutive BOLT test vector sections which cross `# From`
headers.
Also remove leading `...` from nonce quotes in cryptomsg.c/handshake.c
where the actual BOLT text starts a fresh sentence (no prior quote in file).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
sCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
….py, check Rust and Python too
Extend check-source-bolt to also check Python and Rust source files.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
check_quotes.py gains --coverage=FILE: on each successful match, atomically
appends one line '{bolt} {section_idx} {start} {end}' to FILE using a single
os.write() call so parallel make invocations don't interleave records.
find_quote() and find_quote_immediate() are updated to return match start
positions (needed to record the covered range, not just the end).
bolt-coverage.py reads the coverage file and reports BOLT text not covered
by any source comment. By default it restricts output to Requirements
sections; --all-sections shows every section. --bolt N restricts to
a single BOLT number.
Exit status is 0 if everything in the selected sections is covered, 1 if
anything is uncovered.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prints out a report of uncovered Requirements sections of the BOLTs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Claude messed up about half of these: putting them too far from the
appropriate code. After this I did it myself.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: use BOLT4's paranoid advice about doing constant-time error decryption.
…hannels.
We can decide to send an HTLC down a preferred channel which leads to the same peer
as the one they asked for, but the spec is clear that you shouldn't send the "wrong"
channel_update in that case.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: when we send errors, we won't include a `channel_update` if we chose a different channel than the one they told us to.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
BOLT 7 says this, but we don't do it. (Actually, it only says that for certain types,
but I've fixed that in lightning/bolts#1331).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
… other chains.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: `gossipd` will now silently ignore gossip for other chains (rather than sending warnings).
This is what was merged in the spec, so update our checks (and bolt quote).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
@rustyrussell
rustyrussellforce-pushed the bolt-quote-improvements branch from 3d50f97 to 28ab45fCompareApril 30, 2026 00:44
@rustyrussell

Copy link
Copy Markdown
CollaboratorAuthor

Pretty cool what Claude can do. Managing BOLT reference is apropos for a large language model 🫡

Actually, when I asked it to place the missing quotes, it was TERRIBLE. I mean, it placed them, but not next to the code which actually did the thing. Mainly because doing it right would require reading a LOT of code?

@rustyrussell
rustyrussell enabled auto-merge (rebase) April 30, 2026 01:43
@rustyrussellrustyrussell mentioned this pull request Apr 30, 2026
@rustyrussell
rustyrussell merged commit e5c7374 into ElementsProject:masterApr 30, 2026
85 of 87 checks passed
@nGolinenGoline mentioned this pull request May 4, 2026
5 tasks
Sign up for freeto 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.

2 participants

@rustyrussell@ddustin
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Bolt quote improvements - #9044

Merged
rustyrussell merged 21 commits into
ElementsProject:masterfrom
rustyrussell:bolt-quote-improvements
Apr 30, 2026
Merged

Bolt quote improvements#9044
rustyrussell merged 21 commits into
ElementsProject:masterfrom
rustyrussell:bolt-quote-improvements

Conversation

@rustyrussell

@rustyrussellrustyrussell commented Apr 10, 2026

Copy link
Copy Markdown
Collaborator

One incredibly valuable thing about Core Lightning is we include, and enforce BOLT checks. This PR takes it to the next level:

  1. Improve our tooling, so we can cover Rust, C and Python files, and get stricter with enforcement:
    1. ... at the beginning means "follows the previous quote"
    2. ... elsewhere means "skip something, but now won't skip over sections.
    3. Any comment starting with BOLT causes a complaint, ensuring we catch typos.
  2. Fix up our tests and other files we now cover, to make them up-to-date.
  3. Add make check-requirements-coverage to show what Requirement sections we don't quote
  4. Include the bulk of them, including writing some new code where we were missing minor things

Greater coverage puts us in a much stronger position when we update to the latest BOLT version at the beginning of a release cycle.

Changelog-None: Users will never see it. Their loss!

@rustyrussellrustyrussell added this to the 26.06 milestone Apr 10, 2026
@rustyrussell
rustyrussellforce-pushed the bolt-quote-improvements branch 4 times, most recently from 24ab569 to 3d50f97CompareApril 13, 2026 04:37
@ddustin

Copy link
Copy Markdown
Collaborator

I think I've seen this CI error before, some kind of flake around askrene?

**BROKEN** plugin-cln-xpay: askrene-age failed with {"code":-32601,"message":"Unknown command 'askrene-age'"}

@ddustin

Copy link
Copy Markdown
Collaborator

Pretty cool what Claude can do. Managing BOLT reference is apropos for a large language model 🫡

Update BOLT quotes in test and library Python files to match current BOLT
text: punctuation (periods to semicolons), capitalization (Lightning on
Bitcoin mainnet), fix field ordering in invoice breakdowns, add ... to skip
features fields and SHA256 hex details, correct backtick-quoting of field
names, and remove incorrect BOLT #7 label from a plain comment.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…ker.
We're going to get stricter, so "/* BOLT #N to-local output */" or "/* BOLT11 ... */"
will upset it.
Also remove a stray bare blank line in a BOLT comment block.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…_final_cltv_expiry_delta.
The BOLT #7 was updated to use the new default 18 as min_final_cltv_expiry_delta, so
update our quote and test, and fix other textual spec changes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Some of these are malformed (thus were unchecked!), some are from the
stricter interpretation of `...` which won't cross section boundaries.
Several BOLT quotes had drifted from the current spec text:
- connectd/queries.c: BOLT #7 uses 'full_information' not 'complete';
remove a second quote that referenced query_channel_range but was
actually wrong (that requirement is for query_short_channel_ids).
- lightningd/dual_open_control.c: channel reserve is 1% rounded down
(not just 1%); witness weight check now says SHOULD broadcast rather
than MUST fail; RBF quotes simplified to match actual BOLT wording.
- openingd/openingd.c: 'The sending node' became 'The sender';
invalid signature response now says MUST send warning/error not just
MUST fail the channel.
- openingd/dualopend.c: same invalid-signature quote as openingd.c.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mose of these are from the stricter `...` which won't cross section
boundaries. The listoffers_done doesn't actually need the ellipsis at
all.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Textual updates: the tests are actually correct. The invoice.c change
is to cross a section boundary.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
The Python tool (copied from lnprototest) handles multiple comment styles.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Splits BOLT files into per-section chunks so wildcards can't inadvertently
cross section headers, supports `...`-at-start semantics, and adds make-style `-k`
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…ics.
The new check_quotes.py tool will treat `...` at the start of a quote as
"immediately follows previous quote in BOLT text". To prepare for that,
we change existing quotes which used leading `...` to mean "skip some
text": split them into two consecutive BOLT comments (the second starting
with `...` to use the existing wildcard match), and add explicit `*...`
markers between consecutive BOLT test vector sections which cross `# From`
headers.
Also remove leading `...` from nonce quotes in cryptomsg.c/handshake.c
where the actual BOLT text starts a fresh sentence (no prior quote in file).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
sCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
….py, check Rust and Python too
Extend check-source-bolt to also check Python and Rust source files.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
check_quotes.py gains --coverage=FILE: on each successful match, atomically
appends one line '{bolt} {section_idx} {start} {end}' to FILE using a single
os.write() call so parallel make invocations don't interleave records.
find_quote() and find_quote_immediate() are updated to return match start
positions (needed to record the covered range, not just the end).
bolt-coverage.py reads the coverage file and reports BOLT text not covered
by any source comment. By default it restricts output to Requirements
sections; --all-sections shows every section. --bolt N restricts to
a single BOLT number.
Exit status is 0 if everything in the selected sections is covered, 1 if
anything is uncovered.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prints out a report of uncovered Requirements sections of the BOLTs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Claude messed up about half of these: putting them too far from the
appropriate code. After this I did it myself.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: use BOLT4's paranoid advice about doing constant-time error decryption.
…hannels.
We can decide to send an HTLC down a preferred channel which leads to the same peer
as the one they asked for, but the spec is clear that you shouldn't send the "wrong"
channel_update in that case.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: when we send errors, we won't include a `channel_update` if we chose a different channel than the one they told us to.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
BOLT 7 says this, but we don't do it. (Actually, it only says that for certain types,
but I've fixed that in lightning/bolts#1331).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
… other chains.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: `gossipd` will now silently ignore gossip for other chains (rather than sending warnings).
This is what was merged in the spec, so update our checks (and bolt quote).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
@rustyrussell
rustyrussellforce-pushed the bolt-quote-improvements branch from 3d50f97 to 28ab45fCompareApril 30, 2026 00:44
@rustyrussell

Copy link
Copy Markdown
CollaboratorAuthor

Pretty cool what Claude can do. Managing BOLT reference is apropos for a large language model 🫡

Actually, when I asked it to place the missing quotes, it was TERRIBLE. I mean, it placed them, but not next to the code which actually did the thing. Mainly because doing it right would require reading a LOT of code?

@rustyrussell
rustyrussell enabled auto-merge (rebase) April 30, 2026 01:43
@rustyrussellrustyrussell mentioned this pull request Apr 30, 2026
@rustyrussell
rustyrussell merged commit e5c7374 into ElementsProject:masterApr 30, 2026
85 of 87 checks passed
@nGolinenGoline mentioned this pull request May 4, 2026
5 tasks
Sign up for freeto 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.

2 participants

@rustyrussell@ddustin
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Bolt quote improvements - #9044

Merged
rustyrussell merged 21 commits into
ElementsProject:masterfrom
rustyrussell:bolt-quote-improvements
Apr 30, 2026
Merged

Bolt quote improvements#9044
rustyrussell merged 21 commits into
ElementsProject:masterfrom
rustyrussell:bolt-quote-improvements

Conversation

@rustyrussell

@rustyrussellrustyrussell commented Apr 10, 2026

Copy link
Copy Markdown
Collaborator

One incredibly valuable thing about Core Lightning is we include, and enforce BOLT checks. This PR takes it to the next level:

  1. Improve our tooling, so we can cover Rust, C and Python files, and get stricter with enforcement:
    1. ... at the beginning means "follows the previous quote"
    2. ... elsewhere means "skip something, but now won't skip over sections.
    3. Any comment starting with BOLT causes a complaint, ensuring we catch typos.
  2. Fix up our tests and other files we now cover, to make them up-to-date.
  3. Add make check-requirements-coverage to show what Requirement sections we don't quote
  4. Include the bulk of them, including writing some new code where we were missing minor things

Greater coverage puts us in a much stronger position when we update to the latest BOLT version at the beginning of a release cycle.

Changelog-None: Users will never see it. Their loss!

@rustyrussellrustyrussell added this to the 26.06 milestone Apr 10, 2026
@rustyrussell
rustyrussellforce-pushed the bolt-quote-improvements branch 4 times, most recently from 24ab569 to 3d50f97CompareApril 13, 2026 04:37
@ddustin

Copy link
Copy Markdown
Collaborator

I think I've seen this CI error before, some kind of flake around askrene?

**BROKEN** plugin-cln-xpay: askrene-age failed with {"code":-32601,"message":"Unknown command 'askrene-age'"}

@ddustin

Copy link
Copy Markdown
Collaborator

Pretty cool what Claude can do. Managing BOLT reference is apropos for a large language model 🫡

Update BOLT quotes in test and library Python files to match current BOLT
text: punctuation (periods to semicolons), capitalization (Lightning on
Bitcoin mainnet), fix field ordering in invoice breakdowns, add ... to skip
features fields and SHA256 hex details, correct backtick-quoting of field
names, and remove incorrect BOLT #7 label from a plain comment.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…ker.
We're going to get stricter, so "/* BOLT #N to-local output */" or "/* BOLT11 ... */"
will upset it.
Also remove a stray bare blank line in a BOLT comment block.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…_final_cltv_expiry_delta.
The BOLT #7 was updated to use the new default 18 as min_final_cltv_expiry_delta, so
update our quote and test, and fix other textual spec changes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Some of these are malformed (thus were unchecked!), some are from the
stricter interpretation of `...` which won't cross section boundaries.
Several BOLT quotes had drifted from the current spec text:
- connectd/queries.c: BOLT #7 uses 'full_information' not 'complete';
remove a second quote that referenced query_channel_range but was
actually wrong (that requirement is for query_short_channel_ids).
- lightningd/dual_open_control.c: channel reserve is 1% rounded down
(not just 1%); witness weight check now says SHOULD broadcast rather
than MUST fail; RBF quotes simplified to match actual BOLT wording.
- openingd/openingd.c: 'The sending node' became 'The sender';
invalid signature response now says MUST send warning/error not just
MUST fail the channel.
- openingd/dualopend.c: same invalid-signature quote as openingd.c.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mose of these are from the stricter `...` which won't cross section
boundaries. The listoffers_done doesn't actually need the ellipsis at
all.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Textual updates: the tests are actually correct. The invoice.c change
is to cross a section boundary.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
The Python tool (copied from lnprototest) handles multiple comment styles.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Splits BOLT files into per-section chunks so wildcards can't inadvertently
cross section headers, supports `...`-at-start semantics, and adds make-style `-k`
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…ics.
The new check_quotes.py tool will treat `...` at the start of a quote as
"immediately follows previous quote in BOLT text". To prepare for that,
we change existing quotes which used leading `...` to mean "skip some
text": split them into two consecutive BOLT comments (the second starting
with `...` to use the existing wildcard match), and add explicit `*...`
markers between consecutive BOLT test vector sections which cross `# From`
headers.
Also remove leading `...` from nonce quotes in cryptomsg.c/handshake.c
where the actual BOLT text starts a fresh sentence (no prior quote in file).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
sCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
….py, check Rust and Python too
Extend check-source-bolt to also check Python and Rust source files.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
check_quotes.py gains --coverage=FILE: on each successful match, atomically
appends one line '{bolt} {section_idx} {start} {end}' to FILE using a single
os.write() call so parallel make invocations don't interleave records.
find_quote() and find_quote_immediate() are updated to return match start
positions (needed to record the covered range, not just the end).
bolt-coverage.py reads the coverage file and reports BOLT text not covered
by any source comment. By default it restricts output to Requirements
sections; --all-sections shows every section. --bolt N restricts to
a single BOLT number.
Exit status is 0 if everything in the selected sections is covered, 1 if
anything is uncovered.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prints out a report of uncovered Requirements sections of the BOLTs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Claude messed up about half of these: putting them too far from the
appropriate code. After this I did it myself.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: use BOLT4's paranoid advice about doing constant-time error decryption.
…hannels.
We can decide to send an HTLC down a preferred channel which leads to the same peer
as the one they asked for, but the spec is clear that you shouldn't send the "wrong"
channel_update in that case.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: when we send errors, we won't include a `channel_update` if we chose a different channel than the one they told us to.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
BOLT 7 says this, but we don't do it. (Actually, it only says that for certain types,
but I've fixed that in lightning/bolts#1331).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
… other chains.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: `gossipd` will now silently ignore gossip for other chains (rather than sending warnings).
This is what was merged in the spec, so update our checks (and bolt quote).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
@rustyrussell
rustyrussellforce-pushed the bolt-quote-improvements branch from 3d50f97 to 28ab45fCompareApril 30, 2026 00:44
@rustyrussell

Copy link
Copy Markdown
CollaboratorAuthor

Pretty cool what Claude can do. Managing BOLT reference is apropos for a large language model 🫡

Actually, when I asked it to place the missing quotes, it was TERRIBLE. I mean, it placed them, but not next to the code which actually did the thing. Mainly because doing it right would require reading a LOT of code?

@rustyrussell
rustyrussell enabled auto-merge (rebase) April 30, 2026 01:43
@rustyrussellrustyrussell mentioned this pull request Apr 30, 2026
@rustyrussell
rustyrussell merged commit e5c7374 into ElementsProject:masterApr 30, 2026
85 of 87 checks passed
@nGolinenGoline mentioned this pull request May 4, 2026
5 tasks
Sign up for freeto 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.

2 participants

@rustyrussell@ddustin
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Bolt quote improvements - #9044

Merged
rustyrussell merged 21 commits into
ElementsProject:masterfrom
rustyrussell:bolt-quote-improvements
Apr 30, 2026
Merged

Bolt quote improvements#9044
rustyrussell merged 21 commits into
ElementsProject:masterfrom
rustyrussell:bolt-quote-improvements

Conversation

@rustyrussell

@rustyrussellrustyrussell commented Apr 10, 2026

Copy link
Copy Markdown
Collaborator

One incredibly valuable thing about Core Lightning is we include, and enforce BOLT checks. This PR takes it to the next level:

  1. Improve our tooling, so we can cover Rust, C and Python files, and get stricter with enforcement:
    1. ... at the beginning means "follows the previous quote"
    2. ... elsewhere means "skip something, but now won't skip over sections.
    3. Any comment starting with BOLT causes a complaint, ensuring we catch typos.
  2. Fix up our tests and other files we now cover, to make them up-to-date.
  3. Add make check-requirements-coverage to show what Requirement sections we don't quote
  4. Include the bulk of them, including writing some new code where we were missing minor things

Greater coverage puts us in a much stronger position when we update to the latest BOLT version at the beginning of a release cycle.

Changelog-None: Users will never see it. Their loss!

@rustyrussellrustyrussell added this to the 26.06 milestone Apr 10, 2026
@rustyrussell
rustyrussellforce-pushed the bolt-quote-improvements branch 4 times, most recently from 24ab569 to 3d50f97CompareApril 13, 2026 04:37
@ddustin

Copy link
Copy Markdown
Collaborator

I think I've seen this CI error before, some kind of flake around askrene?

**BROKEN** plugin-cln-xpay: askrene-age failed with {"code":-32601,"message":"Unknown command 'askrene-age'"}

@ddustin

Copy link
Copy Markdown
Collaborator

Pretty cool what Claude can do. Managing BOLT reference is apropos for a large language model 🫡

Update BOLT quotes in test and library Python files to match current BOLT
text: punctuation (periods to semicolons), capitalization (Lightning on
Bitcoin mainnet), fix field ordering in invoice breakdowns, add ... to skip
features fields and SHA256 hex details, correct backtick-quoting of field
names, and remove incorrect BOLT #7 label from a plain comment.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…ker.
We're going to get stricter, so "/* BOLT #N to-local output */" or "/* BOLT11 ... */"
will upset it.
Also remove a stray bare blank line in a BOLT comment block.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…_final_cltv_expiry_delta.
The BOLT #7 was updated to use the new default 18 as min_final_cltv_expiry_delta, so
update our quote and test, and fix other textual spec changes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Some of these are malformed (thus were unchecked!), some are from the
stricter interpretation of `...` which won't cross section boundaries.
Several BOLT quotes had drifted from the current spec text:
- connectd/queries.c: BOLT #7 uses 'full_information' not 'complete';
remove a second quote that referenced query_channel_range but was
actually wrong (that requirement is for query_short_channel_ids).
- lightningd/dual_open_control.c: channel reserve is 1% rounded down
(not just 1%); witness weight check now says SHOULD broadcast rather
than MUST fail; RBF quotes simplified to match actual BOLT wording.
- openingd/openingd.c: 'The sending node' became 'The sender';
invalid signature response now says MUST send warning/error not just
MUST fail the channel.
- openingd/dualopend.c: same invalid-signature quote as openingd.c.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mose of these are from the stricter `...` which won't cross section
boundaries. The listoffers_done doesn't actually need the ellipsis at
all.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Textual updates: the tests are actually correct. The invoice.c change
is to cross a section boundary.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
The Python tool (copied from lnprototest) handles multiple comment styles.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Splits BOLT files into per-section chunks so wildcards can't inadvertently
cross section headers, supports `...`-at-start semantics, and adds make-style `-k`
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…ics.
The new check_quotes.py tool will treat `...` at the start of a quote as
"immediately follows previous quote in BOLT text". To prepare for that,
we change existing quotes which used leading `...` to mean "skip some
text": split them into two consecutive BOLT comments (the second starting
with `...` to use the existing wildcard match), and add explicit `*...`
markers between consecutive BOLT test vector sections which cross `# From`
headers.
Also remove leading `...` from nonce quotes in cryptomsg.c/handshake.c
where the actual BOLT text starts a fresh sentence (no prior quote in file).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
sCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
….py, check Rust and Python too
Extend check-source-bolt to also check Python and Rust source files.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
check_quotes.py gains --coverage=FILE: on each successful match, atomically
appends one line '{bolt} {section_idx} {start} {end}' to FILE using a single
os.write() call so parallel make invocations don't interleave records.
find_quote() and find_quote_immediate() are updated to return match start
positions (needed to record the covered range, not just the end).
bolt-coverage.py reads the coverage file and reports BOLT text not covered
by any source comment. By default it restricts output to Requirements
sections; --all-sections shows every section. --bolt N restricts to
a single BOLT number.
Exit status is 0 if everything in the selected sections is covered, 1 if
anything is uncovered.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prints out a report of uncovered Requirements sections of the BOLTs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Claude messed up about half of these: putting them too far from the
appropriate code. After this I did it myself.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: use BOLT4's paranoid advice about doing constant-time error decryption.
…hannels.
We can decide to send an HTLC down a preferred channel which leads to the same peer
as the one they asked for, but the spec is clear that you shouldn't send the "wrong"
channel_update in that case.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: when we send errors, we won't include a `channel_update` if we chose a different channel than the one they told us to.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
BOLT 7 says this, but we don't do it. (Actually, it only says that for certain types,
but I've fixed that in lightning/bolts#1331).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
… other chains.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: `gossipd` will now silently ignore gossip for other chains (rather than sending warnings).
This is what was merged in the spec, so update our checks (and bolt quote).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
@rustyrussell
rustyrussellforce-pushed the bolt-quote-improvements branch from 3d50f97 to 28ab45fCompareApril 30, 2026 00:44
@rustyrussell

Copy link
Copy Markdown
CollaboratorAuthor

Pretty cool what Claude can do. Managing BOLT reference is apropos for a large language model 🫡

Actually, when I asked it to place the missing quotes, it was TERRIBLE. I mean, it placed them, but not next to the code which actually did the thing. Mainly because doing it right would require reading a LOT of code?

@rustyrussell
rustyrussell enabled auto-merge (rebase) April 30, 2026 01:43
@rustyrussellrustyrussell mentioned this pull request Apr 30, 2026
@rustyrussell
rustyrussell merged commit e5c7374 into ElementsProject:masterApr 30, 2026
85 of 87 checks passed
@nGolinenGoline mentioned this pull request May 4, 2026
5 tasks
Sign up for freeto 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.

2 participants

@rustyrussell@ddustin
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Bolt quote improvements - #9044

Merged
rustyrussell merged 21 commits into
ElementsProject:masterfrom
rustyrussell:bolt-quote-improvements
Apr 30, 2026
Merged

Bolt quote improvements#9044
rustyrussell merged 21 commits into
ElementsProject:masterfrom
rustyrussell:bolt-quote-improvements

Conversation

@rustyrussell

@rustyrussellrustyrussell commented Apr 10, 2026

Copy link
Copy Markdown
Collaborator

One incredibly valuable thing about Core Lightning is we include, and enforce BOLT checks. This PR takes it to the next level:

  1. Improve our tooling, so we can cover Rust, C and Python files, and get stricter with enforcement:
    1. ... at the beginning means "follows the previous quote"
    2. ... elsewhere means "skip something, but now won't skip over sections.
    3. Any comment starting with BOLT causes a complaint, ensuring we catch typos.
  2. Fix up our tests and other files we now cover, to make them up-to-date.
  3. Add make check-requirements-coverage to show what Requirement sections we don't quote
  4. Include the bulk of them, including writing some new code where we were missing minor things

Greater coverage puts us in a much stronger position when we update to the latest BOLT version at the beginning of a release cycle.

Changelog-None: Users will never see it. Their loss!

@rustyrussellrustyrussell added this to the 26.06 milestone Apr 10, 2026
@rustyrussell
rustyrussellforce-pushed the bolt-quote-improvements branch 4 times, most recently from 24ab569 to 3d50f97CompareApril 13, 2026 04:37
@ddustin

Copy link
Copy Markdown
Collaborator

I think I've seen this CI error before, some kind of flake around askrene?

**BROKEN** plugin-cln-xpay: askrene-age failed with {"code":-32601,"message":"Unknown command 'askrene-age'"}

@ddustin

Copy link
Copy Markdown
Collaborator

Pretty cool what Claude can do. Managing BOLT reference is apropos for a large language model 🫡

Update BOLT quotes in test and library Python files to match current BOLT
text: punctuation (periods to semicolons), capitalization (Lightning on
Bitcoin mainnet), fix field ordering in invoice breakdowns, add ... to skip
features fields and SHA256 hex details, correct backtick-quoting of field
names, and remove incorrect BOLT #7 label from a plain comment.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…ker.
We're going to get stricter, so "/* BOLT #N to-local output */" or "/* BOLT11 ... */"
will upset it.
Also remove a stray bare blank line in a BOLT comment block.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…_final_cltv_expiry_delta.
The BOLT #7 was updated to use the new default 18 as min_final_cltv_expiry_delta, so
update our quote and test, and fix other textual spec changes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Some of these are malformed (thus were unchecked!), some are from the
stricter interpretation of `...` which won't cross section boundaries.
Several BOLT quotes had drifted from the current spec text:
- connectd/queries.c: BOLT #7 uses 'full_information' not 'complete';
remove a second quote that referenced query_channel_range but was
actually wrong (that requirement is for query_short_channel_ids).
- lightningd/dual_open_control.c: channel reserve is 1% rounded down
(not just 1%); witness weight check now says SHOULD broadcast rather
than MUST fail; RBF quotes simplified to match actual BOLT wording.
- openingd/openingd.c: 'The sending node' became 'The sender';
invalid signature response now says MUST send warning/error not just
MUST fail the channel.
- openingd/dualopend.c: same invalid-signature quote as openingd.c.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mose of these are from the stricter `...` which won't cross section
boundaries. The listoffers_done doesn't actually need the ellipsis at
all.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Textual updates: the tests are actually correct. The invoice.c change
is to cross a section boundary.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
The Python tool (copied from lnprototest) handles multiple comment styles.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Splits BOLT files into per-section chunks so wildcards can't inadvertently
cross section headers, supports `...`-at-start semantics, and adds make-style `-k`
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…ics.
The new check_quotes.py tool will treat `...` at the start of a quote as
"immediately follows previous quote in BOLT text". To prepare for that,
we change existing quotes which used leading `...` to mean "skip some
text": split them into two consecutive BOLT comments (the second starting
with `...` to use the existing wildcard match), and add explicit `*...`
markers between consecutive BOLT test vector sections which cross `# From`
headers.
Also remove leading `...` from nonce quotes in cryptomsg.c/handshake.c
where the actual BOLT text starts a fresh sentence (no prior quote in file).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
sCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
….py, check Rust and Python too
Extend check-source-bolt to also check Python and Rust source files.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
check_quotes.py gains --coverage=FILE: on each successful match, atomically
appends one line '{bolt} {section_idx} {start} {end}' to FILE using a single
os.write() call so parallel make invocations don't interleave records.
find_quote() and find_quote_immediate() are updated to return match start
positions (needed to record the covered range, not just the end).
bolt-coverage.py reads the coverage file and reports BOLT text not covered
by any source comment. By default it restricts output to Requirements
sections; --all-sections shows every section. --bolt N restricts to
a single BOLT number.
Exit status is 0 if everything in the selected sections is covered, 1 if
anything is uncovered.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prints out a report of uncovered Requirements sections of the BOLTs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Claude messed up about half of these: putting them too far from the
appropriate code. After this I did it myself.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: use BOLT4's paranoid advice about doing constant-time error decryption.
…hannels.
We can decide to send an HTLC down a preferred channel which leads to the same peer
as the one they asked for, but the spec is clear that you shouldn't send the "wrong"
channel_update in that case.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: when we send errors, we won't include a `channel_update` if we chose a different channel than the one they told us to.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
BOLT 7 says this, but we don't do it. (Actually, it only says that for certain types,
but I've fixed that in lightning/bolts#1331).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
… other chains.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: `gossipd` will now silently ignore gossip for other chains (rather than sending warnings).
This is what was merged in the spec, so update our checks (and bolt quote).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
@rustyrussell
rustyrussellforce-pushed the bolt-quote-improvements branch from 3d50f97 to 28ab45fCompareApril 30, 2026 00:44
@rustyrussell

Copy link
Copy Markdown
CollaboratorAuthor

Pretty cool what Claude can do. Managing BOLT reference is apropos for a large language model 🫡

Actually, when I asked it to place the missing quotes, it was TERRIBLE. I mean, it placed them, but not next to the code which actually did the thing. Mainly because doing it right would require reading a LOT of code?

@rustyrussell
rustyrussell enabled auto-merge (rebase) April 30, 2026 01:43
@rustyrussellrustyrussell mentioned this pull request Apr 30, 2026
@rustyrussell
rustyrussell merged commit e5c7374 into ElementsProject:masterApr 30, 2026
85 of 87 checks passed
@nGolinenGoline mentioned this pull request May 4, 2026
5 tasks
Sign up for freeto 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.

2 participants

@rustyrussell@ddustin
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Bolt quote improvements - #9044

Merged
rustyrussell merged 21 commits into
ElementsProject:masterfrom
rustyrussell:bolt-quote-improvements
Apr 30, 2026
Merged

Bolt quote improvements#9044
rustyrussell merged 21 commits into
ElementsProject:masterfrom
rustyrussell:bolt-quote-improvements

Conversation

@rustyrussell

@rustyrussellrustyrussell commented Apr 10, 2026

Copy link
Copy Markdown
Collaborator

One incredibly valuable thing about Core Lightning is we include, and enforce BOLT checks. This PR takes it to the next level:

  1. Improve our tooling, so we can cover Rust, C and Python files, and get stricter with enforcement:
    1. ... at the beginning means "follows the previous quote"
    2. ... elsewhere means "skip something, but now won't skip over sections.
    3. Any comment starting with BOLT causes a complaint, ensuring we catch typos.
  2. Fix up our tests and other files we now cover, to make them up-to-date.
  3. Add make check-requirements-coverage to show what Requirement sections we don't quote
  4. Include the bulk of them, including writing some new code where we were missing minor things

Greater coverage puts us in a much stronger position when we update to the latest BOLT version at the beginning of a release cycle.

Changelog-None: Users will never see it. Their loss!

@rustyrussellrustyrussell added this to the 26.06 milestone Apr 10, 2026
@rustyrussell
rustyrussellforce-pushed the bolt-quote-improvements branch 4 times, most recently from 24ab569 to 3d50f97CompareApril 13, 2026 04:37
@ddustin

Copy link
Copy Markdown
Collaborator

I think I've seen this CI error before, some kind of flake around askrene?

**BROKEN** plugin-cln-xpay: askrene-age failed with {"code":-32601,"message":"Unknown command 'askrene-age'"}

@ddustin

Copy link
Copy Markdown
Collaborator

Pretty cool what Claude can do. Managing BOLT reference is apropos for a large language model 🫡

Update BOLT quotes in test and library Python files to match current BOLT
text: punctuation (periods to semicolons), capitalization (Lightning on
Bitcoin mainnet), fix field ordering in invoice breakdowns, add ... to skip
features fields and SHA256 hex details, correct backtick-quoting of field
names, and remove incorrect BOLT #7 label from a plain comment.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…ker.
We're going to get stricter, so "/* BOLT #N to-local output */" or "/* BOLT11 ... */"
will upset it.
Also remove a stray bare blank line in a BOLT comment block.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…_final_cltv_expiry_delta.
The BOLT #7 was updated to use the new default 18 as min_final_cltv_expiry_delta, so
update our quote and test, and fix other textual spec changes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Some of these are malformed (thus were unchecked!), some are from the
stricter interpretation of `...` which won't cross section boundaries.
Several BOLT quotes had drifted from the current spec text:
- connectd/queries.c: BOLT #7 uses 'full_information' not 'complete';
remove a second quote that referenced query_channel_range but was
actually wrong (that requirement is for query_short_channel_ids).
- lightningd/dual_open_control.c: channel reserve is 1% rounded down
(not just 1%); witness weight check now says SHOULD broadcast rather
than MUST fail; RBF quotes simplified to match actual BOLT wording.
- openingd/openingd.c: 'The sending node' became 'The sender';
invalid signature response now says MUST send warning/error not just
MUST fail the channel.
- openingd/dualopend.c: same invalid-signature quote as openingd.c.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mose of these are from the stricter `...` which won't cross section
boundaries. The listoffers_done doesn't actually need the ellipsis at
all.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Textual updates: the tests are actually correct. The invoice.c change
is to cross a section boundary.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
The Python tool (copied from lnprototest) handles multiple comment styles.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Splits BOLT files into per-section chunks so wildcards can't inadvertently
cross section headers, supports `...`-at-start semantics, and adds make-style `-k`
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…ics.
The new check_quotes.py tool will treat `...` at the start of a quote as
"immediately follows previous quote in BOLT text". To prepare for that,
we change existing quotes which used leading `...` to mean "skip some
text": split them into two consecutive BOLT comments (the second starting
with `...` to use the existing wildcard match), and add explicit `*...`
markers between consecutive BOLT test vector sections which cross `# From`
headers.
Also remove leading `...` from nonce quotes in cryptomsg.c/handshake.c
where the actual BOLT text starts a fresh sentence (no prior quote in file).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
sCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
….py, check Rust and Python too
Extend check-source-bolt to also check Python and Rust source files.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
check_quotes.py gains --coverage=FILE: on each successful match, atomically
appends one line '{bolt} {section_idx} {start} {end}' to FILE using a single
os.write() call so parallel make invocations don't interleave records.
find_quote() and find_quote_immediate() are updated to return match start
positions (needed to record the covered range, not just the end).
bolt-coverage.py reads the coverage file and reports BOLT text not covered
by any source comment. By default it restricts output to Requirements
sections; --all-sections shows every section. --bolt N restricts to
a single BOLT number.
Exit status is 0 if everything in the selected sections is covered, 1 if
anything is uncovered.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prints out a report of uncovered Requirements sections of the BOLTs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Claude messed up about half of these: putting them too far from the
appropriate code. After this I did it myself.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: use BOLT4's paranoid advice about doing constant-time error decryption.
…hannels.
We can decide to send an HTLC down a preferred channel which leads to the same peer
as the one they asked for, but the spec is clear that you shouldn't send the "wrong"
channel_update in that case.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: when we send errors, we won't include a `channel_update` if we chose a different channel than the one they told us to.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
BOLT 7 says this, but we don't do it. (Actually, it only says that for certain types,
but I've fixed that in lightning/bolts#1331).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
… other chains.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: `gossipd` will now silently ignore gossip for other chains (rather than sending warnings).
This is what was merged in the spec, so update our checks (and bolt quote).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
@rustyrussell
rustyrussellforce-pushed the bolt-quote-improvements branch from 3d50f97 to 28ab45fCompareApril 30, 2026 00:44
@rustyrussell

Copy link
Copy Markdown
CollaboratorAuthor

Pretty cool what Claude can do. Managing BOLT reference is apropos for a large language model 🫡

Actually, when I asked it to place the missing quotes, it was TERRIBLE. I mean, it placed them, but not next to the code which actually did the thing. Mainly because doing it right would require reading a LOT of code?

@rustyrussell
rustyrussell enabled auto-merge (rebase) April 30, 2026 01:43
@rustyrussellrustyrussell mentioned this pull request Apr 30, 2026
@rustyrussell
rustyrussell merged commit e5c7374 into ElementsProject:masterApr 30, 2026
85 of 87 checks passed
@nGolinenGoline mentioned this pull request May 4, 2026
5 tasks
Sign up for freeto 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.

2 participants

@rustyrussell@ddustin
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Bolt quote improvements - #9044

Merged
rustyrussell merged 21 commits into
ElementsProject:masterfrom
rustyrussell:bolt-quote-improvements
Apr 30, 2026
Merged

Bolt quote improvements#9044
rustyrussell merged 21 commits into
ElementsProject:masterfrom
rustyrussell:bolt-quote-improvements

Conversation

@rustyrussell

@rustyrussellrustyrussell commented Apr 10, 2026

Copy link
Copy Markdown
Collaborator

One incredibly valuable thing about Core Lightning is we include, and enforce BOLT checks. This PR takes it to the next level:

  1. Improve our tooling, so we can cover Rust, C and Python files, and get stricter with enforcement:
    1. ... at the beginning means "follows the previous quote"
    2. ... elsewhere means "skip something, but now won't skip over sections.
    3. Any comment starting with BOLT causes a complaint, ensuring we catch typos.
  2. Fix up our tests and other files we now cover, to make them up-to-date.
  3. Add make check-requirements-coverage to show what Requirement sections we don't quote
  4. Include the bulk of them, including writing some new code where we were missing minor things

Greater coverage puts us in a much stronger position when we update to the latest BOLT version at the beginning of a release cycle.

Changelog-None: Users will never see it. Their loss!

@rustyrussellrustyrussell added this to the 26.06 milestone Apr 10, 2026
@rustyrussell
rustyrussellforce-pushed the bolt-quote-improvements branch 4 times, most recently from 24ab569 to 3d50f97CompareApril 13, 2026 04:37
@ddustin

Copy link
Copy Markdown
Collaborator

I think I've seen this CI error before, some kind of flake around askrene?

**BROKEN** plugin-cln-xpay: askrene-age failed with {"code":-32601,"message":"Unknown command 'askrene-age'"}

@ddustin

Copy link
Copy Markdown
Collaborator

Pretty cool what Claude can do. Managing BOLT reference is apropos for a large language model 🫡

Update BOLT quotes in test and library Python files to match current BOLT
text: punctuation (periods to semicolons), capitalization (Lightning on
Bitcoin mainnet), fix field ordering in invoice breakdowns, add ... to skip
features fields and SHA256 hex details, correct backtick-quoting of field
names, and remove incorrect BOLT #7 label from a plain comment.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…ker.
We're going to get stricter, so "/* BOLT #N to-local output */" or "/* BOLT11 ... */"
will upset it.
Also remove a stray bare blank line in a BOLT comment block.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…_final_cltv_expiry_delta.
The BOLT #7 was updated to use the new default 18 as min_final_cltv_expiry_delta, so
update our quote and test, and fix other textual spec changes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Some of these are malformed (thus were unchecked!), some are from the
stricter interpretation of `...` which won't cross section boundaries.
Several BOLT quotes had drifted from the current spec text:
- connectd/queries.c: BOLT #7 uses 'full_information' not 'complete';
remove a second quote that referenced query_channel_range but was
actually wrong (that requirement is for query_short_channel_ids).
- lightningd/dual_open_control.c: channel reserve is 1% rounded down
(not just 1%); witness weight check now says SHOULD broadcast rather
than MUST fail; RBF quotes simplified to match actual BOLT wording.
- openingd/openingd.c: 'The sending node' became 'The sender';
invalid signature response now says MUST send warning/error not just
MUST fail the channel.
- openingd/dualopend.c: same invalid-signature quote as openingd.c.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mose of these are from the stricter `...` which won't cross section
boundaries. The listoffers_done doesn't actually need the ellipsis at
all.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Textual updates: the tests are actually correct. The invoice.c change
is to cross a section boundary.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
The Python tool (copied from lnprototest) handles multiple comment styles.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Splits BOLT files into per-section chunks so wildcards can't inadvertently
cross section headers, supports `...`-at-start semantics, and adds make-style `-k`
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…ics.
The new check_quotes.py tool will treat `...` at the start of a quote as
"immediately follows previous quote in BOLT text". To prepare for that,
we change existing quotes which used leading `...` to mean "skip some
text": split them into two consecutive BOLT comments (the second starting
with `...` to use the existing wildcard match), and add explicit `*...`
markers between consecutive BOLT test vector sections which cross `# From`
headers.
Also remove leading `...` from nonce quotes in cryptomsg.c/handshake.c
where the actual BOLT text starts a fresh sentence (no prior quote in file).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
sCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
….py, check Rust and Python too
Extend check-source-bolt to also check Python and Rust source files.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
check_quotes.py gains --coverage=FILE: on each successful match, atomically
appends one line '{bolt} {section_idx} {start} {end}' to FILE using a single
os.write() call so parallel make invocations don't interleave records.
find_quote() and find_quote_immediate() are updated to return match start
positions (needed to record the covered range, not just the end).
bolt-coverage.py reads the coverage file and reports BOLT text not covered
by any source comment. By default it restricts output to Requirements
sections; --all-sections shows every section. --bolt N restricts to
a single BOLT number.
Exit status is 0 if everything in the selected sections is covered, 1 if
anything is uncovered.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prints out a report of uncovered Requirements sections of the BOLTs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Claude messed up about half of these: putting them too far from the
appropriate code. After this I did it myself.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: use BOLT4's paranoid advice about doing constant-time error decryption.
…hannels.
We can decide to send an HTLC down a preferred channel which leads to the same peer
as the one they asked for, but the spec is clear that you shouldn't send the "wrong"
channel_update in that case.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: when we send errors, we won't include a `channel_update` if we chose a different channel than the one they told us to.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
BOLT 7 says this, but we don't do it. (Actually, it only says that for certain types,
but I've fixed that in lightning/bolts#1331).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
… other chains.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: `gossipd` will now silently ignore gossip for other chains (rather than sending warnings).
This is what was merged in the spec, so update our checks (and bolt quote).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
@rustyrussell
rustyrussellforce-pushed the bolt-quote-improvements branch from 3d50f97 to 28ab45fCompareApril 30, 2026 00:44
@rustyrussell

Copy link
Copy Markdown
CollaboratorAuthor

Pretty cool what Claude can do. Managing BOLT reference is apropos for a large language model 🫡

Actually, when I asked it to place the missing quotes, it was TERRIBLE. I mean, it placed them, but not next to the code which actually did the thing. Mainly because doing it right would require reading a LOT of code?

@rustyrussell
rustyrussell enabled auto-merge (rebase) April 30, 2026 01:43
@rustyrussellrustyrussell mentioned this pull request Apr 30, 2026
@rustyrussell
rustyrussell merged commit e5c7374 into ElementsProject:masterApr 30, 2026
85 of 87 checks passed
@nGolinenGoline mentioned this pull request May 4, 2026
5 tasks
Sign up for freeto 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.

2 participants

@rustyrussell@ddustin
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Bolt quote improvements - #9044

Merged
rustyrussell merged 21 commits into
ElementsProject:masterfrom
rustyrussell:bolt-quote-improvements
Apr 30, 2026
Merged

Bolt quote improvements#9044
rustyrussell merged 21 commits into
ElementsProject:masterfrom
rustyrussell:bolt-quote-improvements

Conversation

@rustyrussell

@rustyrussellrustyrussell commented Apr 10, 2026

Copy link
Copy Markdown
Collaborator

One incredibly valuable thing about Core Lightning is we include, and enforce BOLT checks. This PR takes it to the next level:

  1. Improve our tooling, so we can cover Rust, C and Python files, and get stricter with enforcement:
    1. ... at the beginning means "follows the previous quote"
    2. ... elsewhere means "skip something, but now won't skip over sections.
    3. Any comment starting with BOLT causes a complaint, ensuring we catch typos.
  2. Fix up our tests and other files we now cover, to make them up-to-date.
  3. Add make check-requirements-coverage to show what Requirement sections we don't quote
  4. Include the bulk of them, including writing some new code where we were missing minor things

Greater coverage puts us in a much stronger position when we update to the latest BOLT version at the beginning of a release cycle.

Changelog-None: Users will never see it. Their loss!

@rustyrussellrustyrussell added this to the 26.06 milestone Apr 10, 2026
@rustyrussell
rustyrussellforce-pushed the bolt-quote-improvements branch 4 times, most recently from 24ab569 to 3d50f97CompareApril 13, 2026 04:37
@ddustin

Copy link
Copy Markdown
Collaborator

I think I've seen this CI error before, some kind of flake around askrene?

**BROKEN** plugin-cln-xpay: askrene-age failed with {"code":-32601,"message":"Unknown command 'askrene-age'"}

@ddustin

Copy link
Copy Markdown
Collaborator

Pretty cool what Claude can do. Managing BOLT reference is apropos for a large language model 🫡

Update BOLT quotes in test and library Python files to match current BOLT
text: punctuation (periods to semicolons), capitalization (Lightning on
Bitcoin mainnet), fix field ordering in invoice breakdowns, add ... to skip
features fields and SHA256 hex details, correct backtick-quoting of field
names, and remove incorrect BOLT #7 label from a plain comment.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…ker.
We're going to get stricter, so "/* BOLT #N to-local output */" or "/* BOLT11 ... */"
will upset it.
Also remove a stray bare blank line in a BOLT comment block.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…_final_cltv_expiry_delta.
The BOLT #7 was updated to use the new default 18 as min_final_cltv_expiry_delta, so
update our quote and test, and fix other textual spec changes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Some of these are malformed (thus were unchecked!), some are from the
stricter interpretation of `...` which won't cross section boundaries.
Several BOLT quotes had drifted from the current spec text:
- connectd/queries.c: BOLT #7 uses 'full_information' not 'complete';
remove a second quote that referenced query_channel_range but was
actually wrong (that requirement is for query_short_channel_ids).
- lightningd/dual_open_control.c: channel reserve is 1% rounded down
(not just 1%); witness weight check now says SHOULD broadcast rather
than MUST fail; RBF quotes simplified to match actual BOLT wording.
- openingd/openingd.c: 'The sending node' became 'The sender';
invalid signature response now says MUST send warning/error not just
MUST fail the channel.
- openingd/dualopend.c: same invalid-signature quote as openingd.c.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mose of these are from the stricter `...` which won't cross section
boundaries. The listoffers_done doesn't actually need the ellipsis at
all.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Textual updates: the tests are actually correct. The invoice.c change
is to cross a section boundary.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
The Python tool (copied from lnprototest) handles multiple comment styles.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Splits BOLT files into per-section chunks so wildcards can't inadvertently
cross section headers, supports `...`-at-start semantics, and adds make-style `-k`
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
…ics.
The new check_quotes.py tool will treat `...` at the start of a quote as
"immediately follows previous quote in BOLT text". To prepare for that,
we change existing quotes which used leading `...` to mean "skip some
text": split them into two consecutive BOLT comments (the second starting
with `...` to use the existing wildcard match), and add explicit `*...`
markers between consecutive BOLT test vector sections which cross `# From`
headers.
Also remove leading `...` from nonce quotes in cryptomsg.c/handshake.c
where the actual BOLT text starts a fresh sentence (no prior quote in file).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
sCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
….py, check Rust and Python too
Extend check-source-bolt to also check Python and Rust source files.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
check_quotes.py gains --coverage=FILE: on each successful match, atomically
appends one line '{bolt} {section_idx} {start} {end}' to FILE using a single
os.write() call so parallel make invocations don't interleave records.
find_quote() and find_quote_immediate() are updated to return match start
positions (needed to record the covered range, not just the end).
bolt-coverage.py reads the coverage file and reports BOLT text not covered
by any source comment. By default it restricts output to Requirements
sections; --all-sections shows every section. --bolt N restricts to
a single BOLT number.
Exit status is 0 if everything in the selected sections is covered, 1 if
anything is uncovered.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prints out a report of uncovered Requirements sections of the BOLTs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Claude messed up about half of these: putting them too far from the
appropriate code. After this I did it myself.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: use BOLT4's paranoid advice about doing constant-time error decryption.
…hannels.
We can decide to send an HTLC down a preferred channel which leads to the same peer
as the one they asked for, but the spec is clear that you shouldn't send the "wrong"
channel_update in that case.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: when we send errors, we won't include a `channel_update` if we chose a different channel than the one they told us to.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
BOLT 7 says this, but we don't do it. (Actually, it only says that for certain types,
but I've fixed that in lightning/bolts#1331).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
… other chains.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: Protocol: `gossipd` will now silently ignore gossip for other chains (rather than sending warnings).
This is what was merged in the spec, so update our checks (and bolt quote).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
@rustyrussell
rustyrussellforce-pushed the bolt-quote-improvements branch from 3d50f97 to 28ab45fCompareApril 30, 2026 00:44
@rustyrussell

Copy link
Copy Markdown
CollaboratorAuthor

Pretty cool what Claude can do. Managing BOLT reference is apropos for a large language model 🫡

Actually, when I asked it to place the missing quotes, it was TERRIBLE. I mean, it placed them, but not next to the code which actually did the thing. Mainly because doing it right would require reading a LOT of code?

@rustyrussell
rustyrussell enabled auto-merge (rebase) April 30, 2026 01:43
@rustyrussellrustyrussell mentioned this pull request Apr 30, 2026
@rustyrussell
rustyrussell merged commit e5c7374 into ElementsProject:masterApr 30, 2026
85 of 87 checks passed
@nGolinenGoline mentioned this pull request May 4, 2026
5 tasks
Sign up for freeto 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.

2 participants

@rustyrussell@ddustin