Repository navigation
Conversation
…dress rests the whole gift A freeFirst replay answers from the plan silently, so a gift sitting idle beside a fat balance — its address blocked by the vendor's firewall, its quota spent, its host failing — looks like the option doing nothing. Every refusal is now recorded and the usage card names it until the rest is out: freeFirst answers from the coding plan until 14:02 (the network's address is blocked / its quota said spent / it answered 500). A block page rests every model the gift serves for the route's ten minutes — an address block outlasts a minute — so the fallback costs no round trips while it holds; a spent answer rests its one model for a minute, as before.
yetone
left a comment
There was a problem hiding this comment.
Thanks for this. I pulled 0d2c15c and ran it on a Mac: HOME=$(mktemp -d) bun test packages/zcode gives 185 pass, 0 fail (main has 182), and your three new tests pass. Resting the gift's models for longer than a minute on a block page is right, and so is the card line. I'm not merging yet, because of these points:
-
3012 is not an address block.
startRefusedmatches both Alibaba Cloud's block page (EDGE_PAGE) and ZCode's JSONcode 3012"request has been blocked due to unusual activity". 3012 is ZCode's risk control on the account: ZCode's own app is refused too (#348), and outside freeFirststartBlockedtells it as START_RESTRICTED, not START_EDGE. On freeGift, the PR sends both torest(..., "blocked"), and the card then says "the network's address is blocked". The first new test uses a 3012 body as "a firewall block". Please tell them apart (e.g.EDGE_PAGE.test(text)gives "blocked", anything else gives "restricted" with words like "ZCode restricted this account"), and add a test with each body.
On magpie's side, the gateway did the same mix-up.provider.APIErrorrewrote any "request has been blocked" body to the firewall hint, so a 3012 was told as an IP block and rested as a plain failure. That is fixed in magpie now (a body carrying ZCodeRestrictedHint keeps its words and rests as restricted). So the plugin's wording is what decides what the user reads. -
"Any other failure" says something that isn't happening. For a status ≥400 that isn't spent,
refusedis set for 60s, but nothing goes intoblocked. So the next request still tries the gift first. The card says "freeFirst answers from the coding plan until HH:MM", which is true only for the request that was replayed. Either rest the asked model for that minute too (asspentdoes), or word this line as what happened ("the gift answered 500 at HH:MM; the plan answered"). -
A later success doesn't clear
refused. If the gift answers 200 within the window, the card still says it is refusing. Deleterefused.get(refusedId(s))on a gift answer< 400(and whenblockedis cleared for the account). -
The block rest reaches the
-Trialentries, with another name.giftUsablereadsblocked, so for the next ten minutes aGLM-5.3-Flash-Trialrequest gets the plugin's local 429 "ZCode's limited quota for … is exhausted or temporarily unavailable". magpie's gateway reads that 429 as the trial's quota and rests that model for its quota rest, which is longer than your ten minutes, under a quota label. Resting the Trial entries is fine. But the answer should say the gift is blocked from this network (or 3012 restricted), not that its quota is used up. Please add a test: a block page, then a-Trialrequest, then check the error text. -
Minor:
refusedis never pruned.blockedis swept inrest, so do the same forrefused.- A
busy()cap (the plugin's own concurrency 429) is recorded as "it answered 429", the same as a refusal from ZCode. Leave it out whencapis true.
Point 1 matters most. Points 2 to 4 are about the card and the error saying what is actually true. Happy to re-run it after a push.
Review: a 3012 body is ZCode's risk control on the account, not the address — the edge firewall page is — and the card said the address for both. EDGE_PAGE now picks the why: a page reads 'the network's address is blocked', a 3012 reads 'ZCode restricted this account'. The card's 'answers from the coding plan until' also said more than it did for other failures, which rested nothing: the asked model now rests the minute with the record, a success clears the record, the gift's own waited-out busy cap is not recorded, and refused is pruned with blocked. A -Trial request refused while the gift is blocked or restricted says that instead of a quota the model has not spent.
|
All five points addressed on e717472, tests red first. 1. The two block kinds. 2. Other failures hold their line. A ≥400 that isn't spent (and isn't the gift's own cap) rests the asked model for the minute with the record, so "answers from the coding plan until HH:MM" is true for the window, and the 500 test still sees its status named. 3. Success clears. A gift answer under 400 — JSON or stream — deletes the account's refused record; new test: block page, then (block aged) a gift 200, then the card carries no refusing line. 4. The -Trial refusal says the truth. The local 429 consults the fresh record: while the gift is blocked it reads "ZCode's gift is blocked from this network; wait a while, or switch to another network or proxy", while 3012-restricted reads "ZCode's gift is restricted by its risk control (code 3012); only ZCode support lifts it"; the quota wording stays for a genuinely spent bucket. New test pins the blocked wording with no "quota" in it. 5. Minors.
|
yetone
left a comment
There was a problem hiding this comment.
Thanks. I checked out e717472 and ran it on a Mac mini in a throwaway HOME: bun test packages/zcode (189 of 189 of your tests pass) and bun run check (clean). Then I put your new dual.test.mjs on the old head, 0d2c15c, to see which tests are red there, and added five probes of my own.
Fixed and checked:
- 3012 is the account, not the network. "a 3012 says the account is restricted, not the address" is red on 0d2c15c and green now. The card line's "why" tells a block page and a 3012 apart.
- The card's "until HH:MM" is now true.
rest()puts every gift model inblockedfor the window, so the line matches what happens. My probe (a gift 500, then a second request skips the gift and goes straight to the plan) is red on 0d2c15c and green now. Your PR has no test for this, so please add one. - A gift success clears the line. "a gift success clears the card's refusal line" is red on the old head. My probe for a streamed 200 also passes now. Your PR has no test for it, so please add one too.
- Pruning, and the busy cap. "the gift's own busy cap is not a refusal for the card" is red on the old head. My pruning probe (an expired entry is gone after the next
rest()) passes now.
Still wrong: point 4, a -Trial entry while the gift is refused (index.mjs:2366-2373)
The words are right now, but the reply around them is still a quota reply:
429 {"type":"error","error":{"type":"rate_limit_error","message":"ZCode's gift is restricted by its risk control (code 3012); only ZCode support lifts it"}}
429 {"type":"error","error":{"type":"rate_limit_error","message":"ZCode's gift is blocked from this network; wait a while, or switch to another network or proxy"}}
magpie's gateway decides by the reply, not by the words a person reads (internal/gateway/routing.go, failure()). A 429 whose body says rate_limit_error is a rate limit (rate.?limit matches it), so magpie still rests the route as rate-limited. It also shows that label. The restricted path (restrictedSaid) needs magpie's own sentence in the body, and the edge path (provider.EdgeBlocked) needs the BlockedHint sentence. Neither text is in this reply. This is the mislabelled rest from point 4, with new words.
The fix is to answer the way startBlocked already does, when the gift is refused:
why === "restricted"→ status 403,type: "permission_error", and the message carriesSTART_RESTRICTEDword for word (it is magpie'sZCodeRestrictedHint);why === "blocked"→ status 403,permission_error, and the message carriesSTART_EDGEword for word (magpie'sBlockedHint).
You can keep your sentence in front, the way startBlocked puts said — START_….
Two more details on the same lines:
- When
rawis unset, the entry has no gift model at all, so its answer is the 400 "no active limited quota for …". Right now a live refusal swaps that for "blocked" or "restricted", so a model the gift never serves is reported as blocked. Pick the refusal text only whenrawis set. - Please add a test for each kind that checks the status,
error.typeand the hint sentence, not only the words. They should be red on e717472.
When that's in, say which head to look at and I'll run it again and merge.
Review: the words were right but the reply's shape was still a quota one, and magpie's gateway classifies by the reply, not the words — a 429 whose error.type says rate_limit_error rests the route as rate-limited. A -Trial refusal while the gift is blocked or restricted now carries invalid_request_error and the block's own hint, the way startBlocked words them: START_EDGE for a blocked address, START_RESTRICTED for a 3012, the plugin's sentence in front. A model the gift never serves keeps its no-quota 400 even with a refusal fresh, and each kind is pinned by a test checking status, error.type and the hint sentence.
|
Point 4 reworked on 346e902 — head to run: 346e902. The reply's shape now says what happened, not just its words:
A test per kind, each checking status, |
Follows #505 (merged, 0.1.38) and the undiscoverability thread in #536. Run against real accounts: with the machine's address blocked by zcode.z.ai's firewall, a dual account's freeFirst replay worked but was invisible — the gift's balance sat fat while the plan's windows moved, and nothing said why. This makes the refusal visible and the fallback cheap.
The card names the refusal
Every freeFirst gift refusal that the plan answers is recorded per account (
refused), and the usage card carries an aside line until the rest is out:The why is specific:
the network's address is blockedfor a block page,its quota said spentfor a spent answer,it answered 500for anything else.A blocked address rests the whole gift
A block page is the network's address being refused, not one model's quota — it outlasts a minute.
rest(models, ms, why)(the oldrestModel, parameterized) now rests every model the gift serves for the route's ten minutes on a block page, so the requests behind it go straight to the plan with no doomed round trip each minute; the-Trialentries rest too, answering the plugin's local 429 instead of the same block page. A spent answer keeps its one-minute, one-model rest. Other failures record the card line only.Tests
Three new cases in
dual.test.mjs(red first): a block page answers 200 from the plan, the card names the block until HH:MM, and the next request makes no gift try; a spent 1113 shows the line naming the quota; a 500 shows the line with its status.bun test packages/zcodeat 0d2c15c: 185 pass (13 over 0.1.39's 172),checkclean. The README's free-first section documents the card line and the rests.