Skip to content

[obvious-fleet] feat(ios): recommend from the 763-recipe catalog through the real engine - #172

Draft
SamGu-NRX wants to merge 12 commits into
obv/burst6-fridgeluck-trunkfrom
obv/burst6-fridgeluck-catalog-recommend
Draft

SamGu-NRX wants to merge 12 commits into
obv/burst6-fridgeluck-trunkfrom
obv/burst6-fridgeluck-catalog-recommend

Conversation

@SamGu-NRX

@SamGu-NRX SamGu-NRX commented Oct 15, 2026 •

Copy link
Copy Markdown
Owner

fleet-packet: burst6-fridgeluck-catalog-recommend

Human author: Sam Gu (sgu07966@gmail.com)

What changed and why

The shipped bundle-v2 catalog (763 recipes) was hydrated into recipes_catalog but invisible
to recommendations: findMakeable/findNearMatch only searched the legacy pool, and the
preview drawer loaded catalog recipes through the legacy recipe path, which does not exist for
catalog rows. This makes the catalog a first-class recommendation pool:

  • Identity bridge (RecipeCatalogIngredientBridge + recipes_catalog_ingredient_bridge
    migration): resolves every catalog ingredient key to app ingredient row ids via legacy_id
    or the bundled USDA name/alias mapping; keys with no safe resolution stay unmapped. The
    bridge is rebuilt inside the same transaction as the vocabulary upsert on both the v2 and
    legacy hydration paths, so resolution can never drift from the vocabulary. The migration
    registers after the catalog vocabulary migration (its FK parent table must exist first).
  • Merged engine (RecipeRepositoryCatalogRecommend.swift, RecipeScoring.swift,
    RecipeRepository.swift): catalog candidates must resolve every required line through the
    bridge, pass allergen and diet-claim gates, and gain use-soon urgency from the existing
    three-day expiry query. Results share the legacy ranker; ScoredRecipe now carries catalog
    provenance and a pooled ScoredRecipeID identity unique across pools, and legacy-successor
    catalog rows are excluded per candidate so a legacy recipe and its catalog successor never
    double-rank (legacy wins; its integer id anchors history).
  • Cook packets and UI (RecipeRepositoryCatalog.swift, RecipePreviewDrawer.swift): a
    catalog cook-packet API maps catalog lines to CookQuantity and structured steps (timers,
    thermometer checks) to CookStep; the drawer loads bridged catalog ingredients. Results
    grid, transitions, cook sessions, and the reverse-scan selection key moved to pooled
    identity so catalog recipes with no legacy integer id stay distinct.
  • Tests (apps/ios/Tests/RecipeCatalogRecommendTests.swift): 12 cases covering merged
    pools and identity, unresolved keys, allergen/diet gates, successor dedup, use-soon scoring
    and reasons, cook packets, and bridge rebuilding.

How I checked it

All commands run on Linux (Swift 6.4 toolchain) against production sources:

  • swiftc -parse over every changed Swift file — no diagnostics.
  • Linux harness compiling the production persistence sources + migrations + repositories with
    GRDB: swift test — all tests pass, including the 12 catalog cases (12/12).
  • Real-bundle scale run through the production hydration sequence exactly as
    AppDatabase bootstraps it (loadInto → ensureBundledRecipesHydrated →
    ensureUSDACatalogHydrated → ensureCatalogHydrated) with the shipped resources:
    legacy=166 catalog=763 lines=5010, bridge resolves 124 rows via the real Bundle.main USDA
    path, zero dangling legacy_recipe_id links under enforced foreign keys.
  • Recommendation engine at scale: bridge-keyed pantry (115 ids) → findMakeable merged=20 (catalog=20) in 0.07s; full pantry → merged=20 (catalog=12, legacy=8), proving both pools
    coexist in one ranked list; identities unique in every run; near-match tier runs over the
    merged pool (20); cook packet retrieval for rcp-000269 rev1 returns 8 lines, 3 steps.
  • swift-format lint clean on all 12 changed files; base branch CI green (run 38805706914).

What I could not check

  • No Xcode/macOS in this environment: the iOS app build, SwiftUI changes, and the XCTest
    target have only been verified by swiftc -parse here; hosted macOS CI runs on this push.
  • The scale run lives in an external harness (not committed); it exercises the committed code
    but is not part of the repo test suite.
  • Intermediate commits were not compiled individually; HEAD is the verified state.
  • Successor deduplication has no shipped-data exercise: the bundle reserves rcp-000001–
    rcp-000166 for legacy and starts at rcp-000167, so it ships zero successors by design;
    that path is covered by unit tests only.

Assumptions

  • The shipped bundle carries no legacy_recipe_id fields and 232 of 329 ingredient keys are
    fdc-only, so bridge coverage comes from USDA names/aliases (124 rows); 116 of the bundle's
    219 distinct FDC ids are absent from the bundled USDA catalog and stay unresolved rather
    than guessed — those lines gate their recipes out of exact matches until the data pipeline
    ships legacy ids or a broader USDA catalog.
  • First-launch hydration equals the AppDatabase bootstrap sequence used in the scale run;
    ensureBundledRecipesHydrated skipped its catalog-mapping stage via marker logic in this
    environment, matching what the same sequence does on a fresh install.
  • Base branch obv/burst6-fridgeluck-trunk (PR feat(ios): one integration branch where every overhaul slice builds together #170's integration branch) per the burst
    integration flow; this branch was cut from 90386c6 on that trunk.

🔗 Obvious Project · 🧵 Obvious Thread · 🔀 Obvious PR Artifact


Opened by the maintainer from the Obvious thread's own description, so every review bot reviews it (CodeRabbit skips PRs authored by bots). The work and its commits are by Obvious.

Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>

Review round (2026-10-16) — changes-requested review addressed

Independent review (comment 6205373538) verdict "changes needed"; all three ranked findings fixed at head 5a33152, no findings disputed.

Finding 1 (High) — catalog recommendations dead-ended at cooking and Le Chef. Fixed: RecipeRepositoryCatalog.swift gains catalogCookPacket(for: ScoredRecipe) and cookPacketIngredients(_:) — the single structured path (steps + bridged ingredient lines in the legacy (Ingredient, RecipeIngredient) shape). CookingGuideView now builds its guide steps and ingredient list from the packet (async load, same pattern as before), RecipeResultsView.storeRecipeForAssistant passes the bridged lines to LiveAssistantRecipeContext, and RecipePreviewDrawer uses the same repository helper instead of its private mapping. Fails-first: pre-fix, the repository had no path at all — no member 'cookPacketIngredients', no catalogCookPacket(for:) (compile error in the portable harness); new test testCatalogRecommendationYieldsCookPacketAndBridgedIngredients pins non-empty steps and bridged lines for a catalog result and passes after the fix (harness 14/14).

Finding 2 (High) — keto gate failed open on the catalog pool. Fixed: the gate switch now has a keto arm that excludes the pool — the claims schema has no low-carb field, so no catalog recipe can prove compliance while the legacy pool enforces .lowCarb. Fails-first: testKetoDietExcludesCatalogPoolFailingClosed reproduced the ungated catalog entry (XCTAssertFalse failed) before the arm landed; green after. The review's pescatarian note (no legacy gate, no asymmetry) matches the code, so pescatarian is untouched.

Finding 3 (Low, pre-existing) — TasteEventStoreTests rejected by Linux Swift 6.4. Ported trunk fix 9de29858 (cookedEvent returns TasteEventRecord). Fails-first reproduced locally: reverting just that line in the portable harness gives 16 conversion errors / build exit 1; with the fix, build exit 0. Not a semantic change (the function returns what it constructs).

Commands and results: portable harness (Linux x86_64 Swift 6.4, production persistence sources, GRDB): red runs as above, then swift test --filter RecipeCatalogRecommendTests → Executed 14 tests, with 0 failures (12 prior + 2 new); swift format lint --strict clean on the six touched files (TasteEventStoreTests.swift carries pre-existing LineLength findings on lines 82+ that this PR does not introduce and does not touch). Hosted macOS/iOS CI on the new head: see the checks below — started on push of 5a33152.

Not verified: no Xcode/device — the SwiftUI cooking flow (Start Cooking on a catalog entry, Le Chef handoff rendering) is compile-checked by hosted macOS CI and call-chain-reviewed, not runtime-verified; Linux portable checks cover the repository layer, which is where all logic in this round lives.

ObviousApp and others added 6 commits October 15, 2026 21:17
ScoredRecipe now carries catalog provenance and a pooled identity that
is unique across both pools. findMakeable and findNearMatch search the
catalog pool beside the legacy pool and merge one ranked list: catalog
candidates must resolve every required line through the identity bridge,
pass allergen and diet-claim gates, and gain use-soon urgency from the
existing expiry query; legacy-successor recipes are excluded per
candidate so a catalog row and its legacy recipe never double-rank.
Shared ranking keeps ordering identical across pools.

Co-authored-by: Sam Gu <sgu07966@gmail.com>
The bundled catalog names ingredients by stable keys (fdc_id or legacy
id) while the app pantry stores ingredient row ids. Add the
recipes_catalog_ingredient_bridge table and RecipeCatalogIngredientBridge,
which resolves each catalog key to app ingredient ids via legacy_id or
the bundled USDA name/alias mapping, leaving unresolved keys unmapped
rather than guessing. Rebuild the bridge inside the same transaction as
the vocabulary upsert on both the v2 and legacy hydration paths so key
resolution can never drift from the vocabulary. The migration registers
after the catalog vocabulary migration so its parent tables exist first.

Co-authored-by: Sam Gu <sgu07966@gmail.com>
Add a catalog cook-packet API that maps catalog lines to CookQuantity
and structured steps (timers and thermometer checks) to CookStep, and
wire the preview drawer to load bridged catalog ingredients with
quantity display helpers instead of the legacy recipe path.

Co-authored-by: Sam Gu <sgu07966@gmail.com>
Results-grid and transition identities move to pooled ScoredRecipe
identity, and the reverse-scan selection key follows it so catalog
recipes with no legacy integer id stay distinct instead of colliding.

Co-authored-by: Sam Gu <sgu07966@gmail.com>
Twelve cases covering merged pools and identity, unresolved bridge keys,
allergen and diet gates, successor deduplication, use-soon scoring and
reasons, cook packets, and identity-bridge rebuilding.

Co-authored-by: Sam Gu <sgu07966@gmail.com>
Co-authored-by: Sam Gu <sgu07966@gmail.com>
@SamGu-NRX

Copy link
Copy Markdown
Owner Author

@codex review

@coderabbitai

coderabbitai Bot commented Oct 15, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-15T21:49:49.205019Z 9f5a701 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9f5a7017fe

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +141 to +148
let recipe = Recipe(
id: nil,
title: title,
timeMinutes: minutes,
servings: servings,
instructions: "",
tags: 0,
source: .bundled,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve structured cook data for catalog recommendations

Catalog matches are materialized as a Recipe with id: nil and an empty instructions string, but the start-cooking flow still constructs CookingGuideView from that Recipe. As a result, selecting any catalog recommendation opens a guide with no ingredient rows or steps (CookingGuideView.loadIngredients returns immediately for a nil id and CookingGuideSteps parses the empty instructions), so the newly recommended catalog recipes cannot actually be cooked.

Useful? React with 👍 / 👎.

Comment on lines +87 to +94
switch profile.selectedDietID {
case "vegetarian" where claims?.vegetarian != true:
continue
case "vegan" where claims?.vegan != true:
continue
default:
break
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Fail closed for unsupported dietary restrictions

The catalog diet gate only rejects recipes for vegetarian and vegan; HealthProfile also supports keto and pescatarian, but those cases fall through to default and every catalog recipe is admitted regardless of its claims. The legacy query applies the corresponding tag mask, so users with either restriction can receive catalog recipes that violate their selected diet.

Useful? React with 👍 / 👎.

Comment on lines +87 to +94
switch profile.selectedDietID {
case "vegetarian" where claims?.vegetarian != true:
continue
case "vegan" where claims?.vegan != true:
continue
default:
break
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Reject catalog recipes for keto and pescatarian profiles

The catalog pool bypasses HealthProfile.requiredRecipeTagMask and only checks vegetarian/vegan claims. For keto and pescatarian, selectedDietID falls through this switch, so catalog recipes with no compatible claim are still recommended even though the legacy pool excludes them; this can surface recipes that violate the user's active dietary restriction.

Useful? React with 👍 / 👎.

Comment on lines +141 to +148
let recipe = Recipe(
id: nil,
title: title,
timeMinutes: minutes,
servings: servings,
instructions: "",
tags: 0,
source: .bundled,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Pass catalog ingredients and steps to Le Chef

When a catalog result is sent to Le Chef, the results view only loads ingredients through ingredientsForRecipe when scored.recipe.id is non-nil. Catalog results deliberately have no legacy integer id, so LiveAssistantRecipeContext receives an empty ingredient list and the synthesized recipe has empty instructions as well, leaving the assistant without the structured catalog content that was just matched.

Useful? React with 👍 / 👎.

The drawer's quantity helpers reference CookQuantity from the
FLFeatureLogic package; sibling feature files already import it, and
macOS CI flagged the two missing-symbol errors this import fixes. The
Linux portable check cannot compile SwiftUI targets, so this surface is
CI-verified only.

Co-authored-by: Sam Gu <sgu07966@gmail.com>
The candidate id, its selection state, and the dedupe set move to the
pooled ScoredRecipeID, which already covers the old title-hash fallback
via .unsaved. The screen's chosen-recipe key now branches on how the
choice was made: the legacy row id for manual picks, the pooled identity
for candidate picks, so catalog entries stay distinct.

Co-authored-by: Sam Gu <sgu07966@gmail.com>
The test target compiles against the FLFeatureLogic framework target, so
its public types need the explicit import; the Linux harness builds the
same sources as one module and could not surface this.

Co-authored-by: Sam Gu <sgu07966@gmail.com>
@obvious-autobuild

Copy link
Copy Markdown

Heads-up from the weekly-plan PR (#178): the FLFeatureLogic import fix unblocks RecipeCatalogRecommendTests, but the same test target then type-checks Tests/TasteStore/TasteEventStoreTests.swift, which does not compile on this lineage — cookedEvent declares -> TasteEvent while constructing TasteEventRecord (seven type errors; store.append takes the record type).

It is masked in every run so far because compilation aborted at the CookThermometer error first, so the rerun of 38263783 will likely fail there. Verified present verbatim at 9f5a7017 via git show — pre-existing, not from #178's delta.

The trunk integration already carries the one-line fix: 9de29858 ("fix(ios): cookedEvent helper returns the store record type", CI-green at trunk, run 38805706914). #178 cherry-picked it as 121244d5; merging that fix here would clear the path for both PRs.

obvious-autobuild Bot pushed a commit that referenced this pull request Oct 15, 2026
The app and catalog targets compile at 95ec322; CI now fails in the
inherited TasteEventStore tests — the cookedEvent helper is declared
-> TasteEvent while constructing a TasteEventRecord, which only
compiles in PR #172's merge preview because the trunk branch supplies
its fixed copy (9de2985). The catalog-recommend base carries the
pre-fix file, so PR #174's merge preview fails. Apply the same
one-line return-type correction the trunk made, so the branch matches
the trunk-fixed version and future base merges resolve cleanly.

Co-authored-by: Sam Gu <sgu07966@gmail.com>
@obvious-autobuild

Copy link
Copy Markdown

Independent review (Obvious, Autobuild + Max)

Verdict: changes needed

The engine work is solid and the test claims check out (12/12 reproduced independently on Linux against the production sources, both key behaviors fails-first-verified). What blocks readiness is that the new recommendations dead-end at the two actions that make them useful — cooking and Le Chef — and the keto diet gate fails open on the catalog pool.

Findings

1. High — catalog recommendations can't actually be cooked, and Le Chef sees an empty plate.
RecipeRepositoryCatalogRecommend.swift:142-157 materializes catalog entries as Recipe(id: nil, instructions: ""). Downstream:

  • CookingGuideView.swift:33 builds the guide from scoredRecipe.recipe.instructions → empty for every catalog recipe; CookingGuideView.swift:294-296 returns early in loadIngredients() when recipe.id == nil → no ingredient list either.
  • RecipeResultsView.swift:370-376 sets ingredients: [] in LiveAssistantRecipeContext for nil ids, so "Cook with Le Chef" on a catalog recommendation starts with zero context.
    The cook-packet API exists and is good (catalogCookPacket, bridged lines with CookQuantity, steps with timers/thermometer) — but only RecipePreviewDrawer.swift consumes it. Smallest fix: route CookingGuideView and storeRecipeForAssistant through the same packet for catalog?.ref entries. Source-verified only: no test exercises Start Cooking with a catalog entry, and I have no Xcode here, so this finding is from reading the call chain, not from a device run.

2. High — keto gate fails open on the catalog pool.
HealthProfile.swift:103-107 selects keto as a supported diet; HealthProfile.swift:119-130 maps it to the .lowCarb tag mask and the legacy SQL enforces it (RecipeRepository.swift:156). The catalog gate switch (RecipeRepositoryCatalogRecommend.swift:88-92) handles only vegetarian/vegan and lets keto fall to default; RecipeCatalogClaims has no low-carb field at all. Live probe against the production sources (keto profile, pantry = egg+rice, single migrated DB): result set is [catalog("rcp-000001")] — the legacy pool is correctly emptied by the tag mask while the catalog recipe carrying claims: "{}" sails through. So a keto user's catalog results are entirely ungated while their legacy results vanish — worse than either pool alone. Smallest fix: fail closed — diets whose claims the schema can't prove (keto) exclude the catalog pool until the data pipeline ships a low-carb claim. Note: pescatarian (raised in the Codex review) has no legacy tag mask today, so there's no legacy/catalog asymmetry there — keto is the live gap.

3. Low, pre-existing — Linux-portable runs on this lineage trip over TasteEventStoreTests.
Tests/TasteStore/TasteEventStoreTests.swift:44-50 declares cookedEvent(...) -> TasteEvent while constructing TasteEventRecord(...); TasteEventStore.append takes TasteEventRecord (TasteEventStore.swift:33,43). On Linux Swift 6.4 that file produces 6+ type-conversion errors (reproduced in my harness); hosted macOS CI compiles and runs the same file green (12 cases passed in run 38817702837). Not introduced by this PR (the diff 9f5a7017..38263783 doesn't touch it), and trunk already fixed it (9de2985, cherry-picked into #178 as 121244d). Suggest merging that cherry-pick here before un-drafting so Linux portable checks work on this branch. I can't fully explain why the Apple toolchain accepts the conversion; both results are reported as observed.

What I verified (commands + results)

  • Read the body, all comments (Codex review + 4 inline findings), the full diff (13 files, +1342/−25) at head 382637837c2e (merge-point base 90386c63).
  • Linux harness (Swift 6.4, vendored GRDB 7.10.0, production Platform/Persistence + Domain sources; excluded 8 unreferenced Apple-only files, the CookProposal* pair and LiveAssistantPanelLayout; shims: CryptoKit→swift-crypto, Notification.Name.inventoryDidChange): swift test --filter RecipeCatalogRecommendTests -Xswiftc -DSQLITE_DISABLE_SNAPSHOT → Executed 12 tests, with 0 failures — the body's 12/12 claim holds.
  • Fails-first (working-tree-only reverts, restored after each, repo clean): disabling the successor dedupe (RecipeRepositoryCatalogRecommend.swift:245) fails testFindMakeableMergesLegacyAndCatalogPools on exactly the two successor assertions; disabling the use-soon bonus (:178) fails testUseSoonBonusAppliesToBothPools with 0.0 ≠ 6.0 on the catalog entry. The new tests bite.
  • CI: run 38817702837 SUCCESS at this exact head sha; log compiles both test files and shows the catalog test cases passing on the simulator.
  • Body bundle claims vs the shipped resource (jq over apps/ios/Resources/RecipeCatalog/recipes-v2.json): 763 recipes ✅, 5,010 lines ✅, 0 recipes with a legacy_recipe_id field ✅, ids start at rcp-000167 ✅ (legacy 1–166 reserved, so shipped data exercises no successor dedupe — the body says the same).
  • swift format lint --strict over all 13 changed files: clean (body says "12 changed files" — trivial count slip).
  • Use-soon predicate matches InventoryRepository.useSoonSuggestions verbatim (InventoryRepository.swift:396-405); allergen-gate parity holds (legacy whole-recipe exclusion over all recipe_ingredients rows == catalog gate over all bridged lines); recipes_catalog.claims is NOT NULL so the strict String read can't crash.

Couldn't verify

  • No Xcode/macOS here: SwiftUI rendering, the real Start-Cooking flow, and the reverse-scan identity plumbing are compile-checked only by hosted macOS CI (green). Finding 1 is call-chain-verified, not runtime-verified.
  • The external scale-run numbers in the body (bridge 124 rows / 116 unmapped, findMakeable 0.07 s, cook packet rcp-000269) aren't committed, so I didn't re-run them; the bundle counts above are checked against the shipped resource instead.
  • Why the macOS toolchain compiles TasteEventStoreTests that Linux rejects (finding 3).

Codex's four inline findings: #1 (cook dead-end) and #4 (Le Chef empty context) confirmed; #2/#3 confirmed for keto, not for pescatarian (no legacy gate exists to be asymmetric with).

🔗 Obvious Project · 🧵 Obvious Thread · 🔀 Obvious PR Artifact

ObviousApp and others added 3 commits October 16, 2026 01:33
The claims schema has no low-carb field, so no catalog recipe can prove
keto compliance, while the legacy pool enforces the .lowCarb tag mask —
without this arm a keto user loses every legacy result yet keeps every
catalog result. Fails-first: testKetoDietExcludesCatalogPoolFailingClosed
reproduces the ungated catalog entry before the gate arm lands.

Co-authored-by: Sam Gu <sgu07966@gmail.com>
Catalog entries materialize as nil-id legacy stand-ins, so Start Cooking
rendered an empty guide, loadIngredients returned nothing, and Le Chef
received zero ingredient context. Add catalogCookPacket(for:) and
cookPacketIngredients(_:) on the repository — the single structured path
— and route the preview drawer, the cooking guide, and the assistant
context through it. Fails-first: the packet path had no repository API
before this commit and
testCatalogRecommendationYieldsCookPacketAndBridgedIngredients pins
non-empty steps and bridged ingredient lines for a catalog result.

Co-authored-by: Sam Gu <sgu07966@gmail.com>
TasteEventStoreTests declared cookedEvent -> TasteEvent while
constructing a TasteEventRecord, which Linux Swift 6.4 rejects with 16
conversion errors (reproduced in the portable harness; fails-first).
Ports trunk commit 9de2985 so the Linux portable checks compile on this
lineage too. macOS CI compiles both forms; semantics are unchanged.

Co-authored-by: Sam Gu <sgu07966@gmail.com>
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