Skip to content

Add reusable run_sampler.yml workflow#30

Merged
michieldegezelle merged 7 commits into
mainfrom
sampler-production-workflow
Jul 16, 2026
Merged

Add reusable run_sampler.yml workflow#30
michieldegezelle merged 7 commits into
mainfrom
sampler-production-workflow

Conversation

@michieldegezelle

Copy link
Copy Markdown
Collaborator

Summary

  • Adds run_sampler.yml, a workflow_call-only reusable workflow that runs the Liquid Sampler (silverfin-cli run-sampler) for a single partner's already-classified templates and reports back.
  • Implements the locked design from silverfin-cli's CI_AUTH_SAMPLER_PLAN.md §6 (D1-D9) and §8: per-partner PARTNER_CONFIG_JSON_<partner> secret (sole writer, write-back gated on a before/after token diff, not log-scraping), per-partner concurrency: { group, queue: max } living inside this reusable workflow, poll-and-retry on the backend's cross-repo "already in progress" 422, results.zip uploaded as a 7-day artifact, and a per-partner PR comment (<!-- silverfin-sampler-result-<partner> -->) with the --compact diff.
  • Deliberately repo-layout-agnostic — classification (which templates changed, which partner) is the calling wrapper's job. First caller: lu_market (companion PR incoming).

Known open items (not blockers for this PR, tracked in the plan doc)

  • Depends on silverfin-cli PR #261 (agustin-bso-sampler-easy-results: --compact, result-URL surfacing, spinner fix) merging to main before a real run will produce a compact diff — the CLI install step is intentionally unpinned (matches every other workflow here), so it will pick that up automatically once merged.
  • queue: max is a GitHub Actions beta concurrency sub-key; actionlint's schema doesn't recognize it yet (false positive) but it's the same syntax already validated end-to-end on staging in be_market's TEST harness. Fallback documented inline if a target repo's plan ever rejects it.
  • Not yet run against real staging (staging environment is being set up) — this PR is the build/setup half; validation follows once available.

Test plan

  • actionlint clean (done locally)
  • End-to-end run against lu_market once staging + partner secrets are set up (see companion PR)

Given a partner id, classified handles/account templates, and firm ids, loads
that partner's PARTNER_CONFIG_JSON secret, runs the Liquid Sampler CLI with
retry-on-cross-repo-422, writes the partner token back only if it rotated
mid-run, uploads results.zip as a short-lived artifact, and posts a per-partner
PR comment. Market-repo-specific classification (which templates changed,
which partner they belong to) stays in each caller's wrapper workflow.

Implements the locked sampler design from silverfin-cli's
CI_AUTH_SAMPLER_PLAN.md (§6 D1-D9, §8) — first caller is lu_market.
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d012c6e9-07d2-4abf-be79-31583dfe9476

📥 Commits

Reviewing files that changed from the base of the PR and between 07b40a1 and d7f7579.

📒 Files selected for processing (2)
  • .github/workflows/run_sampler.yml
  • README.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • README.md
  • .github/workflows/run_sampler.yml

Walkthrough

Changes

Liquid sampler workflow

Layer / File(s) Summary
Workflow contract and execution setup
.github/workflows/run_sampler.yml, README.md
Defines reusable inputs and secrets, partner-scoped concurrency, validation, checkout, Node.js setup, CLI and credential initialization, and documentation for invoking the workflow.
Sampler execution and credential rotation
.github/workflows/run_sampler.yml
Captures the partner token, runs the sampler with bounded retries, extracts report data, and updates the partner configuration secret when the token rotates.
Result publication and final status
.github/workflows/run_sampler.yml
Uploads available results as a seven-day artifact, creates or updates a PR comment, and fails the job when sampling is unsuccessful.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding a reusable run_sampler.yml workflow.
Description check ✅ Passed The description is substantive and covers summary, open items, and test plan, though it omits some template sections.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sampler-production-workflow

Comment @coderabbitai help to get the list of available commands.

grep -oE finding no match (any run that doesn't complete - a timed-out
retry, an unrelated hard failure) made the whole pipeline's exit status
non-zero under set -eo pipefail, even though head/sed after it succeed on
empty input. That aborted the step immediately, before report_url and the
compact-diff output were ever set - silently dropping the PR comment on
every non-completed run, since the comment step has no `if: always()`.

Caught by extracting this step's script and running it locally against a
mocked CLI across three scenarios (always-in-progress timeout, retry-then-
succeed, immediate hard failure) - all three now produce correct outputs
without aborting.
@michieldegezelle

Copy link
Copy Markdown
Collaborator Author

Ran a local test pass on the two riskiest hand-written bash sections (couldn't do a live GitHub Actions dispatch pre-merge — workflow_dispatch workflows only get registered from the default branch, confirmed via the Actions API).

Classify logic (lu_market wrapper): extracted the script, ran it against synthetic fixtures covering every branch — single in-scope partner, zero in-scope partner, multiple in-scope partners, missing partner_id, config-only changes (must never surface per D4), and zero touched templates. All 6 cases produced the expected matrix_json/skipped/has_partners.

This reusable workflow's retry/output-parsing logic: extracted the "Run liquid sampler" step, mocked the CLI, and ran 3 scenarios (persistent "already in progress" → graceful timeout, retry-once-then-succeed, immediate unrelated hard failure → no retry). Found and fixed a real bug: the REPORT_URL extraction's grep -oE finding no match made the whole pipeline exit non-zero under set -eo pipefail, aborting the step before report_url/compact were ever set — which meant the "Post result comment" step (no if: always()) silently never ran on any non-completed run. Fixed with || true (47fd951). All 3 scenarios now pass with correct outputs and no abort.

Not yet tested: an actual live sampler run against beta (blocked on silverfin-cli#261 merging + staging confirmation), and the cross-repo 422 collision drill (§8 validation item 4).

The CLI checks for these at process startup for every command, including a
bare -V version probe - the "Install silverfin-cli" step only had them on
the later "Run liquid sampler" step, so it failed with "Missing API
credentials" before ever reaching the actual sampler call. Caught live via
the throwaway lu_market#763 harness (pull_request_review firing this
branch's copy of the workflow pre-merge).
if: always() meant a run that failed at "Load PARTNER_CONFIG_JSON" (e.g.
the secret is missing a partnerCredentials entry) still ran this step,
compared an empty before-token (steps.before was skipped) against
whatever AFTER_TOKEN happened to parse to, read that as "rotated", and
wrote the same invalid content back to the secret. Caught live. No data
loss occurred (it wrote back the same content it read), but the logic was
wrong regardless. Now requires steps.before.outcome == 'success'.
@michieldegezelle michieldegezelle marked this pull request as ready for review July 15, 2026 18:05

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
.github/workflows/run_sampler.yml (1)

126-134: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Consider pinning the silverfin-cli install to a commit SHA/tag.

npm install https://github.com/silverfin/silverfin-cli.git pulls whatever is on main at run time, and the comment notes this workflow already has a real, time-sensitive dependency on a specific just-merged PR. Any later unrelated change on main (or a compromised push) would silently change what this workflow executes, with no lockfile/integrity check backing it (zizmor's adhoc-packages finding). This matches an existing convention elsewhere in the repo (see add_shared_parts_production.yml), so treat as a deferrable, repo-wide follow-up rather than blocking this PR.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/run_sampler.yml around lines 126 - 134, Pin the
silverfin-cli dependency in the “Install silverfin-cli” workflow step to a
specific immutable commit SHA or release tag, following the established
convention in add_shared_parts_production.yml, instead of installing the moving
GitHub main branch. Keep the existing version-reporting command unchanged.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/run_sampler.yml:
- Around line 115-120: Update the Checkout repository at PR head step to set
persist-credentials to false, leaving the existing ref and fetch-depth settings
unchanged.
- Around line 268-283: Update the curl invocation in the “Download results.zip
for the workflow artifact” step to include the --fail option, ensuring HTTP
4xx/5xx responses enter the existing warning path instead of being marked as
downloaded.

---

Nitpick comments:
In @.github/workflows/run_sampler.yml:
- Around line 126-134: Pin the silverfin-cli dependency in the “Install
silverfin-cli” workflow step to a specific immutable commit SHA or release tag,
following the established convention in add_shared_parts_production.yml, instead
of installing the moving GitHub main branch. Keep the existing version-reporting
command unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bc980b28-c491-4f78-9aa9-a198b2bef132

📥 Commits

Reviewing files that changed from the base of the PR and between 1b05cbf and ed16c91.

📒 Files selected for processing (1)
  • .github/workflows/run_sampler.yml

Comment thread .github/workflows/run_sampler.yml
Comment thread .github/workflows/run_sampler.yml
Comment thread .github/workflows/run_sampler.yml Outdated
Comment thread .github/workflows/run_sampler.yml Outdated
Comment thread .github/workflows/run_sampler.yml Outdated
Comment thread .github/workflows/run_sampler.yml Outdated
Comment thread .github/workflows/run_sampler.yml Outdated
Comment thread .github/workflows/run_sampler.yml
- Splice handles/account_templates/firm_ids/partner through env: instead
  of directly into run: scripts (GitHub Actions expression-injection
  anti-pattern), including the highest-impact instance in the write-back
  step that runs with a repo-write PAT active.
- Reject whitespace-only handles/account_templates/firm_ids, not just
  empty string.
- Add persist-credentials: false to the checkout step (unused here).
- Add --fail to the results.zip curl download so a non-2xx response
  isn't treated as a successful download.
- Add always() to the post-comment, upload-artifact, and fail-job steps
  so an earlier hard failure doesn't skip them silently.
- Fix a jq filter broken by invalid backslash-escaping inside a
  single-quoted string (silently blanked the Host: diagnostic).
- Document run_sampler.yml in README.md's Individual Action
  Documentation section, matching the push_to_review_firm.yml precedent.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
README.md (1)

281-285: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Clarify the scope of the “sole writer” guarantee.

Because this is reusable and cross-repository concurrency is not enforced, this is a repository/process invariant rather than something the workflow can guarantee globally. State the scope explicitly and clarify that callers must map their PARTNER_CONFIG_JSON_<partner> secret into the reusable workflow’s generic PARTNER_CONFIG_JSON secret.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 281 - 285, Revise the workflow documentation near the
“sole writer” statement to scope that guarantee to this repository/process, not
globally across repositories or concurrent callers. Clarify that each caller
must map its partner-specific PARTNER_CONFIG_JSON_<partner> secret to the
reusable workflow’s generic PARTNER_CONFIG_JSON secret.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/run_sampler.yml:
- Line 268: Update the token comparison in the sampler workflow to avoid
interpolating steps.before.outputs.token directly into Bash source. Pass the
output through the workflow environment or another safely quoted mechanism, then
compare AFTER_TOKEN against that runtime variable while preserving the existing
equality check.
- Around line 148-150: Update the jq validation in the partner configuration
check to require that .partnerCredentials[$p].token is a string with non-zero
length. Keep the existing error message and exit behavior for missing, empty, or
non-string tokens.
- Around line 110-113: Update the input validation in the workflow’s
handles/account_templates check to reject values containing only any whitespace,
including tabs and newlines, rather than removing literal spaces only. Apply the
same whitespace normalization and rejection logic to the FIRM_IDS check,
preserving the existing error-and-exit behavior.

In `@README.md`:
- Line 276: Update the README bullet describing the PR result comment to qualify
that the full-report link is included only when a report URL is available, and
state that the artifact remains the fallback when no URL exists.

---

Nitpick comments:
In `@README.md`:
- Around line 281-285: Revise the workflow documentation near the “sole writer”
statement to scope that guarantee to this repository/process, not globally
across repositories or concurrent callers. Clarify that each caller must map its
partner-specific PARTNER_CONFIG_JSON_<partner> secret to the reusable workflow’s
generic PARTNER_CONFIG_JSON secret.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8ea6f0c4-026d-4cb5-89f8-6d9f5fcad922

📥 Commits

Reviewing files that changed from the base of the PR and between ed16c91 and 07b40a1.

📒 Files selected for processing (2)
  • .github/workflows/run_sampler.yml
  • README.md

Comment thread .github/workflows/run_sampler.yml Outdated
Comment thread .github/workflows/run_sampler.yml Outdated
Comment thread .github/workflows/run_sampler.yml Outdated
Comment thread README.md Outdated
- Reject tabs/newlines, not just literal spaces, as whitespace-only
  handles/account_templates/firm_ids.
- Require the partner token to be a non-empty string during the
  PARTNER_CONFIG_JSON validation (previously accepted empty string,
  numbers, objects, null as "present").
- Stop splicing steps.before.outputs.token into shell source in the
  write-back step's comparison — route it through env: like the other
  values in this file.
- README: qualify that the full-report link is only included when a
  report URL was produced; results.zip artifact is the fallback.
@michieldegezelle michieldegezelle merged commit 55ee8aa into main Jul 16, 2026
7 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