Skip to main content

aidp-acceptance-contract

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".

Aller à l'installation

Informations de source

Dépôt
oracle-samples/oracle-aidp-samples
Dernière activité de la source
24 juin 2026 à 21:21
Langue détectée de SKILL.md
anglais
Étoiles
46
Forks
30

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
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).
Voir sur GitHub