Skip to content
Back to skills

User Skip Telemetry

ASecurity

Counts Q&A skip events from the abort-safe-handler and qa-loop-ui outputs. Shows an optional skip-reason dropdown when a user-initiated skip occurred. Produces a structured skip_metrics_record suitable for PostHog ingestion. Used in Stage 4 of the /gaai:bootstrap pipeline after abort-safe-handler returns.

  • 162 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 23, 2026
ai-agentsgoapi

Works with

  • claude code
  • cursor
  • api

Security analysis

A100/100

Scanned September 23, 2026

npx -y skills add digipulse-engineering/GAAI-framework --skill user-skip-telemetry --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of User Skip Telemetry?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for User Skip Telemetry
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/digipulse-engineering-user-skip-telemetry/badge)](https://www.skillsdirectory.com/skills/digipulse-engineering-user-skip-telemetry)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: user-skip-telemetry
description: Counts Q&A skip events from the abort-safe-handler and qa-loop-ui outputs. Shows an optional skip-reason dropdown when a user-initiated skip occurred. Produces a structured skip_metrics_record suitable for PostHog ingestion. Used in Stage 4 of the /gaai:bootstrap pipeline after abort-safe-handler returns.
license: ELv2
compatibility: Works in any interactive AI coding agent context (Claude Code, Cursor) where inline Q&A is supported
metadata:
  author: gaai-framework
  version: "1.0"
  category: cross
  track: cross-cutting
  id: SKILL-USER-SKIP-TELEMETRY-001
  updated_at: 2026-04-29
  status: stable
inputs:
  - abort_safe_result     # output of abort-safe-handler — contains skip_telemetry
  - qa_session_result     # output of qa-loop-ui — optional; null when user skipped at entry gate
  - workspace_id          # string — workspace scope
  - workspace_size_class  # optional string: "solo" | "small" | "medium" | null
outputs:
  - skip_metrics_record   # structured telemetry record for PostHog ingestion
---

# User-Skip Telemetry

## Purpose / When to Activate

Activate:
- Immediately after `abort-safe-handler` returns — the orchestrator invokes this skill to capture skip event counts before proceeding to synthesis
- Works for all return paths: pre-loop skip, mid-loop skip-all, per-question skips, and no-skip sessions
- One invocation per bootstrap session

When `abort_safe_result.abort_reason == "no_questions"` (no questions were generated), return a
`{skip_occurred: false, skip_type: "no_questions"}` record with zero counts. No reason dropdown is
shown (no user-facing skip choice was presented).

**What this skill does NOT do:**
- Persist or accumulate counts across sessions (orchestrator responsibility — forward to PostHog)
- Display Q&A questions (that is `qa-loop-ui`)
- Wrap or gate the Q&A loop (that is `abort-safe-handler`)
- Enrich or analyse skip patterns across workspaces (V1.5+ analytics)

---

## Input Schema

```yaml
abort_safe_result:
  skipped: bool
  qa_answers: array | null
  skip_telemetry:                        # null only on no-questions shortcut
    skip_reason: string | null           # "user_skip_entire" | "user_abort" | null
    skipped_at: string | null            # ISO 8601 UTC
    workspace_id: string
    response_time_ms: number | null
  abort_reason: string | null            # "user_abort" | "no_questions" | null

qa_session_result:                       # null when skipped at entry gate
  answers:
    - question_id: string
      answer_text: string
      skipped: bool
      response_time_ms: number
  partial: bool
  skipped_all: bool
  abort_reason: string | null
  qa_duration_ms: number

workspace_id: string
workspace_size_class: string | null      # "solo" | "small" | "medium" | null
```

---

## Process

### Step 0 — No-questions shortcut

```
if abort_safe_result.abort_reason == "no_questions":
  log: "[user-skip-telemetry] no questions were generated — Stage 4 was a no-op"
  return {
    skip_occurred: false,
    skip_type: "no_questions",
    skip_reason: null,
    per_question_skips: [],
    questions_presented: 0,
    questions_skipped: 0,
    questions_answered: 0,
    workspace_id: workspace_id,
    workspace_size_class: workspace_size_class ?? null,
    recorded_at: iso_timestamp()
  }
```

### Step 1 — Classify skip type

Determine `skip_type` using the following priority order:

```
if abort_safe_result.skip_telemetry?.skip_reason == "user_abort":
  skip_type = "user_abort"             # involuntary — Ctrl+C / context terminated

elif abort_safe_result.skip_telemetry?.skip_reason == "user_skip_entire":
  skip_type = "pre_loop"               # user chose [N] at the Stage 4 entry gate

elif qa_session_result != null AND qa_session_result.skipped_all == true:
  skip_type = "mid_loop_skip_all"      # user typed "skip all" during the Q&A loop

elif qa_session_result != null AND
     qa_session_result.answers.some(a => a.skipped == true):
  skip_type = "per_question_only"      # some questions skipped individually, no skip-all

else:
  skip_type = "none"                   # user answered all questions
```

Log classification:
```
log: "[user-skip-telemetry] skip_type={skip_type}  workspace_id={workspace_id}"
```

### Step 2 — Per-question skip metrics (AC1)

Compute per-question metrics from `qa_session_result.answers` if available. **Record position only —
no question content or question_id text must appear in the metrics record** (privacy-respecting aggregate).

```
per_question_skips = []
questions_presented = 0
questions_skipped = 0
questions_answered = 0

if qa_session_result != null AND qa_session_result.answers != null:
  for i, answer in enumerate(qa_session_result.answers):
    questions_presented++
    if answer.skipped == true:
      questions_skipped++
      per_question_skips.push({position: i + 1, skipped: true})
    else:
      questions_answered++
      per_question_skips.push({position: i + 1, skipped: false})
```

`per_question_skips` contains only position integers and boolean flags — no text, no topic names,
no question IDs that could be reverse-mapped to question content.

### Step 3 — Optional reason capture (AC2)

Show the reason dropdown ONLY when skip_type is `"pre_loop"` or `"mid_loop_skip_all"` (user made
a deliberate skip choice). Do NOT show for `"user_abort"` (involuntary) or `"per_question_only"`
(individual question skips, covered by per_question_skips already) or `"none"`.

```
skip_reason = null

if skip_type == "pre_loop" OR skip_type == "mid_loop_skip_all":
  display:
    "(Optional) Why did you skip the Q&A? Press Enter to skip this.
       1. not relevant
       2. too vague
       3. time-pressed
       4. other"

  raw_input = trim(await_user_input())
  normalized = lowercase(raw_input)

  skip_reason = match normalized:
    "1" | "not relevant"  → "not_relevant"
    "2" | "too vague"     → "too_vague"
    "3" | "time-pressed"  → "time_pressed"
    "4" | "other"         → "other"
    ""                    → null    # user skipped the reason prompt
    _                     → null    # unrecognised input treated as no reason
```

If `skip_type` is NOT `"pre_loop"` or `"mid_loop_skip_all"`, set `skip_reason = null` and do NOT
prompt the user.

### Step 4 — Produce skip_metrics_record (AC3)

```
recorded_at = iso_timestamp()

skip_metrics_record = {
  event: "bootstrap.qa_skip",
  skip_occurred: (skip_type != "none" AND skip_type != "no_questions"),
  skip_type: skip_type,
  skip_reason: skip_reason,
  per_question_skips: per_question_skips,
  questions_presented: questions_presented,
  questions_skipped: questions_skipped,
  questions_answered: questions_answered,
  workspace_id: workspace_id,
  workspace_size_class: workspace_size_class ?? null,
  recorded_at: recorded_at
}

log: "[user-skip-telemetry] metrics record produced:
  skip_type={skip_type}  skip_reason={skip_reason ?? "none"}
  questions={questions_presented}  skipped={questions_skipped}  answered={questions_answered}"

return skip_metrics_record
```

---

## Orchestrator responsibility after this skill (AC3)

The orchestrator MUST forward `skip_metrics_record` to PostHog as a fire-and-forget event:

```
gaai_admin(action: "log_posthog",
           event: skip_metrics_record.event,
           props: skip_metrics_record)
```

This call is non-blocking. If PostHog is unreachable or `POSTHOG_API_KEY` is absent, the event is
silently dropped — never block bootstrap continuation on telemetry delivery.

The orchestrator then proceeds to `bootstrap-llm-synthesis` regardless of telemetry outcome.

---

## Output Schema

```yaml
skip_metrics_record:
  event: "bootstrap.qa_skip"           # PostHog event name
  skip_occurred: bool                  # false only for "none" and "no_questions" skip_types
  skip_type:
    "pre_loop"         # user chose [N] at the Stage 4 entry gate
    | "mid_loop_skip_all"   # user typed "skip all" during Q&A loop
    | "per_question_only"   # some individual questions skipped, no skip-all
    | "none"                # user answered all questions
    | "user_abort"          # involuntary — Ctrl+C / process signal
    | "no_questions"        # no questions were generated; Stage 4 was skipped entirely
  skip_reason: "not_relevant" | "too_vague" | "time_pressed" | "other" | null
  per_question_skips:
    - position: number    # 1-based question index — NO question content
      skipped: bool
  questions_presented: number
  questions_skipped: number
  questions_answered: number
  workspace_id: string
  workspace_size_class: "solo" | "small" | "medium" | null
  recorded_at: string     # ISO 8601 UTC

# Example — pre-loop skip with reason:
skip_metrics_record:
  event: "bootstrap.qa_skip"
  skip_occurred: true
  skip_type: "pre_loop"
  skip_reason: "time_pressed"
  per_question_skips: []
  questions_presented: 0
  questions_skipped: 0
  questions_answered: 0
  workspace_id: "ws_abc123"
  workspace_size_class: "solo"
  recorded_at: "2026-04-29T10:32:15Z"

# Example — user answered 3 of 4 questions, skipped 1:
skip_metrics_record:
  event: "bootstrap.qa_skip"
  skip_occurred: true
  skip_type: "per_question_only"
  skip_reason: null             # no dropdown shown for per-question-only skips
  per_question_skips:
    - {position: 1, skipped: false}
    - {position: 2, skipped: true}
    - {position: 3, skipped: false}
    - {position: 4, skipped: false}
  questions_presented: 4
  questions_skipped: 1
  questions_answered: 3
  workspace_id: "ws_abc123"
  workspace_size_class: null
  recorded_at: "2026-04-29T10:40:22Z"

# Example — user answered all 3 questions (no skip):
skip_metrics_record:
  event: "bootstrap.qa_skip"
  skip_occurred: false
  skip_type: "none"
  skip_reason: null
  per_question_skips:
    - {position: 1, skipped: false}
    - {position: 2, skipped: false}
    - {position: 3, skipped: false}
  questions_presented: 3
  questions_skipped: 0
  questions_answered: 3
  workspace_id: "ws_abc123"
  workspace_size_class: "small"
  recorded_at: "2026-04-29T10:45:00Z"
```

---

## Quality Checks

- `skip_occurred: true` implies `skip_type` is NOT `"none"` and NOT `"no_questions"`
- `skip_type: "pre_loop"` implies `per_question_skips == []` and `questions_presented == 0`
- `skip_type: "no_questions"` implies all counts are 0 and `per_question_skips == []`
- `skip_reason` is non-null ONLY for `skip_type` in `["pre_loop", "mid_loop_skip_all"]`
- `questions_skipped + questions_answered == questions_presented`
- `per_question_skips.length == questions_presented`
- `per_question_skips[i].position` is 1-based and sequential (1, 2, 3, …)
- No `question_id`, `question_text`, `topic`, or `answer_text` fields in `per_question_skips`
- `recorded_at` is always a non-null ISO 8601 UTC string

---

## Non-Goals

This skill MUST NOT:
- Aggregate or persist skip counts across multiple bootstrap sessions (orchestrator / PostHog responsibility)
- Compare skip rates across workspaces or flag anomalies (V1.5+ analytics)
- Block bootstrap continuation when PostHog delivery fails (fire-and-forget, non-blocking)
- Capture answer content or question text in the metrics record (privacy invariant)
- Prompt for skip reason on `"user_abort"` or `"per_question_only"` skip types
- Invoke `abort-safe-handler` or `qa-loop-ui` (this skill is post-loop only)
- Make governance decisions based on skip patterns (observe, not decide — per the active bootstrap-telemetry DEC, if any)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.