mirror of
https://github.com/BaaRai/ARTEX.git
synced 2026-11-13 11:40:53 +08:00
Three orchestration mechanisms from the Q00/ouroboros evaluation (#99): - Goal ambiguity gate at task creation: a goal must name a target (URL, domain, IPv4, localhost:port or absolute path) and reach a length floor, else the API returns 400 before any token is spent. Deliberately target-less goals opt out with the literal marker [targetless]. Guards against the live failure where a goal naming no target sent every worker to an unrelated asset. - Consecutive-failure escalation on the task LLM chain: quota exhaustion already advances the chain; now 3 consecutive non-quota call failures on the same chain profile advance it too, with the true reason recorded. Escalation-only by design (no auto-downgrade: mid-task model swaps risk behavior drift; the operator keeps the manual chain reset). - Stagnation surfacing in the planner overview: finished intents are fingerprinted (case-folded, digits collapsed); a direction dispatched 3+ times with zero findings since its first attempt is flagged in a self-describing stagnation_warning payload that instructs the planner to diversify instead of grinding. Absent when nothing stagnates. Closes #99
43 lines
1.9 KiB
Go
43 lines
1.9 KiB
Go
package server
|
|
|
|
import (
|
|
"errors"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
// Ambiguity gate (ouroboros take, #99): a task goal must name a concrete target
|
|
// and be long enough to carry a testable objective before any token is spent.
|
|
// The live failure this guards against: a benchmark task whose goal named no
|
|
// target URL passed creation silently and the planner sent every worker to an
|
|
// unrelated asset. A goal that is deliberately target-less (pure analysis over
|
|
// provided material) can opt out with the literal marker [targetless].
|
|
var (
|
|
goalMinLen = 80
|
|
|
|
goalTargetlessRE = regexp.MustCompile(`\[targetless\]`)
|
|
goalURLRE = regexp.MustCompile(`(?i)\bhttps?://\S+`)
|
|
goalDomainRE = regexp.MustCompile(`(?i)\b[a-z0-9][a-z0-9-]{1,61}\.[a-z]{2,}(:[0-9]+)?(/\S*)?\b`)
|
|
goalIPv4RE = regexp.MustCompile(`\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(:\d+)?\b`)
|
|
goalLocalhostRE = regexp.MustCompile(`(?i)\blocalhost:[0-9]+\b`)
|
|
goalPathRE = regexp.MustCompile(`(?i)(^|\s)/[a-z0-9_-]+(/[a-z0-9_.-]+)+`)
|
|
)
|
|
|
|
// goalGateCheck returns a descriptive error when the goal is too ambiguous to
|
|
// dispatch workers against. Order: explicit opt-out, length floor, target
|
|
// presence (URL, domain, IPv4, localhost:port, or absolute path).
|
|
func goalGateCheck(goal string) error {
|
|
g := strings.TrimSpace(goal)
|
|
if goalTargetlessRE.MatchString(g) {
|
|
return nil
|
|
}
|
|
if len(g) < goalMinLen {
|
|
return errors.New("goal is too short to carry a testable objective (min 80 chars): name the target and what counts as success; add the literal marker [targetless] only for genuinely target-less analysis tasks")
|
|
}
|
|
if goalURLRE.MatchString(g) || goalDomainRE.MatchString(g) ||
|
|
goalIPv4RE.MatchString(g) || goalLocalhostRE.MatchString(g) || goalPathRE.MatchString(g) {
|
|
return nil
|
|
}
|
|
return errors.New("goal names no target: include the URL/host/IP/path under test (or the literal marker [targetless] for target-less analysis tasks) so workers cannot be dispatched against an unrelated asset")
|
|
}
|