arkaos 5.17.2 → 5.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THE-ARKAOS-GUIDE.md +2 -2
- package/VERSION +1 -1
- package/arka/SKILL.md +2 -1
- package/arka/skills/costs/SKILL.md +16 -0
- package/config/claude-agents/marta-cqo.md +10 -0
- package/config/decisions/corpora/bash-effect.jsonl +38 -0
- package/config/decisions/corpora/creation-intent.jsonl +47 -0
- package/config/decisions/corpora/dispatch-role.jsonl +32 -0
- package/config/decisions/corpora/forge-complexity.jsonl +102 -0
- package/config/decisions/corpora/forge-departments.jsonl +34 -0
- package/config/decisions/corpora/heldout/learning-signal.jsonl +17 -0
- package/config/decisions/corpora/heldout/qg-prescreen.jsonl +20 -0
- package/config/decisions/corpora/heldout/slop-score.jsonl +20 -0
- package/config/decisions/corpora/learning-signal.jsonl +35 -0
- package/config/decisions/corpora/phantom-action.jsonl +34 -0
- package/config/decisions/corpora/qg-prescreen.jsonl +46 -0
- package/config/decisions/corpora/refine.jsonl +104 -0
- package/config/decisions/corpora/route.jsonl +33 -0
- package/config/decisions/corpora/skill-hints.jsonl +34 -0
- package/config/decisions/corpora/skill-proposer.jsonl +32 -0
- package/config/decisions/corpora/slop-score.jsonl +33 -0
- package/config/decisions/corpora/subagent-discipline.jsonl +32 -0
- package/config/decisions/corpora/sycophancy.jsonl +34 -0
- package/config/decisions/corpora/topic-drift.jsonl +34 -0
- package/config/decisions/corpora/ui-in-ts.jsonl +60 -0
- package/config/hooks/gate-manifest.json +1 -0
- package/config/models.yaml +10 -2
- package/core/decisions/__init__.py +8 -0
- package/core/decisions/backoff.py +137 -0
- package/core/decisions/cache.py +92 -0
- package/core/decisions/client.py +191 -0
- package/core/decisions/config.py +159 -0
- package/core/decisions/cost_effect.py +242 -0
- package/core/decisions/engine.py +400 -0
- package/core/decisions/models.py +118 -0
- package/core/decisions/paths.py +39 -0
- package/core/decisions/privacy.py +378 -0
- package/core/decisions/promotion.py +126 -0
- package/core/decisions/registry.py +23 -0
- package/core/decisions/replay.py +852 -0
- package/core/decisions/replay_report.py +413 -0
- package/core/decisions/shadow.py +147 -0
- package/core/decisions/site.py +343 -0
- package/core/decisions/sites/__init__.py +1 -0
- package/core/decisions/sites/command.py +58 -0
- package/core/decisions/sites/dispatch.py +161 -0
- package/core/decisions/sites/forge.py +230 -0
- package/core/decisions/sites/governance.py +361 -0
- package/core/decisions/sites/prompt.py +195 -0
- package/core/decisions/sites/quality.py +281 -0
- package/core/decisions/telemetry.py +335 -0
- package/core/decisions/telemetry_cli.py +149 -0
- package/core/decisions/transport.py +97 -0
- package/core/egress/audit.py +46 -6
- package/core/egress/credentials.py +1296 -0
- package/core/egress/policy.py +7 -4
- package/core/evals/verdict_labels.py +25 -5
- package/core/forge/budget.py +32 -0
- package/core/forge/complexity.py +11 -3
- package/core/forge/jev_sites.py +80 -0
- package/core/forge/orchestrator.py +76 -72
- package/core/governance/aggregate_guard.py +175 -77
- package/core/governance/carry_advisor.py +36 -19
- package/core/governance/evidence_checks.py +134 -55
- package/core/governance/fence_recovery.py +165 -0
- package/core/governance/harness_scanner.py +4 -0
- package/core/governance/jev_advisory.py +154 -0
- package/core/governance/leak_scanner.py +2 -2
- package/core/governance/literal_git.py +66 -0
- package/core/governance/qg_prescreen.py +518 -0
- package/core/governance/qg_tier.py +17 -0
- package/core/governance/reviewer_ledger.py +225 -46
- package/core/governance/skill_proposer.py +38 -13
- package/core/governance/slop_check.py +169 -0
- package/core/hooks/operator_message.py +128 -0
- package/core/hooks/stop.py +418 -38
- package/core/hooks/stop_budget.py +43 -0
- package/core/hooks/subagent_stop.py +39 -9
- package/core/hooks/ups_dispatch.py +243 -0
- package/core/hooks/user_prompt_submit.py +458 -106
- package/core/keys.py +4 -0
- package/core/runtime/model_router.py +38 -0
- package/core/runtime/pricing.py +8 -0
- package/core/synapse/command_menu.py +70 -0
- package/core/synapse/layers.py +108 -66
- package/core/workflow/flow_enforcer.py +71 -1
- package/core/workflow/frontend_gate.py +57 -1
- package/core/workflow/transcript_scope.py +34 -25
- package/departments/quality/SKILL.md +29 -2
- package/harness/codex/AGENTS.md +1 -1
- package/harness/copilot/copilot-instructions.md +1 -1
- package/harness/cursor/rules/arkaos.mdc +2 -2
- package/harness/gemini/GEMINI.md +1 -1
- package/harness/opencode/AGENTS.md +1 -1
- package/harness/opencode/agents/arka-architect-gabriel.md +1 -1
- package/harness/opencode/agents/arka-brand-director-valentina.md +1 -1
- package/harness/opencode/agents/arka-cfo-helena.md +1 -1
- package/harness/opencode/agents/arka-chief-of-staff-afonso.md +1 -1
- package/harness/opencode/agents/arka-community-strategist-beatriz.md +1 -1
- package/harness/opencode/agents/arka-content-strategist-rafael.md +1 -1
- package/harness/opencode/agents/arka-conversion-strategist-ines.md +1 -1
- package/harness/opencode/agents/arka-coo-sofia.md +1 -1
- package/harness/opencode/agents/arka-copy-director-eduardo.md +1 -1
- package/harness/opencode/agents/arka-cqo-marta.md +1 -1
- package/harness/opencode/agents/arka-cto-marco.md +1 -1
- package/harness/opencode/agents/arka-design-ops-lead-iris.md +1 -1
- package/harness/opencode/agents/arka-ecom-director-ricardo.md +1 -1
- package/harness/opencode/agents/arka-knowledge-director-clara.md +1 -1
- package/harness/opencode/agents/arka-leadership-director-rodrigo.md +1 -1
- package/harness/opencode/agents/arka-marketing-director-luna.md +1 -1
- package/harness/opencode/agents/arka-ops-lead-daniel.md +1 -1
- package/harness/opencode/agents/arka-pm-director-carolina.md +1 -1
- package/harness/opencode/agents/arka-revops-lead-vicente.md +1 -1
- package/harness/opencode/agents/arka-saas-strategist-tiago.md +1 -1
- package/harness/opencode/agents/arka-sales-director-miguel.md +1 -1
- package/harness/opencode/agents/arka-strategy-director-tomas.md +1 -1
- package/harness/opencode/agents/arka-tech-director-francisca.md +1 -1
- package/harness/opencode/agents/arka-tech-lead-paulo.md +1 -1
- package/harness/opencode/agents/arka-video-producer-simao.md +1 -1
- package/harness/zed/.rules +1 -1
- package/installer/config-seed.js +71 -1
- package/installer/keys.js +1 -1
- package/installer/update.js +29 -0
- package/knowledge/commands-registry.json +17 -4
- package/knowledge/commands-registry.json.bak +6739 -0
- package/knowledge/skills-manifest.json +1 -1
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/scripts/synapse-bridge.py +17 -1
- package/scripts/tools/corpus_merge.py +402 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""Decisions config — the ``decisions`` block of ``~/.arkaos/config.json``.
|
|
2
|
+
|
|
3
|
+
The installer seed (``installer/config-seed.js``) writes three keys::
|
|
4
|
+
|
|
5
|
+
"decisions": {"enabled": true, "transport": "openrouter",
|
|
6
|
+
"redactClients": true}
|
|
7
|
+
|
|
8
|
+
Everything else has its default in code (``hookTimeoutMs``,
|
|
9
|
+
``cacheTtlSeconds``, ``thresholds`` here; each site's mode in
|
|
10
|
+
``Site.default_mode``). A key the operator writes overrides that
|
|
11
|
+
default and is never rewritten, for example::
|
|
12
|
+
|
|
13
|
+
"sites": {"topic-drift": "shadow",
|
|
14
|
+
"route": {"mode": "act", "minConfidence": 0.8}}
|
|
15
|
+
|
|
16
|
+
Loading never raises: a missing, oversized, corrupt or invalid file
|
|
17
|
+
yields the defaults. ``ARKA_BYPASS_DECISIONS=1`` turns every site off.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import json
|
|
23
|
+
import os
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from typing import TYPE_CHECKING, Any, Literal
|
|
26
|
+
|
|
27
|
+
from pydantic import BaseModel, ConfigDict, Field, ValidationError, field_validator
|
|
28
|
+
|
|
29
|
+
if TYPE_CHECKING:
|
|
30
|
+
from core.decisions.site import Site
|
|
31
|
+
|
|
32
|
+
Mode = Literal["off", "shadow", "act"]
|
|
33
|
+
MODES: frozenset[str] = frozenset({"off", "shadow", "act"})
|
|
34
|
+
|
|
35
|
+
# Default action thresholds by site risk. Read at decision time (never
|
|
36
|
+
# copied into a config instance) so a config override and this table
|
|
37
|
+
# stay the only two sources — pinned by test_write_threshold_is_load_bearing.
|
|
38
|
+
THRESHOLDS: dict[str, float] = {"read": 0.60, "write": 0.75, "destructive": 0.90}
|
|
39
|
+
|
|
40
|
+
CONFIG_PATH: Path = Path.home() / ".arkaos" / "config.json"
|
|
41
|
+
MAX_CONFIG_BYTES = 1_000_000
|
|
42
|
+
BYPASS_ENV = "ARKA_BYPASS_DECISIONS"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class SiteConfig(BaseModel):
|
|
46
|
+
"""Per-site override: mode, action threshold, call ceiling."""
|
|
47
|
+
|
|
48
|
+
model_config = ConfigDict(populate_by_name=True, extra="ignore")
|
|
49
|
+
|
|
50
|
+
# None = "the site's own ``default_mode``" (PR5 D3): an override that
|
|
51
|
+
# only tunes ``timeoutMs`` or ``minConfidence`` must not flip a shadow
|
|
52
|
+
# site to act, as the old ``"act"`` default did.
|
|
53
|
+
mode: Mode | None = None
|
|
54
|
+
min_confidence: float | None = Field(default=None, alias="minConfidence", ge=0.0, le=1.0)
|
|
55
|
+
timeout_ms: int | None = Field(default=None, alias="timeoutMs", gt=0)
|
|
56
|
+
|
|
57
|
+
@field_validator("mode", mode="before")
|
|
58
|
+
@classmethod
|
|
59
|
+
def _unknown_mode_is_off(cls, value: object) -> object:
|
|
60
|
+
if value is None:
|
|
61
|
+
return None
|
|
62
|
+
return value if isinstance(value, str) and value in MODES else "off"
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class DecisionsConfig(BaseModel):
|
|
66
|
+
"""The whole ``decisions`` block with safe defaults."""
|
|
67
|
+
|
|
68
|
+
model_config = ConfigDict(populate_by_name=True, extra="ignore")
|
|
69
|
+
|
|
70
|
+
enabled: bool = True
|
|
71
|
+
transport: str = "openrouter"
|
|
72
|
+
redact_clients: bool = Field(default=True, alias="redactClients")
|
|
73
|
+
hook_timeout_ms: int = Field(default=1500, alias="hookTimeoutMs", gt=0)
|
|
74
|
+
cache_ttl_seconds: int = Field(default=86400, alias="cacheTtlSeconds", ge=0)
|
|
75
|
+
thresholds: dict[str, float] = Field(default_factory=dict)
|
|
76
|
+
sites: dict[str, SiteConfig] = Field(default_factory=dict)
|
|
77
|
+
|
|
78
|
+
@field_validator("sites", mode="before")
|
|
79
|
+
@classmethod
|
|
80
|
+
def _coerce_sites(cls, value: object) -> dict[str, Any]:
|
|
81
|
+
if not isinstance(value, dict):
|
|
82
|
+
return {}
|
|
83
|
+
out: dict[str, Any] = {}
|
|
84
|
+
for name, raw in value.items():
|
|
85
|
+
if isinstance(raw, str):
|
|
86
|
+
out[str(name)] = {"mode": raw}
|
|
87
|
+
elif isinstance(raw, dict):
|
|
88
|
+
out[str(name)] = raw
|
|
89
|
+
else:
|
|
90
|
+
out[str(name)] = {"mode": "off"}
|
|
91
|
+
return out
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def load_decisions_config(path: Path | None = None) -> DecisionsConfig:
|
|
95
|
+
"""Read the ``decisions`` block; any failure returns the defaults."""
|
|
96
|
+
target = path or CONFIG_PATH
|
|
97
|
+
try:
|
|
98
|
+
if target.stat().st_size > MAX_CONFIG_BYTES:
|
|
99
|
+
return DecisionsConfig()
|
|
100
|
+
data = json.loads(target.read_text(encoding="utf-8"))
|
|
101
|
+
except (OSError, ValueError):
|
|
102
|
+
return DecisionsConfig()
|
|
103
|
+
block = data.get("decisions") if isinstance(data, dict) else None
|
|
104
|
+
if not isinstance(block, dict):
|
|
105
|
+
return DecisionsConfig()
|
|
106
|
+
try:
|
|
107
|
+
return DecisionsConfig.model_validate(block)
|
|
108
|
+
except ValidationError:
|
|
109
|
+
return DecisionsConfig()
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def bypassed() -> bool:
|
|
113
|
+
"""Global kill-switch for diagnosis: ``ARKA_BYPASS_DECISIONS=1``."""
|
|
114
|
+
return os.environ.get(BYPASS_ENV, "").strip() == "1"
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def configured_mode(cfg: DecisionsConfig, site: Site) -> Mode:
|
|
118
|
+
"""The operator's ``mode`` for ``site`` when set, else ``site.default_mode``.
|
|
119
|
+
|
|
120
|
+
Ignores the kill-switch and ``enabled``: this is what the config says,
|
|
121
|
+
for reports; :func:`site_mode` is what a call site runs.
|
|
122
|
+
"""
|
|
123
|
+
override = cfg.sites.get(site.name)
|
|
124
|
+
if override is None or override.mode is None:
|
|
125
|
+
return site.default_mode
|
|
126
|
+
return override.mode
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def site_mode(cfg: DecisionsConfig, site: Site) -> Mode:
|
|
130
|
+
"""Effective mode: bypass/disabled → off, else config, else site default."""
|
|
131
|
+
if bypassed() or not cfg.enabled:
|
|
132
|
+
return "off"
|
|
133
|
+
return configured_mode(cfg, site)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def threshold_for(cfg: DecisionsConfig, site: Site) -> float:
|
|
137
|
+
"""Operator ``minConfidence`` > ``Site.min_confidence`` > config table > ``THRESHOLDS``.
|
|
138
|
+
|
|
139
|
+
A site's own floor (spec PR5 D3; route = 0.70) outranks the risk table,
|
|
140
|
+
including an operator ``thresholds`` override, because the table speaks
|
|
141
|
+
for a risk class and the site value for one decision point. Only the
|
|
142
|
+
per-site ``sites.<name>.minConfidence`` override beats it.
|
|
143
|
+
"""
|
|
144
|
+
override = cfg.sites.get(site.name)
|
|
145
|
+
if override is not None and override.min_confidence is not None:
|
|
146
|
+
return override.min_confidence
|
|
147
|
+
if site.min_confidence is not None:
|
|
148
|
+
return site.min_confidence
|
|
149
|
+
if site.risk in cfg.thresholds:
|
|
150
|
+
return cfg.thresholds[site.risk]
|
|
151
|
+
return THRESHOLDS[site.risk]
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def site_timeout_ms(cfg: DecisionsConfig, site: Site) -> int:
|
|
155
|
+
"""Site ``timeoutMs`` override, else the site's own ceiling."""
|
|
156
|
+
override = cfg.sites.get(site.name)
|
|
157
|
+
if override is not None and override.timeout_ms is not None:
|
|
158
|
+
return override.timeout_ms
|
|
159
|
+
return site.timeout_ms
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
"""Decisions cost and effect: what Jev costs, what it changed, what it could save.
|
|
2
|
+
|
|
3
|
+
Read-only view for ``/arka decisions`` and ``/arka status`` (spec PR5, D5).
|
|
4
|
+
|
|
5
|
+
* **Cost** is measured: the LLM cost ledger split into production
|
|
6
|
+
(``category=decision``) and replay-harness runs (``decision-replay``),
|
|
7
|
+
so evidence runs never read as production spend.
|
|
8
|
+
* **Effect** is counted per site from ``decisions.jsonl``.
|
|
9
|
+
* **Saving** is never measured today. Four sites carry a counterfactual
|
|
10
|
+
(plan numbering): #7 forge-complexity (runs in shadow), #10
|
|
11
|
+
dispatch-role (escalate-only, so it never saves by construction), #11
|
|
12
|
+
qg-prescreen (advisory, never removes a reviewer) and #22
|
|
13
|
+
subagent-discipline (advisory, no ledger row links to a turn). Only #11
|
|
14
|
+
has a dollar figure, and it is a CEILING labelled ``counterfactual``:
|
|
15
|
+
it is never added to the cost and never called a saving.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from dataclasses import dataclass, field
|
|
21
|
+
from datetime import datetime
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from typing import Any
|
|
24
|
+
|
|
25
|
+
from core.decisions.paths import telemetry_path
|
|
26
|
+
from core.decisions.telemetry import (
|
|
27
|
+
COST_CATEGORY,
|
|
28
|
+
REPLAY_COST_CATEGORY,
|
|
29
|
+
REPLAY_SESSION_ID,
|
|
30
|
+
VALID_PERIODS,
|
|
31
|
+
_period_cutoff,
|
|
32
|
+
_read_jsonl,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
COUNTERFACTUAL = "counterfactual (ceiling)"
|
|
36
|
+
NO_SAVING = "—"
|
|
37
|
+
NO_MEASURED_SAVING = (
|
|
38
|
+
"No measured saving is claimable today: forge-complexity and qg-prescreen "
|
|
39
|
+
"do not change what runs, dispatch-role only escalates, and no ledger row "
|
|
40
|
+
"links a subagent to the turn that suggested it. Cost is measured; the "
|
|
41
|
+
"rows below are effect counts and counterfactuals."
|
|
42
|
+
)
|
|
43
|
+
REVIEWER_CATEGORIES = frozenset({"subagent:eduardo-copy", "subagent:francisca-tech"})
|
|
44
|
+
_TIER_ORDER = {"SHALLOW": 0, "STANDARD": 1, "DEEP": 2}
|
|
45
|
+
|
|
46
|
+
Rows = list[dict[str, Any]]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass(frozen=True)
|
|
50
|
+
class LedgerSplit:
|
|
51
|
+
"""Ledger cost of Jev calls: production vs replay runs."""
|
|
52
|
+
|
|
53
|
+
production_usd: float = 0.0
|
|
54
|
+
production_calls: int = 0
|
|
55
|
+
replay_usd: float = 0.0
|
|
56
|
+
replay_calls: int = 0
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@dataclass(frozen=True)
|
|
60
|
+
class Counterfactual:
|
|
61
|
+
"""One cost site's effect count and saving status."""
|
|
62
|
+
|
|
63
|
+
number: int
|
|
64
|
+
site: str
|
|
65
|
+
effect: str
|
|
66
|
+
count: int
|
|
67
|
+
detail: dict[str, int] = field(default_factory=dict)
|
|
68
|
+
saving: str = NO_SAVING
|
|
69
|
+
ceiling_usd: float | None = None
|
|
70
|
+
not_measurable: str = ""
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@dataclass(frozen=True)
|
|
74
|
+
class CostEffect:
|
|
75
|
+
"""The whole cost-and-effect view of one period."""
|
|
76
|
+
|
|
77
|
+
period: str
|
|
78
|
+
ledger: LedgerSplit
|
|
79
|
+
counterfactuals: list[Counterfactual]
|
|
80
|
+
has_data: bool
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@dataclass(frozen=True)
|
|
84
|
+
class Sources:
|
|
85
|
+
"""Where each input lives (tests point these at tmp files)."""
|
|
86
|
+
|
|
87
|
+
decisions: Path
|
|
88
|
+
ledger: Path
|
|
89
|
+
verdicts: Path
|
|
90
|
+
activations: Path
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def default_sources() -> Sources:
|
|
94
|
+
"""The live paths, each honouring its own env override."""
|
|
95
|
+
from core.evals.verdict_labels import _labels_path
|
|
96
|
+
from core.governance import activation_tracker
|
|
97
|
+
from core.runtime.llm_cost_telemetry import _telemetry_path
|
|
98
|
+
|
|
99
|
+
return Sources(telemetry_path(), _telemetry_path(), _labels_path(),
|
|
100
|
+
activation_tracker.TELEMETRY_PATH)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def is_replay_row(row: dict[str, Any]) -> bool:
|
|
104
|
+
"""A replay row: ``decision-replay``, or an older ``decision`` row of session "replay"."""
|
|
105
|
+
category = row.get("category")
|
|
106
|
+
return category == REPLAY_COST_CATEGORY or (
|
|
107
|
+
category == COST_CATEGORY and row.get("session_id") == REPLAY_SESSION_ID)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def ledger_split(ledger: Rows) -> LedgerSplit:
|
|
111
|
+
"""Sum the ledger's decision rows: production vs replay runs."""
|
|
112
|
+
rep = [r for r in ledger if is_replay_row(r)]
|
|
113
|
+
prod = [r for r in ledger if r.get("category") == COST_CATEGORY and not is_replay_row(r)]
|
|
114
|
+
return LedgerSplit(_usd(prod), len(prod), _usd(rep), len(rep))
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _usd(rows: Rows) -> float:
|
|
118
|
+
return round(sum(float(r.get("estimated_cost_usd") or 0.0) for r in rows), 8)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _site_rows(decisions: Rows, site: str) -> Rows:
|
|
122
|
+
return [r for r in decisions if r.get("site") == site]
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _tier(dims: object) -> str | None:
|
|
126
|
+
"""The Forge tier of a dimensions dict; None unless it has exactly the five dimensions."""
|
|
127
|
+
from core.decisions.sites.forge import DIMENSIONS
|
|
128
|
+
|
|
129
|
+
if not isinstance(dims, dict) or set(dims) != set(DIMENSIONS):
|
|
130
|
+
return None
|
|
131
|
+
from core.forge.complexity import calculate_weighted_score, determine_tier
|
|
132
|
+
from core.forge.schema import ComplexityDimensions
|
|
133
|
+
|
|
134
|
+
try:
|
|
135
|
+
return determine_tier(calculate_weighted_score(ComplexityDimensions(**dims))).value.upper()
|
|
136
|
+
except (TypeError, ValueError):
|
|
137
|
+
return None
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def forge_complexity(decisions: Rows) -> Counterfactual:
|
|
141
|
+
"""#7: rows where Jev's dimensions give another Forge tier than the heuristic's."""
|
|
142
|
+
up = down = 0
|
|
143
|
+
for row in _site_rows(decisions, "forge-complexity"):
|
|
144
|
+
h, j = _tier(row.get("heuristic_result")), _tier(row.get("jev_result"))
|
|
145
|
+
if h is None or j is None or h == j:
|
|
146
|
+
continue
|
|
147
|
+
if _TIER_ORDER[j] > _TIER_ORDER[h]:
|
|
148
|
+
up += 1
|
|
149
|
+
else:
|
|
150
|
+
down += 1
|
|
151
|
+
return Counterfactual(
|
|
152
|
+
7, "forge-complexity", "counterfactual: tier would differ", up + down,
|
|
153
|
+
{"up": up, "down": down},
|
|
154
|
+
not_measurable="cost of a tier: the ledger has no Forge category")
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def dispatch_role(decisions: Rows) -> Counterfactual:
|
|
158
|
+
"""#10: escalations Jev acted on; downgrades the rule blocked."""
|
|
159
|
+
rows = _site_rows(decisions, "dispatch-role")
|
|
160
|
+
escalated = sum(1 for r in rows if r.get("acted_on") == "jev"
|
|
161
|
+
and r.get("jev_result") != r.get("heuristic_result"))
|
|
162
|
+
blocked = sum(1 for r in rows if r.get("reason") == "downgrade-blocked")
|
|
163
|
+
return Counterfactual(
|
|
164
|
+
10, "dispatch-role", "escalations acted on", escalated,
|
|
165
|
+
{"downgrade_blocked": blocked},
|
|
166
|
+
saving=f"{NO_SAVING} escalate-only: never saves by construction",
|
|
167
|
+
not_measurable="whether the orchestrator followed the marker (Task model has no hook)")
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def _prescreen_rounds(verdicts: Rows) -> list[tuple[str, str]]:
|
|
171
|
+
"""``(predicted, final)`` per QG round that carried a prescreen, lower case."""
|
|
172
|
+
out: list[tuple[str, str]] = []
|
|
173
|
+
for row in verdicts:
|
|
174
|
+
pre = row.get("prescreen")
|
|
175
|
+
if isinstance(pre, dict) and pre.get("verdict") in ("approved", "rejected"):
|
|
176
|
+
out.append((str(pre["verdict"]), str(row.get("verdict") or "").lower()))
|
|
177
|
+
return out
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _rejected_sessions(verdicts: Rows) -> set[str]:
|
|
181
|
+
return {str(r.get("session_id") or "") for r in verdicts
|
|
182
|
+
if isinstance(r.get("prescreen"), dict)
|
|
183
|
+
and r["prescreen"].get("verdict") == "rejected"
|
|
184
|
+
and str(r.get("verdict") or "").upper() == "REJECTED"} - {""}
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def qg_prescreen(verdicts: Rows, ledger: Rows) -> Counterfactual:
|
|
188
|
+
"""#11: prediction accuracy and the reviewer-cost ceiling of correct rejections.
|
|
189
|
+
|
|
190
|
+
The ceiling sums the reviewers' ledger cost over whole SESSIONS with a
|
|
191
|
+
correctly predicted rejection: the ledger has no round id, so this
|
|
192
|
+
over-counts by design (an upper bound, never an estimate).
|
|
193
|
+
"""
|
|
194
|
+
rounds = _prescreen_rounds(verdicts)
|
|
195
|
+
agree = sum(1 for predicted, final in rounds if predicted == final)
|
|
196
|
+
sessions = _rejected_sessions(verdicts)
|
|
197
|
+
ceiling = _usd([r for r in ledger if r.get("category") in REVIEWER_CATEGORIES
|
|
198
|
+
and str(r.get("session_id") or "") in sessions])
|
|
199
|
+
return Counterfactual(
|
|
200
|
+
11, "qg-prescreen", "rounds with a prescreen", len(rounds),
|
|
201
|
+
{"agree_with_final": agree, "sessions_rejected_as_predicted": len(sessions)},
|
|
202
|
+
saving=COUNTERFACTUAL, ceiling_usd=ceiling,
|
|
203
|
+
not_measurable="real saving: the prescreen never skips a reviewer")
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _isolate_value(row: dict[str, Any]) -> object:
|
|
207
|
+
return row.get("jev_result") if row.get("acted_on") == "jev" else row.get("heuristic_result")
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def subagent_discipline(decisions: Rows, activations: Rows) -> Counterfactual:
|
|
211
|
+
"""#22: turns told not to isolate, and how many of their sessions launched a subagent."""
|
|
212
|
+
no_turns = [r for r in _site_rows(decisions, "subagent-discipline")
|
|
213
|
+
if _isolate_value(r) is False]
|
|
214
|
+
sessions = {str(r.get("session_id") or "") for r in no_turns} - {""}
|
|
215
|
+
launched = {str(a.get("session_id") or "") for a in activations} & sessions
|
|
216
|
+
return Counterfactual(
|
|
217
|
+
22, "subagent-discipline", "turns marked isolate=no", len(no_turns),
|
|
218
|
+
{"sessions": len(sessions), "sessions_with_a_subagent": len(launched)},
|
|
219
|
+
saving=f"{NO_SAVING} correlation per session, not attribution",
|
|
220
|
+
not_measurable="a subagent that was not launched leaves no trace")
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _load(sources: Sources, cutoff: datetime | None) -> dict[str, Rows]:
|
|
224
|
+
paths = {"decisions": sources.decisions, "ledger": sources.ledger,
|
|
225
|
+
"verdicts": sources.verdicts, "activations": sources.activations}
|
|
226
|
+
return {name: _read_jsonl(path, cutoff)[0] for name, path in paths.items()}
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def cost_effect(
|
|
230
|
+
period: str = "today", *, sources: Sources | None = None, now: datetime | None = None
|
|
231
|
+
) -> CostEffect:
|
|
232
|
+
"""Cost, effect and counterfactuals of one period (today | week | month | all)."""
|
|
233
|
+
if period not in VALID_PERIODS:
|
|
234
|
+
raise ValueError(f"invalid period: {period!r}")
|
|
235
|
+
data = _load(sources or default_sources(), _period_cutoff(period, now))
|
|
236
|
+
split = ledger_split(data["ledger"])
|
|
237
|
+
rows = [forge_complexity(data["decisions"]), dispatch_role(data["decisions"]),
|
|
238
|
+
qg_prescreen(data["verdicts"], data["ledger"]),
|
|
239
|
+
subagent_discipline(data["decisions"], data["activations"])]
|
|
240
|
+
has_data = bool(split.production_calls or split.replay_calls or data["decisions"]
|
|
241
|
+
or any(r.count for r in rows))
|
|
242
|
+
return CostEffect(period, split, rows, has_data)
|