Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions core/surface/includes/codex-host-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ bodies name *actions* — this file is where those actions map to this host.

## Degraded / pending surfaces (ledgered in docs/parity.md)

- **No subagents yet** — Codex plugins cannot ship agents; generated
`.codex/agents/*.toml` scaffolding arrives with M4. Until then, when a
routine says to dispatch a reviewer or author agent, perform that role
inline: load the named agent's charter from the `ca` plugin repo if
available, otherwise apply the routine's stated review obligations yourself.
A review is never skipped because the agent is unavailable.
- **Subagents are host-provided** — current Codex releases can dispatch and
inspect agent threads, but this plugin does not yet vendor custom agent
definitions. Load the named reviewer/author charter, dispatch an available
host agent with that role, and retain the returned thread ID when a workflow
needs an exact per-agent receipt. If an older host exposes no subagents,
perform the role inline; a review is never skipped because dispatch is
unavailable.
- **No statusline** — governance state (stage, overrides-since-checkpoint,
in-flight tasks) appears in the startup briefing instead.
- **No transcript prune** — the prune engine is Claude-transcript-specific;
Expand Down
3 changes: 2 additions & 1 deletion core/surface/skills/tribunal/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ Dispatch the active lenses in the wave partition recorded at Phase 1 (default in
- Each `tribunal-*` agent writes each finding to its own file `findings/<lens>/<finding-id>.json` the moment it is found — one file per finding, never a batched write at the end (write contract: `references/finding-record.md`).
- **Evidence-or-drop.** Every finding cites a concrete `path:line` and the minimal snippet. An absence claim — "no handler", "no teardown", "missing validation" — requires reading the whole unit, never a truncated window.
- Specialists never dispatch further subagents. Update each wave's status in `run.jsonl` as it flushes.
- When a lens's summary returns, record a `lens-completed` event in `run.jsonl` with `surface_seen`/`findings`/`model` taken from the agent's summary, plus `tokens` when the orchestrator can observe that lens's spend.
- When a lens's summary returns, record a `lens-completed` event in `run.jsonl` with `surface_seen`/`findings`/`model` taken from the agent's summary, plus `tokens` when the orchestrator can observe that lens's spend.{{IF:codex}}
- **Codex usage receipt.** If the current host has no subagent dispatch capability and a lens must run inline, record `tokens_status: unavailable` and `tokens_reason: host-usage-unsupported`. If dispatch succeeds but returns no usable thread ID, record `tokens_status: unavailable` and `tokens_reason: host-result-missing`. Otherwise capture the returned agent thread ID on the `lens-launched` event. After that lens completes, resolve the installed plugin root from this routine's own loaded `SKILL.md` path (ordinary shell calls do not inherit a plugin-root environment variable) and run `hooks/tribunal-usage.py observe --thread-id <agent-thread-id>`. The helper reads only metadata and cumulative token-count events from the exact agent session. On `status: observed`, copy its integer `tokens` and component `token_usage`, set `tokens_status: observed`, and copy `source` as `tokens_source` into `lens-completed`. On `status: unavailable`, omit `tokens`, set `tokens_status: unavailable`, and copy `reason` as `tokens_reason`; never turn a parser or capability failure into an unexplained omission. Codex session JSONL is explicitly not a stable extension interface, so this recovery remains best-effort and every changed-format path must degrade to a reason, not block the tribunal.{{END}}

Gate: every active lens has flushed its `findings/<lens>/` files, and each wave's status is recorded.

Expand Down
2 changes: 1 addition & 1 deletion core/surface/skills/tribunal/references/report.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## Structure

- **Header** — run-id, scope, date, models used (from `run.jsonl`), the token estimate from Phase 0 vs. actuals (summed from `lens-completed` `tokens` in `run.jsonl` when present; best-effort, since the orchestrator cannot always observe subagent spend), and a launched/skipped-lens summary with the skip reason per lens.
- **Header** — run-id, scope, date, models used (from `run.jsonl`), the token estimate from Phase 0 vs. actuals (summed from `lens-completed` `tokens` in `run.jsonl` when present; best-effort, since the orchestrator cannot always observe subagent spend){{IF:codex}}, including the `complete|partial|unavailable` status and unavailable reasons{{END}}, and a launched/skipped-lens summary with the skip reason per lens.
- **Findings** — grouped by **calibrated** `final_severity` (critical to low), then by lens/type within each severity. Each entry on one line: `id` · `path:line(s)` · one-line description · remediation shape · triage `decision` · link to `plans/phase-<n>.md`. Only `keep`/`combine` findings appear here.
- **Decisions needed** — a separate section for `decision-required` findings, each as its question + options. These need a decision, not a fix; do not fold them into the severity list.
- **Investigate appendix** — medium/low findings below the confidence gate after calibration (defined in `triage.md`; below-gate critical/high land in Decisions needed instead); `id` + `path:line` + one terse line each. Preserved, not filed.
Expand Down
4 changes: 2 additions & 2 deletions core/surface/skills/tribunal/references/schemas.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ The finding record (what agents emit) is in `finding-record.md`. This file holds
## run/v1 — one state event per line in `run.jsonl`

```json
{"schema":"run/v1","event":"run-started|lens-launched|lens-skipped|lens-completed|wave-flushed|wave-triaged|report-written|issues-filed|telemetry-sent|run-aborted","wave":1,"lens":"<lens>","detail":"<optional>","surface_seen":0,"findings":0,"model":"<model>","tokens":0,"at":"<iso8601>"}
{"schema":"run/v1","event":"run-started|lens-launched|lens-skipped|lens-completed|wave-flushed|wave-triaged|report-written|issues-filed|telemetry-sent|run-aborted","wave":1,"lens":"<lens>","detail":"<optional>","surface_seen":0,"findings":0,"model":"<model>","tokens":0{{IF:codex}},"agent_thread_id":"<dispatch thread id>","tokens_status":"observed|unavailable","tokens_reason":"<required when unavailable>","tokens_source":"codex-session-transcript-best-effort","token_usage":{"input_tokens":0,"cached_input_tokens":0,"cache_write_input_tokens":0,"output_tokens":0,"reasoning_output_tokens":0,"total_tokens":0}{{END}},"at":"<iso8601>"}
```

`run-aborted` records a deliberate abandon (optional `detail` = reason) and marks the run terminal.

A `lens-completed` event carries `surface_seen` (int — the lens's Exposure denominator), `findings` (int — count the lens emitted), and `model` (the model the lens ran on, as dispatched); `model` also appears on `lens-launched`. `tokens` (int, optional) records the lens's observed token spend when the orchestrator can see it; null/omitted when unobserved.
A `lens-completed` event carries `surface_seen` (int — the lens's Exposure denominator), `findings` (int — count the lens emitted), and `model` (the model the lens ran on, as dispatched); `model` also appears on `lens-launched`. `tokens` (int, optional) records the lens's observed token spend when the orchestrator can see it; null/omitted when unobserved.{{IF:codex}} Codex `lens-launched` also records the returned `agent_thread_id`. Every Codex `lens-completed` carries `tokens_status`: `observed` requires integer `tokens`, `tokens_source`, and the component `token_usage`; `unavailable` requires `tokens_reason`. Reasons distinguish host capability (`host-usage-unsupported`), missing host results (`host-result-missing`), missing local artifacts (`transcript-unavailable`), an unsupported changed transcript shape (`transcript-format-unsupported`), bounded-parser limits (`transcript-scan-limit-exceeded` or `transcript-over-limit`), invalid usage (`usage-invalid`), and an invalid dispatch identifier (`invalid-agent-thread-id`). Aggregation maps any unknown or malformed reason to the fixed `reason-invalid` enum before telemetry.{{END}}

The `run-started` event's `detail` carries the chosen wave partition — the lens list per wave (default or repartitioned-for-cause, per `cost-and-models.md`). This is the single record of the partition; nothing else derives or re-derives it.

Expand Down
6 changes: 4 additions & 2 deletions core/surface/skills/tribunal/references/telemetry.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ Reading the corpus is the maintainer's judgment, not skill behavior — and a su
## Payload — `telemetry.json`

```json
{"schema":"telemetry/v1","skill_version":"<x.y.z>","run_id":"<random>","at":"<iso8601>","tag":"<omitted unless --tag>","loc_total":0,"loc_by_language":{"<lang>":0},"files_scanned":0,"primary_language":"<lang>","lenses_run":0,"lenses_skipped":0,"model_orchestrator":"<api-string>","models_by_tier":{"opus":0,"sonnet":0,"haiku":0},"tokens_estimated":0,"tokens_actual":null,"lens_exposure":{"<lens>":{"ran":true,"surface_seen":0,"findings":0,"false_positives":0}},"issues_found":0,"severity_breakdown":{"critical":0,"high":0,"medium":0,"low":0},"decision_breakdown":{"keep":0,"combine":0,"duplicate":0,"false_positive":0,"defer":0,"accept_risk":0,"decision_required":0,"investigate":0},"issues_filed":0,"run_duration_sec":0}
{"schema":"telemetry/v1","skill_version":"<x.y.z>","run_id":"<random>","at":"<iso8601>","tag":"<omitted unless --tag>","loc_total":0,"loc_by_language":{"<lang>":0},"files_scanned":0,"primary_language":"<lang>","lenses_run":0,"lenses_skipped":0,"model_orchestrator":"<api-string>","models_by_tier":{"opus":0,"sonnet":0,"haiku":0},"tokens_estimated":0,"tokens_actual":null{{IF:codex}},"tokens_actual_status":"complete|partial|unavailable","tokens_unavailable_reasons":[]{{END}},"lens_exposure":{"<lens>":{"ran":true,"surface_seen":0,"findings":0,"false_positives":0}},"issues_found":0,"severity_breakdown":{"critical":0,"high":0,"medium":0,"low":0},"decision_breakdown":{"keep":0,"combine":0,"duplicate":0,"false_positive":0,"defer":0,"accept_risk":0,"decision_required":0,"investigate":0},"issues_filed":0,"run_duration_sec":0}
```

`lens_exposure` is the field that makes the corpus interpretable; `surface_seen` and `model_orchestrator`/`models_by_tier` are sourced from `run.jsonl` `lens-launched`/`lens-completed` events, not hand-tallied. `tokens_estimated` vs `tokens_actual` calibrates the cost estimate (a guardrail, not a measure of review quality); `tokens_actual` sums `run.jsonl` `lens-completed` `tokens` when present, and is otherwise optional/best-effort — null when the orchestrator could not observe subagent spend. `issues_found` is the post-triage kept count (the `keep` + `combine` decision groups), distinct from the per-lens raw `findings` counts in `lens_exposure`. `skill_version` is read from `plugin.json`, not hand-set.
`lens_exposure` is the field that makes the corpus interpretable; `surface_seen` and `model_orchestrator`/`models_by_tier` are sourced from `run.jsonl` `lens-launched`/`lens-completed` events, not hand-tallied. `tokens_estimated` vs `tokens_actual` calibrates the cost estimate (a guardrail, not a measure of review quality); `tokens_actual` sums `run.jsonl` `lens-completed` `tokens` when present, and is otherwise optional/best-effort — null when the orchestrator could not observe subagent spend.{{IF:codex}} `tokens_actual_status` is `complete` when every completed lens has numeric usage, `partial` when only some do, and `unavailable` when none do. `tokens_unavailable_reasons` is the sorted, deduplicated enum set from the unobserved lenses, so an unsupported host capability cannot be confused with missing or broken instrumentation and arbitrary log text cannot enter telemetry. Run-level reasons are `no-completed-lenses`, `run-log-unavailable`, `run-log-over-limit`, and `run-log-invalid`; malformed lens reasons become `reason-invalid`.{{END}} `issues_found` is the post-triage kept count (the `keep` + `combine` decision groups), distinct from the per-lens raw `findings` counts in `lens_exposure`. `skill_version` is read from `plugin.json`, not hand-set.

## Send procedure

{{IF:codex}}- Before writing the payload, resolve the installed plugin root from this routine's loaded `SKILL.md` path and run `hooks/tribunal-usage.py aggregate --run-log <run-dir>/run.jsonl`. Copy its three output fields into the payload exactly; do not hand-tally or silently convert `partial` to `complete`.
{{END}}
- Write `telemetry.json`; show it in full.
- State plainly, in one line: these aggregates post publicly to the codeArbiter repo; they carry no code, paths, or finding text, and no repo identity unless you added `--tag`.
- **Default:** print `gh issue create --repo arbiterForge/codeArbiter --label telemetry --title "run-metrics <at>" --body-file telemetry.json`. Stop.
Expand Down
4 changes: 4 additions & 0 deletions plugins/ca-codex/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ All notable changes to the **ca-codex** plugin are recorded here. Format follows
## [0.3.0] — 2026-07-12 — Shared-state concurrency hardening

### Fixed
- Tribunal runs recover cumulative usage from each exact Codex agent thread
when its local session artifact is readable, and otherwise record an explicit
capability or instrumentation reason instead of leaving `tokens_actual`
unexplained.
- Shared statusline ledger records use ownership-safe atomic shards, so
concurrent host activity cannot discard session token/cost state.
- Linked-worktree branch metadata is parsed from Git pointer files instead of
Expand Down
Loading