Documentation
¶
Overview ¶
Package glmlane drives the GLM coding plan through the OFFICIAL claude binary pointed at api.z.ai — the proven smoke shape (2ca0b5e/d5bbbcb). The lane REUSES the entire claudelane machinery (BuildArgs hard rules, Parse, F15 tree-kill): the only deltas are env and defaults, so the GLM result schema stays claudelane-parser-compatible by construction (fixture-proven, both models).
R10 discipline: the coding-plan token is read at dispatch time from the statepaths-resolved file, lives ONLY in the child's env, and is excluded from every error/log/dispatch path — errors carry the PATH, never any value; argv never contains it.
Index ¶
- Constants
- func Env(token, model string) []string
- func LatchAlert(path string, e GLMErr, now time.Time) error
- func Latched(path string) (note string, latched bool)
- func Multiplier(model string, now time.Time, fzs []fuses.Fuse) int64
- func Pace(dir string, pc PaceConfig, now func() time.Time, sleep func(time.Duration)) (unlock func(), waited time.Duration, err error)
- func Run(ctx context.Context, req claudelane.RunReq, tokenPath string) (claudelane.Outcome, []byte, error)
- func Token(path string) (string, error)
- type ErrAction
- type GLMErr
- type PaceConfig
Constants ¶
const BaseURL = "https://api.z.ai/api/anthropic" // the proven smoke shape (2ca0b5e/d5bbbcb)
const CheapModel = "glm-4.7"
CheapModel is the always-1× tier (fact refresh §3): pinned as the haiku alias so cheap subagent calls inside a dispatch never burn 5.2 quota units.
const DefaultModel = "glm-5.2"
DefaultModel: R14a (operator directive, 2026-07-06) — the lane defaults to its strongest model; glm-4.7 is chosen ONLY where the capability baseline measures it admissible (cheap-tier tool loops; haiku-pin below).
Variables ¶
This section is empty.
Functions ¶
func Env ¶
Env pins the child process to the GLM endpoint: base URL + auth token + the fact-refresh §3 timeout, plus ALL THREE model-alias pins (alias-drift belt — an unpinned alias would silently route to an Anthropic model name z.ai doesn't serve).
func LatchAlert ¶
LatchAlert writes the 1313 hard-stop latch, WRITE-ONCE: the FIRST violation's code+timestamp is the evidence — later violations never overwrite it (mirrors the codex burn-anomaly latch). `probe --ack-glm` clears.
func Latched ¶
Latched reports whether the 1313 latch is set. This is the ONE place that fails SAFE rather than open: an existing-but-unreadable latch file stays latched (the latch guards an account-loss event; the explicit ack is the only way out — R11 override exists via ack-then-run, a deliberate two-step).
func Multiplier ¶
Multiplier prices one GLM prompt in quota units (fact refresh §1/§2):
glm-4.7* → always 1×
peak (14:00–18:00 UTC+8 == 06:00–10:00 UTC) → 3× for glm-5.2/turbo
off-peak → 1× while the glm-offpeak-promo
fuse is active, else 2×
The promo is a DATED fuse (config-with-expiry, never a constant): when it expires the off-peak price reverts to 2× with zero code change.
func Pace ¶
func Pace(dir string, pc PaceConfig, now func() time.Time, sleep func(time.Duration)) (unlock func(), waited time.Duration, err error)
Pace acquires the lane's concurrency lock and enforces the inter-dispatch interval, then stamps the dispatch start. now/sleep are injected so the wait math is deterministic under test. The returned unlock releases the lock (callers defer it around the dispatch); err is non-nil ONLY when the lock wait is exhausted — the caller relegates (RS5), never hangs.
func Run ¶
func Run(ctx context.Context, req claudelane.RunReq, tokenPath string) (claudelane.Outcome, []byte, error)
Run resolves the token, injects the GLM env, and delegates to claudelane.Run — same classified-Outcome contract (error return = config only). A missing/empty token is a config error carrying the path, never a value (R10).
Types ¶
type ErrAction ¶
type ErrAction string
const ( ActRetry ErrAction = "retry_backoff" // 1302, 1305 — transient (concurrency/backpressure), no ledger write ActCooldown ErrAction = "cooldown_5h" // 1308, 1316 — until embedded next_flush_time (else now+5h, RS5) ActOffline ErrAction = "offline_weekly" // 1310, 1317, 1318, 1319, 1320, 1321 — weekly-reset class ActConfig ErrAction = "config_error" // 1311 ActHardStop ErrAction = "hard_stop_alert" // 1313 — Fair Usage; >3 violations = ban; LATCH ActUnknown ErrAction = "unknown" // any other 13xx: classified, no ledger write (fail-open) )
type GLMErr ¶
func ClassifyError ¶
ClassifyError scans raw result bytes for a GLM 13xx error code. ok=false when none is present (clean results, non-GLM errors — the S2R-8 generic fallback handles those). next_flush_time parses VERBATIM here (pure extraction); the staleness guard (a reset in the past must not anchor a cooldown that instantly rolls) lives at the observation site, which holds the authoritative now.
type PaceConfig ¶
type PaceConfig struct {
MinInterval time.Duration // floor between dispatch STARTS
Jitter time.Duration // uniform random addition to the floor
LockWait time.Duration // max wait on the concurrency lock before relegating
LockStale time.Duration // steal locks older than this (a genuinely DEAD holder)
// Heartbeat is how often a HELD lock's mtime is refreshed (A2R-#5). A live
// holder keeps its lock fresh, so LockStale only ever reclaims a holder that
// has genuinely STOPPED refreshing (crashed) — a long (>LockStale) but live
// dispatch is never stolen. Zero uses defaultHeartbeat.
Heartbeat time.Duration
// Poll is the wait-loop poll interval (test seam). Zero uses defaultPollEvery.
Poll time.Duration
}
func DefaultPace ¶
func DefaultPace(minSec, jitterSec int64) PaceConfig
DefaultPace builds the config-seconds into a PaceConfig. A live lock holder heartbeats its mtime every 30s, so LockStale (90s = 3 missed beats) only reclaims a holder that has genuinely died — even though a GLM dispatch can run >20min (API_TIMEOUT_MS=50min). LockWait comfortably EXCEEDS LockStale so a waiter can always reclaim a genuinely-dead lock before it relegates, and never false-relegates a live long-running holder (A2R-#5).