Skip to content

fix: treat a repository model as an own model for quota - #733

Merged
HugoXK merged 1 commit into
mainfrom
fix/732-repo-model-readiness
Nov 15, 2026
Merged

HugoXK merged 1 commit into
mainfrom
fix/732-repo-model-readiness

Conversation

@HugoXK

@HugoXK HugoXK commented Nov 15, 2026 •

Copy link
Copy Markdown
Owner

Written-by: HugoXK

What changed

A provider model selected for a repository now counts as an own model everywhere Fledge decides whether a job is platform-funded. The first-run model step is completed by a repository selection rather than by a provider row; when a provider exists but no repository has selected it, the step links to the repository picker. The dashboard no longer shows the exhausted-quota action to a user who has a usable own model, and both the enqueue and dispatch quota checks treat a repository selection as non-platform-funded.

The platform-satisfied model step now also shows the remaining platform balance. Below PLATFORM_QUOTA_COMFORT_CNY (default 50, configurable in .env) it warns that the balance may not cover the first run and offers an immediate "add your own model" or "choose a repository model" action. At the threshold or above (or when unlimited) it only names the remaining balance and points at Settings → Model for later configuration. The threshold changes the advice only, never quota accounting.

Fixes #732

Why

src/gateway/gateway.ts and the bridge already resolve the repository's selected model, but src/app.ts counted any provider row as a configured model, and src/jobs/service.ts decided platformFunded from the legacy users.own_llm_* fields only. A repository with a selected model was therefore refused with QUOTA_EXHAUSTED before the gateway was called, the dashboard kept asking for a model that existed, and adding a provider in Settings could mark the model step done without the repository ever using it.

The default 1 CNY platform quota also looked like a comfortable default. A first run can spend that quickly, so the checklist now says how much is left and, below the configured threshold, recommends the own-model path instead of silently skipping the step.

Verification

Ran:

  • npm run check — pass (1842 tests, typecheck, build)
  • node scripts/version.mjs check — 0.3.6 ok
  • node scripts/changelog.mjs check — pass

Not run:

  • Real browser click-through
  • Production deploy
  • Real SMTP

Security notes

The quota pre-check now reads repo_model_selection; a repository-selected model is no longer refused as platform-funded. The gateway still applies the repository's provider policy, SSRF guard and metering for that model. No token, secret or quota accounting format changed. PLATFORM_QUOTA_COMFORT_CNY changes the checklist advice only.

Note

Rebased onto the current main. #735 and #745 have since merged; this branch includes both tips. No further overlap is expected.

@HugoXK-bot HugoXK-bot 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.

Verdict: PASS at e488223
Written-by: HugoXK-bot
Author: Fledge Platform Reviewer
Posted-by: HugoXK-bot

T3 quota change: a repository model selection counts as the user's own model, so a job that will run on that selection is no longer treated as platform-funded (and is no longer refused for an exhausted platform quota).

Reviewed at the tip: src/app.ts, src/jobs/service.ts, src/views/checklist.ts, src/views/pages.ts, test/jobs.test.ts, test/nextAction.test.ts, test/nextScheduledRun.test.ts, test/setupChecklist.test.ts, docs/quota.md, docs/architecture.md, changelog. 11 files, +146/−21.

What I checked:

  • one predicate, two call sites: platformFundedFor() (src/jobs/service.ts:58-68) is !legacyOwnModel && listRepoModelSelection(repoId).length === 0, and both the enqueue check (:1008-1011) and the run-time check (:3144-3147) now use it. That is the same row set the gateway resolves (src/gateway/gateway.ts:165, :222) and the bridge patches from (src/flybot/instances.ts:374, :416), so the three cannot disagree about who pays.
  • legacyOwnModel is the exact negation of the old condition (own_llm_base_url non-empty and own_llm_key_enc non-null), so the pre-existing user-level model keeps its old behaviour.
  • the checklist separates providerConfigured (a provider has a model) from modelConfigured (a repository can actually run on an own model) (src/views/checklist.ts:11-30, :73-98). A provider that no repository selected now names the missing action "Choose a model for the repository" and links to the repository, instead of claiming the step is done; the instance blocker names the same missing action.
  • src/views/pages.ts:837-845 only shows the platform-quota card when the setup has no own model, which is the same distinction; a user with an own model is not told to add one.
  • the route-level test creates a provider, asserts data-setup-next="model", then sets the selection and asserts data-setup-next="instance" — it tests the wiring, not only the pure function.

Ran (this turn, at this tip):

  • npx tsx --test test/jobs.test.ts test/nextAction.test.ts test/nextScheduledRun.test.ts test/setupChecklist.test.ts — pass 135/135

Red half (same four suites against base b0adcc5f): 130 pass / 5 fail, first failure not ok 9 - a repository model bypasses the platform quota check in enqueue and dispatch, plus 107, 123, 125, 131.

Merge-order note (not a finding against this tip): #731 edits the same setupChecklist model step, app.ts setup block and nextAction.test.ts at base b0adcc5f. Whichever lands second will conflict; merge one, then have the other rebased and re-judged at the new tip rather than resolving the conflict by hand. The two intents are compatible (platform funding vs own model are two ways to satisfy the same step) but the combined predicate must keep both.

Not run: a real own-provider call; the suite drives the gateway with fakes.

Conclusion: PASS — the paying party is decided by one predicate shared with the gateway and bridge, the checklist names the real missing action, and the quota card follows the same rule.

@HugoXK-bot HugoXK-bot added the review:approved Issue reviewed and approved by the Fledge Platform Reviewer label Nov 15, 2026
@HugoXK
HugoXK force-pushed the fix/732-repo-model-readiness branch from e488223 to 219ee3f Compare November 15, 2026 03:17

@HugoXK-bot HugoXK-bot 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.

Verdict: PASS at 219ee3f
Written-by: HugoXK-bot
Author: Fledge Platform Reviewer
Posted-by: HugoXK-bot

Re-judged at the forward-merged tip. My earlier PASS 5908787902 bound e48822384ea4 and is void at this tip; this review reads the merge resolution, not the old conclusion.

T3 quota change (#732): a repository model selection is an own model for quota purposes. The merge brought main up to d1a91cd2 and had to combine this change with #731's platform-quota model step.

Reviewed at the tip: 11 files, +155/−26 against live fc6825c6; the change itself is src/app.ts, src/jobs/service.ts, src/views/checklist.ts, src/views/pages.ts, four test files, docs/quota.md, docs/architecture.md, changelog.

What I checked in the merged result:

  • the two ways to satisfy the model step now compose instead of fighting: done: state.modelConfigured || state.platformAvailable, optional only when the platform funds and no own model exists, and the "Choose a model for the repository" title only when a provider exists, no repository selected it, and the platform cannot fund (src/views/checklist.ts:78-113). The instance blocker is !modelConfigured && !platformAvailable, so neither half is dropped by the resolution.
  • the quota path is unchanged by the merge: platformFundedFor() (src/jobs/service.ts:58-68) is still shared by enqueue and dispatch, and src/views/pages.ts still shows the quota action only when no own model exists.
  • jobs: jobsTotal remains main's value at this base (#735 is a separate, unmerged PR; this branch does not anticipate it). No setup field is duplicated by the merge.
  • the unrelated main changes the merge carried in (memory audience, recent-auth, asset versioning) are main's own and are not modified by this PR.

Ran (this turn, at this tip):

  • npx tsx --test test/jobs.test.ts test/nextAction.test.ts test/nextScheduledRun.test.ts test/setupChecklist.test.ts — pass 139/139 (the extra four over the old tip are #731's platform-quota tests, now running together with #732's)

Not run: a real own-provider call; the suites drive the gateway with fakes.

Sequencing note: this tip is behind live main by #736, #737 and #741; two of them touch src/views/pages.ts, the same file this PR edits. The tip's ci-ok therefore did not exercise the combined tree. If a forward-merge lands to catch up, this PASS dies at the new tip and I re-judge it; if the merge queue runs the checks on the merge result, the current tip is green and this PASS stands.

Conclusion: PASS — the merge resolution keeps both the own-model and platform-quota paths intact, and the combined suites pass.

@HugoXK
HugoXK force-pushed the fix/732-repo-model-readiness branch from 219ee3f to 930e2e3 Compare November 15, 2026 03:24
@HugoXK
HugoXK force-pushed the fix/732-repo-model-readiness branch from 930e2e3 to 09cbad8 Compare November 15, 2026 03:34
@HugoXK

HugoXK commented Nov 15, 2026

Copy link
Copy Markdown
Owner Author

Written-by: HugoXK

This fix moved to #678 so it reuses the existing PR record as requested. Closing this new PR without merging; the branch is kept for reference. #678 carries the final content.

@HugoXK HugoXK closed this Nov 15, 2026
@HugoXK HugoXK reopened this Nov 15, 2026

@HugoXK-bot HugoXK-bot 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.

Verdict: PASS at 09cbad8
Written-by: HugoXK-bot
Author: Fledge Platform Reviewer
Posted-by: HugoXK-bot

Re-judged at the current tip. My earlier PASSes bound e48822384ea4 (5908787902) and 219ee3f8b559 (5908828974); both are void at this head, and this review reads the rebased tree.

T3 quota change (#732): a repository model selection counts as an own model, and the platform-satisfied model step shows the remaining balance.

Reviewed at the tip (against ada57f6): 17 files, +311/−39 — src/app.ts, src/config.ts, src/jobs/service.ts, src/views/checklist.ts, src/views/pages.ts, public/app.css, five test files, docs, changelog.

What I checked:

  • the rebase kept #735's fix: jobs: setupJobsTotal (the unfiltered account count) is still what setup.jobs receives (src/app.ts:1244, :1265), so the filtered jobsTotal did not come back with the merge.
  • the two ways to satisfy the model step compose: done: modelConfigured || platformAvailable, optional only when the platform funds and no own model exists, and the "Choose a model for the repository" title only when a provider exists, no selection, and the platform cannot fund (src/views/checklist.ts:78-113). The instance blocker checks both halves.
  • the quota decision is one predicate shared by enqueue and dispatch (platformFundedFor, src/jobs/service.ts:58-68), and the dashboard quota card is suppressed only when an own model exists (src/views/pages.ts:837-845).
  • the new comfort threshold is a config value, not a second default: quota.comfortCny from PLATFORM_QUOTA_COMFORT_CNY (default 50, src/config.ts:321-324), read by the checklist as state.platformQuotaComfortCny; docs/quota.md, docs/deploy.md and .env.example all name it.
  • the tip is now mergeable: true against live main and no longer dirty; the merge that moved it kept both #735's count and this change.

Ran (this turn, at this tip):

  • npx tsx --test test/jobs.test.ts test/nextAction.test.ts test/nextScheduledRun.test.ts test/setupChecklist.test.ts — pass 145/145

Not run: a real own-provider call; the suites drive the gateway with fakes.

One non-blocking product question, worth confirming rather than blocking: the default initial platform quota is 1 CNY (INITIAL_QUOTA_CNY default 1) while the comfort threshold defaults to 50 CNY, so a brand-new account — whose first run the platform is supposed to fund — always lands in the "balance may not cover the first run" warning on a step that is marked done. If that is deliberate (a first run really can cost more than 1 CNY), fine; otherwise the default threshold should sit below the initial quota, or the sentence should state the remaining balance without predicting what it covers. The note itself is only advisory and does not block the run or the step.

Conclusion: PASS — the rebase preserves the platform and own-model paths and #735's unfiltered count, the threshold is one config knob, and the combined suites pass.

@HugoXK
HugoXK merged commit e5397e1 into main Nov 15, 2026
93 of 98 checks passed
@HugoXK
HugoXK deleted the fix/732-repo-model-readiness branch November 15, 2026 03:47
HugoXK added a commit that referenced this pull request Nov 15, 2026
Main moved to e5397e1 (#733) and touched docs/architecture.md and
public/app.css. Both changes are kept: the #235 owner/operator text and the
repository-model quota text stay, and the notification-stack paragraph and rules
sit beside them.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review:approved Issue reviewed and approved by the Fledge Platform Reviewer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: a repository model is not treated as an own model when quota is checked

2 participants