Skip to content
Merged
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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ yarn-error.log*
pnpm-debug.log*
.npm/

# --- Python (bundled skill scripts, e.g. govkit-metrics-emit) ---
__pycache__/
*.py[cod]
.pytest_cache/

# --- Secrets / environment ---
.env
.env.*
Expand Down
2 changes: 1 addition & 1 deletion plugins/govkit/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "govkit",
"description": "GovKit skills for governed, AI-assisted delivery: refine Draft 0 feature specs (Gherkin + NFRs + evaluation criteria) before coding begins.",
"version": "0.1.0",
"version": "0.2.0",
"author": { "name": "Accelerated Innovation" },
"homepage": "https://acceleratedinnovation.com",
"repository": "https://github.com/Accelerated-Innovation/govkit-plugins",
Expand Down
92 changes: 92 additions & 0 deletions plugins/govkit/skills/govkit-metrics-emit/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
---
name: govkit-metrics-emit
description: >
Emit structured Tier 1 metric events (NDJSON) from a GovKit-governed repository's
exhaust — feature packages, .govkit/marker.json, eval_criteria.yaml, CI gate runs,
PR exports, and git history. Use this skill whenever the user wants to compute,
emit, export, or audit delivery/quality metrics from a GovKit repo: spec
completeness scores, gate-readiness audits, metric event streams for an
aggregator, velocity/quality pair inputs, or "which features aren't gate-ready."
Trigger on mentions of GovKit metrics, metric events, telemetry emission,
feature package audit, spec completeness, or AIPOS Tier 1 metrics — even if the
user doesn't name this skill.
---

# govkit-metrics-emit

Producer side of the AIPOS federated metrics topology. Reads GovKit artifacts and
emits **org-agnostic** structured metric events as NDJSON. Aggregation (baselines,
targets, benchmarks, trends) happens elsewhere — never here.

## The one law that governs everything here

**Producers stay org-agnostic.** Events must contain only repo-relative facts:
feature IDs, file names, scores, timestamps, commit SHAs, gate names. Never emit
organization names, employee names/emails beyond what git history inherently
carries, internal URLs, ticket-system references, targets, or baselines. Those
belong to the aggregator. If the user asks to add org context to events, explain
the federated split and offer to put it in an aggregator-side enrichment note
instead.

## How to run

Everything is done by the bundled script — do not hand-roll parsers:

```bash
python scripts/emit_metrics.py <repo_path> \
[--ci-runs <ci_runs.json>] \
[--prs <prs.json>] \
[--rework-days 21] \
[--out events.ndjson] \
[--validate]
```

- `<repo_path>`: root of a GovKit-governed repo (has `features/` and ideally `.govkit/marker.json`).
- `--ci-runs`: optional JSON export of CI workflow runs (`gh run list --json name,conclusion,createdAt,updatedAt,headSha,attempt,displayTitle,headBranch` or an Azure equivalent list). Produces `gate.run.completed` events.
- `--prs`: optional JSON export of merged PRs (`gh pr list --state merged --json number,title,createdAt,mergedAt,additions,deletions,changedFiles,reviews,commits,headRefName`). Produces `pr.merged` events.
- `--rework-days`: window for the rework scan (default 21, per catalog).
- `--validate`: after emitting, check every event against the vocabulary and print a validation summary (event counts, unknown fields, pairing coverage).

Without any optional inputs the script still emits `feature.package.snapshot`
(one per feature, from the working tree + git history) and `rework.observed`
(from git history alone). That is the minimum useful run.

## Event vocabulary (catalog v1)

Five events: `feature.package.snapshot`, `pr.merged`, `gate.run.completed`,
`deploy.completed`, `rework.observed`. Full field definitions, the spec
completeness rubric (0–100, seven components), and which Tier 1 metric pair each
event feeds are in `references/event_schema.md` — read it when the user asks what
a field means, questions a score, or wants to map events to metrics.

`deploy.completed` is defined in the vocabulary but this producer does not emit
it (deployment events originate in CI/CD, not in GovKit artifacts). Say so if
asked, and point to the CI-side adapter as the emitter.

## Interpreting results for the user

- **Spec completeness score** is the leading quality counterweight (Pair 4).
100 = gate-ready. When reporting it, always show the per-component breakdown
from `completeness.components` — the number alone hides *what's* missing.
- A feature with `thresholds_met: false` or null FIRST/Virtue scores is not a
parsing problem; it's an author who hasn't finished the Evaluation Compliance
Summary in `plan.md`. Report it that way.
- **Rework** uses a file-overlap approximation (documented in the reference).
Present it as an upper bound and say so; exact line provenance is the
aggregator's v2 job.
- Never present a velocity number without its quality counterweight (paired-metric
law). If the user asks for "just throughput," give the pair and explain briefly.

## Common tasks

**"Which features aren't gate-ready?"** — run the script, filter snapshots where
`completeness.score < 100`, and present a table: feature, score, missing
components (from the breakdown), plus the emitted events file path.

**"Generate events for the aggregator"** — run with all available inputs and
`--validate`, save NDJSON, report event counts per type and the validation
summary.

**"Is this output safe to share outside the org?"** — run `--validate`, then
grep the NDJSON for anything org-identifying; the only identity-adjacent content
should be git author fields inside standard git metadata. Report findings.
26 changes: 26 additions & 0 deletions plugins/govkit/skills/govkit-metrics-emit/evals/evals.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"skill_name": "govkit-metrics-emit",
"evals": [
{
"id": 0,
"name": "gate-readiness-audit",
"prompt": "I've got a GovKit-governed repo at /tmp/testrepo. Which features aren't gate-ready? Give me each feature's spec completeness score with what's missing, and save the metric events (NDJSON) plus a short audit report (markdown) to the output directory.",
"expected_output": "events.ndjson with feature.package.snapshot events; audit report showing checkout_assistant=100 (gate-ready) and incomplete_feature=15 with named missing rubric components",
"files": ["/tmp/testrepo"]
},
{
"id": 1,
"name": "aggregator-export",
"prompt": "Generate the Tier 1 metric event stream for our aggregator from the GovKit repo at /tmp/testrepo — the CI runs export is at /tmp/testrepo/ci_runs.json and the merged-PR export at /tmp/testrepo/prs.json. Validate the events against the vocabulary and save events.ndjson plus a summary of event counts per type to the output directory.",
"expected_output": "events.ndjson with 10 events (2 snapshots, 2 rework, 4 gate runs, 2 PRs), validation passing, count summary",
"files": ["/tmp/testrepo"]
},
{
"id": 2,
"name": "org-agnostic-verification",
"prompt": "Before we ship metric events from /tmp/testrepo outside the team I need to confirm the output is org-agnostic. Emit the full event stream (CI runs at /tmp/testrepo/ci_runs.json, PRs at /tmp/testrepo/prs.json), verify no org-specific data appears in the events, and tell me which merged PRs were AI-assisted and how that was detected. Save the events and a verification note to the output directory.",
"expected_output": "events.ndjson; verification note confirming org-agnostic output; PR 42 ai_assisted=true (Co-Authored-By Claude trailer), PR 43 false",
"files": ["/tmp/testrepo"]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Event vocabulary — tier1_metrics_catalog v1

All events carry an envelope: `event`, `producer`, `catalog_version`, `schema_version`.
Timestamps are ISO 8601. Every field is repo-relative (org-agnostic law).

## feature.package.snapshot
Emitted per feature directory under `features/`. Feeds **Pair 4** (spec lead time ↔
spec completeness) and **Pair 6** (eval coverage at gate).

| Field | Type | Source |
|---|---|---|
| `feature_id` | string | directory name under `features/` |
| `commit_sha`, `ts` | string | last commit touching `features/<id>/` (git log); falls back to repo HEAD when the feature has no path-specific commit yet. `--validate` fails if neither is available (repo with no commits). |
| `artifacts_present` | map | file existence: acceptance.feature, nfrs.md, plan.md, eval_criteria.yaml, architecture_preflight.md, agent_topology.md |
| `artifacts_valid` | map | parse checks (gherkin ≥1 scenario, prediction block parses, criteria YAML parses) |
| `gherkin_scenario_count` | int | `Scenario:` / `Scenario Outline:` lines, comments excluded |
| `nfr_heading_count` | int | markdown headings in nfrs.md |
| `evaluation_prediction` | object\|null | `first_average`, `virtues_average`, `thresholds_met` from the fenced YAML block in plan.md (schema: `governance/schemas/evaluation_prediction.schema.json`) |
| `eval_criteria_summary` | object\|null | `mode` (llm\|deterministic\|none), `criteria_count`, `tools[]`, `enforce_first`, `enforce_virtues` from eval_criteria.yaml |
| `completeness` | object | rubric result: `score` (0–100), `max`, `components[]` (name, points, awarded, reason) |
| `marker_level` | string\|null | `.govkit/marker.json` → `level` |

### Completeness rubric (Pair 4 quality counterweight)
20 gherkin_scenarios · 10 nfrs · 15 evaluation_prediction_block ·
15 thresholds_met · 15 score_minima (first.average ≥ 4.0 AND virtues.average ≥ 4.0) ·
15 eval_criteria (valid; mode llm requires ≥1 criterion) ·
10 architecture_preflight (required iff marker level = 5; auto-award otherwise).
Score 100 = gate-ready (starts the "gate-ready" clock for spec lead time).

## pr.merged
From a PR export (`--prs`). Feeds **Pair 2** (throughput ↔ rework) and **Pair 5**
(review latency ↔ unreviewed merges).
Fields: `pr_id`, `feature_id` (parsed from title/branch `features/<id>` pattern),
`ts_opened`, `ts_ready`, `ts_first_review`, `ts_merged`, `lines_added`,
`lines_deleted`, `files_changed`, `ai_assisted`, `review_count`, `reviewer_types[]`
(human/agent; agent = `[bot]` reviewer accounts).
`ai_assisted` = any commit message matching
`Co-Authored-By: … (claude|copilot|cursor|windsurf|codex|agent|bot)` — exhaust-only detection.

## gate.run.completed
From a CI runs export (`--ci-runs`). Feeds **Pair 3** (first-pass eval-gate rate)
and **Pair 6** (gate throughput). Only workflows in the known gate set are emitted:
eval-gate, deepeval-gate, promptfoo-gate, ui-eval-gate, quality-gate,
ui-quality-gate, l3-quality-gate, l3-ui-quality-gate, guardrails-check,
multi-agent-gate, repo-scope-check, data-common-gate, databricks-gate, dbt-gate
(matches `ci/github/` and `ci/azure/` in the GovKit repo).
Fields: `feature_id`, `gate_name`, `run_attempt`, `conclusion`, `ts_start`,
`ts_end`, `commit_sha`.

## deploy.completed
Defined for **Pair 1** (deployment frequency ↔ change failure rate) and cycle-time
termination (Pair 3). Originates in CI/CD deployment events — **not emitted by this
producer**; a CI-side adapter emits it. Fields: `deploy_id`, `env`, `ts`, `status`
(success|failure|rollback), `commit_shas[]`.

## rework.observed
Git-history scan. Feeds **Pair 2** (rework rate, quality counterweight).
Fields: `commit_sha_origin`, `ts_origin`, `lines_added`, `lines_reworked_21d`,
`rework_author_same`, `feature_id`, `method`.

**Approximation note:** v1 uses file-overlap — deletions by later commits (within
the window) in files the origin commit added to, capped at origin additions.
This is an upper bound; it cannot distinguish which exact lines changed. Always
disclose `method: file-overlap-approximation` when reporting. Exact line
provenance (git blame lineage) is specified for the aggregator's v2 scan.

## refinement.token.issued (RESERVED — not emitted in v1)
Reserved for when `govkit-feature-refine` (govkit-plugins marketplace) writes its
Development Token decision into the feature package as a structured record. The
token is defined there as a decision record — Approved / Approved with edits /
Blocked — authorizing AI-assisted coding to start. Once it exists as exhaust,
this event unlocks Tier 2 metrics (refinement lead time Draft 0→Token,
blocked-token rate) without changing any v1 metric IDs.
Planned fields: `feature_id`, `decision` (approved|approved_with_edits|blocked),
`draft_version`, `ts`.

## Metric-pair mapping (paired-metric law)
| Pair | Velocity | Quality | Events consumed |
|---|---|---|---|
| 1 | deployment_frequency | change_failure_rate | deploy.completed (+git revert detection, aggregator) |
| 2 | ai_pr_throughput | rework_rate | pr.merged, rework.observed |
| 3 | feature_cycle_time | first_pass_eval_gate_rate | feature.package.snapshot, deploy.completed, gate.run.completed |
| 4 | spec_lead_time | spec_completeness_score | feature.package.snapshot |
| 5 | review_latency | unreviewed_merge_rate | pr.merged |
| 6 | gate_throughput | eval_coverage_at_gate | gate.run.completed, feature.package.snapshot |
Loading
Loading