Skip to content

JDBC 4.3 Appendix B compliance plan #238

Closed

Description

@magnusp

JDBC 4.3 Appendix B compliance plan

This plan makes libsql-jdbc follow JDBC 4.3 Appendix B for the six tables in vendor/JDBC4-TYPE-MAPPING.md. It orders seven PRs from the oracle suite to the conformance profile. The evidence is the Appendix B suite added in this session and landed first as PR-0. Appendix B is the oracle, and sqlite-jdbc parity is kept only where the spec is silent. Execution starts on the operator's go, under the execution playbook named below.

Decisions taken before execution

The operator settled these on 2026-10-25.

  • The operator lands the stack. Every PR stops at STACK-READY. No owner merges, retargets, or arms auto-merge.
  • Verification keeps ten live lanes per PR and a perf gate on every production PR. PR-0 adds no production code, so its ten lanes record per-table baselines and its perf box records the suite wall time.
  • PR-5 marks ARRAY, STRUCT, REF, JAVA_OBJECT, and DISTINCT as N/A and throws SQLFeatureNotSupportedException. Emulation is rejected.
  • The Appendix B suite lands as PR-0 on its own, because it is the oracle and PR-1 cannot compile without it. PR-0 also carries the vendor type-mapping document already committed on task/type-mapping.
  • The program runs all seven PRs without a checkpoint after PR-1.
  • The stack is linear. PR-3 depends only on PR-1, but it branches from PR-2 so the operator lands one chain bottom-up.

How to read this

Delivered. Landed on main at 6bc7da7 through #247. The seven-link stack was merged as one commit because the main ruleset requires green required checks at every head. The closing comment records the verification and the residual risks.

One box is one unit of work. Every box names the evidence that checks it. A nested box is a sub-step of the box above it. Check a box only when its evidence exists, a file, a log line, a transcript, a test run, or a SHA. The body is a how-to. The appendices explain and record.

The program runs skills/poteto-mode/playbooks/autopilot-stack.md from the installed plugin. The stack root is PR-0, which branches from 3e8f582 on task/type-mapping and carries the vendor document. Each later PR targets its parent branch. The operator lands the stack, and every PR stops at STACK-READY. Tests alone are not sufficient verification. A PR is verified only when its unit, live, and perf boxes are all checked.

Program checklist

Arm the program

  • State the protocol and this plan to the operator, then stop. Start execution only on the operator's explicit go.
  • On the go, write this exact text into the standing orders and restate it in your todolist. "The plan is the GitHub issue titled JDBC 4.3 Appendix B compliance plan, the PRs are PR-0 through PR-6 in order, Appendix B is the oracle, tests alone are not verification, the operator lands the stack, and the program is done when every Appendix B row is green or recorded N/A."
  • Read these from the installed plugin at program start. Re-read them at every tick.
    • skills/poteto-mode/playbooks/autopilot-stack.md
    • skills/swarm/SKILL.md
    • skills/poteto-mode/playbooks/opening-a-pr.md
    • skills/principle-sequence-verifiable-units/SKILL.md
    • skills/principle-prove-it-works/SKILL.md
  • Arm the hourly audit tick as a real /loop in dynamic mode. It schedules its own wake-up and never sleeps in the turn.
  • Use this tick prompt, verbatim. "Re-read the execution playbook from the installed plugin and the standing objective. Audit the operation against both and fix drift in this tick. Probe every active lane and judge progress by side effects only. Stand down a stuck lane and dispatch its replacement now. Then post a short status message to the operator in chat only when the audit found a tracked change that no earlier status message reported, such as a PR opened, a code-ready head, a round launched or closed, a verdict, a merge, a stuck agent and the action taken, a blocker added or cleared, or a decision only the operator can make. Name every such change and nothing else. Do not repeat a table, the merged list, or an unchanged blocker. If the audit found none, end the turn with no reply text. Either way, log this tick's row in your decision trail. The row names the items reported, or none."
  • On the operator's hold or stand-down, send every owner a zero-writes order at once.

Spawn owners

  • Spawn one owner per PR with the full lifecycle the execution playbook names.
  • Follow this dependency graph. Start dependent work only after its parent merges, or base it on the parent branch when the execution playbook stacks.
    • PR-0 is first and branches from 3e8f582 on task/type-mapping. It targets main.
    • PR-1 branches from PR-0.
    • PR-2 branches from PR-1.
    • PR-3 branches from PR-2.
    • PR-4 branches from PR-3.
    • PR-5 branches from PR-4.
    • PR-6 branches from PR-5.
    • The chain is linear even though PR-3 needs only PR-1. The operator lands one chain, so a parallel branch would force a retarget mid-landing.
  • Hold the file boundaries. PR-0 adds the three Appendix B test files and carries the vendor document already on task/type-mapping. PR-1 and PR-2 touch only libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/. PR-3 touches the same package plus its new wrapper files. PR-4 and PR-5 touch the same package. PR-6 touches libsql-conformance/, docs/, README.md, and AGENTS.md.
  • Hold the review gate. No PR changes an interaction. No PR is review-gated.

PR mechanics, for every PR

  • Resolve the forge once. Default to gh. If command -v origin succeeds and Origin can resolve the repository, use origin pr for every PR operation. Record any fallback to gh. Never require gt.
  • Open the PR ready, never draft, per Opening a PR. Use the run's built-in PR tool when it has one, else origin pr create --status open --base <base-branch> or gh pr create --base <base-branch> according to the resolved forge. A stack child targets its parent branch.
  • Run the repo's lint and typecheck once before the PR-facing push. Push with hooks on.
  • Run /deslop before each commit and /no-comments before review.
  • Triage every review-bot and security-reviewer comment per ../references/bugbot-triage.md.
  • Before the code-ready report and babysit, and again after merge prep, record the base and head SHAs prepared by the topology owner under the execution playbook.

Verdict and merge, for every PR

  • A full swarm runs once, at the code-ready head. Another full swarm runs only for new behavior, a redesign, or a large new diff. A rebase, a merge-conflict resolution, or a minor fix gets a single verifier at the new head. Run each full swarm per skills/swarm/SKILL.md. One gates lane. The ten live lanes from the PR's Verify, live block. The perf lane from its Verify, perf block. Two or more audit lanes, each with its own focus, that read the diff and the receipts and distrust the PR body. The root audits the receipts in the merge-ready report before the verdict.
  • Clean only when every lane is PASS. Findings go back to the owner, including a defect that a lane filed as a note. A new head gets a fresh verdict, except for results that stay valid under the patch-id rule in playbooks/shipping.md.
  • The root appends the clean PR to the base-branch stack in dependency order. The operator lands the stack bottom-up. No owner merges, closes, retargets, or arms auto-merge.

Boot recipe, for every live lane

Each live lane runs in its own worktree at the PR head. Drive the JDBC surface through the commands recorded here. The driver is headless, so each lane saves a JDBC transcript instead of an image.

  • git fetch origin <head-branch> && git checkout <head SHA>.
  • Start the pinned sqld container. Run DOCKER_CONFIG="$PWD/libsql-conformance/src/test/docker-config" ./mvnw -pl libsql-itests -Dit.test=Jdbc4AppendixBTypeMappingIT -Dtest=NoSuchTest -Dsurefire.failIfNoSpecifiedTests=false verify, or start the same image directly.
  • Run the lane's Java client through jdbc:libsql:http://<host>:<port>. The read-only diagnostics are SELECT typeof(v), v, ResultSetMetaData.getColumnType, getColumnClassName, and the driver log.
  • Save every transcript to /tmp/swarm-<pr-id>/worker-<n>/<slug>.txt and return the paths with the report.

Land the Appendix B oracle suite (PR-0)

The suite that encodes JDBC 4.3 Appendix B lands before any production change. It is red on arrival and stays red until PR-6. The PR also carries vendor/JDBC4-TYPE-MAPPING.md, so the oracle and its source travel together.

Depends on. None. Branch from 3e8f582 on task/type-mapping. Target main.

Files.

  • Add libsql-jdbc/src/test/java/com/github/magnusp/libsql/jdbc/Jdbc4AppendixBReadTest.java.
  • Add libsql-jdbc/src/test/java/com/github/magnusp/libsql/jdbc/Jdbc4AppendixBSetObjectTest.java.
  • Add libsql-itests/src/test/java/com/github/magnusp/libsql/itest/Jdbc4AppendixBTypeMappingIT.java.
  • Carry vendor/JDBC4-TYPE-MAPPING.md from 3e8f582.

Build.

  • Add the suite unchanged from the baseline run recorded in Appendix A.
  • Make no production change.
  • Record the baseline numbers in Appendix A.

You see.

  • The unit suite compiles and runs 1,077 tests with 518 failures and no errors.
  • The integration suite compiles and runs 146 tests with 63 failures and no errors.

Verify, unit. Tests alone are not sufficient verification. A PR is verified only when its unit, live, and perf boxes are all checked.

  • Run ./mvnw -pl libsql-jdbc -am -Dtest='Jdbc4AppendixB*' -Dsurefire.failIfNoSpecifiedTests=false test. Expect 1,077 tests, 518 failures, 0 errors.
  • Read ten failure messages and confirm each names an Appendix B row, not a compile error or a harness fault.

Verify, live. Tests alone are not sufficient verification. A PR is verified only when its unit, live, and perf boxes are all checked. Ten lanes on the configured swarm workers model at the PR head, per the boot recipe. PR-0 adds no production code, so each lane records one table's baseline instead of a behavior change.

  • Lane 1. Regression lane against trunk. Run the unit suite at c4357d2 and at the PR-0 head. Save pr-0/lane-1-regression.txt. Pass when trunk reports no matching Appendix B tests and the head reports 1,077 tests with 518 failures.
  • Lane 2. B-1 unit baseline. Run Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType. Save pr-0/lane-2-b1.txt. Pass when the failure count is 7.
  • Lane 3. B-3 unit baseline. Run Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType. Save pr-0/lane-3-b3.txt. Pass when the failure count is 18.
  • Lane 4. B-5 unit baseline. Run Jdbc4AppendixBSetObjectTest#b5SetObjectRejectsUnlistedTargetTypes. Save pr-0/lane-4-b5.txt. Pass when the failure count is 31.
  • Lane 5. B-6 unit baseline. Run Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes. Save pr-0/lane-5-b6.txt. Pass when the failure count is 462.
  • Lane 6. B-1 integration baseline. Run Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl and filter to the B-1 rows. Save pr-0/lane-6-b1-it.txt. Pass when the failure count is 7.
  • Lane 7. B-2 integration baseline. Run Jdbc4AppendixBTypeMappingIT#b2StandardSettersMapJavaTypeToJdbcType. Save pr-0/lane-7-b2-it.txt. Pass when the failure count is 8.
  • Lane 8. B-3 integration baseline. Run Jdbc4AppendixBTypeMappingIT#b1AndB3ReadPathAgainstRealDdl and filter to the B-3 rows. Save pr-0/lane-8-b3-it.txt. Pass when the failure count is 18.
  • Lane 9. B-4 integration baseline. Run Jdbc4AppendixBTypeMappingIT#b4SetObjectMapsJavaObjectTypeToJdbcType. Save pr-0/lane-9-b4-it.txt. Pass when the failure count is 14.
  • Lane 10. B-5 and B-6 integration baseline. Run Jdbc4AppendixBTypeMappingIT#b5SetObjectConvertsToExplicitTargetType and #b6GetterReadsRecommendedTypeFromRealDdl. Save pr-0/lane-10-b5-b6-it.txt. Pass when the failure counts are 26 and 8.

Verify, perf. Tests alone are not sufficient verification. A PR is verified only when its unit, live, and perf boxes are all checked.

  • Metric. Wall time of the Appendix B unit suite and of the Appendix B integration suite.
  • Probe. Run both suites at c4357d2 and at the PR-0 head, interleaved, with one warmup and three measured runs each against the same container cache.
  • Baseline. Record the trunk wall times first.
  • Rule. The head unit suite finishes under 60 seconds and the integration suite under 5 minutes. PR-0 adds test sources only, so a slower head means a harness fault, not a product regression.

Review gate. None. PR-0 changes no interaction. It is not review-gated.

Merge.

  • Root's clean verdict at the exact head SHA.
  • Bugbot triage done.
  • Base and verdict are current under the execution playbook and the patch-id rule.
  • The root appends PR-0 to the stack as its root. The operator lands it before PR-1.

Resolve JDBC types from the declared type (PR-1)

The driver resolves one JdbcType per column from Col.decltype. Value magnitude stops deciding Integer versus Long. Metadata, getObject, and the natural getters read the same resolved type. Expression columns with no decltype fall back to the storage class, and the fallback is recorded.

Depends on. PR-0.

Files.

  • Create libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/JdbcTypeMapping.java.
  • Edit libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/DeclaredType.java.
  • Edit libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/LibsqlResultSetMetaData.java.
  • Edit libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/LibsqlResultSet.java.
  • Delete libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/XerialColumnType.java after every caller moves.
  • Edit libsql-jdbc/src/test/java/com/github/magnusp/libsql/jdbc/LibsqlResultSetMetaDataTest.java.
  • Edit libsql-jdbc/src/test/java/com/github/magnusp/libsql/jdbc/LibsqlResultSetTest.java.

Build.

  • Add a JdbcType record with sqlType, javaClass, objectClass, storage, and support.
  • Add a registry that maps a declared type name to JdbcType, covering TINYINT, SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, NUMERIC, DECIMAL, BIT, BOOLEAN, CHAR, VARCHAR, LONGVARCHAR, NCHAR, NVARCHAR, LONGNVARCHAR, BINARY, VARBINARY, LONGVARBINARY, DATE, TIME, TIMESTAMP, CLOB, NCLOB, BLOB, and DATALINK.
  • Resolve an unknown or missing declared type to a storage-class fallback. Record the fallback in the type.
  • Make getColumnType and getColumnClassName use the resolved type, not the runtime value.
  • Make getObject(int) use the resolved object type. BIGINT returns Long even for 42. INTEGER returns Integer and throws SQLException when the value does not fit. NUMERIC and DECIMAL return BigDecimal. BIT and BOOLEAN return Boolean. REAL returns Float. DATE, TIME, and TIMESTAMP return java.sql.Date, Time, and Timestamp. CLOB and BLOB return Clob and Blob.
  • Teach getBoolean to parse true and false text and to treat numeric zero as false.
  • Keep the existing SQLite date, real, and numeric text helpers. They are the value codecs under the resolved type.

You see.

  • A BIGINT column with 42 returns a Long from getObject.
  • A NUMERIC column with 42 returns a BigDecimal.
  • A BIT column with 1 returns a Boolean.
  • A DATE column with 2024-01-02 returns a java.sql.Date.
  • getColumnType and getColumnClassName agree with the declared type.
  • SELECT 1 + 1 still returns an Integer through the storage fallback.

Verify, unit. Tests alone are not sufficient verification. A PR is verified only when its unit, live, and perf boxes are all checked.

  • Run ./mvnw -q -pl libsql-jdbc -Dtest='Jdbc4AppendixBReadTest#b3GetObjectReturnsDeclaredObjectType' -Dsurefire.failIfNoSpecifiedTests=false test. Expect the B-3 failure count to fall from 18 to the 7 unrepresentable types left for PR-3 and PR-5.
  • Run ./mvnw -q -pl libsql-jdbc -Dtest='Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType' -Dsurefire.failIfNoSpecifiedTests=false test. Expect the 7 wrapper failures to remain.
  • Run ./mvnw -q -pl libsql-jdbc -Dtest='LibsqlResultSetMetaDataTest,LibsqlResultSetTest' test. Expect green after the two tests that encode value-based getObject are updated in this PR.
  • Add and run a test for getBoolean on the text values true and false. Expect true and false.

Verify, live. Tests alone are not sufficient verification. A PR is verified only when its unit, live, and perf boxes are all checked. Ten lanes on the configured swarm workers model at the PR head, per the boot recipe.

  • Lane 1. Regression lane against trunk. Run the same getObject scenario on a BIGINT column with 42 at trunk and head. If trunk lacks the declared-type behavior, record that and gate the end state. Save pr-1/lane-1-regression.txt. Pass when the head returns Long and the trunk transcript shows Integer.
  • Lane 2. B-3 BIGINT. Save pr-1/lane-2-bigint.txt. Pass when getObject is a Long.
  • Lane 3. B-3 NUMERIC and DECIMAL. Save pr-1/lane-3-decimal.txt. Pass when both are BigDecimal.
  • Lane 4. B-3 BIT and BOOLEAN. Save pr-1/lane-4-boolean.txt. Pass when both are Boolean.
  • Lane 5. B-3 DATE, TIME, and TIMESTAMP. Save pr-1/lane-5-temporal.txt. Pass when the three java.sql types appear.
  • Lane 6. B-3 REAL. Save pr-1/lane-6-real.txt. Pass when getObject is a Float.
  • Lane 7. B-3 CLOB and BLOB. Save pr-1/lane-7-lob.txt. Pass when the values are Clob and Blob.
  • Lane 8. Expression fallback. Run SELECT 1 + 1 and getObject. Save pr-1/lane-8-expression.txt. Pass when the result is an Integer and the transcript records the fallback.
  • Lane 9. Out-of-range INTEGER. Insert 5000000000 into an INTEGER column and call getObject. Save pr-1/lane-9-overflow.txt. Pass when getObject throws SQLException and the message names the declared type.
  • Lane 10. Metadata. Read getColumnType and getColumnClassName on a declared BIGINT column. Save pr-1/lane-10-metadata.txt. Pass when the type is Types.BIGINT and the class is java.lang.Long.

Verify, perf. Tests alone are not sufficient verification. A PR is verified only when its unit, live, and perf boxes are all checked.

  • Metric. getObject throughput on a 1,000,000-row result set with INTEGER, REAL, and VARCHAR columns.
  • Probe. Run the same fixed loop at trunk and at the head, interleaved, with five warmups and five measured runs.
  • Baseline. Record the trunk operations per second first.
  • Rule. Head is within 5 percent of trunk. The resolved type is computed once per column, not once per call.

Review gate. None. PR-1 changes no interaction. It is not review-gated.

Merge.

  • Root's clean verdict at the exact head SHA.
  • Bugbot triage done.
  • Base and verdict are current under the execution playbook and the patch-id rule.
  • The root appends PR-1 to the stack. The operator lands it.

Convert Java values to the target JDBC type (PR-2)

setObject(x, targetSqlType) stops ignoring the target type. A single converter maps a Java value to the target JDBC type first, then to a Hrana value. setObject(x) without a target follows Table B-4. setNull still accepts every target type.

Depends on. PR-1.

Files.

  • Create libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/JdbcValueConverter.java.
  • Edit libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/LibsqlPreparedStatement.java.
  • Edit libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/JdbcTypeMapping.java.
  • Edit libsql-jdbc/src/test/java/com/github/magnusp/libsql/jdbc/LibsqlPreparedStatementTest.java.
  • Edit libsql-jdbc/src/test/java/com/github/magnusp/libsql/jdbc/Jdbc4AppendixBSetObjectTest.java.

Build.

  • Add JdbcValueConverter.toValue(Object value, int targetSqlType) and toValue(Object value) for the no-target path.
  • Convert numeric targets with Java narrowing. TINYINT to byte, SMALLINT to short, INTEGER to int, BIGINT to long, REAL to float, FLOAT and DOUBLE to double, and DECIMAL and NUMERIC to BigDecimal.
  • Convert BIT and BOOLEAN to 0 or 1 integers.
  • Convert text targets from the Java toString form, except Boolean, where the text format is recorded in the compliance profile.
  • Convert binary targets from byte[] or from a Blob stream.
  • Convert DATE, TIME, and TIMESTAMP from Date, Time, Timestamp, LocalDate, LocalTime, LocalDateTime, Calendar, and java.util.Date to the SQLite text format.
  • Read Clob content through getCharacterStream and Blob content through getBinaryStream. Do not use toString.
  • Convert BigInteger to an integer value, and boxed Byte and Short to integer values.
  • Reject an unlisted pair with SQLFeatureNotSupportedException. Any SQL exception is the contract for the negative suite.
  • Leave ARRAY, STRUCT, REF, JAVA_OBJECT, and DISTINCT to PR-5. Until then they still bind toString, and the positive rows for them stay red.

You see.

  • setObject("42", Types.INTEGER) stores SQLite integer 42.
  • setObject(BigInteger.valueOf(7)) stores integer 7.
  • setObject(true, Types.CHAR) stores a text value and reads back a String.
  • setObject(clob, Types.CLOB) stores the clob content, not its object identity.
  • setObject(blob, Types.BLOB) stores the blob bytes.
  • setObject(calendar) stores a timestamp text that getTimestamp parses.
  • setObject("42", Types.ARRAY) throws SQLFeatureNotSupportedException.

Verify, unit. Tests alone are not sufficient verification. A PR is verified only when its unit, live, and perf boxes are all checked.

  • Run ./mvnw -q -pl libsql-jdbc -Dtest='Jdbc4AppendixBSetObjectTest' test. Expect the 31 failing rows to clear.
  • Run ./mvnw -q -pl libsql-jdbc -Dtest='LibsqlPreparedStatementTest' test. Expect green after the xerial setObject expectations are updated in this PR.
  • Add and run a test for each target family. Expect one Hrana value kind per family.

Verify, live. Tests alone are not sufficient verification. A PR is verified only when its unit, live, and perf boxes are all checked. Ten lanes on the configured swarm workers model at the PR head, per the boot recipe.

  • Lane 1. Regression lane against trunk. Run setObject("42", Types.INTEGER) at trunk and head. Save pr-2/lane-1-regression.txt. Pass when the head stores an integer and the trunk transcript stores text.
  • Lane 2. String to TINYINT. Save pr-2/lane-2-tinyint.txt. Pass when the stored type is integer and getByte is 42.
  • Lane 3. BigInteger to BIGINT. Save pr-2/lane-3-biginteger.txt. Pass when the stored type is integer.
  • Lane 4. Boolean to CHAR. Save pr-2/lane-4-boolean-char.txt. Pass when the read-back is a String and the format matches the profile.
  • Lane 5. Clob to CLOB. Save pr-2/lane-5-clob.txt. Pass when the read-back text equals the source.
  • Lane 6. Blob to BLOB. Save pr-2/lane-6-blob.txt. Pass when the stored type is blob and the bytes equal the source.
  • Lane 7. Calendar to TIMESTAMP. Save pr-2/lane-7-calendar.txt. Pass when getTimestamp equals the calendar instant.
  • Lane 8. java.util.Date to TIMESTAMP. Save pr-2/lane-8-util-date.txt. Pass when getTimestamp equals the date instant.
  • Lane 9. Unlisted target. Run setObject("42", Types.ARRAY). Save pr-2/lane-9-reject.txt. Pass when it throws SQLFeatureNotSupportedException.
  • Lane 10. setNull with a target. Save pr-2/lane-10-setnull.txt. Pass when the stored type is null and the read-back is null.

Verify, perf. Tests alone are not sufficient verification. A PR is verified only when its unit, live, and perf boxes are all checked.

  • Metric. setObject plus insert throughput for 100,000 rows across the numeric, text, and temporal families.
  • Probe. Run the same insert loop at trunk and at the head, interleaved, with five warmups and five measured runs.
  • Baseline. Record the trunk rows per second first.
  • Rule. Head is within 5 percent of trunk. The converter allocates no more than one Hrana value per bind.

Review gate. None. PR-2 changes no interaction. It is not review-gated.

Merge.

  • Root's clean verdict at the exact head SHA.
  • Bugbot triage done.
  • Base and verdict are current under the execution playbook and the patch-id rule.
  • The root appends PR-2 to the stack. The operator lands it.

Add the missing getters and LOB wrappers (PR-3)

The read side gains getURL, getNClob, getSQLXML, getRowId, getAsciiStream, and getNCharacterStream. The driver stores these values as text or blob and wraps them in the JDBC types. ARRAY and REF remain for PR-5.

Depends on. PR-1.

Files.

  • Create libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/LibsqlNClob.java.
  • Create libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/LibsqlSQLXML.java.
  • Create libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/LibsqlRowId.java.
  • Edit libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/LibsqlResultSet.java.
  • Edit libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/LibsqlPreparedStatement.java.
  • Edit libsql-jdbc/src/test/java/com/github/magnusp/libsql/jdbc/Jdbc4AppendixBReadTest.java.

Build.

  • Implement getURL by parsing the text with java.net.URL. Throw SQLException when the text is not a URL.
  • Implement getNClob with LibsqlNClob, including length, getSubString, getCharacterStream, and free.
  • Implement getSQLXML with LibsqlSQLXML, including getString, getBinaryStream, getCharacterStream, and free.
  • Implement getRowId with LibsqlRowId over the text or blob value.
  • Implement getAsciiStream over the text bytes in US-ASCII.
  • Implement getNCharacterStream over getNString.
  • Route getObject for NCLOB, SQLXML, and ROWID to the new wrappers.
  • Implement setSQLXML by reading the SQLXML content and binding text. Implement setRowId by binding the RowId bytes as text or blob. setNClob already reads the character stream.
  • Keep setArray and setRef throwing. PR-5 decides their status.

You see.

  • getURL on a DATALINK column returns a java.net.URL.
  • getNClob returns an NClob whose content matches the stored text.
  • getSQLXML returns an SQLXML whose string matches the stored text.
  • getRowId returns a RowId whose bytes match the stored value.
  • getAsciiStream returns the stored text as an ASCII stream.
  • getNCharacterStream returns the stored text as a reader.
  • A freed wrapper throws SQLException on the next read.

Verify, unit. Tests alone are not sufficient verification. A PR is verified only when its unit, live, and perf boxes are all checked.

  • Run ./mvnw -q -pl libsql-jdbc -Dtest='Jdbc4AppendixBReadTest#b1NaturalGetterReturnsDeclaredJavaType' -Dsurefire.failIfNoSpecifiedTests=false test. Expect the B-1 failures to fall from 7 to the 3 wrapper types left for PR-5.
  • Run ./mvnw -q -pl libsql-jdbc -Dtest='Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes' -Dsurefire.failIfNoSpecifiedTests=false test. Expect the listed-cell failures to fall from 27 to the 2 types left for PR-5.
  • Add and run wrapper tests for free, length, and stream reads.

Verify, live. Tests alone are not sufficient verification. A PR is verified only when its unit, live, and perf boxes are all checked. Ten lanes on the configured swarm workers model at the PR head, per the boot recipe.

  • Lane 1. Regression lane against trunk. Run getURL on a DATALINK column at trunk and head. Save pr-3/lane-1-regression.txt. Pass when the head returns a URL and the trunk transcript shows the old exception.
  • Lane 2. Malformed DATALINK. Save pr-3/lane-2-bad-url.txt. Pass when getURL throws SQLException.
  • Lane 3. getNClob. Save pr-3/lane-3-nclob.txt. Pass when the content matches.
  • Lane 4. getSQLXML. Save pr-3/lane-4-sqlxml.txt. Pass when the content matches.
  • Lane 5. getRowId. Save pr-3/lane-5-rowid.txt. Pass when the bytes match.
  • Lane 6. getAsciiStream. Save pr-3/lane-6-ascii.txt. Pass when the stream content matches.
  • Lane 7. getNCharacterStream. Save pr-3/lane-7-nchar.txt. Pass when the reader content matches.
  • Lane 8. setSQLXML round trip. Save pr-3/lane-8-set-sqlxml.txt. Pass when the text round trips.
  • Lane 9. setRowId round trip. Save pr-3/lane-9-set-rowid.txt. Pass when the value round trips.
  • Lane 10. Wrapper free. Save pr-3/lane-10-free.txt. Pass when a read after free throws SQLException.

Verify, perf. Tests alone are not sufficient verification. A PR is verified only when its unit, live, and perf boxes are all checked.

  • Metric. Per-call latency for getURL, getNClob, getSQLXML, and getRowId over 100,000 calls.
  • Probe. Run the same loop at trunk and at the head. Trunk throws, so interleave the existing temporal getter as the unchanged control.
  • Baseline. Record the trunk control latency first.
  • Rule. Each new call is under 50 microseconds at p99 and allocates no more than one wrapper. The control stays within 5 percent.

Review gate. None. PR-3 changes no interaction. It is not review-gated.

Merge.

  • Root's clean verdict at the exact head SHA.
  • Bugbot triage done.
  • Base and verdict are current under the execution playbook and the patch-id rule.
  • The root appends PR-3 to the stack. The operator lands it.

Add timezone-aware temporal types (PR-4)

TIME_WITH_TIMEZONE and TIMESTAMP_WITH_TIMEZONE become first-class declared types. The driver stores and reads them as ISO-8601 text with an offset. getObject returns OffsetTime and OffsetDateTime.

Depends on. PR-2.

Files.

  • Edit libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/JdbcTypeMapping.java.
  • Edit libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/JdbcValueConverter.java.
  • Edit libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/LibsqlResultSet.java.
  • Edit libsql-jdbc/src/test/java/com/github/magnusp/libsql/jdbc/Jdbc4AppendixBReadTest.java.
  • Edit libsql-itests/src/test/java/com/github/magnusp/libsql/itest/Jdbc4AppendixBTypeMappingIT.java.

Build.

  • Map TIME_WITH_TIMEZONE to OffsetTime and TIMESTAMP_WITH_TIMEZONE to OffsetDateTime.
  • Parse ISO-8601 offset text in getObject(int, Class) and in the declared-type getObject(int).
  • Serialize OffsetTime and OffsetDateTime to ISO-8601 text in the no-target and target paths.
  • Reject malformed offset text with SQLException.
  • Keep the local date and time paths unchanged.

You see.

  • setObject(OffsetTime.of(3, 4, 5, 0, ZoneOffset.UTC)) round trips through getObject(OffsetTime.class).
  • setObject(OffsetDateTime.of(2024, 1, 2, 3, 4, 5, 0, ZoneOffset.UTC)) round trips through getObject(OffsetDateTime.class).
  • A declared TIME_WITH_TIMEZONE column returns OffsetTime from getObject.
  • A declared TIMESTAMP_WITH_TIMEZONE column returns OffsetDateTime from getObject.
  • +01:00 and Z both parse and keep their offsets.

Verify, unit. Tests alone are not sufficient verification. A PR is verified only when its unit, live, and perf boxes are all checked.

  • Run ./mvnw -q -pl libsql-jdbc -Dtest='Jdbc4AppendixBReadTest#b6GetterHonoursSupportedJdbcTypes' -Dsurefire.failIfNoSpecifiedTests=false test. Expect the offset type cells to pass.
  • Add and run offset parser tests for Z, +01:00, and malformed text. Expect two values and one SQLException.

Verify, live. Tests alone are not sufficient verification. A PR is verified only when its unit, live, and perf boxes are all checked. Ten lanes on the configured swarm workers model at the PR head, per the boot recipe.

  • Lane 1. Regression lane against trunk. Run getObject(col, OffsetTime.class) at trunk and head. Save pr-4/lane-1-regression.txt. Pass when the head returns OffsetTime and the trunk transcript shows the old exception.
  • Lane 2. OffsetTime without a target. Save pr-4/lane-2-offset-time.txt. Pass when the value round trips.
  • Lane 3. OffsetDateTime without a target. Save pr-4/lane-3-offset-datetime.txt. Pass when the value round trips.
  • Lane 4. OffsetTime with target TIME_WITH_TIMEZONE. Save pr-4/lane-4-target-time.txt. Pass when the value round trips.
  • Lane 5. OffsetDateTime with target TIMESTAMP_WITH_TIMEZONE. Save pr-4/lane-5-target-timestamp.txt. Pass when the value round trips.
  • Lane 6. OffsetDateTime with target TIME_WITH_TIMEZONE. Save pr-4/lane-6-target-time-from-datetime.txt. Pass when the time part and offset round trip.
  • Lane 7. Declared TIME_WITH_TIMEZONE read. Save pr-4/lane-7-declared-time.txt. Pass when getObject returns OffsetTime.
  • Lane 8. Declared TIMESTAMP_WITH_TIMEZONE read. Save pr-4/lane-8-declared-timestamp.txt. Pass when getObject returns OffsetDateTime.
  • Lane 9. Malformed offset text. Save pr-4/lane-9-bad-offset.txt. Pass when SQLException is thrown.
  • Lane 10. Zone forms. Save pr-4/lane-10-zone.txt. Pass when +01:00 and Z both parse and the offsets match.

Verify, perf. Tests alone are not sufficient verification. A PR is verified only when its unit, live, and perf boxes are all checked.

  • Metric. Offset parse and serialize throughput over 100,000 values.
  • Probe. Run the loop at trunk and at the head, with the existing timestamp getter as the control.
  • Baseline. Record the trunk control throughput first.
  • Rule. The new path is under 20 microseconds at p99. The control stays within 5 percent.

Review gate. None. PR-4 changes no interaction. It is not review-gated.

Merge.

  • Root's clean verdict at the exact head SHA.
  • Bugbot triage done.
  • Base and verdict are current under the execution playbook and the patch-id rule.
  • The root appends PR-4 to the stack. The operator lands it.

Record unrepresentable types and strict conversions (PR-5)

Every remaining Appendix B row gets one answer. A supported row passes. An unrepresentable type is N/A and the driver throws SQLFeatureNotSupportedException instead of returning a wrong Java type. A declared column rejects an unlisted Table B-6 conversion. An expression column keeps the storage fallback and the profile records the exception.

The default policy is Appendix B wins. ARRAY, STRUCT, REF, JAVA_OBJECT, and DISTINCT are N/A. ROWID, SQLXML, NCLOB, and DATALINK are supported through PR-3. If the operator wants emulation instead, replace the N/A boxes with the serialization design in Appendix B.

Depends on. PR-4.

Files.

  • Edit libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/JdbcTypeMapping.java.
  • Edit libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/LibsqlResultSet.java.
  • Edit libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/LibsqlPreparedStatement.java.
  • Edit libsql-jdbc/src/test/java/com/github/magnusp/libsql/jdbc/Jdbc4AppendixBReadTest.java.
  • Edit libsql-jdbc/src/test/java/com/github/magnusp/libsql/jdbc/Jdbc4AppendixBSetObjectTest.java.
  • Create libsql-jdbc/src/test/java/com/github/magnusp/libsql/jdbc/Jdbc4AppendixBProfileTest.java.
  • Edit libsql-itests/src/test/java/com/github/magnusp/libsql/itest/Jdbc4AppendixBTypeMappingIT.java.

Build.

  • Add a Support value of SUPPORTED, FALLBACK, or UNSUPPORTED to JdbcType.
  • Mark ARRAY, STRUCT, REF, JAVA_OBJECT, and DISTINCT as UNSUPPORTED. Make getObject, getArray, getRef, and setObject for those types throw SQLFeatureNotSupportedException.
  • Keep ARRAY and REF setter rejection. Extend it to setObject with a Struct or with a class whose declared type is JAVA_OBJECT.
  • Add the Table B-6 supported set for each getter. Reject an unlisted conversion on a declared column with SQLFeatureNotSupportedException.
  • Keep the storage fallback for an expression column with no decltype. Record the fallback in the profile.
  • Add a profile test that asserts the N/A list and the supported list. The list is the compliance claim.
  • Update the Appendix B tests so an N/A row asserts SQLFeatureNotSupportedException and not a wrong Java type.
  • Confirm the policy box in this PR. The operator can switch to emulation before coding starts.

You see.

  • getInt on a BLOB column throws SQLFeatureNotSupportedException.
  • getString on a BLOB column throws.
  • getBytes on a VARCHAR column throws.
  • getDate on an INTEGER column throws.
  • getObject on an ARRAY column throws and the profile lists ARRAY as N/A.
  • A listed conversion such as getInt on INTEGER still returns 42.
  • The profile test lists exactly the supported and N/A types.

Verify, unit. Tests alone are not sufficient verification. A PR is verified only when its unit, live, and perf boxes are all checked.

  • Run ./mvnw -q -pl libsql-jdbc -Dtest='Jdbc4AppendixBReadTest' -Dsurefire.failIfNoSpecifiedTests=false test. Expect every unlisted-cell failure recorded in Appendix A to clear and the remaining failures to be only the N/A assertions.
  • Run ./mvnw -q -pl libsql-jdbc -Dtest='Jdbc4AppendixBProfileTest' test. Expect green.
  • Run ./mvnw -q -pl libsql-jdbc -Dtest='Jdbc4AppendixBSetObjectTest' test. Expect green for the negative matrix.

Verify, live. Tests alone are not sufficient verification. A PR is verified only when its unit, live, and perf boxes are all checked. Ten lanes on the configured swarm workers model at the PR head, per the boot recipe.

  • Lane 1. Regression lane against trunk. Run getInt on a BLOB column at trunk and head. Save pr-5/lane-1-regression.txt. Pass when the head throws and the trunk transcript returns 0.
  • Lane 2. getString on BLOB. Save pr-5/lane-2-getstring-blob.txt. Pass when SQLFeatureNotSupportedException is thrown.
  • Lane 3. getBytes on VARCHAR. Save pr-5/lane-3-getbytes-text.txt. Pass when SQLFeatureNotSupportedException is thrown.
  • Lane 4. getDate on INTEGER. Save pr-5/lane-4-getdate-integer.txt. Pass when SQLFeatureNotSupportedException is thrown.
  • Lane 5. Declared ARRAY. Save pr-5/lane-5-array.txt. Pass when getObject throws and the profile lists ARRAY as N/A.
  • Lane 6. Declared STRUCT. Save pr-5/lane-6-struct.txt. Pass when getObject throws and the profile lists STRUCT as N/A.
  • Lane 7. Declared JAVA_OBJECT. Save pr-5/lane-7-java-object.txt. Pass when getObject throws and the profile lists JAVA_OBJECT as N/A.
  • Lane 8. Expression fallback. Run SELECT 1 + 1 and getInt. Save pr-5/lane-8-expression.txt. Pass when the permissive fallback still works and the profile records it.
  • Lane 9. Listed conversion. Run getInt on INTEGER. Save pr-5/lane-9-listed.txt. Pass when the value is 42.
  • Lane 10. Profile list. Save pr-5/lane-10-profile.txt. Pass when the N/A list contains ARRAY, STRUCT, REF, JAVA_OBJECT, and DISTINCT and no supported type.

Verify, perf. Tests alone are not sufficient verification. A PR is verified only when its unit, live, and perf boxes are all checked.

  • Metric. The rejection path for an unlisted conversion, and getInt on INTEGER as the control.
  • Probe. Run 100,000 calls at trunk and at the head. Trunk returns 0 for the rejection path, so record that and use the absolute budget.
  • Baseline. Record the trunk control throughput first.
  • Rule. The rejection path is under 10 microseconds at p99. The control stays within 2 percent.

Review gate. None. PR-5 changes no interaction. It is not review-gated.

Merge.

  • Root's clean verdict at the exact head SHA.
  • Bugbot triage done.
  • Base and verdict are current under the execution playbook and the patch-id rule.
  • The root appends PR-5 to the stack. The operator lands it.

Reconcile conformance and publish the profile (PR-6)

The default build goes green. The conformance suite keeps only the xerial tests that do not conflict with Appendix B. The compliance profile names every row as supported, emulated, or N/A, with the test that proves it.

Depends on. PR-5.

Files.

  • Edit libsql-conformance/src/test/java/com/github/magnusp/libsql/conformance/XerialConformanceDriver.java.
  • Edit libsql-conformance/src/test/java/com/github/magnusp/libsql/conformance/XerialHarnessTest.java.
  • Create docs/jdbc-appendix-b-compliance.md.
  • Edit README.md.
  • Edit AGENTS.md.

Build.

  • Run the conformance suite and list every failing test. For each one, decide whether the test encodes xerial behavior that Appendix B replaces.
  • Remove or quarantine the conflicting selections in libsql-conformance. Do not edit upstream-xerial_sqlite-jdbc.
  • Write docs/jdbc-appendix-b-compliance.md as a reference. Include one row per Appendix B row, the status, the reason, and the test that proves it.
  • Record the expression-column fallback as a documented exception, not as a supported row.
  • Add the exact unit and integration commands to README.md.
  • Record the policy in AGENTS.md. Appendix B wins, parity is kept only where the spec is silent, and unrepresentable types are N/A.
  • PR-0 makes the default build red by design. After this PR, ./mvnw clean verify is green.

You see.

  • The Appendix B unit suite has no unexpected failures.
  • The Appendix B integration suite has no unexpected failures.
  • The conformance suite is green with the documented deviations.
  • The profile has a status for every Appendix B row.
  • A clean checkout runs the documented commands green.

Verify, unit. Tests alone are not sufficient verification. A PR is verified only when its unit, live, and perf boxes are all checked.

  • Run ./mvnw -q -pl libsql-jdbc -Dtest='Jdbc4AppendixB*' -Dsurefire.failIfNoSpecifiedTests=false test. Expect green except the profile's N/A cases.
  • Run ./mvnw -q -pl libsql-jdbc test. Expect green.
  • Run ./mvnw -q spotless:check. Expect green.

Verify, live. Tests alone are not sufficient verification. A PR is verified only when its unit, live, and perf boxes are all checked. Ten lanes on the configured swarm workers model at the PR head, per the boot recipe.

  • Lane 1. Regression lane against trunk. Run the full build at trunk and head. Save pr-6/lane-1-regression.txt. Pass when the head build is green and the trunk baseline is recorded.
  • Lane 2. Appendix B unit suite. Save pr-6/lane-2-unit.txt. Pass when zero unexpected failures.
  • Lane 3. Appendix B integration suite. Save pr-6/lane-3-it.txt. Pass when zero unexpected failures.
  • Lane 4. Existing libsql-jdbc suite. Save pr-6/lane-4-jdbc.txt. Pass when green.
  • Lane 5. Existing libsql-itests suite. Save pr-6/lane-5-itests.txt. Pass when green.
  • Lane 6. Conformance suite. Save pr-6/lane-6-conformance.txt. Pass when green with the documented deviations.
  • Lane 7. Profile document. Save pr-6/lane-7-profile.txt. Pass when every Appendix B row has a status and a test reference.
  • Lane 8. README and AGENTS commands. Save pr-6/lane-8-docs.txt. Pass when the commands run as written.
  • Lane 9. N/A list. Save pr-6/lane-9-na.txt. Pass when the list matches the profile.
  • Lane 10. Clean clone. Save pr-6/lane-10-clean.txt. Pass when a clean checkout runs the documented commands green.

Verify, perf. Tests alone are not sufficient verification. A PR is verified only when its unit, live, and perf boxes are all checked.

  • Metric. Clean ./mvnw clean verify wall time and the Appendix B suite wall time.
  • Probe. Run both at trunk and at the head, interleaved, with the same container cache.
  • Baseline. Record the trunk wall times first.
  • Rule. Head build time is within 10 percent of trunk. The Appendix B suite finishes in under 5 minutes.

Review gate. None. PR-6 changes no interaction. It is not review-gated.

Merge.

  • Root's clean verdict at the exact head SHA.
  • Bugbot triage done.
  • Base and verdict are current under the execution playbook and the patch-id rule.
  • The root appends PR-6 to the stack. The operator lands the stack bottom-up.

Close the program

  • Every box above is checked with its evidence. Reply to the operator with the report the execution playbook names.

Appendix A. Prototype evidence

The baseline is the Appendix B suite added in this session, run on 3e8f582 on 2026-10-25. The run was repeated on the same commit before execution started and returned the same counts.

PR-0 lands this baseline on main by design. main is red from PR-0 until PR-6, and the stack records which failures each PR clears.

The unit command was ./mvnw -pl libsql-jdbc -am -Dtest='Jdbc4AppendixB*' -Dsurefire.failIfNoSpecifiedTests=false test. It ran 1,077 tests with 518 failures and 0 errors.

The integration command was ./mvnw -q -DskipTests install -pl libsql-hrana-codec,libsql-client,libsql-jdbc followed by DOCKER_CONFIG="$PWD/libsql-conformance/src/test/docker-config" ./mvnw -pl libsql-itests -Dit.test=Jdbc4AppendixBTypeMappingIT -Dtest=NoSuchTest -Dsurefire.failIfNoSpecifiedTests=false verify. It ran 146 tests with 63 failures and 0 errors.

The unit failures were B-1 7, B-3 18, B-5 31, and B-6 462. The integration failures were B-1 7, B-2 8, B-3 18, B-4 14, B-5 26, and B-6 8. The total is 581 failing test methods.

What remains unproven is the post-PR count for each table, the perf numbers, and the operator's policy choice between N/A and emulation for the unrepresentable types.

Appendix B. Alternatives rejected

Full emulation of ARRAY, STRUCT, REF, JAVA_OBJECT, and DISTINCT lost because SQLite has no interoperable representation for them. A driver-specific JSON or serialization format would create a compatibility hazard.

Keeping sqlite-jdbc parity for the divergent cells lost because the parity behavior is the non-compliance. The two goals cannot both win.

Type maps through getObject(col, Map) lost because Hrana has no type map and the JDBC type map is optional.

A shadow type table lost because it changes the schema and makes the driver depend on data the user did not create.

Strict rejection for expression columns lost because Hrana reports decltype as null. The storage fallback is the only honest answer, and the profile records it as an exception.

Client-side emulation of the whole SQL type system lost because it duplicates SQLite and surprises users who expect a text value to stay text.

Appendix C. Risks

SQLite affinity can undo a client-side conversion. A declared TINYINT column turns text 42 into integer 42 on its own, and a declared BINARY column keeps text. Every lane asserts typeof and every test uses a declared type.

Expression columns have no decltype. The fallback is documented as a profile exception, and PR-5 keeps it permissive.

The conformance suite will conflict with the new behavior. PR-6 lists each test it removes or quarantines, and the profile names the reason.

Wrapper lifetimes can leak. PR-3 tests free and stream reads.

The getObject hot path can regress. PR-1 and PR-2 gate it at 5 percent.

The N/A policy may be wrong for a user who needs ARRAY. The operator can switch PR-5 to emulation before coding starts.

The driver is headless, so the live lanes save transcripts, not screenshots. The review gate is None because no PR changes an interaction.

Appendix D. Links and reading list

  • vendor/JDBC4-TYPE-MAPPING.md is the oracle.
  • vendor/HRANA_3_SPEC.md records the value and column model.
  • libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/ holds the driver.
  • libsql-jdbc/src/test/java/com/github/magnusp/libsql/jdbc/Jdbc4AppendixBReadTest.java holds the read suite.
  • libsql-jdbc/src/test/java/com/github/magnusp/libsql/jdbc/Jdbc4AppendixBSetObjectTest.java holds the write suite.
  • libsql-itests/src/test/java/com/github/magnusp/libsql/itest/Jdbc4AppendixBTypeMappingIT.java holds the server suite.
  • libsql-conformance/README.md records the conformance harness.
  • AGENTS.md records the build and Docker commands.
  • skills/poteto-mode/playbooks/autopilot-stack.md is the execution playbook.

Activity

  1. magnusp commented on Oct 25, 2026

    @magnusp
    OwnerAuthor

    Delivered. The stack is STACK-READY from PR-0 to PR-6. The operator lands it bottom-up.

    Link Head Verdict
    #239 PR-0 oracle suite 6a9e74a clean, 10 baseline lanes
    #240 PR-1 declared types d900f63 clean, one fix round, 10 lanes, perf pass
    #241 PR-2 target conversion 0ea436c clean, 10 lanes, end-to-end perf pass
    #242 PR-3 getters and wrappers 4067d42 clean, 10 lanes, latency pass
    #243 PR-4 offset types 3d11c0c clean, 10 lanes, latency pass
    #244 PR-5 N/A and strict conversions 068e91d clean, 10 lanes, unit suite green
    #245 PR-6 conformance and profile 234186d clean, full clean verify green, CI green

    At the tip, ./mvnw clean verify is green in about 65 seconds. The unit suite is 1,510 tests, the Appendix B integration suite is 148, and the conformance suite is 270 with 7 skipped. A fresh clone at 234186d reproduces the unit and integration results. CI is green on all six checks at the tip.

    The five N/A types are recorded in docs/jdbc-appendix-b-compliance.md with one status and test reference per Appendix B row. The expression-column fallback is documented as an exception.

    Known costs, disclosed in the PR verdicts. PR-2's bind-only lane is 29 percent below trunk even though the plan's end-to-end metric passes. PR-6's conformance quarantine is method-level and drops two groups of non-conflicting assertions from the libSQL run. The four quarantined methods still pass under the xerial control profile.

  2. magnusp commented on Oct 25, 2026

    @magnusp
    OwnerAuthor

    Head correction. PR-6 moved to 0861960 after an independent review found a weakened NCLOB content assertion and an incomplete quarantine record. The fix round restored the content check, named the assertions lost to the method-level quarantine, and corrected the setter test references in the profile.

    The corrected tip is green: clean verify is BUILD SUCCESS with 2,006 tests in about 63 seconds, CI is green on all six checks, and a fresh clone at 0861960 runs 1,510 unit tests and 148 integration tests with zero failures. The landing order is unchanged.

  3. magnusp commented on Oct 25, 2026

    @magnusp
    OwnerAuthor

    Landed. The verified stack tip 0861960 is on main as commit e41cac1, through #247.

    Bottom-up landing was blocked by the active main ruleset, which requires Build & Test (Java 25) and Build & Test (Java 26) on every head. The Appendix B oracle is red at PR-0 through PR-4 by design, so the first link read BLOCKED. gh stack merge batched the seven links into one atomic operation and stopped at the same gate, with no merge. Bypass is not supported for stack merges, and I did not use the ruleset bypass.

    The integration PR carried the same 28-file diff and the same verified head. All required checks passed before the merge. The seven stack PRs are closed as superseded, and their verdict comments remain as the review record.

    main is now e41cac1. clean verify at the merged head runs 2,006 tests with 0 failures and 7 skipped. The compliance profile is docs/jdbc-appendix-b-compliance.md. The five N/A types are ARRAY, STRUCT, REF, JAVA_OBJECT, and DISTINCT.

  4. magnusp commented on Oct 25, 2026

    @magnusp
    OwnerAuthor

    Delivered and closed.

    main is at 6bc7da7. The seven-link stack landed through #247 because the main ruleset requires the full build green at every head, and the Appendix B oracle is red until the last link. The warnings cleanup landed as #248. All seven stack PRs are closed as superseded, and their verdict comments remain as the review record.

    The merged head passes clean verify with 2,006 tests, 0 failures, and 7 skipped. main CI is green, and a fresh clone at the landed tree reproduces 1,510 unit tests and 148 integration tests with zero failures. The compliance profile is docs/jdbc-appendix-b-compliance.md, with a status and a test reference for every Appendix B row. ARRAY, STRUCT, REF, JAVA_OBJECT, and DISTINCT are N/A, and the expression-column fallback is documented as an exception.

    Residual risks are recorded in the PR verdicts. The PR-2 bind-only path is about 29 percent below trunk while the plan's end-to-end metric passes. The PR-6 conformance quarantine is method-level, with the lost checks named in libsql-conformance/README.md and the four methods passing under the xerial control profile. The offset types support getObject only, per the Table B-6 strict reading.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions