Skip to content

refactor: migrate Deequ Bot to the shared Shadow engine - #756

Merged
sudsali merged 6 commits into
masterfrom
shadow-engine-migration
Jul 2, 2026
Merged

refactor: migrate Deequ Bot to the shared Shadow engine#756
sudsali merged 6 commits into
masterfrom
shadow-engine-migration

Conversation

@sudsali

@sudsali sudsali commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Migrates the Deequ Bot from a vendored copy of the engine (src/scripts/issue_bot/) to consuming the shared Shadow engine (sudsali/shadow) via its reusable workflow, SHA-pinned to 0ff3d75 (v1.3). Same behavior, one engine maintained upstream instead of a per-repo fork. Net diff removes ~8k lines of vendored code + tests.

What Changes

  • Replaces issue-bot.yml with a thin caller of sudsali/shadow/.github/workflows/shadow-review.yml (all four triggers preserved: issues, issue_comment, pull_request_target, workflow_dispatch)
  • Adds .shadow.yml — engine config (Scala codebase, bot.name: shadow, attribution footer)
  • Deletes the vendored engine (src/scripts/issue_bot/) and its tests (src/scripts/tests/); keeps generate_kb.py
  • Renames the bot's user-facing identity from deequ-bot to shadow

Behavior Preserved

  • Prompts — deequ's language-tuned prompts stay in Secrets Manager (deequ-bot/*), selected via prompt_sm_prefix: deequ-bot; the engine fetches all eight (PR investigator/critic/reporter + 2 commit nudges + issue-classify/respond/followup) in place of its bundled defaults. No new secrets.
  • Auto-approve — clean reviews carry <!-- shadow:clean -->; auto-approve.yml updated in lockstep (workflow name + marker)
  • Surfaces — PR review, issue triage, issue-respond, and follow-up all run from one engine, unchanged
  • BOT_AGENT_PIPELINE=1 was already the live path, so the dropped legacy file-review prompts were dead code

Architecture

GitHub Event → issue-bot.yml (caller) → sudsali/shadow reusable workflow
                ├── Job 1: analyze (id-token, read-only)
                │     ├── Resolve prompts from Secrets Manager (deequ-bot/*)
                │     ├── 3-agent pipeline: Investigator → Critic → Reporter
                │     └── Write JSON artifact
                └── Job 2: act (issues/pull-requests write, no AWS)
                      ├── Post review pinned to analyzed commit (commit_id)
                      ├── Add labels / escalate to Slack
                      └── Footer: "Reviewed by Shadow"

Security

  • OIDC pinning — no IAM change to merge (caller's sub stays repo:awslabs/deequ:*); an optional job_workflow_ref trust narrowing may be applied after merge (applying it before breaks the base-branch vendored bot)
  • SHA-pinned engineuses: and shadow_ref both pin the exact commit; a moved upstream tag can't change what runs
  • Two-job split — read-only analyze (AWS creds, no GitHub write), write-only act (GitHub write, no AWS creds), preserved from the reusable workflow
  • Attribution footer — self-scrubbed (injection markers dropped, @/# auto-link neutralized, marker-spoof-proof)

Files

File Change
.github/workflows/issue-bot.yml Replaced with reusable-workflow caller
.shadow.yml Added — engine config (codebase, bot name, attribution)
.github/workflows/auto-approve.yml Marker + workflow name renamed deequ-botshadow
.github/workflows/update-kb.yml Dropped stale paths-ignore for removed dirs
src/scripts/issue_bot/ Deleted (vendored engine, now upstream)
src/scripts/tests/ Deleted (vendored engine tests)

Testing

All four surfaces exercised against the pinned engine (v1.3) with real Bedrock and deequ's real deequ-bot/* Secrets Manager prompts:

  • PR reviewworkflow_dispatch dry_run: true on GitHub Actions against PR Fix NPE: encode bin edges in BinnedFrequencies state instead of mutab… #722: analyze + act succeed; all 8 prompts resolve from sm:deequ-bot/*; 3-agent pipeline (Investigator → Critic → Reporter, Opus) produces inline findings; review pinned to the analyzed commit (commit_id)
  • Issue triage — real [BUG] Analyzer forces full table read on Iceberg tables, not considering Filter Pushdown #667 content (Iceberg bug): RESPOND on Haiku, issue-classify + issue-respond from sm:deequ-bot/*, substantive answer, bug label applied
  • Follow-up (issue_comment) — reply thread: followup prompt from sm:deequ-bot/*, coherent response, escalates when knowledge base is insufficient
  • Guards — closed-issue and already-commented SKIP paths fire correctly against live issues
  • Engine — 494 unit/integration tests pass upstream

Issue-triage and follow-up were verified via engine replay (real Bedrock + real SM prompts), since workflow_dispatch cannot emit issue_comment events and live issues trip the correct SKIP guards; those two surfaces run natively on real events after merge.

Rollback

Revert this PR — the vendored src/scripts/issue_bot/ returns and runs as before. No data or state migration; secrets and repo variables are untouched.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

Replace the vendored copy of the bot (src/scripts/issue_bot/) with consuming
the shared engine sudsali/shadow via its reusable workflow, SHA-pinned to
3a057597420d7123df162bfe4686aaafb5f7eccd (v1.2). One engine, maintained once
upstream, instead of a per-repo fork.

Zero intended behavior change:
- Deequ's language-tuned prompts stay in Secrets Manager (deequ-bot/* namespace)
  and are selected via prompt_sm_prefix: deequ-bot — the engine fetches all
  eight (pr-investigator/critic/reporter + 2 commit nudges + issue-classify/
  issue-respond/followup) in place of its bundled language-agnostic defaults.
- .shadow.yml sets bot.name: deequ-bot so the clean-review marker stays
  <!-- deequ-bot:clean --> (auto-approve.yml keys on it) and the Scala codebase
  config (src/main/scala, .scala) matches the vendored setup.
- All four surfaces (PR review, issue triage, issue-respond, follow-up), all
  four triggers, and the job-level trigger guard are preserved. Workflow name
  stays "Deequ Bot" (auto-approve.yml keys on it too).

BOT_AGENT_PIPELINE=1 is already the live path, so the dropped legacy file-review
prompts are dead code. generate_kb.py stays (update-kb.yml still runs it); its
stale paths-ignore entries for the removed dirs are cleaned up.

Requires a one-time OIDC trust update on the bot's IAM role (job_workflow_ref →
shadow's reusable workflow), applied out-of-band with an @* version wildcard so
future engine bumps need no IAM change.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found.


Generated by AI (model: us.anthropic.claude-opus-4-7, prompt: 4d2f5d73) — may not be fully accurate. Reply if this doesn't help.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found and CI is passing. Auto-approved.


Generated by AI — human merge required.

The caller works on the current sub-only IAM trust with no change (its OIDC sub
is still repo:awslabs/deequ:*). The job_workflow_ref pin is optional
defense-in-depth to be applied only after this PR merges — applying it while the
base branch still runs the vendored bot denies AssumeRole. Comment-only.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found.


Generated by AI (model: us.anthropic.claude-opus-4-7, prompt: 4d2f5d73) — may not be fully accurate. Reply if this doesn't help.

A reusable-workflow caller must grant, at the top level, the union of
permissions its nested jobs request — GitHub caps nested jobs at the caller's
token and otherwise fails at startup ('is requesting ... but is only allowed
none'). The reusable workflow's analyze (id-token:write, pull-requests:read)
and act (issues:write, pull-requests:write) jobs need this union; the vendored
workflow declared these per-job, which doesn't carry across the workflow_call
boundary. Fixes the workflow_dispatch startup_failure.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found.


Generated by AI (model: us.anthropic.claude-opus-4-7, prompt: 4d2f5d73) — may not be fully accurate. Reply if this doesn't help.

Drop WHAT-narration and multi-paragraph explanations; keep only comments that
prevent a concrete mistake (name coupling, dual-SHA pin, pull_request_target
no-ref, permissions ceiling, marker, if-guard).

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found.


Generated by AI (model: us.anthropic.claude-opus-4-7, prompt: 4d2f5d73) — may not be fully accurate. Reply if this doesn't help.

Surface the Shadow product to the OSS community. Renames the user-facing
identity in lockstep across the three coupled points: .shadow.yml bot.name
(the clean-review marker), the workflow name, and auto-approve.yml (both the
workflows[] trigger and the CLEAN_MARKER it greps). prompt_sm_prefix stays
deequ-bot (private Secrets Manager namespace).

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


Generated by AI (model: us.anthropic.claude-opus-4-7, prompt: 4d2f5d73) — may not be fully accurate. Reply if this doesn't help.

on:
workflow_run:
workflows: ["Java CI with Maven", "Deequ Bot"]
workflows: ["Java CI with Maven", "Shadow"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DESIGN: The PR description no longer matches the diff — it claims the workflow name and marker are preserved as Deequ Bot/deequ-bot:clean, but the diff renames both to Shadow/shadow:clean. Reviewers relying on the description will miss that this is now a rename PR (not a pure infra swap). Update the description to reflect that (a) workflow name changed to "Shadow", (b) marker changed to <!-- shadow:clean -->, and (c) auto-approve.yml did need changes.

PR body: "Marker unchanged." and "auto-approve.yml needs no change". Incremental diff auto-approve.yml line 5: workflows: ["Java CI with Maven", "Shadow"]. Line 75: const CLEAN_MARKER = '<!-- shadow:clean -->';. .shadow.yml line 10: name: shadow.

Bumps the shared-engine SHA to v1.3 (adds bot.attribution) and sets the footer
attribution so posted comments surface the Shadow product to the OSS community.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found.


Generated by AI (model: us.anthropic.claude-opus-4-7, prompt: 4d2f5d73) — may not be fully accurate. Reply if this doesn't help.

@sudsali sudsali changed the title Migrate Deequ Bot to the shared Shadow engine refactor: migrate Deequ Bot to the shared Shadow engine Jul 2, 2026
@sudsali
sudsali marked this pull request as ready for review July 2, 2026 15:29
@sudsali
sudsali merged commit 2cd4bd5 into master Jul 2, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant