Skip to content
Back to skills

Source 83a15410210456a9bcf121c5

ASecurity

YAML-driven acceptance contract for batch and streaming pipelines that need convergence verification, not just "no exceptions". Declares PASS only after K consecutive zero-result windows (consecutive-zero-window convergence). Use for streaming jobs, slowly-draining backfills, or any pipeline whose success is "the pending queue is empty".

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 7, 2026
ai-agentspythongobashsql

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned November 7, 2026

npx -y skills add gutsofpratik/OpenClaude-Skills --skill source-83a15410210456a9bcf121c5 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Source 83a15410210456a9bcf121c5?

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

Security grade badge for Source 83a15410210456a9bcf121c5
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/gutsofpratik-source-83a15410210456a9bcf121c5/badge)](https://www.skillsdirectory.com/skills/gutsofpratik-source-83a15410210456a9bcf121c5)

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: aidp-acceptance-contract
description: YAML-driven acceptance contract for batch and streaming pipelines that need convergence verification, not just "no exceptions". Declares PASS only after K consecutive zero-result windows (consecutive-zero-window convergence). Use for streaming jobs, slowly-draining backfills, or any pipeline whose success is "the pending queue is empty".
---

# `aidp-acceptance-contract` — convergence verification for batch/streaming jobs

A "no exception" pass is not enough for streaming or backfill pipelines. They might still be processing rows that haven't drained yet. This skill wires up a YAML-driven contract: PASS only after K consecutive empty-pending windows.

## When to use

- Source pipeline is **structured streaming** (the migrator's Pass-2 returns when the trigger completes, but the stream itself hasn't necessarily drained).
- Source pipeline is a **slowly-draining batch backfill** (each task processes a partition, the workflow PASSes when the partition is processed but a separate retry queue holds the failed rows).
- User asks "wait for it to settle", "convergence", "acceptance test on convergence".

**Not needed** for plain ETL where success = "the saveAsTable finished".

## The pattern

```
1. Migrator runs Pass-2 to completion.
2. Acceptance contract starts probing periodically (every `sleep_between_s` seconds).
3. Each probe runs `pending_count_sql` and checks `pending = 0`.
4. After `zero_window` consecutive zero-probes → declare PASS.
5. If we hit `max_attempts` without convergence → declare ACCEPTANCE_CONTRACT_VIOLATED.
   Overall migration result is demoted to FAIL.
```

## YAML contract format

Save at `reports/<MyJob>_acceptance.yaml`:

```yaml
# Acceptance contract for <task_key>
task_key: "<task_key>"
description: "Wait until the retry queue drains"
pending_count_sql: "SELECT COUNT(*) AS pending FROM <sandbox_schema>.<retry_queue_table> WHERE status = 'PENDING'"
zero_window: 3                # K consecutive zero windows required for PASS
sleep_between_s: 30           # seconds between probes
max_attempts: 60              # ceiling; 60 × 30s = 30-min hard cap

# Optional: override the cluster (default = use job_migrate's cluster)
cluster_id: null

# Optional: notify-on-violation hook (called once if max_attempts hit before convergence)
on_violation_log_path: "/tmp/<MyJob>_acceptance.log"
```

## Wire into a migration

The contract is loaded by `job_migrate.py` automatically if the YAML exists alongside the manifest:

```bash
# Convention: <MyJob>_manifest.json + <MyJob>_acceptance.yaml side by side
ls reports/
# → reports/<MyJob>_manifest.json
# → reports/<MyJob>_acceptance.yaml

python3 ${CLAUDE_PLUGIN_ROOT}/engine/scripts/job_migrate.py \
  --manifest reports/<MyJob>_manifest.json \
  --acceptance-contract reports/<MyJob>_acceptance.yaml \
  # + the rest of the args
```

If `--acceptance-contract` is omitted, the contract is skipped (default behavior — PASS = Pass-2 cells all green).

## Per-task vs job-wide

The YAML's `task_key` field scopes the contract to ONE task in the manifest. If you have multiple tasks needing convergence, write a list:

```yaml
contracts:
  - task_key: "<task_a>"
    pending_count_sql: "SELECT COUNT(*) FROM <schema>.<queue_a> WHERE pending"
    zero_window: 3
    sleep_between_s: 30
    max_attempts: 60
  - task_key: "<task_b>"
    pending_count_sql: "SELECT COUNT(*) FROM <schema>.<queue_b> WHERE pending"
    zero_window: 5
    sleep_between_s: 60
    max_attempts: 30
```

Contracts run sequentially after their respective tasks complete.

## How to read the verdict

After a run, `JOB_REPORT.md` will include an acceptance-contract section:

```
## Acceptance contracts

| task_key | status | windows_observed | converged_at |
|---|---|---|---|
| <task_a> | PASS | 3 consecutive zeros | 2026-XX-XX HH:MM:SS |
| <task_b> | ACCEPTANCE_CONTRACT_VIOLATED | 60 attempts, 0 consecutive zeros | -- |
```

If ANY contract is VIOLATED, the overall `RESULT:` line is demoted from `PASS` to `ACCEPTANCE_CONTRACT_VIOLATED` regardless of cell-level success.

## Building a good `pending_count_sql`

Some rules of thumb for the query:

- Read from a sandbox table you control (most likely the redirect-schema version of the source's queue / retry table).
- The query must return a single column of integer count (the framework specifically reads column "pending" or position 0).
- The query must be FAST — it runs every `sleep_between_s`. Add appropriate filters / partitions.
- The query must be IDEMPOTENT — running it doesn't mutate state.

Example shapes:

```sql
-- Streaming retry queue
SELECT COUNT(*) AS pending
FROM <sandbox_schema>.<retry_queue_table>
WHERE status IN ('PENDING','RETRYING')
  AND ingest_ts > current_date - INTERVAL 1 DAY

-- Backfill progress
SELECT (target_count - processed_count) AS pending
FROM <sandbox_schema>.backfill_progress
WHERE backfill_id = '<id>'

-- Streaming watermark gap
SELECT GREATEST(
  0,
  CAST((unix_timestamp(current_timestamp()) - unix_timestamp(max(event_ts))) / 60 AS INT)
) AS pending
FROM <sandbox_schema>.<streaming_output_table>
```

## What this skill does NOT do

- Doesn't actually run the streaming job — the underlying job_migrate.py already executed the cells. The contract is a POST-execution verification step.
- Doesn't define what "convergence" means semantically — that's the user's `pending_count_sql`.
- Doesn't retry failed cells — it only signals "the pipeline didn't drain in time". For cell-level retries use [`aidp-fixup-cell`](../aidp-fixup-cell/SKILL.md).

## After this

- If PASS: proceed with downstream verification, sign off the migration.
- If VIOLATED: investigate the queue. Either (a) the underlying job needs more time (bump `max_attempts`), (b) the queue is genuinely stuck (data issue, scheduler issue), or (c) the contract is wrong (check the SQL).

Files in this skill

  • PROVENANCE.json313 B
  • SKILL.md5.8 KB
  • UPSTREAM-LICENSE.txt1.1 KB

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.