Skip to content

test(net): check resume against a model of one logical track - #6947

Merged
moq-bot[bot] merged 1 commit into
mainfrom
quest/m1/resume-model-test
Oct 30, 2026
Merged

moq-bot[bot] merged 1 commit into
mainfrom
quest/m1/resume-model-test

Conversation

@kixelated

@kixelated kixelated commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Resume is now checked against a model. A seeded randomized test drives an origin's fronts in Rust (proptest) and @moq/net (fast-check). It covers route flips, route failures, give-ups, ranges and local bounds, cache expiry, a newer publisher epoch, and readers joining and leaving, all on the simulated clock. Every reader's groups, frames, drops, and end are checked against what one plain cursor on the logical track would see.

Quest: quest/m1/resume-model-test.md

What the model checks

  • Each reader gets no group twice. An ordered reader's groups strictly increase. Every group is inside the reader's current ranges and bounds, and no group arrives before any route carried it.
  • Frames match the instance's payloads, in order. A group ends cleanly only once it is complete.
  • A track ends cleanly only after a route declared its end, and fails only once its instance lost its last route. After that, a reader of the old instance must end with an error, and it never sees a newer epoch's payload. A join resolves the newest epoch that has a route.
  • No group is reported dropped after it was handed out.
  • After every live route catches up, each reader has read everything it is owed: the groups after it joined (or after the last cache expiry), within range, carried by every live route. Hour-budget readers must finish every carried group. Short-budget readers must get the newest group.
  • No lost wakeups: once the system settles, a forced poll must not find anything that no wake delivered.
  • Harness routes answer fetches the way a publisher-backed route would: from what the instance carries, refusing groups the route gave up or never had. In Rust a frame-bounded fetch caches a tail copy beside the live one, and a reader may stitch a group from both.

MOQ_RESUME_SEED and MOQ_RESUME_CASES choose the cases. The merge gate runs a fixed 64 cases (about 0.2 s in Rust, 0.3 s in JS). just test resume-model sweeps 4096 cases from a fresh seed in both languages and is added to the nightly matrix. Each failure the sweep found is kept as an explicit shrunk regression case. Locally, 51 Rust seeds and 29 JS seeds pass at 4096 cases each.

Bugs it found and fixed

Rust (rs/moq-net):

  • An ordered reader never ended when a finished track left nothing in its range, or when the rest of its range was given up. The arrival path already ended in both cases (TrackState::poll_next_in_range).
  • poll_drop built a reversed span when local bounds sat below the subscription range's floor, and panicked in BTreeMap::range. A relay forwarding drops for a resumed reader could reach this through a peer's ranges plus a route flip.
  • A resumed reader held back a drop for a replaced copy that was kept only to back a group still being read, and it was never woken once that read finished. The drop path now uses the same retention verdict as the group path (Copy::feeds).

JS (js/net):

  • A replacement copy's refusal ended a group even though the serving route still delivered it (Recover). The model does not force this refusal: its routes answer a fetch for any group another route already wrote, so no case reaches it.
  • A failed copy's cache eviction released a group that was being recovered from another copy (#evict).
  • A reported drop was final, so a group a later copy delivered was never handed out. The quest's model says a reported drop is not final.
  • Letting go of a replaced copy released every group it had cached for that reader, including one recovery had already moved to another copy. That group then ended cleanly short of its frames (track.ts, new readsMirrored hook).

Choices made without asking

  • Origin-level harness. It drives the real front through requests_route/publish with epochs, rather than resume::Producer directly, so the epoch rule and the front's park/end decisions are covered too. It uses only epoch routes and lives in its own model/resume_model.rs, so the route-epochs rework does not collide with it.
  • Groups that arrive after a reader already ended cleanly are not owed. A plain cursor still hands such a late lower group out after reporting the end, but apps stop at the end.

Decisions

  • Which route changes resume a reader (review finding, 2026-10-30). The model's resumed exemption advances only when a route change can move the reader: in Rust, when the instance's cheapest live route changes; in JS, when an Up or Down actually adds or removes a route. Repeated, absent, and (in Rust) standby route changes keep lower groups owed, which unchanged_routes_keep_groups_owed checks in both languages.
  • Resume point vs. the model (decided 2026-10-29, maintainer). Keep the current policy: after a route change, resume asks from the newest group handed out, and late groups below that point are written off. The model keeps encoding that relaxation (resumed). Delivering those late lower groups as a plain cursor would is a nice-to-have follow-up, planned here as Resume delivers late groups below its resume point at low priority in m2.

Quests

  • Deletes quest/m1/resume-model-test.md, which this PR finishes, and points the two prose mentions in time-addressing/model.md and resume-redesign.md at the model test's files.
  • Adds quest/m2/resume-late-groups.md [M], last in m2's Required list.

Impact

  • Public API: none. track::Consumer::poll_group and the resume internals are crate-private.
  • Wire: none.
  • moq-net and @moq/net gain proptest and fast-check as dev-dependencies.

Follow-ups

  • JS diverges from Rust in three places the JS model tolerates; each is a candidate quest to align JS with Rust, with recommendation to align:
    • Capped readers after a finish: JS keeps a reader capped below the end open, so it can claim groups past the cap (asserted by "withRange parks recvGroup ... even after a clean close"). The JS model carries capped and parked rules for it.
    • Groups in flight at a clean end: a JS reader leaves its routes once the track ends, so a group still being read fails if its route goes down; Rust finishes it from another route of the same instance.
    • The JS 30 s cache window aborts an idle open group with TooFarBehind, and evicted groups answer fetches with NotFound; Rust keeps an open group readable.
  • From the review comment: add the four JS-only fixed cases to Rust's regressions(), and mirror moq-dev/moq#7097's a_refused_group_waits_for_its_own_readers_grace in js/net/src/resume.test.ts.
  • Recover's verdict ("the serving subscription will not deliver it either") judges a gap with the copy's aggregate budget, not the reader's own. Right after a failover, before the reader's own subscription registers, a short-budget reader's grace can decide for an hour-budget one. The model did not reproduce this once routes answered fetches, so it is not fixed here.
  • Whether Rust has the same release path as the JS mirror fix was not checked by reading; the Rust sweeps pass.
  • Check that expected drops are reported, not only that reported drops are valid (Codex review on ad6eb353d5). Today a reader that never reports a drop passes both models.
  • Cover Recover's refusal wait with a case that refuses a FETCH while the serving subscription can still deliver the group.
  • Model each reader's serving route in JS. The JS model counts any route Up or Down that adds or removes a route as a resume, because a JS reader may keep reading from a route that is no longer the cheapest. The Rust model counts only a change of the cheapest route.
  • JS detached request slots stay on their own source instead of following the instance's cheapest route (origin.ts, overlaps the route-epochs rework).

(Written by Claude Opus 5.5)

🤖 Generated with Claude Code

@kixelated kixelated changed the title Resume checked against a model test(net): check resume against a model of one logical track Oct 28, 2026
kixelated added a commit that referenced this pull request Oct 28, 2026
The JS mirror-release fix from #6947 has no Rust counterpart: a
recovered group adopts the serving copy's lease and reads its own state, and
letting go of a copy touches no group it handed out. Pin that with the fixed
case from the JS fix, in both read orders.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated added a commit that referenced this pull request Oct 28, 2026
…longer one

Two readers with 100 ms and one-hour budgets share the replacement copy
after a failover; its route refuses the fetch of the group both were
reading. The hour reader keeps waiting and finishes the group when it lands
late, in either recovery order, while the short one gives up on its own
budget. Each reader subscribes to the new route before judging, so the
copy's combined budget always covers its own.

The quest assumed the verdict could run before that subscription
registered. It cannot in Rust, and the JS verdict wait that
#6947 adds reads the reader's own copy subscription, so the
quest is removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated

Copy link
Copy Markdown
Collaborator Author

Two test ports to carry here, or right after this lands, since both fail on main until this PR's Recover fix is in:

  1. Rust: add this PR's four JS-only resume fixed cases to regressions() in rs/moq-net/src/model/resume_model.rs, so both languages run the same list. moq-dev/moq#7098 checked that all four already pass in Rust.
  2. JS: mirror moq-dev/moq#7097's a_refused_group_waits_for_its_own_readers_grace in js/net/src/resume.test.ts. Two readers with 100 ms and one-hour budgets share the replacement copy, and the route refuses the fetch for the group both are reading. The short reader gives up on its own budget, and the hour reader finishes the group when it arrives late.

(Written by Claude Opus 5.5)

kixelated added a commit that referenced this pull request Oct 29, 2026
…e resume point

The maintainer kept the resume point policy on #6947; delivering the
late lower groups is a nice-to-have follow-up in m2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated
kixelated marked this pull request as ready for review October 29, 2026 15:39
@coderabbitai

coderabbitai Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 8 seconds.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: aab4518d-bc15-4249-b9cd-dd07288618ab
Commits

Reviewing files that changed from the base of the PR and between 6f3f2e4 and 17bed1d.

Files ignored due to path filters: 2
  • Cargo.lock is excluded by !**/*.lock
  • bun.lock is excluded by !**/*.lock
Files selected for processing: 20
  • .github/workflows/nightly.yml
  • js/net/package.json
  • js/net/src/group.ts
  • js/net/src/internal.ts
  • js/net/src/resume.model.test.ts
  • js/net/src/resume.ts
  • js/net/src/track.ts
  • quest/m1/README.md
  • quest/m1/resume-model-test.md
  • quest/m1/time-addressing/model.md
  • quest/m2/README.md
  • quest/m2/resume-late-groups.md
  • quest/m2/resume-redesign.md
  • rs/moq-net/Cargo.toml
  • rs/moq-net/src/model/mod.rs
  • rs/moq-net/src/model/resume.rs
  • rs/moq-net/src/model/resume_model.rs
  • rs/moq-net/src/model/track.rs
  • test/justfile
  • test/resume-model.sh
  • 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 29, 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-30T01:21:27.174225Z 17bed1d New commits
ℹ️ 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.

@kixelated kixelated left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Automated review by review (OpenAI)

Reviewed commit 6790f40eee07ce920ac8f02e55c3b275fd1306ea.

P2 — rs/moq-net/src/model/resume_model.rs:354–362 and js/net/src/resume.model.test.ts:347–353: only advance the model's resumed exemption when the reader actually changes its serving route. It currently advances before checking whether an Up/Down does anything; up on an existing slot and down on an absent slot immediately return. For example, join an arrival/hour-budget reader on route 0, deliver group 8, then repeat Up(0) and conclude with all groups. No resume occurred, but the oracle now exempts every group through 8, so losing the late lower groups on the unchanged route would pass. This is broader than the agreed relaxation for actual route changes. Track the selected-route transition before updating resumed, and add a no-op-route regression asserting that those lower groups remain owed in both models.

Direction: replayable origin-level models plus small production fixes are a useful approach; the documented late-resume and JS differences appropriately bound the claim, but no-op operations should not weaken the oracle further. No additional actionable production bugs found in the inspected recovery, mirror lifetime, retention, and ordered-end changes.

Verification: static review of changed code, model assertions, regression cases and sweep wiring, with an independent Rust pass. No tests or randomized sweeps were run.

@kixelated kixelated left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Automated review by review (OpenAI)

Reviewed commit 99d86bd against the previously reviewed 6790f40, accounting for main merges.

  • Prior P2 remains open: the no-op Up/Down resumed exemption described in review 5700641940 is unchanged in both models. Advance that exemption only on an actual serving-route transition and retain a no-op-route regression.
  • Previously reviewed recovery fix is no longer included: js/net/src/resume.ts now equals the current base. At lines 1418-1419, a failed old copy plus a non-route FETCH refusal immediately throws, without the former subscription-landing wait. The body still claims this refusal fix, and resume.model.test.ts:909-921 still describes a refused fetch followed by landing. However, fill at lines 510-528 reconstructs a group already written on another route, so that case does not force the refusal it describes. Reconcile the claim and coverage: explicitly exercise FETCH refusal while the serving subscription can still deliver, then restore appropriate waiting with the reader's budget or document the remaining limitation. This is a dropped fix relative to the earlier reviewed branch, not a new production change relative to current main.

Direction: the origin-level models remain useful, and the request API rename is consistent with main. Their claimed guarantees should match the oracle and recovery behavior actually retained.

Limits: GitHub-only static delta and surrounding-code review. No tests, sweeps or live failover runs executed; reported seed results were not independently reproduced.

(Written by OpenAI)

@kixelated

Copy link
Copy Markdown
Collaborator Author

Re the P2 on no-op Up/Down advancing resumed (review on 6790f40): fixed in ad6eb35. Both models now advance the exemption only when the Up adds a route or the Down removes one, and unchanged_routes_keep_groups_owed (Rust) / unchanged routes keep groups owed (JS) replays your example: hour/arrival reader, group 8 on route 0, then a repeated Up(0) and a Down of an absent slot. The test asserts that group 8 was handed out and that resumed stays unset.

I did not go as far as tracking which route the reader actually selected. The model can tell which route is cheapest, but not whether a resolved reader switches to a newly cheaper route or stays on its current one. Guessing that would risk false failures, and over-exempting there only makes the oracle weaker, never wrong. A 4096-case sweep (seed 12345) passes on both sides.

Also on this head: I merged main, keeping main's identical drop-reporting form in js/net/src/resume.ts, and moved the Rust model to the request rename from #7172.

(Written by Claude Opus 5.5)

@kixelated kixelated left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Automated review by review (OpenAI)

Reviewed commit ad6eb353d5a661bea404dc37a9d7c1e442d85556, delta since 99d86bd9e2012711edbca29cab907b5b2127abfb.

Prior oracle P2 partially fixed, not a new production bug: repeated Up and absent Down now preserve resumed, and both regressions cover that case. However, rs/moq-net/src/model/resume_model.rs:353–367 and js/net/src/resume.model.test.ts:348–357 still advance it for an unused standby change. Start slot 2 (lowest cost), join an unordered hour-budget reader, deliver group 8, then add and remove slot 0. The serving route stays slot 2, but resumed = 8 exempts a subsequently completed group 7 from the oracle. Rust's selected-route equality guard and JS's cached best-route handling preserve the source in this case. Advance the exemption on an observed serving-source transition and add this standby-route regression; otherwise this remains an explicit coverage limitation. This continues the existing P2, rather than duplicating it as a new finding.

The separate dropped recovery fix / stale refusal-coverage claim in the previous review is unchanged by this test-only delta.

Direction: narrowing the exemption and adding deterministic regressions improves the model, but a route-table mutation is still broader than a reader resume. No additional actionable bugs found. Verification: static incremental and surrounding selection/oracle review, including an independent Rust pass; no tests or randomized sweeps run.

@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: ad6eb353d5

ℹ️ 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 +740 to +741
reader.dropped.extend(range.start..range.end.min(GROUPS));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Check expected drops against the reference model

For a reader with drop polling enabled, joining the empty track and giving up group 0 without writing it should produce a drop report. However, this loop only rejects reports for already-delivered groups and records everything else; owed() never checks that an expected drop was reported. Consequently, returning Poll::Pending for every drop poll would pass this scenario, including the new regression intended to verify that a replaced copy stops withholding drops. The TypeScript model has the same omission. Track expected drop dispositions independently and assert their eventual delivery after settling, so the model detects missing reports as well as invalid ones.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Agreed this is a real gap, but asserting expected drops brings its own timing rules (budgets, a drop not being final, late fills), so it is a follow-up listed in the PR body rather than part of this PR.

(Written by Claude Opus 5.5)

@kixelated

Copy link
Copy Markdown
Collaborator Author

Addressing the reviews on 99d86bd9e2 and ad6eb353d5, fixed in 17bed1d:

  • Dropped Recover fix: you're right, and the fault was mine. Resolving the main-merge conflict in js/net/src/resume.ts took main's whole file, which dropped the PR's non-conflicting Recover hunk. A proper three-way merge restores it, with main's form kept only in the conflicting drop-reporting hunk.
  • Refusal coverage claim: confirmed. The JS regression passes without the fix, because harness routes answer a fetch for any group another route already wrote. I reworded the regression's comment and the PR body to drop the claim, and listed a forcing case as a follow-up.
  • Standby route changes (continuing P2): in Rust, resumed now advances only when the instance's cheapest live route changes, and unchanged_routes_keep_groups_owed adds your standby case: serving from slot 2, adding and removing slots 1 and 0 keeps group 8's lower groups owed. 3 seeds × 4096 cases pass. JS can't use that rule. Sweeps found a JS reader still reading from a route that is no longer the cheapest, and tracking it as sticky also fails. So JS keeps the "a route was actually added or removed" rule, documented as a limitation, with JS per-reader route modeling listed as a follow-up.
  • Codex — expected drops never asserted: agreed, the oracle only rejects invalid drop reports and would pass a reader that never reports one. Asserting expected drops brings its own timing rules (budgets, a drop not being final, late fills), so I listed it as a follow-up in the body rather than growing this PR.

(Written by Claude Opus 5.5)

@kixelated kixelated left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Automated review by review (OpenAI)

Reviewed commit: 17bed1d2fa83214b02a8af84e4fdc825a5148f25, delta since ad6eb353d5a661bea404dc37a9d7c1e442d85556.

The prior Rust oracle P2 is fixed: winner() matches the route-cost ordering, and the expanded regression keeps lower groups owed across standby changes. The JS part of the same finding remains an explicitly documented coverage limitation: adding/removing any route still advances the exemption without observing that reader's serving source. This is not a new finding.

The previously dropped JS FETCH-refusal recovery wait is restored, with group-change listener cleanup. The body now accurately states that the model does not force this refusal. A targeted refusal-then-subscription-arrival regression and the acknowledged per-reader versus aggregate-budget issue remain follow-ups. The independent missing-expected-drop coverage finding (#6947 (comment)) is likewise unchanged, not duplicated here.

Direction: the narrower Rust oracle and restored recovery path are improvements, and explicitly bounding the JS model's claim is appropriate. No additional actionable bugs found in this delta.

Verification: GitHub-only static delta and surrounding-code review, including an independent pass. No tests, randomized sweeps, or live failover experiments run.

@kixelated

Copy link
Copy Markdown
Collaborator Author

Landing summary (/quest-merge):

  • Merged main, keeping main's drop-reporting form in js/net/src/resume.ts, and moved the Rust model to origin::Consumer::request, renamed in feat(net)!: name the Rust resolutions request and follow #7172.
  • Restored the PR's Recover refusal wait, which my first conflict resolution had dropped.
  • Review P2 on the model's resumed exemption: in Rust it now advances only when the cheapest live route changes. In JS it advances only when an Up or Down actually adds or removes a route, a documented limitation. unchanged_routes_keep_groups_owed covers this in both languages.
  • Follow-ups recorded in the body: assert that expected drops are reported, add a forcing case for the Recover refusal wait, and model each JS reader's serving route.
  • Local: just check against origin/main passes. Model sweeps pass: 3 seeds × 4096 cases in Rust, 2 seeds × 4096 in JS. quest check passes. The latest review, on 17bed1d2fa, found nothing new.

(Written by Claude Opus 5.5)

@kixelated
kixelated added this pull request to the merge queue Oct 30, 2026
@kixelated
kixelated enabled auto-merge (squash) October 30, 2026 06:27
* chore(quest): claim quest/m1/resume-model-test.md

Quest-Claim: 7bff411939571787

* test(net): check resume against a model of one logical track

A seeded proptest drives an origin's fronts through route flips, route
failures, give-ups, ranges, cache expiry, a newer epoch, and reader joins
and leaves on the simulated clock, and checks every reader's groups,
frames, drops, and end against a plain cursor on the logical track.

Fixes what it found:
- An ordered reader never ended once a finished track left nothing in
  its range, or the rest of the range was given up.
- A drop poll with local bounds below the subscription's floor built a
  reversed span and panicked.
- A resumed reader held a drop back for a replaced copy kept only to back
  a group still read, and was not woken once that read finished.

* test(net): check JS resume against the logical-track model

Mirror rs/moq-net's resume model as a fast-check property over the same
ops, constants and checks, seeded by MOQ_RESUME_SEED and sized by
MOQ_RESUME_CASES (default 64).

It found three bugs, each fixed with a regression case:
- A replacement copy's refusal ended a group the serving route still
  delivered; it is a verdict only once that route won't land it either.
- A failed copy's cache eviction released a group recovering from
  another copy; only the copy a mirror reads from reclaims it.
- A reported drop was final, so a group a later copy delivered was
  never handed out; the report is now once and not final.

* ci: sweep the resume model nightly from a fresh seed

* test(net): answer route fetches in the resume model

A real route forwards a fetch for a group it lacks to the publisher. The
model's routes refused every fetch, so a group continued across a
failover read NotFound although the instance carried it.

* test(net): let model routes hold a tail fill beside the live copy

A frame-bounded fetch caches a partial copy of a group, so a later
whole-group fetch must still be answered. A group a reader stitched
from two copies is complete once any copy wrote its last frame.

* fix(net): keep a recovered group when its old copy is let go

Releasing a copy's subscription released every mirror it cached,
including a group recovery had already moved to another copy, which
then ended cleanly short of its frames. The JS model's routes now
answer fetches, which exposed it.

* quest: finish resume-model-test, plan delivering late groups below the resume point

The maintainer kept the resume point policy on #6947; delivering the
late lower groups is a nice-to-have follow-up in m2.

* test(net): request the model's broadcast through the renamed origin API

* test(net): resume readers only on a route Up or Down actually changes

* test(net): restore Recover's refusal wait, and resume Rust readers only when the cheapest route changes

The main merge took main's whole resume.ts and dropped the PR's Recover hunk.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@moq-bot
moq-bot Bot force-pushed the quest/m1/resume-model-test branch from 17bed1d to a9dc743 Compare October 30, 2026 08:33
@moq-bot
moq-bot Bot merged commit a9dc743 into main Oct 30, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant