output-coverage-assertion
BEFORE claiming "full coverage" / "covers all N minutes" / "X highlights across the whole recording", assert the min/max timeSec of the real output against…
Skill by signalo-rust
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/signalo-rust-output-coverage-assertion-a51a61
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Use cases: testing
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/output-coverage-assertion
What's inside
- Skill name
output-coverage-assertion- Description
- BEFORE claiming "full coverage" / "covers all N minutes" / "X highlights across the whole recording", assert the min/max timeSec of the real output against the source durationSec. Never use bullet count as proof of coverage. Applies to any time-indexed output — highlights, milestones, attention moments, transcript segments, minute summaries, briefs.
- License
- MIT
- Instructions
- 228 lines in SKILL.md · view on GitHub
Files (1)
- SKILL.md
SKILL.md (first lines)
# Output Coverage Assertion — verify coverage before saying "done"
## Why this skill exists
**The incident:** a report went out as "16 highlights, full coverage of a 49:45 recording". It was believed and the work was closed. 24 hours later the recording was opened — the last highlight was at 31:29, exactly the midpoint. A `BRIEF_MAX_CHARS` cap had truncated the LLM prompt; the last 18 minutes never reached the model. The follow-up fix plus a retroactive re-run across every recording in the regression window cost a whole extra cycle.
**Root cause:** trusting array length (`items.length`) as a proxy for coverage. This is categorically wrong: 16 items in the first half is still 16 items, and `.length === 16` is not lying. **The lie is calling it "covers the full 49:45".**
This skill is a mandatory assertion before any coverage claim. Without checking `max(timeSec) / durationSec` you may not write "full coverage" into a status message, a task file, or a changelog.
Bug class: silent truncation in an LLM pipeline (token limit, char limit, chunk-cut) that does not throw, but returns a schema-valid yet timeline-incomplete output.
---
## When it applies (triggers)
**MANDATORY on any time-indexed output:**
- `highlights[]` (field `timeSec`)
- `milestones[]` (fields `startSec`/`endSec`)
- `attentionMoments[]` (field `timestampSec`)
- `transcript.segments[]` (fields `start`/`end`)
- minute-summary arrays (field `minuteIndex` or `startSec`)
- `brief` (as an object with `keyMoments[]` or `chapters[]`)
- any LLM-generated structured output that has a time field and a known source duration
- any output you are about to describe as "X% coverage" / "covers full N minutes" / "the whole recording is analyzed"
**MANDATORY on text outputs:**
- `transcript.fullText` — check `length / durationSec` against a historical baseline (e.g. ~8-15 chars/sec for continuous speech). If the ratio drops below 4 — truncation.
- `brief.summary` — check that the summary mentions events from the last quarter of the recording (at least one timestamp > 0.75 * durationSec).
**Does NOT apply:**
- Output with no time axis (theme classification, language detection, single-number metrics)
- A single-event output (at 1:30 the user said X) — coverage is not measurable
- The stakeholder explicitly said "this is the first half / partial processing / preview"
---
## Protocol
### Step 1 — before generation, capture the source durationSec
Before the LLM / pipeline call:
```ts
const durationSec = recording.durationSec; // or audioFile.durationSec, or video.metadata.duration
console.log(`[coverage:input] ${recording.id}: source duration ${durationSec}s (${Math.round(durationSec/60)}min)`);
```
If `durationSec === null` / undefined — **that is already a red flag**. Without a known duration you cannot assert coverage; log `console.warn` and continue with an explicit "coverage unverifiable".
### Step 2 — after output returns, compute min/max timeSec
```ts
const min = Math.min(...items.map(x => x.timeSec));
const max = Math.max(...items.map(x => x.timeSec));
```
For multi-field structures (milestones with startSec/endSec) — take `min` of `startSec` and `max` of `endSec`.
### Step 3 — log coverage_ratio
```ts
const ratio = (max - min) / durationSec;
console.log(`[coverage] ${label}: ${items.length} items, range ${Math.round(min)}-${Math.round(max)}s / ${Math.round(durationSec)}s (${(ratio*100).toFixed(0)}%)`);
```
This log should land in a structured log / breadcrumb, so that during an incident you can grep for `[coverage]` and find every recording with a suspicious ratio.
### Step 4 — emit a warning on suspicious coverage
Condition:
- `coverage_ratio < 0.8` (output covered less than 80% of the timeline)
- AND `durationSec > 10*60` (recording longer than 10 minutes — on short recordings the LLM may legitimately give 1 highlight)
→ `console.warn` with full context (recordingId, durationSec, min, max, items.length, label). This goes to an alert.
Additional heuristic for very short outputs:
- `items.length < Math.ceil(durationSec / 600)` (fewer than 1 item per 10 minutes) → also warn.
### Step 5 — before reporting to a stakeholder, quote the real range
**Never:**
> "16 highlights, full coverage of 49:45"
**Always:**
> "16 highlights, range 00:14 – 31:29 (63% of 49:45). Suspicious — the last 18 minutes are not covered. Investigating."
If ratio > 0.95 — you may say "coverage is complete". If 0.8-0.95 — "coverage is nearly complete, last highlight at M:SS of N:NN". If <0.8 — do NOT claim done; go find the cause.
The numbers come from the DB or a log — not a bullet count and not a "subjective sense that it's fine".
---
## Anti-patterns (do NOT do this)
- ❌ **Reporting "N highlights" as evidence of coverage.** `items.length` says nothing about distribution across the timeline. 16 highlights can all sit in the first minute.
- ❌ **Trusting an LLM `responseSchema` array length without a timeSec range check.** Models honor `minItems`/`maxItems` but do not guarantee time distribution. They fill items from whatever part of the prompt they reached.
- ❌ **Assuming truncation caps won't silently trigger.** `BRIEF_MAX_CHARS`, `MAX_PROMPT_TOKENS`, `MAX_CHUNK_SIZE`, batch slicing — all these constants exist and fire silently. If a cap exists, assume it fired; prove otherwise.
- ❌ **Asserting coverage based on `status=DONE` alone.** `status=DONE` means "the pipeline ran without an exception", not "the output is correct". Different things.
- ❌ **"Smoke test on a 5-minute recording" → claim ready for prod.** Truncation caps trigger on long recordings (30+ min); a short smoke test won't reproduce them. Test on a >30 min recording before "done".
- ❌ **Grep "coverage" in logs, find nothing → say "all good".** If the skill isn't integrated and the `[coverage]` log is absent, that means the assertion was never written — not "verified ok".
---
## Examples
### Example A — Brief generation via chunked LLM calls
**Before (broken):**
```ts
const transcriptText = transcript.fullText.slice(0, BRIEF_MAX_CHARS); // 200_000
const result = await llm.generateContent({
contents: [{ role: 'user', parts: [{ text: brief_prompt(transcriptText) }] }],
generationConfig: { responseSchema: HIGHLIGHTS_SCHEMA, responseMimeType: 'application/json' }
});
const highlights = JSON.parse(result.response.text()).highlights;
// silently: on a 49-min recording fullText.length = 380_000, the slice cut at 31:29
console.log(`Generated ${highlights.length} highlights`); // 16
return { highlights }; // stakeholder sees 16, you say "full coverage"From signalo-rust/agent-guardrails, MIT.
More from signalo-rust/agent-guardrails
- 0.497score
anti-bug-prevention
signalo-rust
Production deploy safety pipeline.
SkillCFreshness: C★ 1Claude Code +9 - 0.497score
api-contract-audit
signalo-rust
Inventory every API endpoint that surfaces a field to clients BEFORE dropping, renaming, or semantically changing it.
SkillCFreshness: C★ 1Claude Code +9 - 0.497score
brainstorm-first
signalo-rust
Before starting any non-trivial task (>0.5 day, new feature, new UI page, new integration, refactor spanning >5 files), it is mandatory to ask the requester…
SkillCFreshness: C★ 1Claude Code +9 - 0.497score
content-hash-cache-pattern
signalo-rust
Cache expensive file processing results via SHA-256 content hashes — path-independent, auto-invalidating, service layer separation.
SkillCFreshness: C★ 1Claude Code +9 - 0.497score
docker-push-verify
signalo-rust
After `docker buildx build --push`, always verify the image actually landed on the upstream registry.
SkillCFreshness: C★ 1Claude Code +9 - 0.497score
eval-harness
signalo-rust
Formal eval-driven development (EDD) framework.
SkillCFreshness: C★ 1Claude Code +9 - 0.497score
reviewer-gate
signalo-rust
Run the machine review gate over the current repo — map changed files to the specialist reviewers they require, scan the diff for hardcoded secrets and…
SkillCFreshness: C★ 1Claude Code +9 - 0.494score
money-math-invariants
signalo-rust
Lint checklist for money fields in a billing subsystem.
SkillCFreshness: C★ 1Claude Code +9 - 0.494score
clean-build-verification
signalo-rust
Before committing changes that touch workspace deps, DB schema, or >500 LOC — verify a real clean build.
SkillCFreshness: C★ 1Claude Code +9 - 0.494score
regex-vs-llm-structured-text
signalo-rust
Decision framework for parsing structured text — regex covers 95-98% cheaply and deterministically, and an LLM handles only the low-confidence edge cases.
SkillCFreshness: C★ 1Claude Code +9 - 0.494score
verification-loop
signalo-rust
Run a practical quality gate before closing work — typecheck, sync/consistency check, and task-specific validation.
SkillCFreshness: C★ 1Claude Code +9 - 0.494score
search-first
signalo-rust
Research-before-coding workflow.
SkillCFreshness: C★ 1Claude Code +9
Signals
- Stars
- 1
- Forks
- 0
- Open issues
- 0
- Last commit (this folder)
- Jul 11, 2026 (3 months ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- Repository
- github.com/signalo-rust/agent-guardrails
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
Same skill elsewhere
Copies of this SKILL.md published by others; search shows only one of them.
More from signalo-rust
- 0.497score
anti-bug-prevention
signalo-rust
Production deploy safety pipeline.
SkillCFreshness: C★ 1Claude Code +9 - 0.497score
api-contract-audit
signalo-rust
Inventory every API endpoint that surfaces a field to clients BEFORE dropping, renaming, or semantically changing it.
SkillCFreshness: C★ 1Claude Code +9 - 0.497score
brainstorm-first
signalo-rust
Before starting any non-trivial task (>0.5 day, new feature, new UI page, new integration, refactor spanning >5 files), it is mandatory to ask the requester…
SkillCFreshness: C★ 1Claude Code +9 - 0.497score
content-hash-cache-pattern
signalo-rust
Cache expensive file processing results via SHA-256 content hashes — path-independent, auto-invalidating, service layer separation.
SkillCFreshness: C★ 1Claude Code +9 - 0.497score
docker-push-verify
signalo-rust
After `docker buildx build --push`, always verify the image actually landed on the upstream registry.
SkillCFreshness: C★ 1Claude Code +9 - 0.497score
eval-harness
signalo-rust
Formal eval-driven development (EDD) framework.
SkillCFreshness: C★ 1Claude Code +9
Cite this page
output-coverage-assertion skill. Agent Mart. https://agentmart.dev/skills/signalo-rust-output-coverage-assertion-a51a61 (last updated 2026-10-24)