Skip to content

SK-3061: revert fields→tokens rename, restore data field on bulkInsert response - #408

Merged
Devesh-Skyflow merged 15 commits into
flowvault-release/26.8.13from
devesh/sk-3061
Aug 13, 2026
Merged

SK-3061: revert fields→tokens rename, restore data field on bulkInsert response#408
Devesh-Skyflow merged 15 commits into
flowvault-release/26.8.13from
devesh/sk-3061

Conversation

@Devesh-Skyflow

@Devesh-SkyflowDevesh-Skyflow commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes the deviations from the FlowVault API contract flagged in this Slack thread, plus a documentation/samples cleanup pass that grew out of it.

⚠️ Breaking change (item 6), already regenerated:InsertResponseRecord/BulkInsertResponseRecord's deprecated constructors and getFields() had their tokens generics change. The japicmp baseline (flowvault/api-report/skyflow-flowvault-java.baseline.jar) has been regenerated via scripts/contract-snapshot-update.sh flowvault and is included in this PR — mvn -pl common,flowvault -am verify passes clean against it (confirmed locally once a JDK/Maven became available partway through review; see item 6 and the Testing section for the full picture, including which parts of this turned out to be avoidable and were declined on purpose).

1. Response contract fix

  1. fieldstokens: the SDK had renamed the API's tokens response key to fields, so callers needed getFields() instead of the API-matching getTokens(). Reverted the rename; getFields() stays as a @Deprecated alias that logs a warning and delegates to getTokens() — existing callers keep working unchanged, detokenize/deleteTokens untouched throughout.
  2. data field restored: the API's data field was silently dropped from the bulk insert response. It's wired back through from V1RecordResponseObject.getData(), which already carried it — nothing in Utils.formatBulkInsertResponse was reading it.

Compatibility note:flowvault/pom.xml runs a japicmp binary/source-compatibility check against flowvault/api-report/*.baseline.jar for com.skyflow.vault.data. Rather than changing the existing InsertResponseRecord/BulkInsertResponseRecord constructor signatures (a breaking change under that gate), the old (data-less) constructor overloads are kept as @Deprecated pass-throughs, and data is added via new overloads. No baseline regeneration should be required.

2. flowvault/README.md accuracy pass

Went through the README against the actual source rather than just fixing the two items above:

  • Version snippets said 1.0.0; pom.xml is 1.0.1.
  • CustomHeaderKey sample used names (SkyflowAccountId, etc.) that don't exist — the real enum is SKYFLOW_ACCOUNT_ID/SKYFLOW_ACCOUNT_NAME/REQUEST_ID_HEADER. The README's own code block didn't compile.
  • "vault() takes no arguments, use one client per vault" was false — vault(String vaultId) exists and is tested for multi-vault use on one client. Documented it.
  • "updateType accepts UPDATE (the default)" overstated the SDK's behavior — it omits the field when unset rather than sending "UPDATE" itself; reworded.
  • getHttpStatus() example used "BAD_REQUEST"; the actual hardcoded validation-error string is "Bad Request".
  • Bulk Insert tokens JSON example showed a flat string per column; the real shape is always a list of {token, tokenGroupName} entries per column (one per token group), per a dedicated regression test (testBulkInsert_successWithListOfMapsTokenShape). Fixed the example and added a snippet showing how to read it (there's no typed accessor yet — same gap raised in the Slack thread).
  • Added a "Schema vs. schemaless vaults" table (bulkInsert = structured, bulkTokenize/bulkDeleteTokens = schemaless, bulkDetokenize = both) — flagged in the thread as a known doc gap, confirmed against git history (SK-2646, which shipped tokenize/delete-tokens specifically as "Schemaless vault apis") since there's no code-level enforcement of it. Repeated as a one-line note on each of the four operation sections so it's visible without reading top-to-bottom.
  • Bulk Detokenize metadata JSON example initially backed out a claim about its typical content (only skyflowId was grounded in code; tableName was just a Javadoc description with nothing behind it), then re-grounded it against flowdb_dp_apis.proto's own literal example value for the field, {"table": "table1", "skyflowID": "4524524534623"} — stronger evidence than the description text, which is itself misleading (it says "tableName", the actual wire key is table; Utils.java only renames skyflowIDskyflowId, table passes through unrenamed). Updated the JSON example to match.

3. Samples cleanup (flowvault/samples/)

  • Deleted BearerTokenExpiryExample.java — despite its name, it never touches BearerToken/Token.isExpired(); it's a generic "retry once on 401" wrapper, redundant with BearerTokenGenerationExample's real expiry pattern and the README's own retry guidance.
  • Rewrote samples/README.md — it referenced DetokenizeExample.java, InsertExample.java, GetByIdExample.java, etc., none of which exist in this module (stale boilerplate from a different layout). Replaced with an accurate index of the real samples and correct Maven run instructions.
  • Added response iteration (summary + per-record/per-token walk + retry) to BulkInsertSync/Async, BulkMultiTableInsertSync/Async, BulkDetokenizeSync/Async, and CustomHeaderExample — these previously only did System.out.println(response). BulkTokenizeSync/Async and BulkDeleteTokensSync/Async already had this pattern.

4. Testing

  • Updated ResponseComponentTests, BulkResponseTests, UtilsTests, VaultControllerTests for the rename/restore, including a dedicated test for the deprecated constructor + getFields() alias.
  • Codecov flagged 2 uncovered lines in InsertResponseRecord.java (its own deprecated constructor — never exercised directly, since BulkInsertResponseRecord's deprecated constructor bypasses it). Added a direct test for it.
  • Actually verified, not just written: a JDK/Maven became available partway through this PR's review (none were available in the sandbox this branch was authored in until then). mvn -pl common,flowvault -am test692 tests, 0 failures. mvn -pl common,flowvault -am verify (full reactor, japicmp included) → BUILD SUCCESS against the regenerated baseline from item 6.
    • One unrelated pre-existing failure surfaced along the way and had to be excluded to get a clean run: common's TokenTests.testExpiredTokenForIsExpiredToken reads a TEST_EXPIRED_TOKEN value from a .env file that isn't committed to the repo (a CI-only secret) — nothing to do with this PR, com.skyflow.serviceaccount.util.Token is a pre-existing, unrelated class (JWT expiry check) that this PR never touches.

5. Bug fix: Skyflow.getVaultConfig() crashed on an empty vault list

Found while double-checking the vault()/vault(String) claim above — a different, unrelated method with a real bug:

publicVaultConfiggetVaultConfig() {
Object[] array = this.builder.vaultConfigMap.values().toArray();
return (VaultConfig) array[0]; // unguarded — throws ArrayIndexOutOfBoundsException if empty
}

build() never validates that at least one vault was registered, so a client built with zero addVaultConfig(...) calls is a valid, reachable state — and calling getVaultConfig() on one crashed with an unchecked ArrayIndexOutOfBoundsException rather than failing predictably. Traced every call site in the codebase first: all of them are on VaultController (a different, already-safe method with the same name — it just returns its own single stored config, no lookup involved), never on Skyflow directly. So this had zero usages and zero test coverage anywhere in the suite.

Fixed by mirroring the sibling method's already-correct convention — BaseSkyflow.getVaultConfig(String) is a plain map.get(vaultId) that returns null when absent, no exception, no signature change:

publicVaultConfiggetVaultConfig() {
returnthis.builder.vaultConfigMap.values().stream().findFirst().orElse(null);
}

Deliberately did not make it throw SkyflowException like vault()/vault(String) do — that would diverge from its own sibling method's contract and require adding a checked exception to the signature, a source-incompatible change under this module's japicmp gate, for no real benefit. This fix is implementation-only (same signature), so no baseline update needed. Added 7 tests in SkyflowTests covering the regression case plus the existing untested gaps on the by-id overload.

6. InsertResponseRecord.getTokens() is now typed (Map<String, List<Token>>)

The generic tokens: Map<String, Object> (item 2 above) still required casting/iterating by hand to reach token/tokenGroupName — the exact usability complaint in the Slack thread. First pass at fixing this added a separate typed accessor (getTokenDetails()) alongside the untouched generic getTokens(), keeping both per the thread's "generic for flexibility, typed for UX" clarification. Per explicit direction, went further: getTokens() itself is now the typed oneMap<String, List<Token>> — matching the shape this field had before insert was reworked (flowvault's own pre-rework "v3" Success.tokens was Map<String, List<Token>>; getTokenDetails() no longer exists).

This is the one genuinely breaking change in this PR — confirmed against the actual japicmp diff once a JDK/Maven became available (not just reasoned about in the abstract):

  • getTokens() itself was never breaking. It's reported as a brand-new method against the committed baseline — the pre-SK-3061 codebase only ever had getFields(), so any shape getTokens() returns is additive. My initial writeup here overstated this, assuming a same-arity generic-erasure conflict that doesn't actually apply to a method with zero parameters (erasure conflicts are a parameter-list problem, not a return-type one — a method can't be overloaded by return type at all, regardless of arity, so this was never really in question).
  • What is flagged, all under com.skyflow.vault.data: InsertResponseRecord's deprecated 6-arg constructor and BulkInsertResponseRecord's deprecated 8-arg constructor (both had their tokens parameter generics change), and getFields() (return type generics changed, since it just delegates to getTokens()).
  • These three were avoidable with modest extra code — the deprecated constructors are a different arity than the primary ones, so nothing forces their parameter type to change; getFields() could reverse-map back to the original shape instead of delegating directly. Flagged this and asked; declined in favor of just regenerating the baseline (see the warning banner above and the regenerated flowvault/api-report/skyflow-flowvault-java.baseline.jar in this PR).
  • This also reverses the "keep contract exactly like API" decision made earlier in this same thread — the API's own wire contract types a column's tokens as generic Object. Accepted as the tradeoff for matching the requested typed shape.

Token (getToken()/getTokenGroupName()) isn't a new invention — it's a straight reintroduction of a class flowvault itself had before insert was reworked (deleted in 685a82ff), with final fields and a toString() added to match TokenizeResponseToken's established convention in this package.

The actual parsing (a column's raw wire value can be a list of {token, tokenGroupName} entries, a single such entry, or a bare value) now lives in a new static utility, Token.parseTokens(Map<String, Object>), called once by Utils.formatBulkInsertResponse when constructing each record — not recomputed on every getTokens() call like the first pass's getTokenDetails() was.

Found and fixed a real landmine while adding the Token class: ResponseComponentTests.java had a dangling {@link Token} Javadoc reference left over from the class's original removal, which would have silently started resolving to this new class (while the surrounding comment still said Token "was removed") had I not updated it.

Updated every test that constructed a record with a raw Map<String,Object> tokens value or asserted on the old generic return type, BulkInsertSync/Async, BulkMultiTableInsertSync/Async, and CustomHeaderExample to use getTokens() directly (matching BulkTokenizeSync.java's existing typed per-token loop), and closed every branch in the new parsing logic with tests (a per-column null value, a null element inside a token-group list, a Map entry missing one of its two expected keys). VaultControllerTests.testBulkInsert_successWithListOfMapsTokenShape simplified nicely as a result — no more manual casting needed to assert on it.

Also updated outside this repo

The FlowVault 1.0.0 migration Confluence doc (linked from the Slack thread) has been corrected to match the response-contract change and flags the Object-typing gap (now closed by item 6, but the doc itself is unchanged since this PR).

Not in this PR (flagged as follow-ups)

  • A CI safeguard test to catch future wire-type fields silently going unread (the same failure mode data had here).

🤖 Generated with Claude Code

…rt response
The flowvault SDK renamed the API's `tokens` response key to `fields`,
so callers had to use getFields() instead of the API-matching
getTokens(). Separately, the API's `data` field was silently dropped
from the response entirely. Both were flagged in Slack by a customer
comparing SDK output to the raw API contract.
- InsertResponseRecord/BulkInsertResponseRecord: add tokens/getTokens()
matching the API. getFields() stays as a @deprecated alias that logs
a warning and delegates to getTokens() - existing callers keep
working unchanged.
- Add data/getData(), wired from V1RecordResponseObject.getData() in
Utils.formatBulkInsertResponse (the wire type already carried it;
nothing read it).
- Old constructor overloads (without `data`) are kept, also
@deprecated, rather than changing existing constructor signatures -
this avoids a binary/source-incompatible change against the
japicmp baseline in flowvault/pom.xml.
- detokenize/deleteTokens are untouched; they never had this issue.
- Updated README and tests accordingly, including a dedicated test for
the deprecated constructor + getFields() alias.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@codecov

codecovBot commented Aug 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.66667% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.36%. Comparing base (1145b80) to head (f326ec2).

Files with missing linesPatch %Lines
...lt/src/main/java/com/skyflow/vault/data/Token.java94.87%0 Missing and 2 partials ⚠️
Additional details and impacted files
@@ Coverage Diff @@## flowvault-release/26.8.13 #408 +/- ##
===============================================================
+ Coverage 91.30% 91.36% +0.06% - Complexity 0 475 +475 
===============================================================
Files 157 158 +1 Lines 6392 6440 +48 Branches 850 859 +9 ===============================================================
+ Hits 5836 5884 +48 + Misses 364 362 -2 - Partials 192 194 +2 
FlagCoverage Δ
common88.39% <100.00%> (+<0.01%)⬆️
flowvault88.88% <96.55%> (+0.23%)⬆️
skyvault94.72% <ø> (ø)
unittests-flowvault89.85% <96.22%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

ComponentsCoverage Δ
Module: common88.39% <100.00%> (+<0.01%)⬆️
Module: skyvault94.72% <ø> (ø)
Module: flowvault88.88% <96.55%> (+0.23%)⬆️
Service Account86.69% <ø> (ø)
Vault Data91.66% <96.07%> (+0.23%)⬆️
Vault Tokens99.03% <ø> (ø)
Vault Connection100.00% <ø> (ø)
Vault Controller85.31% <ø> (ø)
Detect100.00% <ø> (ø)
Audit100.00% <ø> (ø)
BIN Lookup100.00% <ø> (ø)
Config96.26% <ø> (ø)
Utils89.22% <100.00%> (+<0.01%)⬆️
Errors100.00% <ø> (ø)
Enums100.00% <ø> (ø)
Logs95.34% <100.00%> (+0.01%)⬆️
Files with missing linesCoverage Δ
...ommon/src/main/java/com/skyflow/logs/InfoLogs.java100.00% <100.00%> (ø)
flowvault/src/main/java/com/skyflow/Skyflow.java93.68% <100.00%> (+2.01%)⬆️
...owvault/src/main/java/com/skyflow/utils/Utils.java87.58% <100.00%> (+0.02%)⬆️
...m/skyflow/vault/data/BulkInsertResponseRecord.java100.00% <100.00%> (ø)
...a/com/skyflow/vault/data/InsertResponseRecord.java100.00% <100.00%> (ø)
...lt/src/main/java/com/skyflow/vault/data/Token.java94.87% <94.87%> (ø)

Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 1145b80...f326ec2. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Devesh-Skyflowand others added 14 commits August 13, 2026 17:20
…dd response iteration to samples
README (flowvault/README.md):
- Version snippets said 1.0.0; pom.xml is 1.0.1.
- CustomHeaderKey enum names were wrong (PascalCase vs actual SCREAMING_SNAKE_CASE) -
the sample code block did not compile.
- "vault() takes no arguments, use one client per vault" was false: Skyflow.vault(String
vaultId) exists and is tested for multi-vault use on one client. Documented it.
- "updateType accepts UPDATE (the default)" overstated what the SDK does - it omits the
field when unset rather than sending "UPDATE"; reworded to say so.
- getHttpStatus() example used "BAD_REQUEST"; the actual hardcoded validation-error
string is "Bad Request".
Samples:
- Deleted BearerTokenExpiryExample.java: despite its name, it never touches BearerToken
or Token.isExpired() at all - it's a generic "retry once on 401" wrapper around
bulkDetokenize, redundant with both BearerTokenGenerationExample's real expiry-check
pattern and the README's own retry guidance.
- Rewrote samples/README.md: it referenced DetokenizeExample.java, InsertExample.java,
GetByIdExample.java etc. - files that don't exist anywhere in this module (leftover
boilerplate from a different samples layout). Replaced with an accurate index of the
actual serviceaccount/ and vault/ samples plus correct Maven run instructions.
- Added response iteration (summary + per-record/per-token walk + retry) to
BulkInsertSync/Async, BulkMultiTableInsertSync/Async, BulkDetokenizeSync/Async, and
CustomHeaderExample - they previously only printed the raw response object.
BulkTokenizeSync/Async and BulkDeleteTokensSync/Async already had this and are
untouched.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Bulk Insert: tokens example showed a flat string per column
("card_number": "5484-..."), but the value is always a LIST of
{token, tokenGroupName} entries - one per token group configured on
that column, even when there's only one. This is the exact shape a
dedicated regression test (testBulkInsert_successWithListOfMapsTokenShape)
guards, and it's what the API's own generic Object typing is for.
Added a populated hashedData example and a code snippet showing how
to read a tokens entry, since there's no typed accessor for it yet.
- Bulk Detokenize: metadata example showed {} on a successful record,
but metadata normally carries skyflowId/tableName on success (per
the wire type's own Javadoc and the key-rename Utils.java performs
on it), and the real "nothing there" case is null, not {}.
Field names/order for all four response record types (verified against
InsertResponseRecord/BulkInsertResponseRecord, TokenizeResponseRecord/
TokenizeResponseToken, DetokenizeResponseRecord/BaseDetokenizeRecordResponse,
DeleteTokensRecord) and the requestId null-on-success/populated-on-error-only
behavior were already correct - no changes needed there.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This was flagged in the Slack thread (Saketh's clarification point 1:
"We have the SDK interface to schema/schemaless vault mapping already
but we haven't added it in the readme, we will add it") and was still
missing - grepping the README for "schema" turned up nothing.
Added a table documenting which of the four bulk operations apply to
which vault type, matching Devesh's original clarification in the
thread: insert is structured/schema-only, tokenize and deleteTokens
are schemaless-only (confirmed by git history - SK-2646 shipped them
specifically as "Schemaless vault apis"), and detokenize works with
both since it only needs the token itself, not a table.
Verified this isn't enforced anywhere in Validations.java, so worded
it as supported/intended usage rather than something the SDK validates
or blocks.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Codecov flagged 2 uncovered lines in InsertResponseRecord.java. The
existing deprecated-constructor test only goes through
BulkInsertResponseRecord's deprecated 8-arg constructor, which
delegates straight to the new 9-arg constructor -> new 7-arg super
constructor, never touching InsertResponseRecord's own deprecated
6-arg constructor. Nothing else in the codebase constructs
InsertResponseRecord directly (it's only ever used via the Bulk
subclass), so that constructor was genuinely untested. Added a test
that instantiates it directly and asserts data defaults to null.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The previous commit asserted metadata "typically carries skyflowId/
tableName" with equal confidence for both keys. Re-checking: skyflowId
is grounded in real code (Utils.java renames a skyflowID key to
skyflowId when present, which only exists because that key is known
to show up), but tableName is only mentioned in one line of Javadoc
on the generated wire type - no transform logic touches it and no
test in the suite constructs or asserts a tableName key anywhere in
metadata. That's a docstring example, not a verified contract.
Reverting the example and the claim rather than asserting a shape I
can't actually back up.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…n section
The "Schema vs. schemaless vaults" table lives under "VaultController -
Bulk operations", but a reader jumping straight to e.g. "# Bulk
Tokenize" via the TOC or a search never sees it. Added a one-line
"Vault type supported" note at the top of each of the four operation
sections (Insert/Tokenize/Detokenize/Delete Tokens), linking back to
the consolidated table for the full picture.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Insert/Tokenize/Detokenize repeated the explanation already in the
consolidated table; shortened to one line each, consistent with the
delete-tokens note.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
CI spellcheck flagged flowvault/samples/README.md:38 - "codehaus" from
the org.codehaus.mojo:exec-maven-plugin groupId in the sample run
instructions. Legitimate Maven groupId, not a typo; added alongside
the other domain-specific terms already in the word list (jfrog,
sonatype, etc.).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Skyflow.getVaultConfig() did:
Object[] array = this.builder.vaultConfigMap.values().toArray();
return (VaultConfig) array[0];
- an unguarded array[0] access. A client built without any
addVaultConfig(...) call (build() never validates this) throws
ArrayIndexOutOfBoundsException instead of failing predictably.
Traced every call site of "getVaultConfig()" in the codebase first:
all of them are on VaultController (which has its own, unrelated,
already-safe getVaultConfig() returning its single stored config -
no lookup involved), never on Skyflow directly. So this method had
zero usages and zero test coverage anywhere in the suite.
Fixed by mirroring the sibling method's established, already-correct
convention: BaseSkyflow.getVaultConfig(String) is a plain
vaultConfigMap.get(vaultId), returning null when absent - no
exception, no signature change. Rewrote the no-arg overload the same
way (.stream().findFirst().orElse(null)) rather than making it throw
SkyflowException like vault()/vault(String) do, since that would
diverge from its own sibling's contract and require adding a checked
exception to the signature - a source-incompatible change under this
module's japicmp gate for no real benefit. This fix needs no baseline
update: same signature, implementation-only.
Added 7 tests covering: single vault, first-of-several (consistent
with vault()'s "first" semantics, and identity-matched against
getVaultConfig(id)), the empty-client regression case itself, null
after removing the only vault, falling back to the remaining vault
after the first is removed, and the two existing gaps on the
by-id overload (unknown id, empty client).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Previously backed out a claim about metadata's typical content since
only skyflowId was grounded (a rename in Utils.java) and tableName
was just a Javadoc description with no code or test behind it.
flowdb_dp_apis.proto's metadata field has its own literal example
value, not just a free-text description: {"table": "table1",
"skyflowID": "4524524534623"}. That's stronger evidence than the
description text, and it reveals the description itself is misleading
- it says "such as tableName or skyflowID" but the actual example key
is "table", not "tableName". Utils.java only renames "skyflowID" to
"skyflowId"; "table" passes through unrenamed.
Documented the real shape and explained the rename explicitly.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds getTokenDetails() to InsertResponseRecord (inherited by
BulkInsertResponseRecord) alongside the existing generic getTokens():
Map<String, Object>. It parses the same data into
Map<String, List<Token>>, so callers get getToken()/getTokenGroupName()
instead of casting Map entries by hand - the exact "known gap" flagged
in the Slack thread and the earlier README note.
Token is a straight reintroduction of flowvault's own pre-rework class
(deleted in 685a82f when insert was reworked around the current
InsertResponseRecord/tokens map), not a new invention - same shape the
user specified, with final fields and a toString() added to match
TokenizeResponseToken's established convention in this package.
getTokenDetails() is purely additive (new method, no signature
changes to anything existing) and computed fresh from getTokens() on
every call rather than stored separately, so the generic and typed
views can never disagree. It normalizes every shape getTokens()'s
value is known to take - a list of {token, tokenGroupName} entries, a
single such entry not wrapped in a list, or a bare token value with no
group info - into a consistent List<Token>, returning null only when
getTokens() itself is null.
Fixed a real landmine along the way: ResponseComponentTests.java had a
dangling {@link Token} javadoc reference left over from the class's
removal - harmless while there was no Token class to resolve to, but
it would have silently started resolving to this new class instead
(with the surrounding comment still saying it "was removed"). Updated
the comment to describe what actually happened.
Added 9 tests covering Token itself and every shape getTokenDetails()
normalizes, including one against BulkInsertResponseRecord directly
(not just the base class) to confirm the inherited method works for
the type callers actually receive. Updated the README's Bulk Insert
section to document getTokenDetails() in place of the manual
cast-it-yourself snippet from the previous commit.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Two changes landed together since both were already staged:
1. BulkInsertSync/Async, BulkMultiTableInsertSync/Async, and
CustomHeaderExample previously printed record.getTokens() (the raw
Map<String, Object>) directly. Updated all five to walk
getTokenDetails() instead - a nested loop over
Map<String, List<Token>>, printing token.getTokenGroupName()/
token.getToken() per column, matching the pattern
BulkTokenizeSync.java already uses for its own typed per-token loop.
2. 3 more tests, closing every branch the previous commit's 9 tests
left untouched in InsertResponseRecord's new parsing logic:
- parseTokenEntries's own null check (a column present in the map
with a null value, as opposed to the whole tokens map being null,
which was already covered) - that column is now omitted from
getTokenDetails() rather than appearing with a null/empty entry.
- toToken's final `return null` and the corresponding "skip adding"
branch in parseTokenEntries's list loop - a null element sitting
inside a column's token-group list, which the loop must skip
rather than NPE on.
- The tokenGroupName-absent ternary branch in toToken's Map-entry
parsing - every existing Map-entry test populated both "token"
and "tokenGroupName" keys, so the "key missing" path was never
exercised.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…en>>), matching v3
Per explicit direction: retype tokens/getTokens() itself to
Map<String, List<Token>> - matching the pre-rework ("v3") shape -
instead of keeping it generic and exposing a separate getTokenDetails()
accessor alongside it (the previous commit's approach).
BREAKING CHANGE - flagged and confirmed before implementing:
- getTokens()'s return type changes (Map<String,Object> ->
Map<String,List<Token>>).
- Both InsertResponseRecord constructors' `tokens` parameter type
changes for the same reason. This isn't a choice - Map<String,Object>
and Map<String,List<Token>> erase to the same raw `Map` type, so
Java forbids two constructor overloads at the same arity that differ
only in that generic parameter. There is no way to add this as a
new overload alongside the old one; the parameter type has to change
in place. Same for BulkInsertResponseRecord's two constructors.
- getFields() (deprecated alias) now returns the typed map too, since
it just delegates to getTokens().
This diverges from "keep contract exactly like API" (the API's own
wire contract types a column's tokens as generic Object) - accepted
as the tradeoff for matching v3's typed shape.
Moved the parsing logic (a column's raw value can be a list of
{token, tokenGroupName} entries, a single such entry, or a bare
value) from InsertResponseRecord into a new static utility,
Token.parseTokens(Map<String, Object>): Map<String, List<Token>>.
Utils.formatBulkInsertResponse now calls it to convert the wire
type's raw tokens map before constructing BulkInsertResponseRecord -
parsing happens once at construction time instead of on every
getTokens() call.
Updated every test that constructed an InsertResponseRecord/
BulkInsertResponseRecord with a raw Map<String,Object> tokens value,
or asserted on the old generic return type. The former
getTokenDetails()-specific tests now test Token.parseTokens()
directly. VaultControllerTests.testBulkInsert_successWithListOfMapsTokenShape
simplifies nicely: it no longer needs to cast the parsed result, since
getTokens() itself is the typed view now.
Updated README and the 5 insert samples (BulkInsertSync/Async,
BulkMultiTableInsertSync/Async, CustomHeaderExample) to use
getTokens() directly instead of the now-removed getTokenDetails().
Needs a japicmp baseline regeneration (scripts/contract-snapshot-
update.sh flowvault) before merge - this is a genuine, intentional
break of the existing contract, unlike every other change in this
branch so far. I could not run mvn/java in this sandbox to regenerate
or verify it myself.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Regenerated via scripts/contract-snapshot-update.sh flowvault, now
that a JDK/Maven are available to run it. Verified mvn -pl
common,flowvault -am verify passes clean (692 tests, japicmp included)
against this new baseline.
The 3 intentional incompatibilities this baseline now accepts, per
the full japicmp diff (flowvault/target/japicmp/default-cli.diff):
- InsertResponseRecord's deprecated 6-arg constructor: tokens param
generics changed (Map<String,Object> -> Map<String,List<Token>>).
- BulkInsertResponseRecord's deprecated 8-arg constructor: same.
- getFields(): return type generics changed to match.
getTokens() itself was never actually flagged - it's reported as a
brand new method against this baseline (the pre-SK-3061 codebase only
ever had getFields()), so making it typed was non-breaking on its
own. The three real breaks above are avoidable (the deprecated
constructors are a different arity than the primary ones, so no
erasure conflict forces their parameter type to change; getFields()
could reverse-map back to the old shape instead of delegating
directly) - flagged and declined in favor of just regenerating the
baseline, per explicit direction.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Contract baseline change detected (flowvault)

This PR updates flowvault/api-report/skyflow-flowvault-java.baseline.jar (the approved public API contract). Here is exactly what it changes, comparing the baseline on flowvault-release/26.8.13 against the baseline committed in this PR:

Compatibility Report

semver MINOR

Summary

Warning

Compatible changes found while checking backward compatibility of version skyflow-flowvault-java.baseline with the previous version old-baseline.

Expand to see options used.
  • Report only summary: No
  • Report only changes: Yes
  • Report only binary-incompatible changes: No
  • Access modifier filter: PROTECTED
  • Old archives:
    • old-baseline unknown
  • New archives:
    • skyflow-flowvault-java.baseline unknown
  • Evaluate annotations: Yes
  • Include synthetic classes and class members: No
  • Include specific elements: Yes
    • com.skyflow.Skyflow
    • com.skyflow.config
    • com.skyflow.enums
    • com.skyflow.errors
    • com.skyflow.serviceaccount.util
    • com.skyflow.vault.audit
    • com.skyflow.vault.bin
    • com.skyflow.vault.connection
    • com.skyflow.vault.controller
    • com.skyflow.vault.data
    • com.skyflow.vault.detect
    • com.skyflow.vault.tokens
  • Exclude specific elements: No
  • Ignore all missing classes: Yes
  • Ignore specific missing classes: No
  • Treat changes as errors:
    • Any changes: No
    • Binary incompatible changes: No
    • Source incompatible changes: No
    • Incompatible changes caused by excluded classes: Yes
    • Semantically incompatible changes: No
    • Semantically incompatible changes, including development versions: No
  • Classpath mode: TWO_SEPARATE_CLASSPATHS
  • Old classpath:
/home/runner/.m2/repository/com/skyflow/common/1.0.0/common-1.0.0.jar:/home/runner/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.17.2/jackson-databind-2.17.2.jar:/home/runner/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.17.2/jackson-annotations-2.17.2.jar:/home/runner/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.17.2/jackson-core-2.17.2.jar:/home/runner/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.18.6/jackson-datatype-jdk8-2.18.6.jar:/home/runner/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.18.6/jackson-datatype-jsr310-2.18.6.jar:/home/runner/.m2/repository/io/github/cdimascio/dotenv-java/2.2.0/dotenv-java-2.2.0.jar:/home/runner/.m2/repository/com/google/code/gson/gson/2.10.1/gson-2.10.1.jar:/home/runner/.m2/repository/com/squareup/okhttp3/okhttp/4.12.0/okhttp-4.12.0.jar:/home/runner/.m2/repository/com/squareup/okio/okio/3.6.0/okio-3.6.0.jar:/home/runner/.m2/repository/com/squareup/okio/okio-jvm/3.6.0/okio-jvm-3.6.0.jar:/home/runner/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-common/1.9.10/kotlin-stdlib-common-1.9.10.jar:/home/runner/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.8.21/kotlin-stdlib-jdk8-1.8.21.jar:/home/runner/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib/1.8.21/kotlin-stdlib-1.8.21.jar:/home/runner/.m2/repository/org/jetbrains/annotations/13.0/annotations-13.0.jar:/home/runner/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.8.21/kotlin-stdlib-jdk7-1.8.21.jar:/home/runner/.m2/repository/io/jsonwebtoken/jjwt/0.12.6/jjwt-0.12.6.jar:/home/runner/.m2/repository/io/jsonwebtoken/jjwt-api/0.12.6/jjwt-api-0.12.6.jar:/home/runner/.m2/repository/io/jsonwebtoken/jjwt-impl/0.12.6/jjwt-impl-0.12.6.jar:/home/runner/.m2/repository/io/jsonwebtoken/jjwt-jackson/0.12.6/jjwt-jackson-0.12.6.jar:/home/runner/.m2/repository/junit/junit/4.13.2/junit-4.13.2.jar:/home/runner/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar:/home/runner/.m2/repository/org/powermock/powermock-module-junit4/2.0.9/powermock-module-junit4-2.0.9.jar:/home/runner/.m2/repository/org/powermock/powermock-module-junit4-common/2.0.9/powermock-module-junit4-common-2.0.9.jar:/home/runner/.m2/repository/org/powermock/powermock-reflect/2.0.9/powermock-reflect-2.0.9.jar:/home/runner/.m2/repository/net/bytebuddy/byte-buddy/1.10.14/byte-buddy-1.10.14.jar:/home/runner/.m2/repository/net/bytebuddy/byte-buddy-agent/1.10.14/byte-buddy-agent-1.10.14.jar:/home/runner/.m2/repository/org/powermock/powermock-core/2.0.9/powermock-core-2.0.9.jar:/home/runner/.m2/repository/org/javassist/javassist/3.27.0-GA/javassist-3.27.0-GA.jar:/home/runner/.m2/repository/org/powermock/powermock-api-mockito2/2.0.9/powermock-api-mockito2-2.0.9.jar:/home/runner/.m2/repository/org/powermock/powermock-api-support/2.0.9/powermock-api-support-2.0.9.jar:/home/runner/.m2/repository/org/mockito/mockito-core/3.3.3/mockito-core-3.3.3.jar:/home/runner/.m2/repository/org/objenesis/objenesis/2.6/objenesis-2.6.jar
  • New classpath:
/home/runner/.m2/repository/com/skyflow/common/1.0.0/common-1.0.0.jar:/home/runner/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.17.2/jackson-databind-2.17.2.jar:/home/runner/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.17.2/jackson-annotations-2.17.2.jar:/home/runner/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.17.2/jackson-core-2.17.2.jar:/home/runner/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.18.6/jackson-datatype-jdk8-2.18.6.jar:/home/runner/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.18.6/jackson-datatype-jsr310-2.18.6.jar:/home/runner/.m2/repository/io/github/cdimascio/dotenv-java/2.2.0/dotenv-java-2.2.0.jar:/home/runner/.m2/repository/com/google/code/gson/gson/2.10.1/gson-2.10.1.jar:/home/runner/.m2/repository/com/squareup/okhttp3/okhttp/4.12.0/okhttp-4.12.0.jar:/home/runner/.m2/repository/com/squareup/okio/okio/3.6.0/okio-3.6.0.jar:/home/runner/.m2/repository/com/squareup/okio/okio-jvm/3.6.0/okio-jvm-3.6.0.jar:/home/runner/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-common/1.9.10/kotlin-stdlib-common-1.9.10.jar:/home/runner/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.8.21/kotlin-stdlib-jdk8-1.8.21.jar:/home/runner/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib/1.8.21/kotlin-stdlib-1.8.21.jar:/home/runner/.m2/repository/org/jetbrains/annotations/13.0/annotations-13.0.jar:/home/runner/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.8.21/kotlin-stdlib-jdk7-1.8.21.jar:/home/runner/.m2/repository/io/jsonwebtoken/jjwt/0.12.6/jjwt-0.12.6.jar:/home/runner/.m2/repository/io/jsonwebtoken/jjwt-api/0.12.6/jjwt-api-0.12.6.jar:/home/runner/.m2/repository/io/jsonwebtoken/jjwt-impl/0.12.6/jjwt-impl-0.12.6.jar:/home/runner/.m2/repository/io/jsonwebtoken/jjwt-jackson/0.12.6/jjwt-jackson-0.12.6.jar:/home/runner/.m2/repository/junit/junit/4.13.2/junit-4.13.2.jar:/home/runner/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar:/home/runner/.m2/repository/org/powermock/powermock-module-junit4/2.0.9/powermock-module-junit4-2.0.9.jar:/home/runner/.m2/repository/org/powermock/powermock-module-junit4-common/2.0.9/powermock-module-junit4-common-2.0.9.jar:/home/runner/.m2/repository/org/powermock/powermock-reflect/2.0.9/powermock-reflect-2.0.9.jar:/home/runner/.m2/repository/net/bytebuddy/byte-buddy/1.10.14/byte-buddy-1.10.14.jar:/home/runner/.m2/repository/net/bytebuddy/byte-buddy-agent/1.10.14/byte-buddy-agent-1.10.14.jar:/home/runner/.m2/repository/org/powermock/powermock-core/2.0.9/powermock-core-2.0.9.jar:/home/runner/.m2/repository/org/javassist/javassist/3.27.0-GA/javassist-3.27.0-GA.jar:/home/runner/.m2/repository/org/powermock/powermock-api-mockito2/2.0.9/powermock-api-mockito2-2.0.9.jar:/home/runner/.m2/repository/org/powermock/powermock-api-support/2.0.9/powermock-api-support-2.0.9.jar:/home/runner/.m2/repository/org/mockito/mockito-core/3.3.3/mockito-core-3.3.3.jar:/home/runner/.m2/repository/org/objenesis/objenesis/2.6/objenesis-2.6.jar

Results

StatusTypeSerializationCompatibility Changes
Modifiedcom.skyflow.vault.data.BulkInsertResponseRecordNot serializableAnnotation deprecated addedMethod parameter generics changed
Modifiedcom.skyflow.vault.data.InsertResponseRecordNot serializableAnnotation deprecated addedMethod return type generics changedMethod parameter generics changedMethod added to public class
Addedcom.skyflow.vault.data.TokenNot serializableMethod added to public class
Expand for details.

com.skyflow.vault.data.BulkInsertResponseRecord

  • Binary-compatible
  • Source-compatible
  • Serialization-compatible
StatusModifiersTypeNameExtendsJDKSerializationCompatibility Changes
ModifiedpublicClassBulkInsertResponseRecordInsertResponseRecordJDK 8Not serializableNo changes

Constructors

StatusModifiersGenericsConstructorAnnotationsThrowsCompatibility Changes
Source-incompatiblepublicBulkInsertResponseRecord(int, String, String, Map<String, Object>Map<String, List<Token>>, Map<String, Object>, int, String, String)Deprecated: forRemoval=true, since="1.0.2"Annotation deprecated addedMethod parameter generics changed
AddedpublicBulkInsertResponseRecord(int, String, String, Map<String, List<Token>>, Map<String, Object>, Map<String, Object>, int, String, String)No changes

com.skyflow.vault.data.InsertResponseRecord

  • Binary-compatible
  • Source-compatible
  • Serialization-compatible
StatusModifiersTypeNameExtendsJDKSerializationCompatibility Changes
ModifiedpublicClassInsertResponseRecordObjectJDK 8Not serializableNo changes

Constructors

StatusModifiersGenericsConstructorAnnotationsThrowsCompatibility Changes
Source-incompatiblepublicInsertResponseRecord(String, String, Map<String, Object>Map<String, List<Token>>, Map<String, Object>, int, String)Deprecated: forRemoval=true, since="1.0.2"Annotation deprecated addedMethod parameter generics changed
AddedpublicInsertResponseRecord(String, String, Map<String, List<Token>>, Map<String, Object>, Map<String, Object>, int, String)No changes

Methods

StatusModifiersGenericsTypeMethodAnnotationsThrowsCompatibility Changes
AddedpublicMap<String, Object>getData()Method added to public class
Source-incompatiblepublicMap<String, Object>Map<String, List<Token>>getFields()Deprecated: forRemoval=true, since="1.0.2"Annotation deprecated addedMethod return type generics changed
AddedpublicMap<String, List<Token>>getTokens()Method added to public class

com.skyflow.vault.data.Token

  • Binary-compatible
  • Source-compatible
  • Serialization-compatible
StatusModifiersTypeNameExtendsJDKSerializationCompatibility Changes
AddedpublicClassTokenObjectJDK 8Not serializableNo changes

Constructors

StatusModifiersGenericsConstructorAnnotationsThrowsCompatibility Changes
AddedpublicToken(String, String)No changes

Methods

StatusModifiersGenericsTypeMethodAnnotationsThrowsCompatibility Changes
AddedpublicStringgetToken()Method added to public class
AddedpublicStringgetTokenGroupName()Method added to public class
AddedstaticpublicMap<String, List<Token>>parseTokens(Map<String, Object>)Method added to public class
AddedpublicStringtoString()Method added to public class

Warning

All missing classes, i.e. superclasses and interfaces that could not be found on the classpath were ignored.

Hence changes caused by these superclasses and interfaces are not reflected in the output.


Generated on: 2026-08-13 15:21:49.670+0000.

@Devesh-Skyflow
Devesh-Skyflow merged commit b17c441 into flowvault-release/26.8.13Aug 13, 2026
27 of 28 checks passed
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

@Devesh-Skyflow