Skip to content

test(ci): publish raw Claude hook latency reports with runner metadata #379

Description

@gnanirahulnutakki

Parent: #364

Depends on: #378

Problem

The informational Claude hook latency job currently prints only median/p95/p99 and assertion output. It does not preserve the raw sample distribution or a machine-readable report, and functional transport failures are mixed with statistical threshold failures in pytest output.

Without a durable artifact, reviewers cannot independently recompute percentiles, compare runner classes, or distinguish a native read failure from hosted-runner tail jitter.

Primary references, rechecked 2026-07-23:

Scope

In scope:

  • Produce versioned machine-readable latency evidence for subprocess cold, native daemon-client, shell-wrapper telemetry, and in-process daemon hot paths.
  • Record every raw duration sample in deterministic ordinal order.
  • Record the percentile method, configured thresholds, and recomputable median/p95/p99.
  • Record bounded runner metadata: source SHA, event, run ID/attempt, runner OS/architecture, ImageOS, ImageVersion, and exact Python implementation/version.
  • Represent functional failures separately from statistical threshold violations.
  • Preserve partial evidence when a warmup or measured call fails.
  • Write reports atomically under ${{ runner.temp }}.
  • Upload the report directory with if: always() using the repository's digest-pinned actions/upload-artifact.
  • Keep the job informational.

Out of scope:

Acceptance criteria

  • Every benchmark path emits a versioned JSON report or a versioned entry in an artifact manifest.
  • Reports contain the complete raw sample distribution, not only summaries.
  • Reported median/p95/p99 can be exactly recomputed from raw samples using the declared method.
  • Non-finite, negative, missing, duplicated, or out-of-order samples are rejected by deterministic validation.
  • Functional outcomes identify the stage and stable native exit/errno classification without request data.
  • Functional failures and threshold violations are separate fields and separate human-readable pytest messages.
  • A report is preserved when a warmup, native call, or threshold assertion fails.
  • Metadata is populated from an explicit allowlist; no environment dump is recorded.
  • Artifacts are uploaded on success and failure with a bounded retention period.
  • Missing report output is visible rather than silently accepted.
  • The job remains continue-on-error and excluded from the blocking tests aggregate.

Targeted tests

  • Report schema/version and required-field tests.
  • Raw-sample ordering, count, finiteness, and percentile recomputation tests.
  • Functional-error fixture distinct from threshold-violation fixture.
  • Partial-report persistence after a simulated native failure.
  • Metadata allowlist and host-path/token redaction tests.
  • Workflow contract test proving if: always(), digest-pinned upload action, ${{ runner.temp }} output, bounded retention, and no silent missing-file behavior.
  • Focused latency-report tests, Ruff, pre-commit, check-local.sh --quick, and YAML validation.

A base-revision red proof should show that raw-report and artifact-contract tests fail on unmodified dev.

Security and cost

Do not serialize environment variables wholesale. Reports must exclude tokens, mission passports, request bodies, tool arguments, usernames, absolute executable paths, socket paths, and temporary-directory paths.

This child must not add benchmark repetitions or runner jobs. Raw JSON for existing bounded samples should be small. Retention must remain explicit and bounded because artifact storage accrues cost.

Dependencies and overlap

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingciCI coverage & reliabilitytaskTask belonging to an epictestsTest quality & coverageverificationVerification and reproducibility

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions