Skip to content

YPE-6186 Return images from unified search - #219

Open
bmanquen wants to merge 5 commits into
mainfrom
YPE-6186-unified-search-images
Open

bmanquen wants to merge 5 commits into
mainfrom
YPE-6186-unified-search-images

Conversation

@bmanquen

@bmanquen bmanquen commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Add SearchImage (opaque id + passageId, a single verse or a range) and SearchResults.images for YPE-6186.
  • "images" is now a valid fields value for search.unified, so images can come back alone or alongside verses.
  • images defaults to empty when the response omits it (prod /v1 doesn't offer images yet), so existing calls keep working.
  • SearchResults.images is a body property set through a new constructor, so 2.6.0's constructor, copy, componentN and equals are unchanged (no major bump). copy doesn't carry images and equals doesn't compare them.
  • SearchImage is a plain class, not a data class, so fields can be added later without a major.
  • An image missing its id or passage is dropped rather than failing the whole search.
  • Search results carry only the image's id and passage, not the full Images metadata.
  • README, CONTEXT.md and the API dump are updated.

Test plan

  • ./gradlew spotlessCheck apiCheck test
  • SearchApiTests: images alongside verses and topics, images alone, images omitted by the platform, and a malformed image dropped while its siblings are kept

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge; no actionable issues remain.

Summary

Adds image results to unified search, with image IDs and passage IDs available through SearchResults.images.

  • Unified search can return images with their passages.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    A[Unified search request] --> B[Platform response]
    B --> C[Verse and topic results]
    B --> D[Image results or empty list]
    D --> E[Skip images missing an ID or passage]
    C --> F[SearchResults]
    E --> F
Loading

Reviews (6) · Last reviewed commit: "fix(core): keep unified search images ad..." · Reviewed by Greptile

- Add SearchImage (opaque id + passageId) and SearchResults.images
- Accept "images" in unified search fields
- Default images to empty when the platform omits them
- Document image results in README and CONTEXT.md
@bmanquen
bmanquen requested a review from camrun91 October 15, 2026 21:59
@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

✅ Commit Lint: passed

All commit messages in this PR conform to Conventional Commits.

📦 Release preview: 2.6.0 → 2.7.0 (minor)

Once merged, this is the version to enter on the next Actions → Release → Run workflow dispatch.

Window: 2.6.0 → main + this PR — 5 commit(s), 5 of them from this PR. This PR on its own would be a minor bump.

Release analyzer output
[analyzer] Analyzing commit: feat(core): return images from unified search

- Add SearchImage (opaque id + passageId) and SearchResults.images
- Accept "images" in unified search fields
- Default images to empty when the platform omits them
- Document image results in README and CONTEXT.md
[analyzer] The release type for the commit is minor
[analyzer] Analyzing commit: docs: show topics in the unified search example
[analyzer] The commit should not trigger a release
[analyzer] Analyzing commit: fix(core): keep SearchResults binary compatible with 2.6.0

- Restore the 5-argument constructor and copy as hidden overloads
- Mark them for removal in 3.0.0
[analyzer] The release type for the commit is patch
[analyzer] Analyzing commit: fix(core): keep the SearchResults constructor callable from Java

- Replace the hidden 5-argument constructor with @JvmOverloads
[analyzer] The release type for the commit is patch
[analyzer] Analyzing commit: fix(core): keep unified search images additive

- Move SearchResults.images into the body with a new constructor so
  2.6.0's constructor, copy, componentN and equals are unchanged
- Make SearchImage a plain class instead of a data class
- Drop a malformed image instead of failing the whole search
- Clarify that the KDoc drop rules apply to verse and image results
- Reword the README search bullet so images read as part of unified search
[analyzer] The release type for the commit is patch
[analyzer] Analysis of 5 commits complete: minor release
[analyzer] Analyzing commit: feat(core): return images from unified search

- Add SearchImage (opaque id + passageId) and SearchResults.images
- Accept "images" in unified search fields
- Default images to empty when the platform omits them
- Document image results in README and CONTEXT.md
[analyzer] The release type for the commit is minor
[analyzer] Analyzing commit: docs: show topics in the unified search example
[analyzer] The commit should not trigger a release
[analyzer] Analyzing commit: fix(core): keep SearchResults binary compatible with 2.6.0

- Restore the 5-argument constructor and copy as hidden overloads
- Mark them for removal in 3.0.0
[analyzer] The release type for the commit is patch
[analyzer] Analyzing commit: fix(core): keep the SearchResults constructor callable from Java

- Replace the hidden 5-argument constructor with @JvmOverloads
[analyzer] The release type for the commit is patch
[analyzer] Analyzing commit: fix(core): keep unified search images additive

- Move SearchResults.images into the body with a new constructor so
  2.6.0's constructor, copy, componentN and equals are unchanged
- Make SearchImage a plain class instead of a data class
- Drop a malformed image instead of failing the whole search
- Clarify that the KDoc drop rules apply to verse and image results
- Reword the README search bullet so images read as part of unified search
[analyzer] The release type for the commit is patch
[analyzer] Analysis of 5 commits complete: minor release

- Restore the 5-argument constructor and copy as hidden overloads
- Mark them for removal in 3.0.0
@bmanquen

Copy link
Copy Markdown
Collaborator Author

@greptileai

@camrun91 camrun91 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice work, tests and api dump look solid. requesting changes for a few things, details inline. the big ones: one bad image in the response shouldn't take down all of unified search, and the "source-compatible, no major bump" claim doesn't hold for java callers. also, can you retitle this to feat(core): return images from unified search to match the commit? otherwise a squash merge gets no minor bump or changelog entry. and squash the two fix(core) commits into the feat commit so they don't show up in the release notes as bug fixes for something that never shipped.

Comment thread README.md Outdated
- Move SearchResults.images into the body with a new constructor so
  2.6.0's constructor, copy, componentN and equals are unchanged
- Make SearchImage a plain class instead of a data class
- Drop a malformed image instead of failing the whole search
- Clarify that the KDoc drop rules apply to verse and image results
- Reword the README search bullet so images read as part of unified search
@github-actions

Copy link
Copy Markdown
Contributor

Code Coverage Report

Overall Line Coverage: 92.4%

Module Line Coverage Threshold
platform-core 93.0% ✅
platform-reader 92.5% ✅
platform-ui 89.0% ✅

Generated from Kover XML report.

@camrun91
camrun91 self-requested a review October 16, 2026 20:30

@camrun91 camrun91 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the quick turn, the compat rework fixes the java break and the plain SearchImage is good. still a few things before this can go in:

  • images isn't part of equals/hashCode/toString and copy drops it. that'll bite anyone holding results in state. see inline.
  • "images": null still fails the whole search.
  • please retitle to feat(core): return images from unified search. squash merge uses the title as the commit subject, so right now this won't version or show up in the changelog as a feature. squashing the fix(core) commits would be nice too.

ci's green and tests look good otherwise.

* The matching images, in rank order. Empty when the platform does not offer image results.
* Not carried over by [copy] and not compared by [equals].
*/
var images: List<SearchImage> = emptyList()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since images is a body property, equals/hashCode/toString ignore it and copy(...) silently resets it to empty. two results that only differ in images compare equal, so StateFlow/distinctUntilChanged/mutableStateOf will swallow an image-only update. can we override equals, hashCode and toString to include images (binary safe, apiCheck stays green), update the KDoc to say only copy drops it, and add tests for both? if dropping on copy isn't ok, the other option is images in the primary constructor as a major.

* @property id The opaque identifier of the image.
* @property passageId The verse or verse range the image illustrates, such as `JHN.3.16` or `1CO.13.4-7`.
*/
class SearchImage(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs equals/hashCode/toString on id + passageId. right now two identical images aren't equal, which also breaks the SearchResults equality fix.

internal data class UnifiedSearchResponse(
@SerialName("verses") val references: List<VerseSearchResultResponse>,
@SerialName("topics") val topics: List<TopicSearchResultResponse>,
@SerialName("images") val images: List<ImageSearchResultResponse> = emptyList(),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"images": null still throws and takes verses and topics down with it. make this List<ImageSearchResultResponse?>? = null and map with orEmpty().mapNotNull { it?.searchImage() }, plus tests for null, a null element, and a non-string id.

var images: List<SearchImage> = emptyList()
private set

constructor(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs a KDoc. this is the only way to set images, so say that, and that the 5-arg constructor leaves it empty.

SearchTopic(id = id, text = text, subtopics = subtopics)

private fun ImageSearchResultResponse.searchImage(): SearchImage? {
return SearchImage(id = id ?: return null, passageId = passageId ?: return null)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a blank id gets through here. use takeIf { it.isNotBlank() } for both fields like the verse parser does, and cover "" in the malformed test.

/**
* An image matching a search, carrying only enough to identify it.
*
* @property id The opaque identifier of the image.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to wait on #218, just say in plain words that this is the id you pass to the verse-image lookup to get the url/size/attribution. same for README:537.

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants