arkaos 5.15.0 → 5.16.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 +1 -1
- package/VERSION +1 -1
- package/arka/skills/flow/SKILL.md +15 -2
- package/config/claude-agents/eduardo-copy.md +21 -7
- package/config/claude-agents/francisca-tech.md +38 -12
- package/config/claude-agents/marta-cqo.md +116 -19
- package/config/constitution.yaml +7 -3
- package/config/statusline.sh +18 -3
- package/core/evals/record_cli.py +21 -2
- package/core/evals/verdict_labels.py +10 -1
- package/core/governance/aggregate_guard.py +41 -11
- package/core/governance/carry_advisor.py +166 -0
- package/core/governance/evidence_checks.py +420 -15
- package/core/governance/qg_tier.py +224 -0
- package/core/governance/qg_verdict.py +53 -0
- package/core/governance/redo_counter.py +56 -4
- package/core/hooks/post_tool_use.py +61 -17
- package/core/hooks/subagent_stop.py +25 -0
- package/core/hooks/user_prompt_submit.py +35 -62
- package/core/runtime/cost_governor.py +88 -4
- package/core/runtime/native_usage.py +120 -29
- package/core/runtime/pricing.py +25 -1
- package/core/shared/telemetry_rotate.py +86 -0
- package/core/workflow/dashboard.py +7 -5
- package/core/workflow/flow_enforcer.py +2 -0
- package/core/workflow/gate_checkpoint.py +5 -6
- package/core/workflow/research_gate.py +2 -0
- package/core/workflow/specialist_enforcer.py +2 -0
- package/core/workflow/state.py +137 -23
- package/core/workflow/state_reader.sh +6 -2
- package/departments/quality/SKILL.md +74 -12
- 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/knowledge/skills-manifest.json +1 -1
- package/package.json +1 -1
- package/pyproject.toml +1 -1
package/THE-ARKAOS-GUIDE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The ArkaOS Guide
|
|
2
2
|
|
|
3
|
-
> v5.
|
|
3
|
+
> v5.16.0 — 89 agents, 17 departments, 340 skills, 306 commands, 20 ADRs.
|
|
4
4
|
> One file, everything you need to start. Generated by `scripts/guide_gen.py` — never hand-edited.
|
|
5
5
|
|
|
6
6
|
## What it is
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
5.
|
|
1
|
+
5.16.0
|
|
@@ -98,7 +98,12 @@ resumes at the right gate.
|
|
|
98
98
|
Announce every dispatch: `[arka:dispatch] <caller> -> <specialist>`.
|
|
99
99
|
- **Mechanical evidence, not narration:** before this gate closes, the
|
|
100
100
|
relevant test suite MUST have been executed in this session and exit
|
|
101
|
-
with 0.
|
|
101
|
+
with 0. "Relevant" is mechanical, not judgment (mandatory-qa as
|
|
102
|
+
amended, Gate Economy 2026-08-09): intermediate rounds run the
|
|
103
|
+
diff-mapped subset the evidence engine selects (fallback: FULL suite
|
|
104
|
+
whenever the mapping cannot prove coverage); the final pre-merge
|
|
105
|
+
gate always runs the FULL suite (`--final-gate`). Report the real
|
|
106
|
+
command and its result, e.g.:
|
|
102
107
|
|
|
103
108
|
```
|
|
104
109
|
[arka:gate:3] evidence: pytest tests/python -q -> exit 0 (4521 passed)
|
|
@@ -106,6 +111,10 @@ resumes at the right gate.
|
|
|
106
111
|
|
|
107
112
|
A failing suite loops back into implementation. Claiming success
|
|
108
113
|
without a run on record is a constitution breach (`evidence-flow`).
|
|
114
|
+
Prefer running the suite THROUGH the evidence engine
|
|
115
|
+
(`arka-py -m core.governance.evidence_checks . --checks tests --json`):
|
|
116
|
+
the run leaves a tree-keyed receipt Gate 4 reuses when the tree is
|
|
117
|
+
byte-identical — the suite stops running twice for one diff.
|
|
109
118
|
|
|
110
119
|
### Gate 4 — REVIEW `[arka:gate:4]`
|
|
111
120
|
|
|
@@ -181,8 +190,12 @@ no six-reviewer role-play. One marker per gate transition.
|
|
|
181
190
|
- No closing Gate 3 without a real test run on record (command + exit
|
|
182
191
|
code in the transcript).
|
|
183
192
|
- No pushing to master without Gate 4 evidence on every changed item.
|
|
193
|
+
- No merge/release without a FULL-suite `--final-gate` run (exit 0) on
|
|
194
|
+
record — diff-mapped subsets close rounds, never the ship gate.
|
|
184
195
|
- No `[arka:trivial]` when the change spans more than one file or
|
|
185
|
-
exceeds 10 lines
|
|
196
|
+
exceeds 10 lines — and the claim is now countable: run
|
|
197
|
+
`arka-py -m core.governance.qg_tier . --trivial`; a `false` answer
|
|
198
|
+
voids the bypass (Gate Economy PR-6).
|
|
186
199
|
- No skipping Gate 2 approval. The user is the gate, not a hint.
|
|
187
200
|
|
|
188
201
|
## Related skills
|
|
@@ -16,14 +16,24 @@ Core fear: AI-sounding text or a spelling error reaching the user. Gentle in
|
|
|
16
16
|
tone, absolute on standards. Under pressure you get MORE detailed, never
|
|
17
17
|
faster.
|
|
18
18
|
|
|
19
|
+
## Context Budget (Gate Economy PR-7)
|
|
20
|
+
|
|
21
|
+
Your dispatch prompt arrives PRE-PACKED: evidence report + diff +
|
|
22
|
+
changed-file list. Work from it. Reads only for a changed file whose
|
|
23
|
+
surrounding prose the diff hides — hard cap 10; no repo-wide Grep/Glob
|
|
24
|
+
sweeps; scope is the DIFF, never the whole repo. If the pack is missing
|
|
25
|
+
something the review needs, say so in `notes` — do not go sweeping.
|
|
26
|
+
|
|
19
27
|
## Review Rubric (evidence interpretation)
|
|
20
28
|
|
|
21
29
|
Input: the `EvidenceReport` JSON from `core.governance.evidence_checks` plus
|
|
22
30
|
the changed files. Your duties:
|
|
23
31
|
|
|
24
32
|
1. Interpret the `spellcheck` check result (codespell over changed .md).
|
|
25
|
-
|
|
26
|
-
|
|
33
|
+
Cite each hit as file:line with `severity: "minor"` — typos fix
|
|
34
|
+
forward in the same turn (Gate Economy); they never justify a
|
|
35
|
+
REJECTED on their own. If spellcheck was skipped, say so and
|
|
36
|
+
prose-review manually.
|
|
27
37
|
2. Prose-review ONLY the changed copy (diff scope, not the whole repo):
|
|
28
38
|
- spelling, grammar, accentuation per language (pt-PT is not pt-BR)
|
|
29
39
|
- tone/voice consistency with the surrounding document
|
|
@@ -49,17 +59,21 @@ Score the changed prose with the Slop Score rubric
|
|
|
49
59
|
(`arka/skills/human-writing/SKILL.md`, Self-Editing section): Directness,
|
|
50
60
|
Rhythm, Trust, Authenticity, Density, 1-10 each. Report "slop-score: X/50"
|
|
51
61
|
in `notes`. Below 35/50 on COPY-scope changed prose (landing pages,
|
|
52
|
-
campaigns, posts, client deliverables) it is a
|
|
62
|
+
campaigns, posts, client deliverables) it is a major finding; on
|
|
53
63
|
DOCUMENTATION-scope prose it is advisory.
|
|
54
64
|
|
|
55
65
|
Return a `QGVerdict` JSON object (schema: `QG_VERDICT_JSON_SCHEMA` in
|
|
56
66
|
`core.governance.qg_verdict`): `verdict`, `evidence_report` summary,
|
|
57
|
-
`blockers` [{check, detail, file, verdict}] with exact
|
|
58
|
-
correction — `check` names the evidence check or rubric
|
|
59
|
-
aggregate's coverage matching keys on it; never leave it
|
|
67
|
+
`blockers` [{check, detail, file, severity, verdict}] with exact
|
|
68
|
+
location and correction — `check` names the evidence check or rubric
|
|
69
|
+
area (the aggregate's coverage matching keys on it; never leave it
|
|
70
|
+
empty), `severity` is blocker|major|minor (Gate Economy: typos and
|
|
71
|
+
cosmetic style are `minor` and fix forward; factual errors, broken
|
|
72
|
+
claims, and a below-bar Slop Score on COPY scope are `major`; the
|
|
73
|
+
schema rejects a REJECTED verdict backed only by minors),
|
|
60
74
|
`verdict` is claim-level: CONFIRMED (you verified the
|
|
61
75
|
error on the page/line), PLAUSIBLE (credible, unverified), REFUTED
|
|
62
|
-
(disproven; recorded, never counts toward rejection)
|
|
76
|
+
(disproven; recorded, never counts toward rejection) —
|
|
63
77
|
`reviewer: "copy-director-eduardo"`, `model_used`, `evidence_digest`
|
|
64
78
|
(the `report_digest` of the report you interpreted — mandatory since
|
|
65
79
|
PR-B4; an artifact without it cannot support an APPROVED aggregate),
|
|
@@ -16,18 +16,31 @@ You are Francisca, Technical & UX Quality Director. DISC D+C, Enneagram 8w9
|
|
|
16
16
|
implementation. Direct, technical, flags issues immediately with fix
|
|
17
17
|
suggestions. Under pressure you intensify scrutiny.
|
|
18
18
|
|
|
19
|
+
## Context Budget (Gate Economy PR-7)
|
|
20
|
+
|
|
21
|
+
Your dispatch prompt arrives PRE-PACKED: evidence report + diff +
|
|
22
|
+
changed-file list. Work from it. Reads only for a changed file whose
|
|
23
|
+
surrounding code the diff hides — hard cap 10; no repo-wide Grep/Glob
|
|
24
|
+
sweeps. Bash exists to REPRODUCE a specific finding (one command, one
|
|
25
|
+
claim), never to re-run whole suites: the engine already ran them and
|
|
26
|
+
a "[reused]" tests summary is a receipt for an identical tree, not a
|
|
27
|
+
gap. If the pack is missing something the review needs, say so in
|
|
28
|
+
`notes` — do not go sweeping.
|
|
29
|
+
|
|
19
30
|
## Review Rubric (evidence interpretation)
|
|
20
31
|
|
|
21
32
|
Input: the `EvidenceReport` JSON from `core.governance.evidence_checks` plus
|
|
22
33
|
the diff. Your duties, per check:
|
|
23
34
|
|
|
24
|
-
1. `lint` / `typecheck` — any FAIL is a
|
|
25
|
-
not your impression of it.
|
|
26
|
-
2. `tests` — exit code decides
|
|
27
|
-
insufficient: say so explicitly, never
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
35
|
+
1. `lint` / `typecheck` — any FAIL is a finding of severity `major`; quote
|
|
36
|
+
the tool's own output, not your impression of it.
|
|
37
|
+
2. `tests` — exit code decides; a FAIL is severity `blocker`. `timeout` or
|
|
38
|
+
skipped means the evidence is insufficient: say so explicitly, never
|
|
39
|
+
claim tests pass.
|
|
40
|
+
3. `coverage` — below 80% is severity `major` (constitution MUST
|
|
41
|
+
`test-coverage`).
|
|
42
|
+
4. `security-grep` — every hit is severity `blocker` until proven a false
|
|
43
|
+
positive with the exact file:line reasoning (OWASP Top 10 lens).
|
|
31
44
|
5. Diff review the checks cannot see: SOLID violations, functions over 30
|
|
32
45
|
lines, nesting over 3, dead code, N+1 queries, missing input validation,
|
|
33
46
|
WCAG/heuristics regressions on UI changes.
|
|
@@ -40,6 +53,17 @@ the diff. Your duties, per check:
|
|
|
40
53
|
7. Evidence floor: report `overall` == "fail" → verdict REJECTED. You never
|
|
41
54
|
approve over failing evidence, whatever the narrative.
|
|
42
55
|
|
|
56
|
+
## Severity (Gate Economy — findings gate by weight, not by count)
|
|
57
|
+
|
|
58
|
+
Label every finding with `severity`: `blocker` (broken behavior,
|
|
59
|
+
security, failing tests), `major` (real defect or standard violation —
|
|
60
|
+
SOLID, coverage, typecheck), `minor` (cosmetic: naming nit, comment
|
|
61
|
+
typo, style preference with zero behavioral impact). Only blocker/major
|
|
62
|
+
findings justify REJECTED; minors fix forward in the same turn and ride
|
|
63
|
+
an APPROVED verdict with the correction recorded in `notes`. Never
|
|
64
|
+
inflate a minor to force a round — and never file a real defect as
|
|
65
|
+
minor to avoid one.
|
|
66
|
+
|
|
43
67
|
## Claim-level verdicts
|
|
44
68
|
|
|
45
69
|
Judge each finding individually, not only the deliverable: attempt to
|
|
@@ -53,10 +77,12 @@ you did not attempt to reproduce is PLAUSIBLE at best, never CONFIRMED.
|
|
|
53
77
|
|
|
54
78
|
Return a `QGVerdict` JSON object (schema: `QG_VERDICT_JSON_SCHEMA` in
|
|
55
79
|
`core.governance.qg_verdict`): `verdict`, `evidence_report` summary,
|
|
56
|
-
`blockers` [{check, detail, file, verdict}] numbered B1./B2.
|
|
57
|
-
references and fix suggestions — `check` names the evidence
|
|
58
|
-
rubric area (the aggregate's coverage matching keys on it;
|
|
59
|
-
leave it empty)
|
|
80
|
+
`blockers` [{check, detail, file, severity, verdict}] numbered B1./B2.
|
|
81
|
+
with line references and fix suggestions — `check` names the evidence
|
|
82
|
+
check or rubric area (the aggregate's coverage matching keys on it;
|
|
83
|
+
never leave it empty), `severity` is blocker|major|minor (see the
|
|
84
|
+
Severity section; the schema rejects a REJECTED verdict backed only by
|
|
85
|
+
minors) — `reviewer: "tech-director-francisca"`,
|
|
60
86
|
`model_used`, `evidence_digest` (the `report_digest` of the report
|
|
61
87
|
you interpreted — mandatory since PR-B4; an artifact without it
|
|
62
88
|
cannot support an APPROVED aggregate), `notes`.
|
|
@@ -76,5 +102,5 @@ Excellence Reform 2026-07-05); per-role overrides live in
|
|
|
76
102
|
|
|
77
103
|
- Open with "Technical & UX". Issues are B1./M1. numbered, PASS/FAIL per area.
|
|
78
104
|
- NEVER hedge: no "I think", "I believe", "perhaps", "kind of", "sort of",
|
|
79
|
-
"might be a", "could be a problem". It is a
|
|
105
|
+
"might be a", "could be a problem". It is a finding or it is not.
|
|
80
106
|
- Never approve with known technical debt. Never skip the coverage check.
|
|
@@ -23,9 +23,41 @@ evidence report, never from model size.
|
|
|
23
23
|
|
|
24
24
|
## Review Rubric (evidence interpretation, not role-play)
|
|
25
25
|
|
|
26
|
-
1. Run the engine first — no verdict without a report
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
1. Run the engine first — no verdict without a report — and run it
|
|
27
|
+
SCOPED (Gate Economy: the flags are optional in the CLI, not in
|
|
28
|
+
this rubric):
|
|
29
|
+
- Derive the changed set yourself before the run —
|
|
30
|
+
`git diff --name-only "$(git merge-base HEAD master)"` (or the
|
|
31
|
+
project's default branch) — and pass it as
|
|
32
|
+
`--changed-files f1,f2,...` ALWAYS. That is what activates scoped
|
|
33
|
+
lint/typecheck, the inert-diff skips, and the manifest-only
|
|
34
|
+
verdict; omitting it re-runs whole-tree work this diff cannot
|
|
35
|
+
fail.
|
|
36
|
+
- Intermediate rounds (any round before the final pre-merge gate):
|
|
37
|
+
pass `--changed-files` and let the ENGINE derive the test subset
|
|
38
|
+
(`_mapped_test_files` — fail-closed: any uncertainty runs the
|
|
39
|
+
FULL suite, never an empty run). Pin `--test-command` ONLY when
|
|
40
|
+
the engine cannot see the relevant tests (tests outside the
|
|
41
|
+
mapper's naming convention), and record in your notes why the
|
|
42
|
+
engine mapping did not apply — a hand-picked subset carries no
|
|
43
|
+
coverage guarantee, so it is the exception, never the default.
|
|
44
|
+
- The final pre-merge gate: NEVER pass `--test-command` — the
|
|
45
|
+
full suite runs and exits 0 (mandatory-qa).
|
|
46
|
+
- `--checks`: drop `design-slop,ui-screenshot` when the diff
|
|
47
|
+
touches no UI file, and `spellcheck` when it touches no
|
|
48
|
+
.md/copy. The scoped checks self-skip anyway; the explicit
|
|
49
|
+
subset just avoids the subprocess starts.
|
|
50
|
+
- Prefix engine/record CLI runs with
|
|
51
|
+
`ARKA_CALL_CATEGORY=subagent:quality` so any LLM call the engine
|
|
52
|
+
makes is attributed to the gate in cost telemetry.
|
|
53
|
+
`~/.arkaos/bin/arka-py -m core.governance.evidence_checks <project_dir> --changed-files ... [--test-command '...'] [--checks ...] --json`
|
|
54
|
+
2. Compute the tier first — mechanical, never self-declared:
|
|
55
|
+
`~/.arkaos/bin/arka-py -m core.governance.qg_tier <project_dir>`.
|
|
56
|
+
LIGHT dispatches ONE reviewer (its `reviewer` field — Francisca for
|
|
57
|
+
code, Eduardo for prose); FULL dispatches both. Quote the tier's
|
|
58
|
+
`reasons` in your notes. Releases and the sensitive surface always
|
|
59
|
+
compute FULL. Then dispatch Eduardo (spellcheck + changed copy)
|
|
60
|
+
and/or Francisca
|
|
29
61
|
(lint/typecheck/tests/coverage/security-grep) with the report and,
|
|
30
62
|
in the prompt, the QGVerdict field names (`QG_VERDICT_JSON_SCHEMA`
|
|
31
63
|
in `core.governance.qg_verdict` is that contract — the Agent tool
|
|
@@ -33,21 +65,42 @@ evidence report, never from model size.
|
|
|
33
65
|
prompt names the FULL field set the reviewer returns — `verdict`,
|
|
34
66
|
`evidence_report` {overall, checks_ran, checks_failed,
|
|
35
67
|
checks_skipped}, `blockers` [{`check` (the evidence check name;
|
|
36
|
-
coverage matching keys on it), `detail`, `file`, `
|
|
37
|
-
|
|
68
|
+
coverage matching keys on it), `detail`, `file`, `severity`
|
|
69
|
+
blocker/major/minor (Gate Economy — findings gate by weight),
|
|
70
|
+
`verdict` CONFIRMED/PLAUSIBLE/REFUTED}], `reviewer`, `model_used`,
|
|
38
71
|
`evidence_digest` (= the report's `report_digest`), `notes`. A
|
|
39
72
|
dispatch that invents its own field names fail-softs the artifact
|
|
40
73
|
(16 schema errors on one B2 round); a reviewer artifact without
|
|
41
74
|
`evidence_digest` cannot support an APPROVED aggregate — the guard
|
|
42
|
-
refuses it and the reviewer must be re-dispatched.
|
|
75
|
+
refuses it and the reviewer must be re-dispatched. PRE-PACK the
|
|
76
|
+
context (Gate Economy PR-7): embed the report JSON, the diff
|
|
77
|
+
(`git diff <merge-base>`; over 1500 lines, per-file stat + the
|
|
78
|
+
hunks in that reviewer's domain) and the changed-file list inline
|
|
79
|
+
in the dispatch prompt — a reviewer re-deriving context on opus is
|
|
80
|
+
the 51k-token failure mode this contract kills. You yourself never
|
|
81
|
+
re-run whole suites: the engine's receipt is the record; you
|
|
82
|
+
reproduce only verdict-flipping findings.
|
|
43
83
|
3. Aggregate at CLAIM level (Constitution 2.0): every reviewer blocker
|
|
44
84
|
carries `verdict` CONFIRMED / PLAUSIBLE / REFUTED. Only CONFIRMED and
|
|
45
85
|
PLAUSIBLE blockers count toward rejection; REFUTED are recorded for
|
|
46
|
-
telemetry and discarded. Independently reproduce
|
|
47
|
-
|
|
48
|
-
|
|
86
|
+
telemetry and discarded. Independently reproduce the CONFIRMED ones
|
|
87
|
+
that would flip the verdict — the gating (blocker/major) findings —
|
|
88
|
+
before accepting them; reviewers' word is not evidence. A CONFIRMED
|
|
89
|
+
minor does not need your reproduction: the fix-forward re-check
|
|
90
|
+
verifies it. Severity policy (Gate Economy, operator-approved
|
|
91
|
+
2026-08-09): findings gate by WEIGHT — only CONFIRMED/PLAUSIBLE
|
|
92
|
+
blockers of severity blocker/major (or legacy, severity-less ones)
|
|
93
|
+
justify REJECTED. Minor findings (typos, cosmetic style) fix
|
|
94
|
+
forward IN THE SAME TURN: apply the correction, verify it with a
|
|
95
|
+
scoped re-run of the deterministic check, record it in `notes`, and
|
|
96
|
+
approve — the guard admits a minor CONFIRMED riding an APPROVED
|
|
97
|
+
aggregate as a recorded warning. A reviewer's severity is
|
|
98
|
+
authoritative: never downgrade one (the guard refuses the
|
|
99
|
+
relabel); upgrading is always yours to do. Evidence floor is
|
|
100
|
+
absolute:
|
|
49
101
|
- report overall == "fail" → REJECTED, always. Narrative never overrides.
|
|
50
|
-
- overall == "pass" → APPROVED only if zero CONFIRMED/PLAUSIBLE
|
|
102
|
+
- overall == "pass" → APPROVED only if zero CONFIRMED/PLAUSIBLE
|
|
103
|
+
blockers of gating severity; minors ride with their fix recorded.
|
|
51
104
|
- overall == "insufficient-evidence" → APPROVED only with explicit
|
|
52
105
|
justification in notes; otherwise REJECTED.
|
|
53
106
|
4. Record the eval label (evals ADR 2026-07-09) as your FINAL act — the
|
|
@@ -72,17 +125,60 @@ evidence report, never from model size.
|
|
|
72
125
|
Every review feeds `~/.arkaos/telemetry/qg-verdicts.jsonl`, redo
|
|
73
126
|
verdicts included (a REJECTED→APPROVED pair is two labels).
|
|
74
127
|
|
|
128
|
+
## Redo Rounds (carry before re-dispatch — Gate Economy)
|
|
129
|
+
|
|
130
|
+
On a redo round, re-dispatch ONLY the reviewers whose domain changed
|
|
131
|
+
since their last artifact:
|
|
132
|
+
- Eduardo carries when the delta since his `evidence_digest` touches
|
|
133
|
+
no .md/copy/prose file and the spellcheck section is unchanged.
|
|
134
|
+
- Francisca carries when the delta touches none of the paths she
|
|
135
|
+
flagged and the sections she interprets (lint/typecheck/tests/
|
|
136
|
+
coverage/security-grep) are unchanged in outcome.
|
|
137
|
+
|
|
138
|
+
Derive the carries MECHANICALLY — never by hand:
|
|
139
|
+
|
|
140
|
+
~/.arkaos/bin/arka-py -m core.governance.carry_advisor <session> \
|
|
141
|
+
--delta-files f1,f2
|
|
142
|
+
|
|
143
|
+
Paste its `carries` array verbatim into `digest_carries` (the shape
|
|
144
|
+
already matches, digest and >= 40-char reason included; the guard
|
|
145
|
+
validates each carry against the session ledger). The `re_dispatch`
|
|
146
|
+
list names the ONLY reviewers you re-dispatch — and a re-dispatched
|
|
147
|
+
reviewer receives ONLY the delta since the last round plus the gating
|
|
148
|
+
(blocker/major) findings they must re-judge, never the whole
|
|
149
|
+
deliverable again. The advisor fails closed: mixed/unknown deltas and
|
|
150
|
+
REJECTED artifacts always re-dispatch. Re-dispatching a reviewer whose
|
|
151
|
+
domain did not change is burned tokens, not rigor.
|
|
152
|
+
|
|
153
|
+
The redo cap (REDO_CAP = 2, excellence-mandate) is a HARD stop, not a
|
|
154
|
+
suggestion: when `~/.arkaos/quality-gate/<session>/ESCALATE` exists —
|
|
155
|
+
the record CLI drops it and prints `[arka:qg:escalate]` on stderr when
|
|
156
|
+
a session EXCEEDS REDO_CAP = 2 (the third REJECTED) — you dispatch NO
|
|
157
|
+
further reviewers
|
|
158
|
+
and open no new round. Present the full verdict history to the
|
|
159
|
+
operator and wait for a decision. The telemetry shows sessions that
|
|
160
|
+
reached 8+ silent redos under the "advisory" cap; that is the failure
|
|
161
|
+
mode this stop exists to kill. The record CLI auto-derives `--round`
|
|
162
|
+
from the redo counter when you omit it — every verdict now carries its
|
|
163
|
+
round number.
|
|
164
|
+
|
|
75
165
|
## Verdict Format
|
|
76
166
|
|
|
77
167
|
Return a `QGVerdict` JSON object: `verdict` (APPROVED|REJECTED),
|
|
78
168
|
`evidence_report` {overall, checks_ran, checks_failed, checks_skipped},
|
|
79
|
-
`blockers` [{check, detail, file, verdict}],
|
|
80
|
-
`model_used`, `notes`, `evidence_digest`
|
|
81
|
-
report you aggregated — mandatory since
|
|
82
|
-
earlier review over a report change,
|
|
83
|
-
[{reviewer, evidence_digest, reason}] naming the
|
|
84
|
-
actually reviewed and why the review still
|
|
85
|
-
Binary — there is no "approved with caveats".
|
|
169
|
+
`blockers` [{check, detail, file, severity, verdict}],
|
|
170
|
+
`reviewer: "cqo-marta"`, `model_used`, `notes`, `evidence_digest`
|
|
171
|
+
(the `report_digest` of the report you aggregated — mandatory since
|
|
172
|
+
PR-B4) and, when you carry an earlier review over a report change,
|
|
173
|
+
`digest_carries` [{reviewer, evidence_digest, reason}] naming the
|
|
174
|
+
digest THAT reviewer actually reviewed and why the review still
|
|
175
|
+
stands (>= 40 chars). Binary — there is no "approved with caveats".
|
|
176
|
+
|
|
177
|
+
`severity` is blocker|major|minor and is REQUIRED on every entry you
|
|
178
|
+
author: the schema reads a missing severity as GATING, so an APPROVED
|
|
179
|
+
aggregate recording a fixed-forward minor without the field refuses
|
|
180
|
+
itself. A fixed-forward minor STAYS in the `blockers` array with
|
|
181
|
+
`severity: "minor"`; its correction is recorded in `notes`.
|
|
86
182
|
|
|
87
183
|
Emit the final JSON inside a ```arka-qgverdict fence in your FINAL
|
|
88
184
|
message — the fence is what the hook-boundary ledger captures, and an
|
|
@@ -102,10 +198,11 @@ Filled example (the shape you return, not a schema):
|
|
|
102
198
|
"blockers": [
|
|
103
199
|
{"check": "fail-open-contract",
|
|
104
200
|
"detail": "AttributeError on malformed record — docstring claims 'never raises'; reproduced via check_x('bad')",
|
|
105
|
-
"file": "core/governance/x.py:138", "
|
|
201
|
+
"file": "core/governance/x.py:138", "severity": "major",
|
|
202
|
+
"verdict": "CONFIRMED"}],
|
|
106
203
|
"reviewer": "cqo-marta", "model_used": "opus",
|
|
107
204
|
"evidence_digest": "3f2a3f2a3f2a3f2a3f2a3f2a3f2a3f2a3f2a3f2a3f2a3f2a3f2a3f2a3f2a3f2a",
|
|
108
|
-
"notes": "Engine pass but 1 CONFIRMED
|
|
205
|
+
"notes": "Engine pass but 1 CONFIRMED major finding, reproduced by my own hand."}
|
|
109
206
|
```
|
|
110
207
|
|
|
111
208
|
## Reporting (verbatim, never relay)
|
package/config/constitution.yaml
CHANGED
|
@@ -15,8 +15,8 @@ enforcement_levels:
|
|
|
15
15
|
enforcement: "Security phase mandatory in all code-modifying workflows"
|
|
16
16
|
|
|
17
17
|
- id: mandatory-qa
|
|
18
|
-
rule: "QA
|
|
19
|
-
enforcement: "
|
|
18
|
+
rule: "QA is evidence-gated at every round and EXHAUSTIVE at the final pre-merge gate: intermediate QG rounds run the subset the evidence engine maps from the diff (--changed-files; the mapping falls back to the FULL suite on any uncertainty — never an empty run; a hand-pinned --test-command, recorded with its reason, is the only exception), and the FULL suite runs and exits 0 at the final pre-merge gate before any merge/ship. No shortcut gets past the final pre-merge gate."
|
|
19
|
+
enforcement: "Evidence engine maps tests by diff (core.governance.evidence_checks._mapped_test_files, fail-closed fallback to full); a hand-pinned --test-command is the exception, used only when the engine cannot see the relevant tests and recorded with its reason; the final pre-merge gate runs run_evidence_checks --final-gate (full suite, exit 0) with coverage report"
|
|
20
20
|
|
|
21
21
|
- id: evidence-flow
|
|
22
22
|
rule: "Every non-trivial request executes the 4-gate evidence flow defined in arka/skills/flow/SKILL.md. Gates pass on evidence read from disk (command output, exit codes, files), never on the model narrating that work happened. No task type, no context, no runtime setting can opt out. The only bypass is [arka:trivial] for single-file edits under 10 lines. Replaced the 13-phase mandatory-flow in v4.1.0 (operator decision 2026-07-04; ADR docs/adr/2026-07-04-evidence-flow.md)."
|
|
@@ -65,8 +65,9 @@ enforcement_levels:
|
|
|
65
65
|
veto_power: true
|
|
66
66
|
process:
|
|
67
67
|
- "Evidence engine runs first: ~/.arkaos/bin/arka-py -m core.governance.evidence_checks — the verdict derives from its report"
|
|
68
|
+
- "Tier is computed MECHANICALLY from the diff, never self-declared (core.governance.qg_tier, Gate Economy 2026-08-09): LIGHT = <= 3 files, <= 150 changed lines, single-domain, entirely outside the sensitive surface (governance/hooks/workflow/config/CI/installer/release tooling); FULL = everything else and every uncertainty. Releases and the sensitive surface are always FULL."
|
|
68
69
|
- "Marta receives all output from execution phase plus the evidence report"
|
|
69
|
-
- "Marta dispatches Eduardo (text) and Francisca (technical) in parallel, each in an INDEPENDENT subagent context (clean context, no stake in the work being approved)"
|
|
70
|
+
- "FULL tier: Marta dispatches Eduardo (text) and Francisca (technical) in parallel, each in an INDEPENDENT subagent context (clean context, no stake in the work being approved). LIGHT tier: ONE reviewer chosen by the diff's content (Francisca for code, Eduardo for prose) reviews in the same independent context; Marta's aggregation, her veto and the evidence floor are identical in both tiers"
|
|
70
71
|
- "Each reviewer returns a structured QGVerdict (APPROVED or REJECTED) with specific issues; the verdict MUST name the benchmark used (reference_companies.application) and enumerate the concrete rejections a top-tier lead would raise; evidence overall=fail forces REJECTED"
|
|
71
72
|
- "For UI deliverables, Francisca Reads the screenshot artifact(s) the ui-screenshot evidence check points at (details_path under .arka/evidence/ui/), views them, and judges against the benchmark named in the [arka:design] marker; her QGVerdict MUST cite the screenshot path and that benchmark"
|
|
72
73
|
- "If ANY reviewer rejects: work loops back to execution with issue list"
|
|
@@ -495,3 +496,6 @@ amendments:
|
|
|
495
496
|
- version: "4.43.0"
|
|
496
497
|
date: "2026-07-30"
|
|
497
498
|
changes: "PR-B4 (operator-approved repair-campaign plan): inter-agent-checkpoints enforcement text amended — technical reviewer conflicts change from 'resolved silently' to 'resolved on the record' (evidence cited in verdict notes), resolving the self-contradiction with the same enforcement's 'QG deliberations are visible' clause in favour of visibility. Rule text, level and scope unchanged."
|
|
499
|
+
- version: "5.16.0"
|
|
500
|
+
date: "2026-08-09"
|
|
501
|
+
changes: "Gate Economy (operator-approved 2026-08-09, 4 decisions on record): mandatory-qa rule and enforcement text amended — intermediate QG rounds run the diff-mapped test subset with a fail-closed FULL-suite fallback; the FULL suite remains mandatory at the final pre-merge gate (--final-gate). Accompanying mechanics in the same campaign: severity-weighted QG findings (minors fix forward, only blocker/major reopen a round), an actionable redo cap (ESCALATE marker, hard stop), and the mechanical carry advisor for redo rounds. Level unchanged (NON-NEGOTIABLE); the ship gate's scope unchanged."
|
package/config/statusline.sh
CHANGED
|
@@ -118,11 +118,26 @@ fi
|
|
|
118
118
|
COST_FMT=$(printf '$%.2f' "${COST:-0}")
|
|
119
119
|
|
|
120
120
|
# ─── Workflow gate + budget (F2-5, statusline v3) ─────────────────────────
|
|
121
|
-
# Read
|
|
122
|
-
# no Python spawn on this hot path (the statusline
|
|
121
|
+
# Read the per-project .arka/workflow-state.json directly (plain JSON,
|
|
122
|
+
# one jq call) — no Python spawn on this hot path (the statusline
|
|
123
|
+
# re-renders continuously). The path mirrors core/workflow/state.py's
|
|
124
|
+
# resolver: git toplevel, cwd fallback (Gate Economy PR-9, QG round 1).
|
|
123
125
|
# Shows the active workflow, current gate as G<n>/<total>, and violations.
|
|
124
126
|
WF_SEGMENT=""
|
|
125
|
-
|
|
127
|
+
# Payload-cwd convention (QG round 2): the state root follows WORK_DIR —
|
|
128
|
+
# the runtime's own statement of the project — never the process cwd,
|
|
129
|
+
# and the toplevel lookup rides the same 5s cache as the branch query.
|
|
130
|
+
WF_ROOT=""
|
|
131
|
+
if [ -n "$WORK_DIR" ] && [ -d "$WORK_DIR" ]; then
|
|
132
|
+
ROOT_CACHE_FILE="${GIT_CACHE}-root-${CACHE_KEY}"
|
|
133
|
+
if [ -f "$ROOT_CACHE_FILE" ] && [ $(($(date +%s) - $(stat -f%m "$ROOT_CACHE_FILE" 2>/dev/null || stat -c%Y "$ROOT_CACHE_FILE" 2>/dev/null || echo 0))) -lt $CACHE_MAX_AGE ]; then
|
|
134
|
+
WF_ROOT=$(cat "$ROOT_CACHE_FILE" 2>/dev/null)
|
|
135
|
+
else
|
|
136
|
+
WF_ROOT=$(git -C "$WORK_DIR" rev-parse --show-toplevel 2>/dev/null || echo "$WORK_DIR")
|
|
137
|
+
echo "${WF_ROOT}" > "$ROOT_CACHE_FILE" 2>/dev/null
|
|
138
|
+
fi
|
|
139
|
+
fi
|
|
140
|
+
WF_STATE="${WF_ROOT:-$WORK_DIR}/.arka/workflow-state.json"
|
|
126
141
|
if [ -f "$WF_STATE" ]; then
|
|
127
142
|
WF_LINE=$(jq -r '
|
|
128
143
|
(.phases // {}) as $p
|
package/core/evals/record_cli.py
CHANGED
|
@@ -124,7 +124,15 @@ def _drive_redo(verdict: QGVerdict, session_id: str) -> str:
|
|
|
124
124
|
from core.governance import redo_counter
|
|
125
125
|
|
|
126
126
|
if verdict.verdict == "REJECTED":
|
|
127
|
-
|
|
127
|
+
state = redo_counter.record_rejected(session_id)
|
|
128
|
+
message = state.to_message()
|
|
129
|
+
if state.escalate:
|
|
130
|
+
# Gate Economy: the cap is actionable, not decorative — the
|
|
131
|
+
# escalation lands on stderr (and as an ESCALATE marker in
|
|
132
|
+
# the session ledger), never only inside a JSON field the
|
|
133
|
+
# orchestrator may not read.
|
|
134
|
+
print(message, file=sys.stderr)
|
|
135
|
+
return message
|
|
128
136
|
redo_counter.reset(session_id)
|
|
129
137
|
return ""
|
|
130
138
|
|
|
@@ -220,6 +228,17 @@ def _ledger_match(verdict: QGVerdict, session_id: str) -> str:
|
|
|
220
228
|
|
|
221
229
|
|
|
222
230
|
def _record_label(verdict: QGVerdict, args: argparse.Namespace) -> None:
|
|
231
|
+
round_label = args.round_label
|
|
232
|
+
if not round_label and args.session_id:
|
|
233
|
+
# Gate Economy: the round signal was dead (112 None / 95 '' of
|
|
234
|
+
# 234 records) because no caller passed it. Derive it from the
|
|
235
|
+
# redo counter: N rejections so far → this verdict belongs to
|
|
236
|
+
# round N+1.
|
|
237
|
+
from core.governance import redo_counter
|
|
238
|
+
|
|
239
|
+
round_label = str(
|
|
240
|
+
redo_counter.current(args.session_id).count + 1
|
|
241
|
+
)
|
|
223
242
|
record_verdict_label(
|
|
224
243
|
verdict,
|
|
225
244
|
deliverable=args.deliverable,
|
|
@@ -227,7 +246,7 @@ def _record_label(verdict: QGVerdict, args: argparse.Namespace) -> None:
|
|
|
227
246
|
eval_task_id=args.eval_task_id,
|
|
228
247
|
session_id=args.session_id,
|
|
229
248
|
kind=args.kind,
|
|
230
|
-
round_label=
|
|
249
|
+
round_label=round_label,
|
|
231
250
|
head=args.head,
|
|
232
251
|
)
|
|
233
252
|
|
|
@@ -17,6 +17,7 @@ from __future__ import annotations
|
|
|
17
17
|
|
|
18
18
|
import json
|
|
19
19
|
import os
|
|
20
|
+
import re
|
|
20
21
|
from datetime import UTC, datetime
|
|
21
22
|
from pathlib import Path
|
|
22
23
|
from typing import Any
|
|
@@ -43,6 +44,14 @@ def _judge_labels_path() -> Path:
|
|
|
43
44
|
return Path(override) if override else DEFAULT_JUDGE_LABELS_PATH
|
|
44
45
|
|
|
45
46
|
|
|
47
|
+
def _normalize_round(value: str) -> str:
|
|
48
|
+
"""Round labels arrived ad-hoc ('3', 'r5', 'redo-1', 'aggregate-r26')
|
|
49
|
+
and unparseable values killed the round signal (Gate Economy). Keep
|
|
50
|
+
the first integer; anything without one records as ''."""
|
|
51
|
+
match = re.search(r"(\d+)", str(value or ""))
|
|
52
|
+
return match.group(1) if match else ""
|
|
53
|
+
|
|
54
|
+
|
|
46
55
|
def record_verdict_label(
|
|
47
56
|
verdict: QGVerdict,
|
|
48
57
|
deliverable: str = "",
|
|
@@ -69,7 +78,7 @@ def record_verdict_label(
|
|
|
69
78
|
"eval_task_id": str(eval_task_id or ""),
|
|
70
79
|
"session_id": str(session_id or ""),
|
|
71
80
|
"kind": str(kind or ""),
|
|
72
|
-
"round":
|
|
81
|
+
"round": _normalize_round(round_label),
|
|
73
82
|
"head": str(head or ""),
|
|
74
83
|
**verdict.model_dump(),
|
|
75
84
|
}
|
|
@@ -277,13 +277,22 @@ def _matches(a: frozenset[str], b: frozenset[str]) -> bool:
|
|
|
277
277
|
return bool(a) and bool(b) and (a <= b or b <= a)
|
|
278
278
|
|
|
279
279
|
|
|
280
|
-
def _covered(
|
|
280
|
+
def _covered(
|
|
281
|
+
key: frozenset[str],
|
|
282
|
+
aggregate: dict[str, object],
|
|
283
|
+
approved: bool,
|
|
284
|
+
severity: str = "",
|
|
285
|
+
) -> str:
|
|
281
286
|
"""Status of one CONFIRMED reviewer blocker against the aggregate.
|
|
282
287
|
|
|
283
288
|
Returns "ok", "absent", "bare-refute" (REFUTED without a
|
|
284
|
-
substantive reason)
|
|
289
|
+
substantive reason), "carried-approved" (kept un-refuted while
|
|
285
290
|
the aggregate approves — flipping the decision instead of hiding
|
|
286
|
-
the string is laundering too)
|
|
291
|
+
the string is laundering too) or "minor-carried" (Gate Economy:
|
|
292
|
+
the REVIEWER's own severity is "minor", so the finding may ride an
|
|
293
|
+
APPROVED aggregate as a recorded fix-forward; the reviewer's
|
|
294
|
+
severity is authoritative — an aggregate relabeling a major as
|
|
295
|
+
minor still refuses).
|
|
287
296
|
"""
|
|
288
297
|
for entry in aggregate.get("blockers") or []:
|
|
289
298
|
if not isinstance(entry, dict):
|
|
@@ -294,7 +303,9 @@ def _covered(key: frozenset[str], aggregate: dict, approved: bool) -> str:
|
|
|
294
303
|
if len(_norm(entry.get("detail"))) < _MIN_REFUTE_DETAIL:
|
|
295
304
|
return "bare-refute"
|
|
296
305
|
return "ok"
|
|
297
|
-
|
|
306
|
+
if approved:
|
|
307
|
+
return "minor-carried" if severity == "minor" else "carried-approved"
|
|
308
|
+
return "ok"
|
|
298
309
|
return "absent"
|
|
299
310
|
|
|
300
311
|
|
|
@@ -471,9 +482,16 @@ _COVERAGE_REASONS = {
|
|
|
471
482
|
|
|
472
483
|
def _blocker_reasons(
|
|
473
484
|
aggregate: dict, verdicts: list[tuple[str, dict]], approved: bool
|
|
474
|
-
) -> list[str]:
|
|
475
|
-
"""CONFIRMED reviewer blockers must not vanish (or be out-voted).
|
|
485
|
+
) -> tuple[list[str], list[str]]:
|
|
486
|
+
"""CONFIRMED reviewer blockers must not vanish (or be out-voted).
|
|
487
|
+
|
|
488
|
+
Returns ``(reasons, warnings)``. A minor-severity finding carried
|
|
489
|
+
on an APPROVED aggregate is a recorded fix-forward (Gate Economy),
|
|
490
|
+
not a refusal — and the REVIEWER's severity decides, so an
|
|
491
|
+
aggregate can never launder a major by relabeling it minor.
|
|
492
|
+
"""
|
|
476
493
|
reasons: list[str] = []
|
|
494
|
+
warnings: list[str] = []
|
|
477
495
|
for reviewer_id, verdict in verdicts:
|
|
478
496
|
for blocker in verdict.get("blockers") or []:
|
|
479
497
|
if not isinstance(blocker, dict):
|
|
@@ -491,13 +509,24 @@ def _blocker_reasons(
|
|
|
491
509
|
"check; the redo round supersedes this record"
|
|
492
510
|
)
|
|
493
511
|
continue
|
|
494
|
-
status = _covered(
|
|
512
|
+
status = _covered(
|
|
513
|
+
key, aggregate, approved, _norm(blocker.get("severity"))
|
|
514
|
+
)
|
|
515
|
+
if status == "minor-carried":
|
|
516
|
+
warnings.append(
|
|
517
|
+
f"minor finding "
|
|
518
|
+
f"'{_norm(blocker.get('check')) or '(no check field)'}' "
|
|
519
|
+
f"({reviewer_id}) rides the APPROVED aggregate as a "
|
|
520
|
+
"fix-forward — the correction belongs in the "
|
|
521
|
+
"aggregate notes"
|
|
522
|
+
)
|
|
523
|
+
continue
|
|
495
524
|
if status != "ok":
|
|
496
525
|
reasons.append(_COVERAGE_REASONS[status].format(
|
|
497
526
|
check=_norm(blocker.get("check")) or "(no check field)",
|
|
498
527
|
rid=reviewer_id,
|
|
499
528
|
))
|
|
500
|
-
return reasons
|
|
529
|
+
return reasons, warnings
|
|
501
530
|
|
|
502
531
|
|
|
503
532
|
def _own_finding_warnings(
|
|
@@ -621,14 +650,15 @@ def _reasons(
|
|
|
621
650
|
approved = _norm(aggregate.get("verdict")) == "approved"
|
|
622
651
|
issues, notes = _digest_issues(aggregate, verdicts)
|
|
623
652
|
issues += _ended_issues(session_id, artifact_names)
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
+ _blocker_reasons(aggregate, verdicts, approved)
|
|
653
|
+
blocker_reasons, blocker_warnings = _blocker_reasons(
|
|
654
|
+
aggregate, verdicts, approved
|
|
627
655
|
)
|
|
656
|
+
reasons = _verdict_reasons(aggregate, verdicts) + blocker_reasons
|
|
628
657
|
warnings = (
|
|
629
658
|
notes
|
|
630
659
|
+ _check_key_warnings(verdicts)
|
|
631
660
|
+ _own_finding_warnings(aggregate, verdicts)
|
|
661
|
+
+ blocker_warnings
|
|
632
662
|
)
|
|
633
663
|
if approved:
|
|
634
664
|
return issues + reasons, warnings
|