fix(coverage): write hit records straight to disk instead of buffering them - #1103

Merged
Chemaclass merged 4 commits into
mainfrom
fix/1101-drop-coverage-buffer
Aug 13, 2026
Merged

fix(coverage): write hit records straight to disk instead of buffering them#1103
Chemaclass merged 4 commits into
mainfrom
fix/1101-drop-coverage-buffer

Conversation

@Chemaclass

Copy link
Copy Markdown
Member

🤔 Background

Related #1101

The trap engine collected hits into a shell variable and flushed every 100
records. A variable dies with the subshell that filled it, so anything recorded
inside a $( ) was lost unless that subshell happened to fill the buffer
first.

On Bash 5 a run reported 196 of 236 real hits, deterministically, while
Bash 3.2 lost none — the same project measured differently depending on the
Bash running it. The missing lines were ordinary code called inside command
substitutions.

💡 Changes

  • Records are appended as they happen; the buffer and its bookkeeping are gone
  • Faster too, since growing a shell string was not cheaper than an append: 8896 ms → 5898 ms on Bash 3.2, 4612 ms → 3988 ms on Bash 5 (hits 196 → 236)
  • Sequential and parallel runs now report the same total, and a one-line append interleaves better between workers than a multi-kilobyte flush
  • New tests record inside ( ) and $( ) and assert the record reached disk — all three fail against the buffered engine
  • The Spying on printf breaks coverage collection #724 guard (a spied printf must not shadow the write) moved with the write into record_line, and its test with it

…g them
The trap engine collected hits into a shell variable and wrote them out every
100 records. A variable dies with the subshell that filled it, so anything
recorded inside a $( ) was lost unless that subshell happened to fill the
buffer first. On Bash 5 a run of tests/unit/assert/basic_test.sh reported 196
of 236 real hits -- deterministically -- while Bash 3.2 lost none, so the same
project measured differently depending on the Bash running it. The missing
lines were ordinary code: bashunit::temp_dir and friends, called inside
command substitutions.
Appending each record is also faster than growing the string was: 8896ms to
5898ms on Bash 3.2, 4612ms to 3988ms on Bash 5, where hits go 196 to 236. A
one-line append also interleaves better between parallel workers than a
multi-kilobyte flush; sequential and parallel runs now report the same total.
flush_buffer keeps its name and its callers -- it means "publish what I
recorded", and now only drops the stale aggregation. The #724 guard against a
spied printf moved with the write into record_line, and its test with it.
Closes#1101
@ChemaclassChemaclass added the bug Something isn't working label Aug 13, 2026
@ChemaclassChemaclass self-assigned this Aug 13, 2026
Three tests encoded the old behaviour as a documented limitation -- a hit
recorded inside ( ), <( ) or a function called from $( ) never reached the
data file, so they asserted the lower count. Those lines are recorded now: 1
to 2, 3 to 4, and 2 to 4.
They are skipped on Bash 3.2, which is why the local runs stayed green and CI
caught them on Linux.
They were skipped on macOS with a comment saying the DEBUG trap reaches
subshells on Linux for every supported Bash. The Bash 3.0 job disproves that:
the counts there are the pre-#1101 ones, because before Bash 4 the trap does
not reach a subshell even under set -T, so nothing is recorded to keep.
Skipping on BASH_VERSINFO < 4 states the real condition and covers both the
macOS system Bash and the Bash 3.0 job.
… still does
The engine section documented the buffer as a known difference -- the trap
engine losing hits recorded inside a command substitution while xtrace kept
them. Records are written as they happen now (#1101), so that difference is
gone.
What remains is the shell: before Bash 4 the DEBUG trap does not reach a
subshell even under set -T, so the same project can report a slightly lower
percentage on Bash 3.x. Worth saying out loud, since nothing in the output
hints at it.
The performance note claimed capture and reporting cost about the same. After
this series the report phase is a few awk passes for the whole run and capture
is the dominant half.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugSomething isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Chemaclass
, '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

fix(coverage): write hit records straight to disk instead of buffering them - #1103

Merged
Chemaclass merged 4 commits into
mainfrom
fix/1101-drop-coverage-buffer
Aug 13, 2026
Merged

fix(coverage): write hit records straight to disk instead of buffering them#1103
Chemaclass merged 4 commits into
mainfrom
fix/1101-drop-coverage-buffer

Conversation

@Chemaclass

Copy link
Copy Markdown
Member

🤔 Background

Related #1101

The trap engine collected hits into a shell variable and flushed every 100
records. A variable dies with the subshell that filled it, so anything recorded
inside a $( ) was lost unless that subshell happened to fill the buffer
first.

On Bash 5 a run reported 196 of 236 real hits, deterministically, while
Bash 3.2 lost none — the same project measured differently depending on the
Bash running it. The missing lines were ordinary code called inside command
substitutions.

💡 Changes

  • Records are appended as they happen; the buffer and its bookkeeping are gone
  • Faster too, since growing a shell string was not cheaper than an append: 8896 ms → 5898 ms on Bash 3.2, 4612 ms → 3988 ms on Bash 5 (hits 196 → 236)
  • Sequential and parallel runs now report the same total, and a one-line append interleaves better between workers than a multi-kilobyte flush
  • New tests record inside ( ) and $( ) and assert the record reached disk — all three fail against the buffered engine
  • The Spying on printf breaks coverage collection #724 guard (a spied printf must not shadow the write) moved with the write into record_line, and its test with it

…g them
The trap engine collected hits into a shell variable and wrote them out every
100 records. A variable dies with the subshell that filled it, so anything
recorded inside a $( ) was lost unless that subshell happened to fill the
buffer first. On Bash 5 a run of tests/unit/assert/basic_test.sh reported 196
of 236 real hits -- deterministically -- while Bash 3.2 lost none, so the same
project measured differently depending on the Bash running it. The missing
lines were ordinary code: bashunit::temp_dir and friends, called inside
command substitutions.
Appending each record is also faster than growing the string was: 8896ms to
5898ms on Bash 3.2, 4612ms to 3988ms on Bash 5, where hits go 196 to 236. A
one-line append also interleaves better between parallel workers than a
multi-kilobyte flush; sequential and parallel runs now report the same total.
flush_buffer keeps its name and its callers -- it means "publish what I
recorded", and now only drops the stale aggregation. The #724 guard against a
spied printf moved with the write into record_line, and its test with it.
Closes#1101
@ChemaclassChemaclass added the bug Something isn't working label Aug 13, 2026
@ChemaclassChemaclass self-assigned this Aug 13, 2026
Three tests encoded the old behaviour as a documented limitation -- a hit
recorded inside ( ), <( ) or a function called from $( ) never reached the
data file, so they asserted the lower count. Those lines are recorded now: 1
to 2, 3 to 4, and 2 to 4.
They are skipped on Bash 3.2, which is why the local runs stayed green and CI
caught them on Linux.
They were skipped on macOS with a comment saying the DEBUG trap reaches
subshells on Linux for every supported Bash. The Bash 3.0 job disproves that:
the counts there are the pre-#1101 ones, because before Bash 4 the trap does
not reach a subshell even under set -T, so nothing is recorded to keep.
Skipping on BASH_VERSINFO < 4 states the real condition and covers both the
macOS system Bash and the Bash 3.0 job.
… still does
The engine section documented the buffer as a known difference -- the trap
engine losing hits recorded inside a command substitution while xtrace kept
them. Records are written as they happen now (#1101), so that difference is
gone.
What remains is the shell: before Bash 4 the DEBUG trap does not reach a
subshell even under set -T, so the same project can report a slightly lower
percentage on Bash 3.x. Worth saying out loud, since nothing in the output
hints at it.
The performance note claimed capture and reporting cost about the same. After
this series the report phase is a few awk passes for the whole run and capture
is the dominant half.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugSomething isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Chemaclass
, '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

fix(coverage): write hit records straight to disk instead of buffering them - #1103

Merged
Chemaclass merged 4 commits into
mainfrom
fix/1101-drop-coverage-buffer
Aug 13, 2026
Merged

fix(coverage): write hit records straight to disk instead of buffering them#1103
Chemaclass merged 4 commits into
mainfrom
fix/1101-drop-coverage-buffer

Conversation

@Chemaclass

Copy link
Copy Markdown
Member

🤔 Background

Related #1101

The trap engine collected hits into a shell variable and flushed every 100
records. A variable dies with the subshell that filled it, so anything recorded
inside a $( ) was lost unless that subshell happened to fill the buffer
first.

On Bash 5 a run reported 196 of 236 real hits, deterministically, while
Bash 3.2 lost none — the same project measured differently depending on the
Bash running it. The missing lines were ordinary code called inside command
substitutions.

💡 Changes

  • Records are appended as they happen; the buffer and its bookkeeping are gone
  • Faster too, since growing a shell string was not cheaper than an append: 8896 ms → 5898 ms on Bash 3.2, 4612 ms → 3988 ms on Bash 5 (hits 196 → 236)
  • Sequential and parallel runs now report the same total, and a one-line append interleaves better between workers than a multi-kilobyte flush
  • New tests record inside ( ) and $( ) and assert the record reached disk — all three fail against the buffered engine
  • The Spying on printf breaks coverage collection #724 guard (a spied printf must not shadow the write) moved with the write into record_line, and its test with it

…g them
The trap engine collected hits into a shell variable and wrote them out every
100 records. A variable dies with the subshell that filled it, so anything
recorded inside a $( ) was lost unless that subshell happened to fill the
buffer first. On Bash 5 a run of tests/unit/assert/basic_test.sh reported 196
of 236 real hits -- deterministically -- while Bash 3.2 lost none, so the same
project measured differently depending on the Bash running it. The missing
lines were ordinary code: bashunit::temp_dir and friends, called inside
command substitutions.
Appending each record is also faster than growing the string was: 8896ms to
5898ms on Bash 3.2, 4612ms to 3988ms on Bash 5, where hits go 196 to 236. A
one-line append also interleaves better between parallel workers than a
multi-kilobyte flush; sequential and parallel runs now report the same total.
flush_buffer keeps its name and its callers -- it means "publish what I
recorded", and now only drops the stale aggregation. The #724 guard against a
spied printf moved with the write into record_line, and its test with it.
Closes#1101
@ChemaclassChemaclass added the bug Something isn't working label Aug 13, 2026
@ChemaclassChemaclass self-assigned this Aug 13, 2026
Three tests encoded the old behaviour as a documented limitation -- a hit
recorded inside ( ), <( ) or a function called from $( ) never reached the
data file, so they asserted the lower count. Those lines are recorded now: 1
to 2, 3 to 4, and 2 to 4.
They are skipped on Bash 3.2, which is why the local runs stayed green and CI
caught them on Linux.
They were skipped on macOS with a comment saying the DEBUG trap reaches
subshells on Linux for every supported Bash. The Bash 3.0 job disproves that:
the counts there are the pre-#1101 ones, because before Bash 4 the trap does
not reach a subshell even under set -T, so nothing is recorded to keep.
Skipping on BASH_VERSINFO < 4 states the real condition and covers both the
macOS system Bash and the Bash 3.0 job.
… still does
The engine section documented the buffer as a known difference -- the trap
engine losing hits recorded inside a command substitution while xtrace kept
them. Records are written as they happen now (#1101), so that difference is
gone.
What remains is the shell: before Bash 4 the DEBUG trap does not reach a
subshell even under set -T, so the same project can report a slightly lower
percentage on Bash 3.x. Worth saying out loud, since nothing in the output
hints at it.
The performance note claimed capture and reporting cost about the same. After
this series the report phase is a few awk passes for the whole run and capture
is the dominant half.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugSomething isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Chemaclass
, '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

fix(coverage): write hit records straight to disk instead of buffering them - #1103

Merged
Chemaclass merged 4 commits into
mainfrom
fix/1101-drop-coverage-buffer
Aug 13, 2026
Merged

fix(coverage): write hit records straight to disk instead of buffering them#1103
Chemaclass merged 4 commits into
mainfrom
fix/1101-drop-coverage-buffer

Conversation

@Chemaclass

Copy link
Copy Markdown
Member

🤔 Background

Related #1101

The trap engine collected hits into a shell variable and flushed every 100
records. A variable dies with the subshell that filled it, so anything recorded
inside a $( ) was lost unless that subshell happened to fill the buffer
first.

On Bash 5 a run reported 196 of 236 real hits, deterministically, while
Bash 3.2 lost none — the same project measured differently depending on the
Bash running it. The missing lines were ordinary code called inside command
substitutions.

💡 Changes

  • Records are appended as they happen; the buffer and its bookkeeping are gone
  • Faster too, since growing a shell string was not cheaper than an append: 8896 ms → 5898 ms on Bash 3.2, 4612 ms → 3988 ms on Bash 5 (hits 196 → 236)
  • Sequential and parallel runs now report the same total, and a one-line append interleaves better between workers than a multi-kilobyte flush
  • New tests record inside ( ) and $( ) and assert the record reached disk — all three fail against the buffered engine
  • The Spying on printf breaks coverage collection #724 guard (a spied printf must not shadow the write) moved with the write into record_line, and its test with it

…g them
The trap engine collected hits into a shell variable and wrote them out every
100 records. A variable dies with the subshell that filled it, so anything
recorded inside a $( ) was lost unless that subshell happened to fill the
buffer first. On Bash 5 a run of tests/unit/assert/basic_test.sh reported 196
of 236 real hits -- deterministically -- while Bash 3.2 lost none, so the same
project measured differently depending on the Bash running it. The missing
lines were ordinary code: bashunit::temp_dir and friends, called inside
command substitutions.
Appending each record is also faster than growing the string was: 8896ms to
5898ms on Bash 3.2, 4612ms to 3988ms on Bash 5, where hits go 196 to 236. A
one-line append also interleaves better between parallel workers than a
multi-kilobyte flush; sequential and parallel runs now report the same total.
flush_buffer keeps its name and its callers -- it means "publish what I
recorded", and now only drops the stale aggregation. The #724 guard against a
spied printf moved with the write into record_line, and its test with it.
Closes#1101
@ChemaclassChemaclass added the bug Something isn't working label Aug 13, 2026
@ChemaclassChemaclass self-assigned this Aug 13, 2026
Three tests encoded the old behaviour as a documented limitation -- a hit
recorded inside ( ), <( ) or a function called from $( ) never reached the
data file, so they asserted the lower count. Those lines are recorded now: 1
to 2, 3 to 4, and 2 to 4.
They are skipped on Bash 3.2, which is why the local runs stayed green and CI
caught them on Linux.
They were skipped on macOS with a comment saying the DEBUG trap reaches
subshells on Linux for every supported Bash. The Bash 3.0 job disproves that:
the counts there are the pre-#1101 ones, because before Bash 4 the trap does
not reach a subshell even under set -T, so nothing is recorded to keep.
Skipping on BASH_VERSINFO < 4 states the real condition and covers both the
macOS system Bash and the Bash 3.0 job.
… still does
The engine section documented the buffer as a known difference -- the trap
engine losing hits recorded inside a command substitution while xtrace kept
them. Records are written as they happen now (#1101), so that difference is
gone.
What remains is the shell: before Bash 4 the DEBUG trap does not reach a
subshell even under set -T, so the same project can report a slightly lower
percentage on Bash 3.x. Worth saying out loud, since nothing in the output
hints at it.
The performance note claimed capture and reporting cost about the same. After
this series the report phase is a few awk passes for the whole run and capture
is the dominant half.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugSomething isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Chemaclass
, '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

fix(coverage): write hit records straight to disk instead of buffering them - #1103

Merged
Chemaclass merged 4 commits into
mainfrom
fix/1101-drop-coverage-buffer
Aug 13, 2026
Merged

fix(coverage): write hit records straight to disk instead of buffering them#1103
Chemaclass merged 4 commits into
mainfrom
fix/1101-drop-coverage-buffer

Conversation

@Chemaclass

Copy link
Copy Markdown
Member

🤔 Background

Related #1101

The trap engine collected hits into a shell variable and flushed every 100
records. A variable dies with the subshell that filled it, so anything recorded
inside a $( ) was lost unless that subshell happened to fill the buffer
first.

On Bash 5 a run reported 196 of 236 real hits, deterministically, while
Bash 3.2 lost none — the same project measured differently depending on the
Bash running it. The missing lines were ordinary code called inside command
substitutions.

💡 Changes

  • Records are appended as they happen; the buffer and its bookkeeping are gone
  • Faster too, since growing a shell string was not cheaper than an append: 8896 ms → 5898 ms on Bash 3.2, 4612 ms → 3988 ms on Bash 5 (hits 196 → 236)
  • Sequential and parallel runs now report the same total, and a one-line append interleaves better between workers than a multi-kilobyte flush
  • New tests record inside ( ) and $( ) and assert the record reached disk — all three fail against the buffered engine
  • The Spying on printf breaks coverage collection #724 guard (a spied printf must not shadow the write) moved with the write into record_line, and its test with it

…g them
The trap engine collected hits into a shell variable and wrote them out every
100 records. A variable dies with the subshell that filled it, so anything
recorded inside a $( ) was lost unless that subshell happened to fill the
buffer first. On Bash 5 a run of tests/unit/assert/basic_test.sh reported 196
of 236 real hits -- deterministically -- while Bash 3.2 lost none, so the same
project measured differently depending on the Bash running it. The missing
lines were ordinary code: bashunit::temp_dir and friends, called inside
command substitutions.
Appending each record is also faster than growing the string was: 8896ms to
5898ms on Bash 3.2, 4612ms to 3988ms on Bash 5, where hits go 196 to 236. A
one-line append also interleaves better between parallel workers than a
multi-kilobyte flush; sequential and parallel runs now report the same total.
flush_buffer keeps its name and its callers -- it means "publish what I
recorded", and now only drops the stale aggregation. The #724 guard against a
spied printf moved with the write into record_line, and its test with it.
Closes#1101
@ChemaclassChemaclass added the bug Something isn't working label Aug 13, 2026
@ChemaclassChemaclass self-assigned this Aug 13, 2026
Three tests encoded the old behaviour as a documented limitation -- a hit
recorded inside ( ), <( ) or a function called from $( ) never reached the
data file, so they asserted the lower count. Those lines are recorded now: 1
to 2, 3 to 4, and 2 to 4.
They are skipped on Bash 3.2, which is why the local runs stayed green and CI
caught them on Linux.
They were skipped on macOS with a comment saying the DEBUG trap reaches
subshells on Linux for every supported Bash. The Bash 3.0 job disproves that:
the counts there are the pre-#1101 ones, because before Bash 4 the trap does
not reach a subshell even under set -T, so nothing is recorded to keep.
Skipping on BASH_VERSINFO < 4 states the real condition and covers both the
macOS system Bash and the Bash 3.0 job.
… still does
The engine section documented the buffer as a known difference -- the trap
engine losing hits recorded inside a command substitution while xtrace kept
them. Records are written as they happen now (#1101), so that difference is
gone.
What remains is the shell: before Bash 4 the DEBUG trap does not reach a
subshell even under set -T, so the same project can report a slightly lower
percentage on Bash 3.x. Worth saying out loud, since nothing in the output
hints at it.
The performance note claimed capture and reporting cost about the same. After
this series the report phase is a few awk passes for the whole run and capture
is the dominant half.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugSomething isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Chemaclass
, '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

fix(coverage): write hit records straight to disk instead of buffering them - #1103

Merged
Chemaclass merged 4 commits into
mainfrom
fix/1101-drop-coverage-buffer
Aug 13, 2026
Merged

fix(coverage): write hit records straight to disk instead of buffering them#1103
Chemaclass merged 4 commits into
mainfrom
fix/1101-drop-coverage-buffer

Conversation

@Chemaclass

Copy link
Copy Markdown
Member

🤔 Background

Related #1101

The trap engine collected hits into a shell variable and flushed every 100
records. A variable dies with the subshell that filled it, so anything recorded
inside a $( ) was lost unless that subshell happened to fill the buffer
first.

On Bash 5 a run reported 196 of 236 real hits, deterministically, while
Bash 3.2 lost none — the same project measured differently depending on the
Bash running it. The missing lines were ordinary code called inside command
substitutions.

💡 Changes

  • Records are appended as they happen; the buffer and its bookkeeping are gone
  • Faster too, since growing a shell string was not cheaper than an append: 8896 ms → 5898 ms on Bash 3.2, 4612 ms → 3988 ms on Bash 5 (hits 196 → 236)
  • Sequential and parallel runs now report the same total, and a one-line append interleaves better between workers than a multi-kilobyte flush
  • New tests record inside ( ) and $( ) and assert the record reached disk — all three fail against the buffered engine
  • The Spying on printf breaks coverage collection #724 guard (a spied printf must not shadow the write) moved with the write into record_line, and its test with it

…g them
The trap engine collected hits into a shell variable and wrote them out every
100 records. A variable dies with the subshell that filled it, so anything
recorded inside a $( ) was lost unless that subshell happened to fill the
buffer first. On Bash 5 a run of tests/unit/assert/basic_test.sh reported 196
of 236 real hits -- deterministically -- while Bash 3.2 lost none, so the same
project measured differently depending on the Bash running it. The missing
lines were ordinary code: bashunit::temp_dir and friends, called inside
command substitutions.
Appending each record is also faster than growing the string was: 8896ms to
5898ms on Bash 3.2, 4612ms to 3988ms on Bash 5, where hits go 196 to 236. A
one-line append also interleaves better between parallel workers than a
multi-kilobyte flush; sequential and parallel runs now report the same total.
flush_buffer keeps its name and its callers -- it means "publish what I
recorded", and now only drops the stale aggregation. The #724 guard against a
spied printf moved with the write into record_line, and its test with it.
Closes#1101
@ChemaclassChemaclass added the bug Something isn't working label Aug 13, 2026
@ChemaclassChemaclass self-assigned this Aug 13, 2026
Three tests encoded the old behaviour as a documented limitation -- a hit
recorded inside ( ), <( ) or a function called from $( ) never reached the
data file, so they asserted the lower count. Those lines are recorded now: 1
to 2, 3 to 4, and 2 to 4.
They are skipped on Bash 3.2, which is why the local runs stayed green and CI
caught them on Linux.
They were skipped on macOS with a comment saying the DEBUG trap reaches
subshells on Linux for every supported Bash. The Bash 3.0 job disproves that:
the counts there are the pre-#1101 ones, because before Bash 4 the trap does
not reach a subshell even under set -T, so nothing is recorded to keep.
Skipping on BASH_VERSINFO < 4 states the real condition and covers both the
macOS system Bash and the Bash 3.0 job.
… still does
The engine section documented the buffer as a known difference -- the trap
engine losing hits recorded inside a command substitution while xtrace kept
them. Records are written as they happen now (#1101), so that difference is
gone.
What remains is the shell: before Bash 4 the DEBUG trap does not reach a
subshell even under set -T, so the same project can report a slightly lower
percentage on Bash 3.x. Worth saying out loud, since nothing in the output
hints at it.
The performance note claimed capture and reporting cost about the same. After
this series the report phase is a few awk passes for the whole run and capture
is the dominant half.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugSomething isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Chemaclass
, '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

fix(coverage): write hit records straight to disk instead of buffering them - #1103

Merged
Chemaclass merged 4 commits into
mainfrom
fix/1101-drop-coverage-buffer
Aug 13, 2026
Merged

fix(coverage): write hit records straight to disk instead of buffering them#1103
Chemaclass merged 4 commits into
mainfrom
fix/1101-drop-coverage-buffer

Conversation

@Chemaclass

Copy link
Copy Markdown
Member

🤔 Background

Related #1101

The trap engine collected hits into a shell variable and flushed every 100
records. A variable dies with the subshell that filled it, so anything recorded
inside a $( ) was lost unless that subshell happened to fill the buffer
first.

On Bash 5 a run reported 196 of 236 real hits, deterministically, while
Bash 3.2 lost none — the same project measured differently depending on the
Bash running it. The missing lines were ordinary code called inside command
substitutions.

💡 Changes

  • Records are appended as they happen; the buffer and its bookkeeping are gone
  • Faster too, since growing a shell string was not cheaper than an append: 8896 ms → 5898 ms on Bash 3.2, 4612 ms → 3988 ms on Bash 5 (hits 196 → 236)
  • Sequential and parallel runs now report the same total, and a one-line append interleaves better between workers than a multi-kilobyte flush
  • New tests record inside ( ) and $( ) and assert the record reached disk — all three fail against the buffered engine
  • The Spying on printf breaks coverage collection #724 guard (a spied printf must not shadow the write) moved with the write into record_line, and its test with it

…g them
The trap engine collected hits into a shell variable and wrote them out every
100 records. A variable dies with the subshell that filled it, so anything
recorded inside a $( ) was lost unless that subshell happened to fill the
buffer first. On Bash 5 a run of tests/unit/assert/basic_test.sh reported 196
of 236 real hits -- deterministically -- while Bash 3.2 lost none, so the same
project measured differently depending on the Bash running it. The missing
lines were ordinary code: bashunit::temp_dir and friends, called inside
command substitutions.
Appending each record is also faster than growing the string was: 8896ms to
5898ms on Bash 3.2, 4612ms to 3988ms on Bash 5, where hits go 196 to 236. A
one-line append also interleaves better between parallel workers than a
multi-kilobyte flush; sequential and parallel runs now report the same total.
flush_buffer keeps its name and its callers -- it means "publish what I
recorded", and now only drops the stale aggregation. The #724 guard against a
spied printf moved with the write into record_line, and its test with it.
Closes#1101
@ChemaclassChemaclass added the bug Something isn't working label Aug 13, 2026
@ChemaclassChemaclass self-assigned this Aug 13, 2026
Three tests encoded the old behaviour as a documented limitation -- a hit
recorded inside ( ), <( ) or a function called from $( ) never reached the
data file, so they asserted the lower count. Those lines are recorded now: 1
to 2, 3 to 4, and 2 to 4.
They are skipped on Bash 3.2, which is why the local runs stayed green and CI
caught them on Linux.
They were skipped on macOS with a comment saying the DEBUG trap reaches
subshells on Linux for every supported Bash. The Bash 3.0 job disproves that:
the counts there are the pre-#1101 ones, because before Bash 4 the trap does
not reach a subshell even under set -T, so nothing is recorded to keep.
Skipping on BASH_VERSINFO < 4 states the real condition and covers both the
macOS system Bash and the Bash 3.0 job.
… still does
The engine section documented the buffer as a known difference -- the trap
engine losing hits recorded inside a command substitution while xtrace kept
them. Records are written as they happen now (#1101), so that difference is
gone.
What remains is the shell: before Bash 4 the DEBUG trap does not reach a
subshell even under set -T, so the same project can report a slightly lower
percentage on Bash 3.x. Worth saying out loud, since nothing in the output
hints at it.
The performance note claimed capture and reporting cost about the same. After
this series the report phase is a few awk passes for the whole run and capture
is the dominant half.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugSomething isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Chemaclass
, '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

fix(coverage): write hit records straight to disk instead of buffering them - #1103

Merged
Chemaclass merged 4 commits into
mainfrom
fix/1101-drop-coverage-buffer
Aug 13, 2026
Merged

fix(coverage): write hit records straight to disk instead of buffering them#1103
Chemaclass merged 4 commits into
mainfrom
fix/1101-drop-coverage-buffer

Conversation

@Chemaclass

Copy link
Copy Markdown
Member

🤔 Background

Related #1101

The trap engine collected hits into a shell variable and flushed every 100
records. A variable dies with the subshell that filled it, so anything recorded
inside a $( ) was lost unless that subshell happened to fill the buffer
first.

On Bash 5 a run reported 196 of 236 real hits, deterministically, while
Bash 3.2 lost none — the same project measured differently depending on the
Bash running it. The missing lines were ordinary code called inside command
substitutions.

💡 Changes

  • Records are appended as they happen; the buffer and its bookkeeping are gone
  • Faster too, since growing a shell string was not cheaper than an append: 8896 ms → 5898 ms on Bash 3.2, 4612 ms → 3988 ms on Bash 5 (hits 196 → 236)
  • Sequential and parallel runs now report the same total, and a one-line append interleaves better between workers than a multi-kilobyte flush
  • New tests record inside ( ) and $( ) and assert the record reached disk — all three fail against the buffered engine
  • The Spying on printf breaks coverage collection #724 guard (a spied printf must not shadow the write) moved with the write into record_line, and its test with it

…g them
The trap engine collected hits into a shell variable and wrote them out every
100 records. A variable dies with the subshell that filled it, so anything
recorded inside a $( ) was lost unless that subshell happened to fill the
buffer first. On Bash 5 a run of tests/unit/assert/basic_test.sh reported 196
of 236 real hits -- deterministically -- while Bash 3.2 lost none, so the same
project measured differently depending on the Bash running it. The missing
lines were ordinary code: bashunit::temp_dir and friends, called inside
command substitutions.
Appending each record is also faster than growing the string was: 8896ms to
5898ms on Bash 3.2, 4612ms to 3988ms on Bash 5, where hits go 196 to 236. A
one-line append also interleaves better between parallel workers than a
multi-kilobyte flush; sequential and parallel runs now report the same total.
flush_buffer keeps its name and its callers -- it means "publish what I
recorded", and now only drops the stale aggregation. The #724 guard against a
spied printf moved with the write into record_line, and its test with it.
Closes#1101
@ChemaclassChemaclass added the bug Something isn't working label Aug 13, 2026
@ChemaclassChemaclass self-assigned this Aug 13, 2026
Three tests encoded the old behaviour as a documented limitation -- a hit
recorded inside ( ), <( ) or a function called from $( ) never reached the
data file, so they asserted the lower count. Those lines are recorded now: 1
to 2, 3 to 4, and 2 to 4.
They are skipped on Bash 3.2, which is why the local runs stayed green and CI
caught them on Linux.
They were skipped on macOS with a comment saying the DEBUG trap reaches
subshells on Linux for every supported Bash. The Bash 3.0 job disproves that:
the counts there are the pre-#1101 ones, because before Bash 4 the trap does
not reach a subshell even under set -T, so nothing is recorded to keep.
Skipping on BASH_VERSINFO < 4 states the real condition and covers both the
macOS system Bash and the Bash 3.0 job.
… still does
The engine section documented the buffer as a known difference -- the trap
engine losing hits recorded inside a command substitution while xtrace kept
them. Records are written as they happen now (#1101), so that difference is
gone.
What remains is the shell: before Bash 4 the DEBUG trap does not reach a
subshell even under set -T, so the same project can report a slightly lower
percentage on Bash 3.x. Worth saying out loud, since nothing in the output
hints at it.
The performance note claimed capture and reporting cost about the same. After
this series the report phase is a few awk passes for the whole run and capture
is the dominant half.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugSomething isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Chemaclass