quota: z.ai credit-bucket back-pressure + resource gate + usage accounting (Redmine 490+491)
The loop now consults quota and host state before every dispatch and
DEFERS gated work with a logged reason instead of letting turns die at
the provider (the 2026-08-28 19:00 quota-wall failure mode, replayed as
a test). Adds internal/quota: 5h/weekly credit buckets (provider poll
when z.ai ships an endpoint - fake-server tested - else locally
estimated from the documented credit formula), TZ-aware peak window
(default 01:00-05:00 America/Chicago weekdays, matching the documented
z.ai peak Mon-Fri 14:00-18:00 Singapore), block/defer thresholds, a
read-only load/mem/disk/IO-PSI monitor, an optional redis shared-state
hop (stdlib RESP2 mini-client) so all instances of an account
coordinate, per-class token+credit accounting in loop.jsonl, and
`harness quota status|probe|gate`. Config: [quota] + [resources]
sections; README runbook covers the redis container and deploy-time
cgroup enforcement.
💘 Generated with Crush
Assisted-by: Crush:glm-5.2
This commit is contained in:
@@ -27,6 +27,7 @@ type fakeRedmine struct {
|
||||
status string
|
||||
updatedOn string
|
||||
notes []string
|
||||
class string
|
||||
}
|
||||
statusIDs map[string]int
|
||||
noted []string // issue ids that got a note, in order
|
||||
@@ -41,6 +42,7 @@ func newFakeRedmine(t *testing.T) *fakeRedmine {
|
||||
status string
|
||||
updatedOn string
|
||||
notes []string
|
||||
class string
|
||||
}{},
|
||||
statusIDs: map[string]int{"New": 1, "In Progress": 2, "Done": 3},
|
||||
}
|
||||
@@ -56,8 +58,12 @@ func newFakeRedmine(t *testing.T) *fakeRedmine {
|
||||
b.WriteString(",")
|
||||
}
|
||||
first = false
|
||||
fmt.Fprintf(&b, `{"id":%s,"subject":%q,"description":"do the thing","updated_on":%q,"status":{"name":%q},"custom_fields":[{"name":"Class","value":"primary"}]}`,
|
||||
id, is.subject, is.updatedOn, is.status)
|
||||
class := is.class
|
||||
if class == "" {
|
||||
class = "primary"
|
||||
}
|
||||
fmt.Fprintf(&b, `{"id":%s,"subject":%q,"description":"do the thing","updated_on":%q,"status":{"name":%q},"custom_fields":[{"name":"Class","value":%q}]}`,
|
||||
id, is.subject, is.updatedOn, is.status, class)
|
||||
}
|
||||
b.WriteString(`]}`)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
@@ -131,6 +137,11 @@ func newFakeRedmine(t *testing.T) *fakeRedmine {
|
||||
}
|
||||
|
||||
func (f *fakeRedmine) addIssue(id, subject, status, updatedOn string) {
|
||||
f.addIssueClass(id, subject, status, updatedOn, "primary")
|
||||
}
|
||||
|
||||
// addIssueClass registers an issue with an explicit Class custom field.
|
||||
func (f *fakeRedmine) addIssueClass(id, subject, status, updatedOn, class string) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
f.issues[id] = struct {
|
||||
@@ -138,7 +149,8 @@ func (f *fakeRedmine) addIssue(id, subject, status, updatedOn string) {
|
||||
status string
|
||||
updatedOn string
|
||||
notes []string
|
||||
}{subject: subject, status: status, updatedOn: updatedOn}
|
||||
class string
|
||||
}{subject: subject, status: status, updatedOn: updatedOn, class: class}
|
||||
}
|
||||
|
||||
func (f *fakeRedmine) setUpdatedOn(id, updatedOn string) {
|
||||
|
||||
Reference in New Issue
Block a user