Catch the client up to ABI 0.14 - #17

Merged
tamnd merged 2 commits into
mainfrom
tablename
Aug 24, 2026
Merged

Catch the client up to ABI 0.14#17
tamnd merged 2 commits into
mainfrom
tablename

Conversation

@tamnd

Copy link
Copy Markdown
Owner

This client was written against ABI 0.12 and the engine has moved twice since. The whole of the gap is three additions to zu.h, and both of the ones that matter bite a program that does nothing unusual: a byte string cell made Type.of throw rather than answer, and a node carried a table id that nothing here could turn into a name.

ZU_TYPE_BYTES is a type of its own rather than a string that happens to hold octets, so this adds Value.Bytes, Type.BYTES and Row.getBytes rather than widening Value.Str. A host that took the octets for a string would decode them, and octets that are not UTF-8 do not survive that. Value.Bytes writes out equals, hashCode and toString because a record over an array compares by identity otherwise, and two byte strings holding the same octets are one value. It spells itself in hex, which is how the engine and the corpus both write one.

zu_conn_table_name is what turns the number in a Value.Node into the name the statement wrote, and it is what a corpus runner needs to spell a node as person#1. Node and rel tables share one id space so one call answers for both kinds, and an id no table has comes back null rather than throwing, because asking is how a host finds out. The doc on Value.Node.table() said the C ABI had no such call, which is no longer true, so it now points at Connection.tableName.

Both providers carry both calls. The FFM side gets two more handles in Abi and two overrides in FfmBinding; utf8 is now written over a shared octets helper so the byte path and the string path copy the same way. The JNI side gets two natives, two shims, two lines in the ZU_SYMBOLS table and two in the registration table.

api/surface.txt is every addition and no removal, which is a minor release.

What was run

On a Linux host with JDK 25 and a libzu at the current engine revision, both providers, the whole TCK:

  • zudb-ffm: 209 tests, 0 failures
  • zudb-jni: 211 tests, 0 failures

That includes the 9 new BytesTest cases and the 3 new TableNameTest cases on each provider, so what is checked is that the two agree rather than that one of them works. scripts/build-shim.sh builds the C shim clean, and the Java compiles under -Xlint:all -Werror as everything here does.

This client was written against ABI 0.12 and the engine has moved twice
since. The whole of the gap is three symbols, and both of them that
matter bite a program that does nothing unusual: a byte string cell made
Type.of throw rather than answer, and a node carried a table id that
nothing here could turn into a name.
ZU_TYPE_BYTES is a type of its own rather than a string that happens to
hold octets, so this adds Value.Bytes, Type.BYTES and Row.getBytes
rather than widening Value.Str. A host that took the octets for a string
would decode them, and octets that are not UTF-8 do not survive that.
Value.Bytes writes out equals, hashCode and toString because a record
over an array compares by identity otherwise, and two byte strings
holding the same octets are one value. It spells itself in hex, which is
how the engine and the corpus both write one.
zu_conn_table_name is what turns the number in a Value.Node into the
name the statement wrote. Node and rel tables share one id space so one
call answers for both kinds, and an id no table has comes back null
rather than throwing, because asking is how a host finds out.
Both providers carry both calls: the FFM side gets two more handles in
Abi and two overrides, the JNI side two natives, two shims and two more
lines in the registration table. The TCK covers them, so what is checked
is that the two providers agree rather than that one of them works.
api/surface.txt is every addition and no removal, which is a minor
release.
The header this client vendors is now the engine's header byte for byte,
which is what CI has been checking all along and what nothing has
satisfied since the check was added.
Catching up to the file rather than to the version turned up four
exported functions the version does not mention. zu_error_subject_kind,
zu_error_subject, zu_error_graph and zu_error_schema arrived in
tamnd/zu#581 with ZU_ABI_VERSION left at 0.14, though the two commits
before it did bump. So reading the macro was never going to find them
and diffing the file was. I have filed that against the engine as
tamnd/zu#697.
The four carry what ISO 39075 subclause 23.2 asks a diagnostic record to
name: which thing the condition is about, what it is called, and the
graph and schema the statement was running in. The kind is kept as its
own word rather than glued to the front of the name, so asking whether a
failure is about a label is one string compared against one word, and an
editor that wants to underline the name gets the name with nothing
around it.
Both providers bind all four, and both TCK suites pass against a real
engine: 209 cases through Panama, 211 through JNI, 44 in the core, no
failures.
This changes the shape of two public members rather than only adding to
them. Diagnostic gains four components, so its canonical constructor and
its of factory both take fifteen arguments where they took eleven. By
the rule in README, a name that changes shape is a major release. Both
are the provider-facing way to build a record, so the callers this
breaks are provider implementations rather than programs that read rows,
but it breaks them and the surface file says so.
ZuException gains four accessors and Diagnostic four component readers,
and those are additions.
@tamnd
tamnd merged commit f3922d9 into mainAug 24, 2026
21 checks passed
@tamnd
tamnd deleted the tablename branch August 24, 2026 16:32
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.

1 participant

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

Catch the client up to ABI 0.14 - #17

Merged
tamnd merged 2 commits into
mainfrom
tablename
Aug 24, 2026
Merged

Catch the client up to ABI 0.14#17
tamnd merged 2 commits into
mainfrom
tablename

Conversation

@tamnd

Copy link
Copy Markdown
Owner

This client was written against ABI 0.12 and the engine has moved twice since. The whole of the gap is three additions to zu.h, and both of the ones that matter bite a program that does nothing unusual: a byte string cell made Type.of throw rather than answer, and a node carried a table id that nothing here could turn into a name.

ZU_TYPE_BYTES is a type of its own rather than a string that happens to hold octets, so this adds Value.Bytes, Type.BYTES and Row.getBytes rather than widening Value.Str. A host that took the octets for a string would decode them, and octets that are not UTF-8 do not survive that. Value.Bytes writes out equals, hashCode and toString because a record over an array compares by identity otherwise, and two byte strings holding the same octets are one value. It spells itself in hex, which is how the engine and the corpus both write one.

zu_conn_table_name is what turns the number in a Value.Node into the name the statement wrote, and it is what a corpus runner needs to spell a node as person#1. Node and rel tables share one id space so one call answers for both kinds, and an id no table has comes back null rather than throwing, because asking is how a host finds out. The doc on Value.Node.table() said the C ABI had no such call, which is no longer true, so it now points at Connection.tableName.

Both providers carry both calls. The FFM side gets two more handles in Abi and two overrides in FfmBinding; utf8 is now written over a shared octets helper so the byte path and the string path copy the same way. The JNI side gets two natives, two shims, two lines in the ZU_SYMBOLS table and two in the registration table.

api/surface.txt is every addition and no removal, which is a minor release.

What was run

On a Linux host with JDK 25 and a libzu at the current engine revision, both providers, the whole TCK:

  • zudb-ffm: 209 tests, 0 failures
  • zudb-jni: 211 tests, 0 failures

That includes the 9 new BytesTest cases and the 3 new TableNameTest cases on each provider, so what is checked is that the two agree rather than that one of them works. scripts/build-shim.sh builds the C shim clean, and the Java compiles under -Xlint:all -Werror as everything here does.

This client was written against ABI 0.12 and the engine has moved twice
since. The whole of the gap is three symbols, and both of them that
matter bite a program that does nothing unusual: a byte string cell made
Type.of throw rather than answer, and a node carried a table id that
nothing here could turn into a name.
ZU_TYPE_BYTES is a type of its own rather than a string that happens to
hold octets, so this adds Value.Bytes, Type.BYTES and Row.getBytes
rather than widening Value.Str. A host that took the octets for a string
would decode them, and octets that are not UTF-8 do not survive that.
Value.Bytes writes out equals, hashCode and toString because a record
over an array compares by identity otherwise, and two byte strings
holding the same octets are one value. It spells itself in hex, which is
how the engine and the corpus both write one.
zu_conn_table_name is what turns the number in a Value.Node into the
name the statement wrote. Node and rel tables share one id space so one
call answers for both kinds, and an id no table has comes back null
rather than throwing, because asking is how a host finds out.
Both providers carry both calls: the FFM side gets two more handles in
Abi and two overrides, the JNI side two natives, two shims and two more
lines in the registration table. The TCK covers them, so what is checked
is that the two providers agree rather than that one of them works.
api/surface.txt is every addition and no removal, which is a minor
release.
The header this client vendors is now the engine's header byte for byte,
which is what CI has been checking all along and what nothing has
satisfied since the check was added.
Catching up to the file rather than to the version turned up four
exported functions the version does not mention. zu_error_subject_kind,
zu_error_subject, zu_error_graph and zu_error_schema arrived in
tamnd/zu#581 with ZU_ABI_VERSION left at 0.14, though the two commits
before it did bump. So reading the macro was never going to find them
and diffing the file was. I have filed that against the engine as
tamnd/zu#697.
The four carry what ISO 39075 subclause 23.2 asks a diagnostic record to
name: which thing the condition is about, what it is called, and the
graph and schema the statement was running in. The kind is kept as its
own word rather than glued to the front of the name, so asking whether a
failure is about a label is one string compared against one word, and an
editor that wants to underline the name gets the name with nothing
around it.
Both providers bind all four, and both TCK suites pass against a real
engine: 209 cases through Panama, 211 through JNI, 44 in the core, no
failures.
This changes the shape of two public members rather than only adding to
them. Diagnostic gains four components, so its canonical constructor and
its of factory both take fifteen arguments where they took eleven. By
the rule in README, a name that changes shape is a major release. Both
are the provider-facing way to build a record, so the callers this
breaks are provider implementations rather than programs that read rows,
but it breaks them and the surface file says so.
ZuException gains four accessors and Diagnostic four component readers,
and those are additions.
@tamnd
tamnd merged commit f3922d9 into mainAug 24, 2026
21 checks passed
@tamnd
tamnd deleted the tablename branch August 24, 2026 16:32
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.

1 participant

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

Catch the client up to ABI 0.14 - #17

Merged
tamnd merged 2 commits into
mainfrom
tablename
Aug 24, 2026
Merged

Catch the client up to ABI 0.14#17
tamnd merged 2 commits into
mainfrom
tablename

Conversation

@tamnd

Copy link
Copy Markdown
Owner

This client was written against ABI 0.12 and the engine has moved twice since. The whole of the gap is three additions to zu.h, and both of the ones that matter bite a program that does nothing unusual: a byte string cell made Type.of throw rather than answer, and a node carried a table id that nothing here could turn into a name.

ZU_TYPE_BYTES is a type of its own rather than a string that happens to hold octets, so this adds Value.Bytes, Type.BYTES and Row.getBytes rather than widening Value.Str. A host that took the octets for a string would decode them, and octets that are not UTF-8 do not survive that. Value.Bytes writes out equals, hashCode and toString because a record over an array compares by identity otherwise, and two byte strings holding the same octets are one value. It spells itself in hex, which is how the engine and the corpus both write one.

zu_conn_table_name is what turns the number in a Value.Node into the name the statement wrote, and it is what a corpus runner needs to spell a node as person#1. Node and rel tables share one id space so one call answers for both kinds, and an id no table has comes back null rather than throwing, because asking is how a host finds out. The doc on Value.Node.table() said the C ABI had no such call, which is no longer true, so it now points at Connection.tableName.

Both providers carry both calls. The FFM side gets two more handles in Abi and two overrides in FfmBinding; utf8 is now written over a shared octets helper so the byte path and the string path copy the same way. The JNI side gets two natives, two shims, two lines in the ZU_SYMBOLS table and two in the registration table.

api/surface.txt is every addition and no removal, which is a minor release.

What was run

On a Linux host with JDK 25 and a libzu at the current engine revision, both providers, the whole TCK:

  • zudb-ffm: 209 tests, 0 failures
  • zudb-jni: 211 tests, 0 failures

That includes the 9 new BytesTest cases and the 3 new TableNameTest cases on each provider, so what is checked is that the two agree rather than that one of them works. scripts/build-shim.sh builds the C shim clean, and the Java compiles under -Xlint:all -Werror as everything here does.

This client was written against ABI 0.12 and the engine has moved twice
since. The whole of the gap is three symbols, and both of them that
matter bite a program that does nothing unusual: a byte string cell made
Type.of throw rather than answer, and a node carried a table id that
nothing here could turn into a name.
ZU_TYPE_BYTES is a type of its own rather than a string that happens to
hold octets, so this adds Value.Bytes, Type.BYTES and Row.getBytes
rather than widening Value.Str. A host that took the octets for a string
would decode them, and octets that are not UTF-8 do not survive that.
Value.Bytes writes out equals, hashCode and toString because a record
over an array compares by identity otherwise, and two byte strings
holding the same octets are one value. It spells itself in hex, which is
how the engine and the corpus both write one.
zu_conn_table_name is what turns the number in a Value.Node into the
name the statement wrote. Node and rel tables share one id space so one
call answers for both kinds, and an id no table has comes back null
rather than throwing, because asking is how a host finds out.
Both providers carry both calls: the FFM side gets two more handles in
Abi and two overrides, the JNI side two natives, two shims and two more
lines in the registration table. The TCK covers them, so what is checked
is that the two providers agree rather than that one of them works.
api/surface.txt is every addition and no removal, which is a minor
release.
The header this client vendors is now the engine's header byte for byte,
which is what CI has been checking all along and what nothing has
satisfied since the check was added.
Catching up to the file rather than to the version turned up four
exported functions the version does not mention. zu_error_subject_kind,
zu_error_subject, zu_error_graph and zu_error_schema arrived in
tamnd/zu#581 with ZU_ABI_VERSION left at 0.14, though the two commits
before it did bump. So reading the macro was never going to find them
and diffing the file was. I have filed that against the engine as
tamnd/zu#697.
The four carry what ISO 39075 subclause 23.2 asks a diagnostic record to
name: which thing the condition is about, what it is called, and the
graph and schema the statement was running in. The kind is kept as its
own word rather than glued to the front of the name, so asking whether a
failure is about a label is one string compared against one word, and an
editor that wants to underline the name gets the name with nothing
around it.
Both providers bind all four, and both TCK suites pass against a real
engine: 209 cases through Panama, 211 through JNI, 44 in the core, no
failures.
This changes the shape of two public members rather than only adding to
them. Diagnostic gains four components, so its canonical constructor and
its of factory both take fifteen arguments where they took eleven. By
the rule in README, a name that changes shape is a major release. Both
are the provider-facing way to build a record, so the callers this
breaks are provider implementations rather than programs that read rows,
but it breaks them and the surface file says so.
ZuException gains four accessors and Diagnostic four component readers,
and those are additions.
@tamnd
tamnd merged commit f3922d9 into mainAug 24, 2026
21 checks passed
@tamnd
tamnd deleted the tablename branch August 24, 2026 16:32
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.

1 participant

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

Catch the client up to ABI 0.14 - #17

Merged
tamnd merged 2 commits into
mainfrom
tablename
Aug 24, 2026
Merged

Catch the client up to ABI 0.14#17
tamnd merged 2 commits into
mainfrom
tablename

Conversation

@tamnd

Copy link
Copy Markdown
Owner

This client was written against ABI 0.12 and the engine has moved twice since. The whole of the gap is three additions to zu.h, and both of the ones that matter bite a program that does nothing unusual: a byte string cell made Type.of throw rather than answer, and a node carried a table id that nothing here could turn into a name.

ZU_TYPE_BYTES is a type of its own rather than a string that happens to hold octets, so this adds Value.Bytes, Type.BYTES and Row.getBytes rather than widening Value.Str. A host that took the octets for a string would decode them, and octets that are not UTF-8 do not survive that. Value.Bytes writes out equals, hashCode and toString because a record over an array compares by identity otherwise, and two byte strings holding the same octets are one value. It spells itself in hex, which is how the engine and the corpus both write one.

zu_conn_table_name is what turns the number in a Value.Node into the name the statement wrote, and it is what a corpus runner needs to spell a node as person#1. Node and rel tables share one id space so one call answers for both kinds, and an id no table has comes back null rather than throwing, because asking is how a host finds out. The doc on Value.Node.table() said the C ABI had no such call, which is no longer true, so it now points at Connection.tableName.

Both providers carry both calls. The FFM side gets two more handles in Abi and two overrides in FfmBinding; utf8 is now written over a shared octets helper so the byte path and the string path copy the same way. The JNI side gets two natives, two shims, two lines in the ZU_SYMBOLS table and two in the registration table.

api/surface.txt is every addition and no removal, which is a minor release.

What was run

On a Linux host with JDK 25 and a libzu at the current engine revision, both providers, the whole TCK:

  • zudb-ffm: 209 tests, 0 failures
  • zudb-jni: 211 tests, 0 failures

That includes the 9 new BytesTest cases and the 3 new TableNameTest cases on each provider, so what is checked is that the two agree rather than that one of them works. scripts/build-shim.sh builds the C shim clean, and the Java compiles under -Xlint:all -Werror as everything here does.

This client was written against ABI 0.12 and the engine has moved twice
since. The whole of the gap is three symbols, and both of them that
matter bite a program that does nothing unusual: a byte string cell made
Type.of throw rather than answer, and a node carried a table id that
nothing here could turn into a name.
ZU_TYPE_BYTES is a type of its own rather than a string that happens to
hold octets, so this adds Value.Bytes, Type.BYTES and Row.getBytes
rather than widening Value.Str. A host that took the octets for a string
would decode them, and octets that are not UTF-8 do not survive that.
Value.Bytes writes out equals, hashCode and toString because a record
over an array compares by identity otherwise, and two byte strings
holding the same octets are one value. It spells itself in hex, which is
how the engine and the corpus both write one.
zu_conn_table_name is what turns the number in a Value.Node into the
name the statement wrote. Node and rel tables share one id space so one
call answers for both kinds, and an id no table has comes back null
rather than throwing, because asking is how a host finds out.
Both providers carry both calls: the FFM side gets two more handles in
Abi and two overrides, the JNI side two natives, two shims and two more
lines in the registration table. The TCK covers them, so what is checked
is that the two providers agree rather than that one of them works.
api/surface.txt is every addition and no removal, which is a minor
release.
The header this client vendors is now the engine's header byte for byte,
which is what CI has been checking all along and what nothing has
satisfied since the check was added.
Catching up to the file rather than to the version turned up four
exported functions the version does not mention. zu_error_subject_kind,
zu_error_subject, zu_error_graph and zu_error_schema arrived in
tamnd/zu#581 with ZU_ABI_VERSION left at 0.14, though the two commits
before it did bump. So reading the macro was never going to find them
and diffing the file was. I have filed that against the engine as
tamnd/zu#697.
The four carry what ISO 39075 subclause 23.2 asks a diagnostic record to
name: which thing the condition is about, what it is called, and the
graph and schema the statement was running in. The kind is kept as its
own word rather than glued to the front of the name, so asking whether a
failure is about a label is one string compared against one word, and an
editor that wants to underline the name gets the name with nothing
around it.
Both providers bind all four, and both TCK suites pass against a real
engine: 209 cases through Panama, 211 through JNI, 44 in the core, no
failures.
This changes the shape of two public members rather than only adding to
them. Diagnostic gains four components, so its canonical constructor and
its of factory both take fifteen arguments where they took eleven. By
the rule in README, a name that changes shape is a major release. Both
are the provider-facing way to build a record, so the callers this
breaks are provider implementations rather than programs that read rows,
but it breaks them and the surface file says so.
ZuException gains four accessors and Diagnostic four component readers,
and those are additions.
@tamnd
tamnd merged commit f3922d9 into mainAug 24, 2026
21 checks passed
@tamnd
tamnd deleted the tablename branch August 24, 2026 16:32
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.

1 participant

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

Catch the client up to ABI 0.14 - #17

Merged
tamnd merged 2 commits into
mainfrom
tablename
Aug 24, 2026
Merged

Catch the client up to ABI 0.14#17
tamnd merged 2 commits into
mainfrom
tablename

Conversation

@tamnd

Copy link
Copy Markdown
Owner

This client was written against ABI 0.12 and the engine has moved twice since. The whole of the gap is three additions to zu.h, and both of the ones that matter bite a program that does nothing unusual: a byte string cell made Type.of throw rather than answer, and a node carried a table id that nothing here could turn into a name.

ZU_TYPE_BYTES is a type of its own rather than a string that happens to hold octets, so this adds Value.Bytes, Type.BYTES and Row.getBytes rather than widening Value.Str. A host that took the octets for a string would decode them, and octets that are not UTF-8 do not survive that. Value.Bytes writes out equals, hashCode and toString because a record over an array compares by identity otherwise, and two byte strings holding the same octets are one value. It spells itself in hex, which is how the engine and the corpus both write one.

zu_conn_table_name is what turns the number in a Value.Node into the name the statement wrote, and it is what a corpus runner needs to spell a node as person#1. Node and rel tables share one id space so one call answers for both kinds, and an id no table has comes back null rather than throwing, because asking is how a host finds out. The doc on Value.Node.table() said the C ABI had no such call, which is no longer true, so it now points at Connection.tableName.

Both providers carry both calls. The FFM side gets two more handles in Abi and two overrides in FfmBinding; utf8 is now written over a shared octets helper so the byte path and the string path copy the same way. The JNI side gets two natives, two shims, two lines in the ZU_SYMBOLS table and two in the registration table.

api/surface.txt is every addition and no removal, which is a minor release.

What was run

On a Linux host with JDK 25 and a libzu at the current engine revision, both providers, the whole TCK:

  • zudb-ffm: 209 tests, 0 failures
  • zudb-jni: 211 tests, 0 failures

That includes the 9 new BytesTest cases and the 3 new TableNameTest cases on each provider, so what is checked is that the two agree rather than that one of them works. scripts/build-shim.sh builds the C shim clean, and the Java compiles under -Xlint:all -Werror as everything here does.

This client was written against ABI 0.12 and the engine has moved twice
since. The whole of the gap is three symbols, and both of them that
matter bite a program that does nothing unusual: a byte string cell made
Type.of throw rather than answer, and a node carried a table id that
nothing here could turn into a name.
ZU_TYPE_BYTES is a type of its own rather than a string that happens to
hold octets, so this adds Value.Bytes, Type.BYTES and Row.getBytes
rather than widening Value.Str. A host that took the octets for a string
would decode them, and octets that are not UTF-8 do not survive that.
Value.Bytes writes out equals, hashCode and toString because a record
over an array compares by identity otherwise, and two byte strings
holding the same octets are one value. It spells itself in hex, which is
how the engine and the corpus both write one.
zu_conn_table_name is what turns the number in a Value.Node into the
name the statement wrote. Node and rel tables share one id space so one
call answers for both kinds, and an id no table has comes back null
rather than throwing, because asking is how a host finds out.
Both providers carry both calls: the FFM side gets two more handles in
Abi and two overrides, the JNI side two natives, two shims and two more
lines in the registration table. The TCK covers them, so what is checked
is that the two providers agree rather than that one of them works.
api/surface.txt is every addition and no removal, which is a minor
release.
The header this client vendors is now the engine's header byte for byte,
which is what CI has been checking all along and what nothing has
satisfied since the check was added.
Catching up to the file rather than to the version turned up four
exported functions the version does not mention. zu_error_subject_kind,
zu_error_subject, zu_error_graph and zu_error_schema arrived in
tamnd/zu#581 with ZU_ABI_VERSION left at 0.14, though the two commits
before it did bump. So reading the macro was never going to find them
and diffing the file was. I have filed that against the engine as
tamnd/zu#697.
The four carry what ISO 39075 subclause 23.2 asks a diagnostic record to
name: which thing the condition is about, what it is called, and the
graph and schema the statement was running in. The kind is kept as its
own word rather than glued to the front of the name, so asking whether a
failure is about a label is one string compared against one word, and an
editor that wants to underline the name gets the name with nothing
around it.
Both providers bind all four, and both TCK suites pass against a real
engine: 209 cases through Panama, 211 through JNI, 44 in the core, no
failures.
This changes the shape of two public members rather than only adding to
them. Diagnostic gains four components, so its canonical constructor and
its of factory both take fifteen arguments where they took eleven. By
the rule in README, a name that changes shape is a major release. Both
are the provider-facing way to build a record, so the callers this
breaks are provider implementations rather than programs that read rows,
but it breaks them and the surface file says so.
ZuException gains four accessors and Diagnostic four component readers,
and those are additions.
@tamnd
tamnd merged commit f3922d9 into mainAug 24, 2026
21 checks passed
@tamnd
tamnd deleted the tablename branch August 24, 2026 16:32
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.

1 participant

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

Catch the client up to ABI 0.14 - #17

Merged
tamnd merged 2 commits into
mainfrom
tablename
Aug 24, 2026
Merged

Catch the client up to ABI 0.14#17
tamnd merged 2 commits into
mainfrom
tablename

Conversation

@tamnd

Copy link
Copy Markdown
Owner

This client was written against ABI 0.12 and the engine has moved twice since. The whole of the gap is three additions to zu.h, and both of the ones that matter bite a program that does nothing unusual: a byte string cell made Type.of throw rather than answer, and a node carried a table id that nothing here could turn into a name.

ZU_TYPE_BYTES is a type of its own rather than a string that happens to hold octets, so this adds Value.Bytes, Type.BYTES and Row.getBytes rather than widening Value.Str. A host that took the octets for a string would decode them, and octets that are not UTF-8 do not survive that. Value.Bytes writes out equals, hashCode and toString because a record over an array compares by identity otherwise, and two byte strings holding the same octets are one value. It spells itself in hex, which is how the engine and the corpus both write one.

zu_conn_table_name is what turns the number in a Value.Node into the name the statement wrote, and it is what a corpus runner needs to spell a node as person#1. Node and rel tables share one id space so one call answers for both kinds, and an id no table has comes back null rather than throwing, because asking is how a host finds out. The doc on Value.Node.table() said the C ABI had no such call, which is no longer true, so it now points at Connection.tableName.

Both providers carry both calls. The FFM side gets two more handles in Abi and two overrides in FfmBinding; utf8 is now written over a shared octets helper so the byte path and the string path copy the same way. The JNI side gets two natives, two shims, two lines in the ZU_SYMBOLS table and two in the registration table.

api/surface.txt is every addition and no removal, which is a minor release.

What was run

On a Linux host with JDK 25 and a libzu at the current engine revision, both providers, the whole TCK:

  • zudb-ffm: 209 tests, 0 failures
  • zudb-jni: 211 tests, 0 failures

That includes the 9 new BytesTest cases and the 3 new TableNameTest cases on each provider, so what is checked is that the two agree rather than that one of them works. scripts/build-shim.sh builds the C shim clean, and the Java compiles under -Xlint:all -Werror as everything here does.

This client was written against ABI 0.12 and the engine has moved twice
since. The whole of the gap is three symbols, and both of them that
matter bite a program that does nothing unusual: a byte string cell made
Type.of throw rather than answer, and a node carried a table id that
nothing here could turn into a name.
ZU_TYPE_BYTES is a type of its own rather than a string that happens to
hold octets, so this adds Value.Bytes, Type.BYTES and Row.getBytes
rather than widening Value.Str. A host that took the octets for a string
would decode them, and octets that are not UTF-8 do not survive that.
Value.Bytes writes out equals, hashCode and toString because a record
over an array compares by identity otherwise, and two byte strings
holding the same octets are one value. It spells itself in hex, which is
how the engine and the corpus both write one.
zu_conn_table_name is what turns the number in a Value.Node into the
name the statement wrote. Node and rel tables share one id space so one
call answers for both kinds, and an id no table has comes back null
rather than throwing, because asking is how a host finds out.
Both providers carry both calls: the FFM side gets two more handles in
Abi and two overrides, the JNI side two natives, two shims and two more
lines in the registration table. The TCK covers them, so what is checked
is that the two providers agree rather than that one of them works.
api/surface.txt is every addition and no removal, which is a minor
release.
The header this client vendors is now the engine's header byte for byte,
which is what CI has been checking all along and what nothing has
satisfied since the check was added.
Catching up to the file rather than to the version turned up four
exported functions the version does not mention. zu_error_subject_kind,
zu_error_subject, zu_error_graph and zu_error_schema arrived in
tamnd/zu#581 with ZU_ABI_VERSION left at 0.14, though the two commits
before it did bump. So reading the macro was never going to find them
and diffing the file was. I have filed that against the engine as
tamnd/zu#697.
The four carry what ISO 39075 subclause 23.2 asks a diagnostic record to
name: which thing the condition is about, what it is called, and the
graph and schema the statement was running in. The kind is kept as its
own word rather than glued to the front of the name, so asking whether a
failure is about a label is one string compared against one word, and an
editor that wants to underline the name gets the name with nothing
around it.
Both providers bind all four, and both TCK suites pass against a real
engine: 209 cases through Panama, 211 through JNI, 44 in the core, no
failures.
This changes the shape of two public members rather than only adding to
them. Diagnostic gains four components, so its canonical constructor and
its of factory both take fifteen arguments where they took eleven. By
the rule in README, a name that changes shape is a major release. Both
are the provider-facing way to build a record, so the callers this
breaks are provider implementations rather than programs that read rows,
but it breaks them and the surface file says so.
ZuException gains four accessors and Diagnostic four component readers,
and those are additions.
@tamnd
tamnd merged commit f3922d9 into mainAug 24, 2026
21 checks passed
@tamnd
tamnd deleted the tablename branch August 24, 2026 16:32
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.

1 participant

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

Catch the client up to ABI 0.14 - #17

Merged
tamnd merged 2 commits into
mainfrom
tablename
Aug 24, 2026
Merged

Catch the client up to ABI 0.14#17
tamnd merged 2 commits into
mainfrom
tablename

Conversation

@tamnd

Copy link
Copy Markdown
Owner

This client was written against ABI 0.12 and the engine has moved twice since. The whole of the gap is three additions to zu.h, and both of the ones that matter bite a program that does nothing unusual: a byte string cell made Type.of throw rather than answer, and a node carried a table id that nothing here could turn into a name.

ZU_TYPE_BYTES is a type of its own rather than a string that happens to hold octets, so this adds Value.Bytes, Type.BYTES and Row.getBytes rather than widening Value.Str. A host that took the octets for a string would decode them, and octets that are not UTF-8 do not survive that. Value.Bytes writes out equals, hashCode and toString because a record over an array compares by identity otherwise, and two byte strings holding the same octets are one value. It spells itself in hex, which is how the engine and the corpus both write one.

zu_conn_table_name is what turns the number in a Value.Node into the name the statement wrote, and it is what a corpus runner needs to spell a node as person#1. Node and rel tables share one id space so one call answers for both kinds, and an id no table has comes back null rather than throwing, because asking is how a host finds out. The doc on Value.Node.table() said the C ABI had no such call, which is no longer true, so it now points at Connection.tableName.

Both providers carry both calls. The FFM side gets two more handles in Abi and two overrides in FfmBinding; utf8 is now written over a shared octets helper so the byte path and the string path copy the same way. The JNI side gets two natives, two shims, two lines in the ZU_SYMBOLS table and two in the registration table.

api/surface.txt is every addition and no removal, which is a minor release.

What was run

On a Linux host with JDK 25 and a libzu at the current engine revision, both providers, the whole TCK:

  • zudb-ffm: 209 tests, 0 failures
  • zudb-jni: 211 tests, 0 failures

That includes the 9 new BytesTest cases and the 3 new TableNameTest cases on each provider, so what is checked is that the two agree rather than that one of them works. scripts/build-shim.sh builds the C shim clean, and the Java compiles under -Xlint:all -Werror as everything here does.

This client was written against ABI 0.12 and the engine has moved twice
since. The whole of the gap is three symbols, and both of them that
matter bite a program that does nothing unusual: a byte string cell made
Type.of throw rather than answer, and a node carried a table id that
nothing here could turn into a name.
ZU_TYPE_BYTES is a type of its own rather than a string that happens to
hold octets, so this adds Value.Bytes, Type.BYTES and Row.getBytes
rather than widening Value.Str. A host that took the octets for a string
would decode them, and octets that are not UTF-8 do not survive that.
Value.Bytes writes out equals, hashCode and toString because a record
over an array compares by identity otherwise, and two byte strings
holding the same octets are one value. It spells itself in hex, which is
how the engine and the corpus both write one.
zu_conn_table_name is what turns the number in a Value.Node into the
name the statement wrote. Node and rel tables share one id space so one
call answers for both kinds, and an id no table has comes back null
rather than throwing, because asking is how a host finds out.
Both providers carry both calls: the FFM side gets two more handles in
Abi and two overrides, the JNI side two natives, two shims and two more
lines in the registration table. The TCK covers them, so what is checked
is that the two providers agree rather than that one of them works.
api/surface.txt is every addition and no removal, which is a minor
release.
The header this client vendors is now the engine's header byte for byte,
which is what CI has been checking all along and what nothing has
satisfied since the check was added.
Catching up to the file rather than to the version turned up four
exported functions the version does not mention. zu_error_subject_kind,
zu_error_subject, zu_error_graph and zu_error_schema arrived in
tamnd/zu#581 with ZU_ABI_VERSION left at 0.14, though the two commits
before it did bump. So reading the macro was never going to find them
and diffing the file was. I have filed that against the engine as
tamnd/zu#697.
The four carry what ISO 39075 subclause 23.2 asks a diagnostic record to
name: which thing the condition is about, what it is called, and the
graph and schema the statement was running in. The kind is kept as its
own word rather than glued to the front of the name, so asking whether a
failure is about a label is one string compared against one word, and an
editor that wants to underline the name gets the name with nothing
around it.
Both providers bind all four, and both TCK suites pass against a real
engine: 209 cases through Panama, 211 through JNI, 44 in the core, no
failures.
This changes the shape of two public members rather than only adding to
them. Diagnostic gains four components, so its canonical constructor and
its of factory both take fifteen arguments where they took eleven. By
the rule in README, a name that changes shape is a major release. Both
are the provider-facing way to build a record, so the callers this
breaks are provider implementations rather than programs that read rows,
but it breaks them and the surface file says so.
ZuException gains four accessors and Diagnostic four component readers,
and those are additions.
@tamnd
tamnd merged commit f3922d9 into mainAug 24, 2026
21 checks passed
@tamnd
tamnd deleted the tablename branch August 24, 2026 16:32
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.

1 participant

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

Catch the client up to ABI 0.14 - #17

Merged
tamnd merged 2 commits into
mainfrom
tablename
Aug 24, 2026
Merged

Catch the client up to ABI 0.14#17
tamnd merged 2 commits into
mainfrom
tablename

Conversation

@tamnd

Copy link
Copy Markdown
Owner

This client was written against ABI 0.12 and the engine has moved twice since. The whole of the gap is three additions to zu.h, and both of the ones that matter bite a program that does nothing unusual: a byte string cell made Type.of throw rather than answer, and a node carried a table id that nothing here could turn into a name.

ZU_TYPE_BYTES is a type of its own rather than a string that happens to hold octets, so this adds Value.Bytes, Type.BYTES and Row.getBytes rather than widening Value.Str. A host that took the octets for a string would decode them, and octets that are not UTF-8 do not survive that. Value.Bytes writes out equals, hashCode and toString because a record over an array compares by identity otherwise, and two byte strings holding the same octets are one value. It spells itself in hex, which is how the engine and the corpus both write one.

zu_conn_table_name is what turns the number in a Value.Node into the name the statement wrote, and it is what a corpus runner needs to spell a node as person#1. Node and rel tables share one id space so one call answers for both kinds, and an id no table has comes back null rather than throwing, because asking is how a host finds out. The doc on Value.Node.table() said the C ABI had no such call, which is no longer true, so it now points at Connection.tableName.

Both providers carry both calls. The FFM side gets two more handles in Abi and two overrides in FfmBinding; utf8 is now written over a shared octets helper so the byte path and the string path copy the same way. The JNI side gets two natives, two shims, two lines in the ZU_SYMBOLS table and two in the registration table.

api/surface.txt is every addition and no removal, which is a minor release.

What was run

On a Linux host with JDK 25 and a libzu at the current engine revision, both providers, the whole TCK:

  • zudb-ffm: 209 tests, 0 failures
  • zudb-jni: 211 tests, 0 failures

That includes the 9 new BytesTest cases and the 3 new TableNameTest cases on each provider, so what is checked is that the two agree rather than that one of them works. scripts/build-shim.sh builds the C shim clean, and the Java compiles under -Xlint:all -Werror as everything here does.

This client was written against ABI 0.12 and the engine has moved twice
since. The whole of the gap is three symbols, and both of them that
matter bite a program that does nothing unusual: a byte string cell made
Type.of throw rather than answer, and a node carried a table id that
nothing here could turn into a name.
ZU_TYPE_BYTES is a type of its own rather than a string that happens to
hold octets, so this adds Value.Bytes, Type.BYTES and Row.getBytes
rather than widening Value.Str. A host that took the octets for a string
would decode them, and octets that are not UTF-8 do not survive that.
Value.Bytes writes out equals, hashCode and toString because a record
over an array compares by identity otherwise, and two byte strings
holding the same octets are one value. It spells itself in hex, which is
how the engine and the corpus both write one.
zu_conn_table_name is what turns the number in a Value.Node into the
name the statement wrote. Node and rel tables share one id space so one
call answers for both kinds, and an id no table has comes back null
rather than throwing, because asking is how a host finds out.
Both providers carry both calls: the FFM side gets two more handles in
Abi and two overrides, the JNI side two natives, two shims and two more
lines in the registration table. The TCK covers them, so what is checked
is that the two providers agree rather than that one of them works.
api/surface.txt is every addition and no removal, which is a minor
release.
The header this client vendors is now the engine's header byte for byte,
which is what CI has been checking all along and what nothing has
satisfied since the check was added.
Catching up to the file rather than to the version turned up four
exported functions the version does not mention. zu_error_subject_kind,
zu_error_subject, zu_error_graph and zu_error_schema arrived in
tamnd/zu#581 with ZU_ABI_VERSION left at 0.14, though the two commits
before it did bump. So reading the macro was never going to find them
and diffing the file was. I have filed that against the engine as
tamnd/zu#697.
The four carry what ISO 39075 subclause 23.2 asks a diagnostic record to
name: which thing the condition is about, what it is called, and the
graph and schema the statement was running in. The kind is kept as its
own word rather than glued to the front of the name, so asking whether a
failure is about a label is one string compared against one word, and an
editor that wants to underline the name gets the name with nothing
around it.
Both providers bind all four, and both TCK suites pass against a real
engine: 209 cases through Panama, 211 through JNI, 44 in the core, no
failures.
This changes the shape of two public members rather than only adding to
them. Diagnostic gains four components, so its canonical constructor and
its of factory both take fifteen arguments where they took eleven. By
the rule in README, a name that changes shape is a major release. Both
are the provider-facing way to build a record, so the callers this
breaks are provider implementations rather than programs that read rows,
but it breaks them and the surface file says so.
ZuException gains four accessors and Diagnostic four component readers,
and those are additions.
@tamnd
tamnd merged commit f3922d9 into mainAug 24, 2026
21 checks passed
@tamnd
tamnd deleted the tablename branch August 24, 2026 16:32
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.

1 participant

@tamnd