Skip to content

feat(release): manifest-driven publish kit with non-disclosing preflight - #507

Open
randlee wants to merge 40 commits into
developfrom
feature/publish-kit-preflight-hardening
Open

feat(release): manifest-driven publish kit with non-disclosing preflight#507
randlee wants to merge 40 commits into
developfrom
feature/publish-kit-preflight-hardening

Conversation

@randlee

@randlee randlee commented Aug 15, 2026

Copy link
Copy Markdown
Owner

Summary

  • The manifest drives each post-release channel workflow and its repository-specific deliverables; the shared channel contract owns credential names and liveness protocol.
  • Publisher coordinates parallel role-specific background workers with structured per-channel results and retry-only-failed behavior.
  • Preflight is non-disclosing and is the sole credential-liveness authority; agents do not ask for or inspect token values.
  • Homebrew supports manifest-declared formula aliases, release_track selection (all stable entries for stable tags; only prerelease entries for prerelease tags), and per-formula binaries. Each selected formula is rendered, Ruby-validated, and committed. test_binary defaults to the first binary; legacy binary entries normalize for vendor compatibility.
  • Scoop remains a generic post-release channel; manifest validation now rejects omitted bucket/manifest/template/binary inputs.

No tag, dispatch, or publication was performed by this PR.

Validation

  • python3 -m pytest scripts/tests/test_release_artifacts.py -q — 36 passed
  • manifest validation
  • workflow YAML parsing
  • just test
  • git diff --check
  • just lint — locally blocked by the pre-existing cargo-deny CLI incompatibility (--config is rejected); this PR does not change that tooling.

@randlee

randlee commented Aug 15, 2026

Copy link
Copy Markdown
Owner Author

QA Gate: FAIL

PR: #507 (feature/publish-kit-preflight-hardeningdevelop)
Commits reviewed: 28a8513 (requirements), e6ddfca (implementation)
Review type: sprint_review — reviewers per explicit task workflow: rust-qa-agent, req-qa, arch-qa, simplification-reviewer
CI: all checks green

Reviewer results

Reviewer Verdict Notes
req-qa FAIL 1 blocking finding (independently reproduced), 2 non-blocking
arch-qa PASS 1 minor doc-staleness finding
rust-qa-agent PASS 1 minor pre-existing/unrelated lint-tooling finding
simplification-reviewer PASS 1 minor doc-duplication finding
rust-best-practices-agent SKIPPED not in task's explicit reviewer list
rust-service-hardening-agent SKIPPED not in task's explicit reviewer list
flaky-test-qa SKIPPED not required, no test changes

Blocking finding — ATM-QA-001

.github/workflows/release-preflight.yml:45

echo "plan=$(python3 scripts/release_artifacts.py preflight-secret-plan --manifest \"${RELEASE_ARTIFACT_MANIFEST}\")" >> "$GITHUB_OUTPUT"

The \"..\" inside a $(...) substitution embeds literal quote characters into the --manifest argument (confirmed via direct reproduction: the received argv becomes '"release/publish-artifacts.toml"', not release/publish-artifacts.toml). This breaks the non-disclosing credential preflight — the sole authority gating the root release workflow — on every real invocation. Five other locations in the same file (lines 161, 175, 182, 188, 197) use the correct unescaped pattern (--manifest "${RELEASE_ARTIFACT_MANIFEST}" \); line 45 is the sole outlier.

Remediation: drop the backslash-escaped inner quotes at line 45 to match the pattern already used elsewhere in the file.

Deliverable completion: 8/11 (72.7%)

Below 100% — does not meet the PASS bar per QA policy regardless of the blocking finding above.

Independent verification of comp's self-reported validation

Reviewed independently rather than accepted as-is, per task instruction. req-qa's blocking finding was reproduced directly (not a reviewer tooling-gap artifact) via manual shell reproduction of the exact substitution pattern.


Filed by quality-mgr per sprint_review gate. Full per-reviewer detail available on request.

@randlee

randlee commented Aug 15, 2026

Copy link
Copy Markdown
Owner Author

QA Recheck Gate: FAIL

PR: #507 (feature/publish-kit-preflight-hardeningdevelop)
Commits reviewed: 28a8513, e6ddfca, 8e70656 (fix)
Task: PUBLISH-KIT-PREFLIGHT-HARDENING-QA-RECHECK
CI at HEAD (8e70656): test (macos-latest) FAIL, test (ubuntu-latest) FAIL, test (windows-latest) FAIL; Format check/clippy/manifest-validation PASS

Reviewer results

Reviewer Verdict Notes
req-qa PASS All 3 fixed_findings + all 5 known_findings verified FIXED; deliverables 7/7 (100%)
arch-qa PASS No new structural regression from 8e70656; prior minor doc-staleness finding (RELEASING.md:210) still open, non-blocking
simplification-reviewer PASS No scope creep/dead paths in the fix; prior minor doc-duplication finding still open, non-blocking
rust-qa-agent FAIL fmt/clippy clean; cargo test --workspace fails — new regression, see below

Status of originally-tracked fixed_findings

  1. ATM-QA-001 (release-preflight.yml:45 quote-escaping) — FIXED, confirmed by req-qa (pattern now matches the 5 other correct call sites in the file) and matches the code as read directly.
  2. Homebrew formula.rb.j2 invalid Rubydesign corrected, but introduced a new regression (see ATM-QA-002 below). The manifest-driven bare-first-component idiom (pkgshare/"examples") is architecturally sound — homebrew_destination_components[0] is validated server-side (scripts/release_artifacts.py:290-296) to match ^[a-z_][a-z0-9_]*$, so it can never require escaping. This matches Homebrew's own Pathname#/ chaining convention.
  3. Scoop manifest path + JSON quotingFIXED. manifest_path = "bucket/sc-compose.json"; all interpolated values in manifest.json.j2 are | tojson-escaped; workflow's mkdir -p "$(dirname ...)" correctly derives the output dir from the manifest-declared path.

New blocking finding — ATM-QA-002

crates/sc-compose/tests/cli/render.rs — existing regression test render_homebrew_formula_escapes_manifest_values_as_ruby_strings (assertion at line ~166) still asserts the pre-fix output shape for the first bundled-path component: ("share"/"quoted\"component"/"examples").install ... (first component quoted as a Ruby string literal). That is exactly the original bug this sprint exists to fix — String has no / method, so a quoted first component is invalid Ruby at runtime. Commit 8e70656 correctly changed the template to emit the first component bare (share/"quoted\"component"/"examples"), which is valid, but did not update this test to match. Result: cargo test --workspace fails on all 3 CI platforms at HEAD.

Remediation: update the test assertion to expect the corrected (bare-first-component) output, consistent with the manifest validator's enforced first-component safety and the fix's intended design. This is a test-only fix, not a design reversal — do not revert the template to the old quoted-first-component form, as that reintroduces the original invalid-Ruby bug.

Deliverable completion: 7/7 (100%) per req-qa's requirements-section trace

Overall gate is FAIL despite 100% requirements-section coverage, because a required regression test fails on live CI at the reviewed commit — never mergeable with red CI regardless of deliverable percentage.


Filed by quality-mgr per sprint_review recheck gate.

@randlee

randlee commented Aug 15, 2026

Copy link
Copy Markdown
Owner Author

QA Recheck2 Gate: PASS

PR: #507 (feature/publish-kit-preflight-hardeningdevelop)
Commits reviewed: 28a8513, e6ddfca, 8e70656, ed8f879 (fix, test-only)
Task: PUBLISH-KIT-PREFLIGHT-HARDENING-QA-RECHECK2
CI at HEAD (ed8f879): all checks green (Format, clippy, manifest-validation, test x3 platforms, python-wheels x3, sc-sha-python wheel x3)

Reviewer results

Reviewer Verdict
req-qa PASS — deliverables 7/7 (100%)
arch-qa PASS — confirmed test-only, no scope creep
rust-qa-agent PASS — fmt/clippy/cargo test --workspace all green, including the previously-failing test
simplification-reviewer PASS — ran the test directly, confirmed it passes; not a weakened assertion

ATM-QA-002 — FIXED

Fix commit ed8f879 is confirmed genuinely test-only (1 file, +1/-1, crates/sc-compose/tests/cli/render.rs only — independently verified via git show --stat). The stale assertion in render_homebrew_formula_escapes_manifest_values_as_ruby_strings now expects the corrected bare-first-component Ruby output (share/"x"/"y") matching the legitimate template fix from 8e70656, rather than the old invalid-Ruby quoted form ("share"/"x"/"y"). All reviewers independently confirmed this matches the actual template rendering and is not a weakened/trivial assertion.

Remaining open items (non-blocking, carried forward, not required for this PR)

  • RELEASING.md:210 — stale "previous checklist format" label (arch-qa)
  • 1 minor doc-duplication finding from original review — still unlocatable on disk despite repeated searches (simplification-reviewer); recommend dropping as unreproducible if not resolved by next touch of this area

Deliverable completion: 7/7 (100%)

All required reviewers PASS, deliverable completion at 100%, CI fully green at the actual PR head SHA. Merge-ready.


Filed by quality-mgr per sprint_review recheck2 gate.

randlee and others added 2 commits August 15, 2026 12:23
Authoritative sprint doc for the PR #507 follow-up: extend non-disclosing
preflight through all publishing subagents, link publish-kit-requirements.md
into top-level req/ADR docs, and add a written agent eval plan.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@randlee

randlee commented Aug 15, 2026

Copy link
Copy Markdown
Owner Author

QA Verdict — Sprint PUBLISH-KIT-AGENT-EVAL-HARDENING — FAIL

Follow-up to already-PASSed PUBLISH-KIT-PREFLIGHT-HARDENING (baseline ed8f879). Commits under review: 5519503 (sprint doc), fca2733 (feat: gate every publish worker on preflight).

Deliverables: 7/10 fully present (70%) — below the 100% threshold required for PASS. 2 blocking findings open.

Reviewer verdicts

  • req-qa: FAIL — deliverable gap + doc/code conflict
  • arch-qa: CONCERNS (merge_ready: false) — gate-artifact hygiene
  • rust-qa-agent: PASS — fmt/clippy/tests all clean (only Rust-scope file: 1-line test assertion, already covered by prior QA round)
  • simplification-reviewer: PASS — no dead code/duplication; one non-blocking CONCERN noted (optional live TestPyPI rehearsal step in the new eval plan mirrors already-approved rehearsal semantics, opt-in only — not a blocker)

Blocking findings (both independently verified against the live worktree, not accepted on reviewer say-so)

ATM-QA-001 (Blocking, req-qa).github/workflows/release-preflight.yml does not actually produce a per-channel preflight result. Its credential/secret checks run once, aggregated across the union of all channels' secrets — there is no per-channel (homebrew/winget/scoop/pypi/crates_io/github_release) keyed pass/fail/blocked output anywhere in the workflow. Confirmed via direct grep: root_channels/post_release_channels/channel_name/matrix all return zero hits in release-preflight.yml.

Yet three normative docs affirmatively claim this exists:

  • docs/publish-kit-requirements.md:39-42 — "returns a sanitized result for every root and post-release channel"
  • docs/publishing-agent.md:37-40 — same claim (confirmed live at line 38)
  • docs/release-checklist.md:17-19 — "Preserve the complete per-channel sanitized preflight result" (confirmed live at line 17)

And .claude/agents/publisher.md:87-89 / .claude/agents/publisher-channel-worker.md:16-27 both require a preflight_result input keyed per channel that the current CI workflow cannot structurally produce.

The Python side (scripts/release_artifacts.py) does correctly implement per-channel preflight-contract construction (_post_release_channel_preflight, _root_channel_preflight) and is tested — but nothing wires that into release-preflight.yml's actual CI execution/output.

Remediation: Extend release-preflight.yml to iterate root_channels/post_release_channels and emit one explicit result per channel (matrix or per-channel job output) consumable by publisher/publisher-channel-worker — or correct the three docs above plus the sprint closure checklist to stop claiming this is implemented, and reopen that checklist item.

ATM-QA-002 (Important, req-qa) — sprint closure checklist item 5 (docs/sprints/publish-kit-agent-eval-hardening.md:59-61) claims cargo fmt --all --check / cargo test --workspace were run and passed, with no CI link/log attached. rust-qa-agent independently ran these clean at fca2733, so this closes the underlying concern, but the sprint doc should still cite CI evidence directly rather than a self-checked box.

ARCH-001 (Blocking, arch-qa, RULE-013)docs/sprints/publish-kit-preflight-hardening-checklist.md:3 and docs/sprints/fix-pr507-release-channel-runtime-checklist.md:3 both declare status: in_progress in frontmatter despite every closure-checklist item in each being checked. Per RULE-013, the artifact's own internal status field governs, not docs/project-plan.md's "Status: Complete" wording. Confirmed live: both files read status: in_progress at line 3.

Remediation: Flip both frontmatter fields to a terminal status now that their checklists are fully checked (or explain why they remain open).

ARCH-002 (Important, arch-qa) — non-blocking coverage-depth note: test_release_preflight_collects_independent_failures_before_denial verifies the fail-closed/not-fail-fast contract via YAML-text substring assertions rather than executing the control flow. arch-qa independently confirmed the actual YAML control flow is correctly wired by direct inspection; this is a test-depth note only.

Non-disclosure / scope guard: holds

  • Credential-silence-unless-preflight-fails contract intact in both publisher.md and the new publisher-channel-worker.md.
  • release-preflight.yml remains workflow_dispatch-only; no tag/dispatch/publish action wired to run anywhere in this diff.

CI

Not re-verified this round pending fix — reviewer-run fmt/clippy/test checks were clean at fca2733, but the workflow-level per-channel gap above (ATM-QA-001) is a design/implementation gap, not a CI-red issue, and must be fixed before this sprint can close.


Merge readiness: not ready. 2 blocking findings across 2 independent reviewers, both independently confirmed against the live worktree.

@randlee

randlee commented Aug 15, 2026

Copy link
Copy Markdown
Owner Author

QA Recheck Verdict — Sprint PUBLISH-KIT-AGENT-EVAL-HARDENING — FAIL (narrowed significantly)

Recheck of fix commit 9f86676 against the prior FAIL verdict (comment).

Both prior blocking findings: RESOLVED (independently re-verified)

  • ATM-QA-001 — FIXED. .github/workflows/release-preflight.yml:256-288 now has a real channel_results step calling scripts/release_artifacts.py channel-preflight-results, which reuses the existing _root_channel_preflight/_post_release_channel_preflight contract builders (no duplicate logic) and emits a genuine per-channel-keyed JSON object (crates_io, github_release, pypi, homebrew, winget, scoop) as job output + GITHUB_STEP_SUMMARY. Backed by real executable subprocess-based tests (scripts/tests/test_release_artifacts.py:560-673) covering passing/failed/blocked/unauthorized scenarios — not text-substring assertions. publisher.md/publisher-channel-worker.md's Channel Gate genuinely consumes this shape. Non-disclosure holds: no credential env vars reach the new step.
  • ARCH-001 — FIXED. Both docs/sprints/publish-kit-preflight-hardening-checklist.md:3 and docs/sprints/fix-pr507-release-channel-runtime-checklist.md:3 now read status: complete, verified live.

Reviewer verdicts

  • rust-qa-agent: PASS — fmt/clippy/tests all clean at 9f86676.
  • arch-qa: PASS, merge_ready: true — 0 blocking. 2 non-blocking Important notes (below).
  • req-qa: FAIL — driven by incomplete deliverable, not a re-opened blocker (below).
  • simplification-reviewer: FAIL — flagged the same gate-wiring gap as blocking; I resolved this independently (below) and am siding with arch-qa/req-qa's non-blocking characterization after direct verification.

Why this is still FAIL: one incomplete deliverable

ATM-QA-003 (Important, non-blocking on code, blocking on deliverable completion)docs/sprints/publish-kit-agent-eval-hardening.md:69-75 "Validation Evidence" section still only cites prose evidence tied to the pre-fix commit fca2733ae741dc49776a22f55a043796768683fc, plus an unsubstantiated line that "the fix follow-up re-runs those commands before closeout." No CI run link, check-run reference, or captured log exists anywhere in the worktree for fix commit 9f86676 itself. I can independently confirm the underlying claim is true — rust-qa-agent ran cargo fmt --all --check, cargo clippy --all-targets --all-features -- -D warnings, and cargo test --workspace clean at HEAD 9f86676 this round — but the sprint doc itself doesn't cite it. Per standing policy, QA never PASSes below 100% deliverable completion; this is the one remaining gap.

Required correction: Update docs/sprints/publish-kit-agent-eval-hardening.md's Validation Evidence section to cite the fix commit 9f86676 explicitly (this quality-mgr round's rust-qa-agent confirmed fmt/clippy/test all clean at that SHA — cite that, or attach the actual CI run).

Resolved reviewer disagreement (independently verified, not deferred to reviewer authority)

Three reviewers converged on the same fact — cmd_channel_preflight_results() always returns 0 regardless of channel content, so the new record channel-results "${CHANNEL_RESULTS}" line in the deny-release gate (release-preflight.yml:311) checks only the script's own execution outcome, not the parsed JSON content — but split on severity (arch-qa/req-qa: non-blocking; simplification-reviewer: blocking). I read release-preflight.yml:290-340 directly: the pre-existing per-step record calls (repository-secrets, credential-liveness, environment-secrets, etc.) are untouched and still independently gate on the exact same underlying failure conditions the new channel JSON derives from. There is no scenario where a channel fails preflight but the job doesn't deny release — the new channel_preflight_results output is an additive downstream artifact for publisher/publisher-channel-worker consumption (which is what ATM-QA-001 actually required), not a second, broken in-job gate. Classified non-blocking (documentation-accuracy: the fix-commit description's "gating the deny-release check on its outcome" phrasing overstates the change slightly — worth a one-line correction, not a code fix).

Non-blocking carryover

ARCH-002 — the deny-release gate's own bash control-flow (record/exit logic) is still tested only via YAML-text-substring assertion, not real execution; the new Python mapping logic now has genuine coverage, but this specific gap is unchanged from last round. Not required to hold.

Non-disclosure / scope guard: holds

Confirmed again this round — no credential values reach the new channel_results step or its JSON output; release-preflight.yml remains workflow_dispatch-only.


Merge readiness: not ready — one narrow doc-citation gap remains. Both structural blockers from the prior round are genuinely fixed. Recommend a fast one-line doc fix and immediate re-recheck (rust-qa-agent's this-round CI result can likely be cited directly rather than requiring a fresh run).

QA-RECHECK (ATM-QA-003) flagged that the Validation Evidence section only
cited the pre-fix commit. Cite the fix commit's independently-confirmed
fmt/clippy/test/scripts results from both comp and quality-mgr's rust-qa-agent.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@randlee

randlee commented Aug 15, 2026

Copy link
Copy Markdown
Owner Author

QA Verdict — Sprint PUBLISH-KIT-AGENT-EVAL-HARDENING — PASS

Second recheck of docs-only fix commit 1639e96 (citation-only, confirmed via git diff --stat 9f86676 1639e96: 1 file, 11 insertions/2 deletions, zero code touched), closing out the sole remaining gap (ATM-QA-003) from the prior recheck.

Reviewer verdicts — all 4 PASS

  • req-qa: PASS — 5/5 deliverables (100%). Validation Evidence section now cites concrete fmt/clippy/test/scripts evidence tied to fix commit 9f86676 specifically (both comp's independent validation and quality-mgr's rust-qa-agent confirmation), not just the pre-fix baseline. ATM-QA-003 confirmed fixed.
  • arch-qa: PASS, merge_ready: true — 0 blocking. Both sprint-doc gate artifacts remain fully closed (status: complete), untouched by this commit. No new RULE-012/RULE-013 issues.
  • rust-qa-agent: PASS — fmt/clippy/tests all clean at HEAD 1639e96. Independently verified the cited commit hashes in the sprint doc match actual git history exactly.
  • simplification-reviewer: PASS — confirmed the commit is narrowly scoped to the doc citation. Notably withdrew its prior blocking classification on the channel_preflight_results/deny-release gate question after re-reading release-preflight.yml:256-345 and scripts/release_artifacts.py:311-404 end to end: all 6 outcome keys feeding per-channel status are direct mirrors of the same raw step outcomes the deny-release step already checks unconditionally, so no scenario exists where a channel is failed/blocked but the job still passes. Confirms this was a documentation-accuracy note, not a functional defect — consistent with quality-mgr's and arch-qa's independent conclusion from the prior round.

Full sprint history now closed

  • ATM-QA-001 (no genuine per-channel preflight result) — fixed at 9f86676, confirmed across 3 reviewer rounds.
  • ARCH-001 (stale status: in_progress frontmatter) — fixed at 9f86676, confirmed.
  • ATM-QA-003 (missing fix-commit CI evidence citation) — fixed at 1639e96, confirmed this round by all 4 reviewers.
  • Carryover non-blocking notes (ARCH-002 coverage-depth, gate-wiring documentation-accuracy) remain open as optional follow-ups, not merge blockers.

CI: green

All 12 checks pass at head SHA 1639e96b2586795412593a6e921e01ba02dd74e8 (Format check, clippy, manifest-validation, python-wheels ×3, sc-sha-python wheel ×3, test ×3 macos/ubuntu/windows).

Non-disclosure / scope guard: holds

Reconfirmed no credential values reach any new code path; release-preflight.yml remains workflow_dispatch-only with no tag/dispatch/publish action wired to run.


Deliverable completion: 5/5 (100%). 0 blocking findings. CI green. Merge-ready pending human/team-lead approval per standing policy.

@randlee

randlee commented Aug 15, 2026

Copy link
Copy Markdown
Owner Author

QA: PUBLISH-KIT-AGENT-EVAL-FIX-001-QA — FAIL

Reviewed (as dispatched): fix commit 819c76a addressing EVAL-001/002/003 from team-lead's live agent eval.
Actual PR head at time of verdict: b736ab3 (3 commits past the dispatched review commit: 09dd094, c73e347, b736ab3 — none of which were named in the QA task).

Reviewer results

  • rust-qa-agent: PASS — no Rust source touched by 819c76a; cargo fmt --check, clippy -D warnings, cargo test --workspace all clean at that commit.
  • simplification-reviewer: PASS — EVAL-001/002/003 all confirmed as clean, non-duplicative fixes; scope of 819c76a (7 files) maps 1:1 to the 3 claimed findings. Flagged (informational) that further uncommitted changes existed in the worktree beyond 819c76a at review time.
  • arch-qa: PASS (evaluated after the branch had already advanced to b736ab3) — no RULE-001–013 violations; EVAL-001/002/003 hold; no regression on ATM-QA-001/ARCH-001/ATM-QA-003.
  • req-qa: FAIL — deliverable completion 5/6 (83.3%). EVAL-001 and EVAL-002 genuinely fixed with real evidence. EVAL-003's relocation is real and internally consistent, but the task's fixed-findings description claims the doc moved to docs/testing/publish-kit-agent-eval-plan.md — that path does not exist anywhere in the repo. The actual, consistently-referenced location is docs/eval/publishing/publish-kit-agent-eval-plan.md. req-qa also flagged that the branch had already advanced two further commits past 819c76a mid-review.

Independent verification (quality-mgr)

Confirmed directly against the worktree and gh pr view 507:

  • gh pr view 507 --json headRefOidb736ab39136a0d706b4da0da43eef7d3eabc969a, i.e. the PR's real current head is not 819c76a. Commits 09dd094 ("docs(eval): group publishing evaluations"), c73e347 ("docs(eval): define durable evaluation outcomes"), and b736ab3 ("docs(eval): require live publisher orchestration") landed on the branch after this QA round was dispatched, without a QA task naming them.
  • gh pr checks 507 at the current head: CI is not green — manifest-validation (ubuntu) still pending.
  • The eval plan doc's real path is docs/eval/publishing/publish-kit-agent-eval-plan.md, confirmed via git ls-tree at HEAD — matching req-qa/arch-qa, not the task's docs/testing/ description.

Verdict

FAIL — not on the merits of EVAL-001/002/003 (those are genuinely fixed), but because:

  1. Deliverable completion is 5/6 (83.3%) per req-qa — the EVAL-003 fix-description/path citation doesn't match what's actually shipped.
  2. The review target moved during the QA round: 3 undispatched commits landed on the branch, so no single reviewer round evaluated the same, final commit consistently.
  3. CI is not yet green at the actual current head (b736ab3).

Recommendation: freeze the branch, correct the EVAL-003 fix-description to cite docs/eval/publishing/publish-kit-agent-eval-plan.md, confirm CI goes green at a stable head, then dispatch a fresh QA round naming that exact commit.

@randlee

randlee commented Aug 17, 2026

Copy link
Copy Markdown
Owner Author

QA: PUBLISH-KIT-AGENT-EVAL-FIX-001-QA-2 — PASS

Reviewed: commit a2c1fb740b2acfc6f9c3577599efdbea3936215e — confirmed stable throughout the entire round (no drift), matching PR #507's actual head via gh pr view 507 --json headRefOid, worktree clean, all 12 CI checks green.

Reviewer results

  • rust-qa-agent: PASS — no in-scope Rust changes; workspace-wide cargo fmt --check, clippy -D warnings, cargo test --workspace all clean at HEAD; HEAD confirmed unchanged before/after.
  • arch-qa: PASS — merge_ready true; EVAL-001/002/003 all hold with file:line evidence; ATM-QA-001/ARCH-001/ATM-QA-003 confirmed not regressed; no new RULE-001–013 violations.
  • simplification-reviewer: PASS — EVAL-001/002/003 all confirmed fixed; relocation is a genuine git-detected rename (no orphaned duplicate); zero stale references to either the old docs-root path or the prior round's wrongly-cited docs/testing/ path; commit range traced 1:1 to sprint-doc scope, no scope creep.
  • req-qa: PASS — deliverable completion 6/6 (100%). All triage records (EVAL-001/002/003, known-findings a/b/c) independently re-verified against live file content, not assumed. EVAL-003's prior-round path-citation defect is fully corrected — all 3 referencing sites now correctly point to docs/eval/publishing/publish-kit-agent-eval-plan.md, repo-wide grep for docs/testing/ returns zero hits.

Independent verification (quality-mgr)

  • gh pr view 507 --json headRefOida2c1fb740b2acfc6f9c3577599efdbea3936215e, matching the dispatched commit exactly, both before dispatch and again just now after all 4 reviewers completed — no drift this round.
  • git status --short in the worktree: clean.
  • gh pr checks 507: 12/12 green.

Verdict

PASS — all three EVAL findings (EVAL-001, EVAL-002, EVAL-003) genuinely fixed and independently re-verified by all 4 reviewers plus quality-mgr directly. The prior round's two process defects (branch drift mid-review, wrong path citation) are both resolved: the branch is stable and the citation now matches the real shipped path.

Merge-ready pending explicit human/team-lead approval.

@randlee

randlee commented Aug 17, 2026

Copy link
Copy Markdown
Owner Author

Critical review QA: PR #507 gap vs per-channel-agent direction — commit 70d1ee1

Verdict: FAIL — deliverables 6/7 (85.7%); CI green (12/12) at stable head 70d1ee1; 0 confirmed blocking findings.

Reviewer results

  • rust-qa-agent: PASS — cargo fmt --all --check clean, cargo clippy --all-targets --all-features -- -D warnings clean. 1 minor cargo test failure (sc_lint_identity_literals, missing SC_LINT_SOURCE_ROOT) independently reproduced identically on baseline a2c1fb7 in an isolated detached worktree — pre-existing environment gap, not caused by this commit. scripts/tests/test_release_artifacts.py independently re-run in an isolated git worktree add --detach checkout of 70d1ee1 (excluding the live worktree's unrelated in-flight uncommitted changes): 27/27 pass.
  • arch-qa: PASS, merge_ready: true, 0 findings. GAP-1–5 and the EVAL-004 regression check all independently confirmed accurate/held.
  • req-qa: FAIL — 6/7 deliverables (85.7%). Blocking finding ATM-QA-001 (Important): checklist item 1 (docs/sprints/publish-kit-agent-eval-hardening.md:29-39) permits keeping the single generic publisher-channel-worker contract instead of six per-channel agent prompts only if the assumption is flagged in a completion report — no such artifact exists anywhere in the repo. GAP-1–5 and EVAL-004 regression check both independently confirmed.
  • simplification-reviewer: reported FAIL on a claimed blocking finding (SKILL.md at 70d1ee1 already referencing nonexistent per-channel agents / ref/channel-contracts.md). I independently verified this against git show 70d1ee1:.claude/skills/publishing/SKILL.md and it is false — the committed SKILL.md at 70d1ee1 has no "Channel publishers" section and makes no such references at all. The reviewer read the live worktree's uncommitted modified copy of SKILL.md and mis-attributed it to the reviewed commit. Discarded. The rest of that reviewer's pass (GAP items, internal-doc consistency, dead-code sweep) found nothing else blocking.

Why this is FAIL despite 0 surviving blocking findings

Per quality-mgr policy, PASS requires 100% deliverable completion. req-qa's ATM-QA-001 leaves deliverable 1 only partially satisfied (6/7 = 85.7%) — not a code defect, but a missing documentation artifact required by the sprint doc's own escape-hatch clause.

Important out-of-band finding (not scored against this commit, flagged for awareness)

The worktree (.../feature/publish-kit-preflight-hardening) currently has substantial uncommitted local changes that were NOT part of and are NOT reviewed by this task: modified .claude/agents/publisher.md, .claude/agents/registry.yaml, .claude/skills/publishing/SKILL.md, .github/workflows/release-preflight.yml, docs/publish-kit-requirements.md, docs/publishing-agent.md, scripts/release_artifacts.py; plus new untracked files crates-io-publisher.md, github-release-publisher.md, homebrew-publisher.md, pypi-publisher.md, scoop-publisher.md, winget-publisher.md, publisher-channel-protocol.md, .claude/skills/publishing/ref/channel-contracts.md, release/publish-channel-contracts.toml. This is exactly the per-channel-agent rework the task described as "not-yet-started" — it appears to already be in progress, uncommitted, in this same worktree. rust-qa-agent also observed the file set growing mid-review, indicating a concurrent writer in the same worktree while this review was running. Recommend serializing dev-agent writes against reviewer reads on a shared worktree path going forward, and landing/committing or stashing this in-flight work explicitly rather than leaving it silently uncommitted.

Merge-readiness pending explicit human/team-lead approval regardless of verdict.

@randlee

randlee commented Aug 17, 2026

Copy link
Copy Markdown
Owner Author

QA: PUBLISH-KIT-CHANNEL-REWORK — commit 818e8e9

Verdict: FAIL — deliverables 6/6 requirements-complete (100%), but 1 blocking architectural finding. CI green (12/12) at stable head 818e8e9, worktree clean.

Reviewer results

  • rust-qa-agent: PASS. cargo fmt --all --check clean, cargo clippy -- -D warnings clean, cargo test --workspace 701/701 passing (no Rust files touched by this commit — regression check only). Independently re-ran pytest scripts/tests/test_release_artifacts.py -q: 29/29 passed, matching comp's self-report exactly. YAML/TOML parse clean.
  • req-qa: PASS, 100% deliverable completion, 0 findings. ATM-QA-001 (the prior round's missing completion-report gap) confirmed resolved — the sprint doc now records the decision and its supersession by six named agents. EVAL-004 (candidate-tag failure = status=failed, never blocked) independently re-confirmed to hold uniformly across publisher.md and all six new channel agents via the shared publisher-channel-protocol.md, with code-level test coverage.
  • arch-qa: FAIL — 1 blocking finding.
    • ARCH-001 (RULE-003, blocking): scripts/release_artifacts.py is now 1190 lines, exceeding the 1000-line decomposition ceiling. I independently verified this — it was already 1060 lines at the parent commit 70d1ee1 (already a pre-existing violation), and this sprint's additions (channel-preflight-results, public-registry-inquiry-plan/public-registry-check-plan) pushed it further over. Not a new regression from zero, but a worsened pre-existing violation.
    • The per-channel-agent design itself is structurally sound: all six agents are uniform, no divergent logic, no secret-name duplication, non-disclosure holds (preflight workflow inspects secret names only, never values), no leftover contradictory generic-worker language.
  • simplification-reviewer: CONCERNS (non-blocking, but should be routed as a fix item). 4 of the 6 new per-channel agent files (github-release-publisher.md, homebrew-publisher.md, winget-publisher.md, scoop-publisher.md) are behaviorally-identical stubs — no channel-specific logic, differing only by name. Only crates-io-publisher and pypi-publisher have genuinely distinct logic (public-registry inquiry). Recommendation: collapse the 4 stub agents back into one generic contract-driven agent; keep crates-io/pypi as the only true specialists.

Why FAIL

One blocking structural finding (ARCH-001) is enough to fail regardless of 100% functional-deliverable completion and green CI, per standing RULE-012/structural-gate policy — a boundary/structure violation is never waved through on "code is clean/tested" grounds alone.

Recommended fix scope for next round

  1. Split scripts/release_artifacts.py into a package (manifest / channel_contracts / preflight / registry_inquiry / cli modules) to clear RULE-003.
  2. Consider simplification-reviewer's finding: collapse the 4 stub channel agents into one generic agent, keeping crates-io-publisher and pypi-publisher as the only named specialists (their public-registry-inquiry logic is genuinely distinct).

Merge-readiness pending explicit human/team-lead approval regardless of verdict.

@randlee

randlee commented Aug 17, 2026

Copy link
Copy Markdown
Owner Author

QA Verdict: ec301d6 — FAIL (Blocking) — RQA-001 still open (4th consecutive round)

Reviewers: rust-qa-agent, req-qa, arch-qa (simplification-reviewer not required for this recheck scope)

req-qa — FAIL (Blocking)

RQA-001 is not resolved. The workflow now correctly computes per-channel outcomes and emits them under new keys (repository_secret_channels, credential_liveness_channels.github/workflows/release-preflight.yml:52-84,111-153,330-350), but the consumer, _channel_preflight_result/_channel_outcome in scripts/release_manifest.py:232-290, never reads those keys. Its lookup table still maps to the old scalar keys repository_secrets / credential_liveness, which in production always hold the aggregate GitHub Actions step outcome (the repository_secrets step still does an unconditional exit 1 on any single missing/revoked secret). Net effect: a revoked SCOOP_BUCKET_TOKEN alone still marks crates_io, homebrew, winget, and scoop all failed in channel_preflight_results — the exact cross-channel contamination RQA-001 describes. The new per-channel dicts are dead data as currently consumed.

Compounding evidence: scripts/tests/test_release_artifacts.py:546-613 (test_channel_preflight_results_execute_contract_outcome_mapping) feeds the real scalar shape and asserts the contaminated result as correct (failed_channels == {crates_io, homebrew, winget, scoop}). The isolation test that does pass (:691-796) only does so by feeding an outcomes shape the real workflow never produces, so it gives false confidence and doesn't exercise the actual integration path.

Findings: ATM-QA-001 (Blocking, non-compliant), ATM-QA-002 (Important, non-compliant — regression test exercises wrong data shape), ATM-QA-003 (Minor — doc/impl mismatch, resolves automatically once code is fixed). Deliverable completion: 40% (2/5).

Required correction: point _channel_preflight_result's outcome_key mapping at repository_secret_channels / credential_liveness_channels (the actual per-channel dicts) instead of the scalar keys, and replace/add a regression test built from the exact outcomes shape the workflow's channel_results step produces (scalar + per-channel dict together), asserting an isolated scoop failure yields failed=[scoop] only.

arch-qa — PASS (superseded)

Confirmed RULE-003 resolved (950/291 lines), no circular deps/duplicate symbols, and traced the workflow's new per-channel emission as structurally correct. This PASS is superseded by req-qa's finding: the workflow-side plumbing is correct, but the consumer in release_manifest.py doesn't read it, so the structural trace didn't reach the actual defect site.

rust-qa-agent — PASS

fmt/clippy/cargo test --workspace clean at ec301d6 (no Rust files touched this round). Secondary checks: pytest scripts/tests/test_release_artifacts.py -v → 31 passed / 0 failed (unchanged count from baseline — consistent with req-qa's finding that no new passing coverage of the real isolation scenario was added). release-preflight.yml parses as valid YAML.

CI

Green except one still-pending check (sc-sha-python wheel (windows-latest)) as of this verdict; not gating given the Blocking code finding above.

Gate

FAIL — Blocking. RQA-001 (cross-channel secret/liveness contamination) remains open across 4 consecutive rounds (3aa9a23, b097d45/d26f6f2, 0cae528, ec301d6). This round is closer than prior ones (workflow-side data is now correctly shaped) but the consumer-side key mismatch means the fix has no effect in production. Merge remains blocked pending team-lead approval regardless of QA outcome.

@randlee

randlee commented Aug 17, 2026

Copy link
Copy Markdown
Owner Author

QA Verdict: 3f63757 — PASS — RQA-001 closed (5th and final round)

Reviewers: req-qa (primary, RQA-001 trace), rust-qa-agent (regression confirmation). arch-qa/simplification-reviewer not re-dispatched — their prior structural findings (RULE-003, no circular deps) are unaffected by this narrow key-mapping fix.

req-qa — PASS, 0 findings, 100% deliverable completion

Direct code trace confirms the fix is real and doesn't reintroduce contamination in a subtler form:

  • _channel_outcome/_channel_preflight_result (scripts/release_manifest.py:232-296) now reads the per-channel repository_secret_channels/credential_liveness_channels dicts first. Critically: when the dict is present but missing a specific channel's entry, it returns None (→ blocked) rather than falling back to the scalar — so the fallback path can't silently reintroduce cross-channel contamination. The scalar fallback only fires when the per-channel key is entirely absent, which never happens in production since release-preflight.yml always emits it (defaulting to {}).
  • test_channel_preflight_results_execute_contract_outcome_mapping (test_release_artifacts.py:598-637) was rewritten to use the real workflow-shaped fixture (scalar + per-channel dict co-present, matching what release-preflight.yml's channel_results step actually produces) and now asserts a Scoop-only failure yields failed_channels == {scoop} — replacing the previous assertion that had locked in the contaminated behavior as "correct."
  • test_background_workers_consume_and_gate_their_own_preflight_contracts (:752-878) adds three further independent isolation cases (crates_io secret failure, scoop liveness failure, github_release permission failure), each confirming no cross-channel bleed.
  • Workflow output shape (release-preflight.yml:52-153,322-350) confirmed unchanged/consistent with what the fixed consumer expects — no drift.

rust-qa-agent — PASS, 0 findings

fmt/clippy/cargo test --workspace clean (405 tests across the workspace, no Rust files touched this round). pytest scripts/tests/test_release_artifacts.py -v: 31 passed / 0 failed, matching comp's claim exactly.

CI

In progress at time of this verdict (Format/clippy/manifest-validation green; platform test matrix still running) — informational only, not gating this QA verdict.

Gate

PASS. RQA-001 (cross-channel secret/liveness contamination) is closed after 4 prior FAILs (3aa9a23, b097d45/d26f6f2, 0cae528, ec301d6) and this 5th round's targeted consumer-side fix. No other open findings from this review chain. Merge remains pending team-lead's approval and CI completion — QA sign-off alone does not authorize merge.

@randlee

randlee commented Aug 17, 2026

Copy link
Copy Markdown
Owner Author

QA Verdict: f1959d1 — FAIL (Blocking) — credential-location mismatch

Reviewer: req-qa

Finding: ATM-QA-001 (Blocking)

.claude/skills/publishing/ref/channel-contracts.md:19 labels CARGO_REGISTRY_TOKEN as an Actions "crates-io environment" secret. The channel-contracts.md's own declared source of truth, release/publish-channel-contracts.toml:8, classifies it under repository_secrets, not environment_secrets — and release-preflight.yml verifies it via the repository-secret presence/liveness path (same as HOMEBREW_TAP_TOKEN/WINGET_GITHUB_TOKEN/SCOOP_BUCKET_TOKEN, all correctly labeled "repository secret" in the same doc), not the environments/{name}/secrets API path used for the PyPI tokens. The environment: crates-io line in release.yml:212 is a deployment-protection gate on the publish job, not evidence the token is environment-scoped — channel-contracts.md conflates the two and contradicts its own other three entries.

All other checks passed: no stale release-preflight.yml behavior claims, no secret values exposed anywhere in the four files, and publisher-preflight.md's eval pass criteria are clear and consistent with publisher.md. Deliverable completion 75% (3/4).

Gate

FAIL — Blocking. Required correction: relabel CARGO_REGISTRY_TOKEN as a repository secret at channel-contracts.md:19.

@randlee

randlee commented Aug 17, 2026

Copy link
Copy Markdown
Owner Author

QA Verdict: 0d65e7b — PASS — credential-location finding resolved

Reviewer: req-qa (narrow recheck)

channel-contracts.md:19-21 now correctly reads CARGO_REGISTRY_TOKEN as a repository secret (matching release/publish-channel-contracts.toml:8 and the other three repository-secret entries), while cleanly preserving the separate, legitimate fact that release.yml's publish job runs under the crates-io GitHub Environment deployment gate — correctly distinguishing "where the secret is stored" from "which environment gates the publish job." No collateral disturbance to the other credential claims in SKILL.md/evals/publisher-preflight.md; no secret values introduced. Deliverable completion 100% (4/4), 0 findings.

Non-blocking note (out of this recheck's scope, flagged for awareness): RELEASING.md:61 still uses the same loosely-worded "configured in GitHub Actions crates-io environment" phrasing for CARGO_REGISTRY_TOKEN that was just corrected in channel-contracts.md. Not part of this PR's four reviewed files and not blocking, but worth a follow-up cleanup for consistency.

Gate

PASS. No open findings from this credential-facts review.

@randlee

randlee commented Aug 17, 2026

Copy link
Copy Markdown
Owner Author

QA Verdict: 040f151 — FAIL (Blocking) — undocumented deliverable

Reviewers: req-qa, arch-qa, rust-qa-agent, simplification-reviewer

req-qa — FAIL (Blocking)

The code itself is technically sound (manifest-driven Homebrew formula-track selection, genuine render/validate/commit wiring, real prerelease/stable test coverage), but the feature is entirely untraceable to any governing document: zero mentions of "prerelease," "formula," or "release_track" anywhere in docs/sprints/publish-kit-agent-eval-hardening.md, docs/publish-kit-requirements.md, CHANGELOG.md, or RELEASING.md's Homebrew operator instructions. Independently confirmed by quality-mgr via direct grep — no hits.

Additionally (ATM-QA-002, Important): comp's description claimed a "Scoop contract update" and "source-kit coverage" — neither is evidenced in the actual diff. Independently confirmed via git diff --stat 0d65e7b..040f151: no scoop-publish.yml or Scoop-manifest changes present at all, and zero "source-kit" hits anywhere in the worktree. The commit's own message (feat(publish): support tracked Homebrew formulas) matches only the Homebrew-track scope — the PR description overclaimed.

Deliverable completion: 57.1% (4/7). Required correction: either amend the sprint doc / publish-kit-requirements.md to authorize and specify the release_track manifest field and tag-based formula selection, and update CHANGELOG.md/RELEASING.md accordingly — or hold this commit out of the PR until properly scoped and documented. Separately, correct the PR/commit description to stop claiming Scoop/source-kit work not present in this diff.

arch-qa — PASS, merge_ready=true (non-blocking note)

No RULE-003 violation (970/1000 lines, ~3% headroom), no circular deps, no duplicate symbols. One Important non-blocking note: release_artifacts.py headroom is thin — recommend splitting channel-specific validators into a dedicated module before the next feature addition.

rust-qa-agent — PASS, 0 findings

fmt/clippy/cargo test --workspace clean (no Rust files touched). pytest scripts/tests/test_release_artifacts.py -v: 33 passed/0 failed, matching comp's claim exactly. Confirmed test_homebrew_workflow_selects_manifest_formula_tracks is a real, non-trivial test (asserts disjoint stable/prerelease formula sets and absence of hardcoded formula identity in the rendered workflow).

simplification-reviewer — PASS, 0 findings

Multi-formula selection is fully wired end-to-end (no dangling/half-finished branch), no duplicated manifest-parsing logic, no dead code left from the old single-formula path (zero remaining references to legacy flat keys), prerelease-tag helper is minimal/single-purpose, Scoop validation addition is proportionate scope-closing (not creep).

Gate

FAIL — Blocking. The code quality is good across all four reviewers, but ATM-QA-001 (undocumented/unauthorized deliverable against every governing doc) blocks PASS per gate policy regardless of implementation quality. This is a documentation/traceability gap, not a functional defect — the fastest path to PASS is likely a follow-up doc-only commit adding the missing sprint/requirements/CHANGELOG/RELEASING.md coverage, plus a corrected PR description.

@randlee

randlee commented Aug 17, 2026

Copy link
Copy Markdown
Owner Author

QA Verdict — d0facaf (PR #507) — FAIL (Blocking)

Scope: Recheck of d0facafcf73f76f9edd66e42a939b5dbe7ca29db, closing ATM-QA-001 (doc traceability) and ATM-QA-002 (Scoop/source-kit description overclaim) from the 040f151 round.

Reviewer results

  • req-qa — PASS, 0 Blocking. ATM-QA-001 confirmed resolved: docs/publish-kit-requirements.md:30-42, docs/sprints/fix-pr507-release-channel-runtime-checklist.md:11-14, CHANGELOG.md:9-12, RELEASING.md:165-170 all now document the release_track/binaries Homebrew feature, self-enforced by scripts/tests/test_release_artifacts.py:1344-1357. ATM-QA-002 confirmed resolved: no Scoop/source-kit overclaim in this round's description. Flagged two items it couldn't verify itself (no Bash access): live test execution and PR body wording. One Minor (ATM-QA-003): comp's claim that this "closes arch's generic multi-binary Homebrew finding" doesn't match any locatable prior arch-qa finding — description-accuracy issue only.
  • arch-qa — PASS, 0 Blocking, 1 Important (ARCH-001, restated): scripts/release_artifacts.py grew 970→977 lines (23 lines of headroom left under RULE-003's 1000-line ceiling); the prior recommendation to extract channel-specific validators into a dedicated module was not carried out. Multi-binary generalization itself (_validate_homebrew_formulas in release_manifest.py:204-258) confirmed structurally sound: single normalization site, correct legacy binarybinaries fallback, no duplicate logic, no circular imports.

Independent verification (quality-mgr, closing req-qa's two gaps)

  • Worktree clean, HEAD d0facaf matches PR head — no drift.
  • python3 -m pytest scripts/tests/test_release_artifacts.py -q36 passed, confirming comp's test-count claim.
  • gh pr view 507 --json body → no "source-kit" mentions; single Scoop mention is a factual statement about pre-existing Scoop validation, not a new-work overclaim. ATM-QA-004 closed.
  • gh pr checks 507: all three test platform jobs (macos/ubuntu/windows) are failing. Root-caused via gh run view --log-failed:
    • crates/sc-compose/tests/cli/render.rs::render_homebrew_formula_escapes_manifest_values_as_ruby_strings panics: assertion failed: formula.contains("bin.install \"bin/sc-compose\"").
    • Cause: release/homebrew/formula.rb.j2 was changed (this commit's diff) to loop over binary_paths (plural) instead of rendering a single binary_path, but the Rust test fixture at crates/sc-compose/tests/cli/render.rs:131 still supplies the old singular "binary_path": "bin/sc-compose" var. The loop has nothing to iterate, so bin.install is never rendered, and the assertion fails.
    • This is a genuine functional regression directly caused by the reviewed diff (the Homebrew template/binary-schema change), not a flaky or unrelated failure. It was not caught by req-qa or arch-qa (neither has Bash/cargo access this round) or by a Python-side test (the fixture lives in the Rust CLI crate, outside scripts/tests/). rust-qa-agent was not re-dispatched this round since its prior PASS was against the pre-change single-binary template and this recheck was scoped only to ATM-QA-001/002.

Gate reasoning

Per standing policy, CI status does not gate the QA↔dev iteration loop in the abstract — but this is not an abstract "CI is red" flag. It's a concrete, root-caused, reproducible functional regression in the exact code path this commit changed, independently confirmed by direct test execution. That makes it a real Blocking finding, on par with req-qa/arch-qa's own code-level findings, not a CI-polling concern.

Required fix: Update crates/sc-compose/tests/cli/render.rs's Homebrew formula-render fixture to supply binary_paths: ["bin/sc-compose"] (or whatever the new schema requires) instead of the stale binary_path singular field, and re-verify cargo test -p sc-compose --test cli passes locally before pushing.

Non-blocking carryover

  • ARCH-001 (Important, restated): release_artifacts.py at 977/1000 lines — recommend extracting _validate_homebrew_bundle_destinations/_validate_scoop_channel/_channel_asset_patterns before further growth.
  • ATM-QA-003 (Minor): correct the "closes arch's generic multi-binary Homebrew finding" attribution — no such arch-qa finding record exists; this is self-motivated work, not a citation of a specific prior finding.

Merge-readiness: Blocked. Requires the render.rs fixture fix, a green cargo test -p sc-compose --test cli run, and explicit human/team-lead merge approval per standing policy.

@randlee

randlee commented Aug 17, 2026

Copy link
Copy Markdown
Owner Author

QA Verdict — 325183c (PR #507) — PASS

Scope: Recheck closing the sole Blocking finding from the d0facaf round: the Homebrew CLI render fixture (crates/sc-compose/tests/cli/render.rs) was stale relative to the formula.rb.j2 template's new binary_paths/test_binary schema, causing all 3 platform test CI jobs to fail.

Verification (quality-mgr, direct)

  • Worktree clean, HEAD 325183c77324eb28603e5dca864d33c68a2195ea matches PR head — no drift.
  • git show 325183c -- crates/sc-compose/tests/cli/render.rs: exact fix applied — "binary_path": "bin/sc-compose""binary_paths": ["bin/sc-compose"], "binary": "sc-compose""test_binary": "sc-compose". Matches the required correction from the prior verdict precisely.
  • cargo test -p sc-compose --test cli182 passed, 0 failed (previously-failing render_homebrew_formula_escapes_manifest_values_as_ruby_strings now passes).
  • python3 -m pytest scripts/tests/test_release_artifacts.py -q36 passed.
  • gh pr checks 507 (opportunistic, not gating): Format check and clippy pass; test jobs still running at time of this check — not waited on, per standing no-poll policy.

No prior req-qa/arch-qa findings were reopened by this fix (mechanical fixture correction, no template/manifest/doc changes) — direct verification is sufficient; no reviewer re-dispatch needed this round.

Merge-readiness: Code/test gate clear. Pending: platform test CI jobs to finish green, and explicit human/team-lead merge approval per standing policy.

@randlee

randlee commented Aug 17, 2026

Copy link
Copy Markdown
Owner Author

QA Verdict — f26cc8a (PR #507) — FAIL (Blocking)

Scope: New deliverable — publisher output-contract fix for a Luna durable-eval-discovered ambiguity (skipped checks required to be tagged required while required was simultaneously prohibited as a checks.status value). Adds required_checks: [{kind, reason}], clarifies observed-only checks semantics, updates the durable eval plan. Diff: 3 files, 22 insertions / 9 deletions (.claude/agents/publisher.md, .claude/skills/publishing/evals/publisher-preflight.md, docs/eval/publishing/publish-kit-agent-eval-plan.md).

Blocking finding (quality-mgr, independently confirmed)

python3 -m pytest scripts/tests/test_release_artifacts.py -q1 failed, 35 passed:

FAILED scripts/tests/test_release_artifacts.py::test_publish_kit_guidance_is_manifest_driven_and_token_non_disclosing
AssertionError: assert "`required` describes a contract requirement" in publisher_text

Root cause: publisher.md's old paragraph containing the literal phrase `required` describes a contract requirement, not an observed check result... was rewritten as part of this fix (replaced with the new required_checks explanation) — but the self-enforcing doc-consistency test at scripts/tests/test_release_artifacts.py:1411 still asserts that exact literal string and was never updated.

comp's claim ("just test and diff check pass") did not catch this: just test is a report-rendering recipe (sc-compose report-render-many ...), not a test runner — it never executes pytest or cargo test. Verified via direct inspection of justfile's test: target.

Required fix: update scripts/tests/test_release_artifacts.py:1411 (and any other stale literal-string assertions referencing the old required paragraph) to match the new required_checks contract language, then actually run pytest scripts/tests/test_release_artifacts.py (not just test) locally before pushing.

Important — converged across 3 independent reviewers (arch-qa, simplification-reviewer, req-qa)

.claude/agents/publisher-channel-protocol.md — the sole schema document every background channel worker (crates-io-publisher.md, pypi-publisher.md, homebrew-publisher.md, winget-publisher.md, scoop-publisher.md, github-release-publisher.md) delegates to verbatim — was not updated in this commit. Its Result JSON schema (lines 27-39) still has no required_checks field, even though publisher.md:88-91 now instructs "the worker" to populate required_checks. The ambiguity this commit set out to resolve at the aggregation layer is still live at the layer that actually produces the JSON. req-qa treats this as contributing to non-compliance (deliverable completion 75%, cross-doc conflict unresolved); arch-qa/simplification-reviewer rate it non-blocking on its own but recommend fixing before merge.

Required fix: add required_checks: [{kind, reason}] to publisher-channel-protocol.md's Result schema (or explicitly state that publisher, not the worker, synthesizes this field from contract knowledge), and update its prose at lines 18-20 accordingly.

Important (req-qa)

docs/sprints/publish-kit-agent-eval-hardening.md's Validation Evidence section (status: complete) stops at commit 0cae528 and doesn't record this fix or the ambiguity it discovered/resolved, despite the sprint being marked complete.

Required fix: add a Validation Evidence entry for f26cc8a.

Minor

  • simplification-reviewer: required_checks[].reason is documented as free text but every instance across all 3 files hardcodes the same literal not_run_after_invalid_release_authorization — consider narrowing to the single-cause representation actually used, non-blocking.
  • req-qa self-flagged its own tool-access gap (no Bash/git); did not affect the substance of its findings, all independently corroborated.

Clean

  • rust-qa-agent: PASS, 0 findings. Full workspace green (182/182 CLI tests, 33/33 binaries, clippy clean, fmt clean) — expected since no Rust source was touched.
  • No regression in EVAL-001/002/004 semantics (all three independently re-confirmed intact by req-qa).
  • scripts/release_artifacts.py re-confirmed at 977/1000 lines, no drift (arch-qa).

Gate reasoning

One genuine, independently-executed test regression (Blocking) plus a 3-way-converged unresolved cross-document contract gap and a stale sprint-doc closure record (both Important) put this well below the 100% deliverable-completion bar required for PASS.

Merge-readiness: Blocked pending: (1) fix the stale pytest assertion and confirm pytest scripts/tests/test_release_artifacts.py is green, (2) extend the required_checks fix to publisher-channel-protocol.md, (3) update the sprint doc's Validation Evidence, (4) explicit human/team-lead merge approval.

@randlee

randlee commented Aug 17, 2026

Copy link
Copy Markdown
Owner Author

QA Verdict — a847d58 (PR #507) — PASS

Scope: Fix-round closing all 3 findings from the f26cc8a round: the Blocking stale pytest assertion, the Important publisher-channel-protocol.md schema gap, and the Important stale sprint-doc Validation Evidence.

Reviewer results

  • req-qa — PASS, 0 findings, 100% deliverable completion. All three prior findings verified closed with file:line evidence: publisher-channel-protocol.md:41 now defines required_checks with consistent ownership prose (worker populates, publisher supplies the reason string); the sprint doc's Validation Evidence now records f26cc8a; the pytest assertions now check live schema text instead of the removed literal. Spot-check of all six per-channel worker files found no new inconsistency (none define an independent schema — all delegate verbatim to publisher-channel-protocol.md).
  • arch-qa — PASS, 0 Blocking, 1 Important. required_checks ownership ambiguity resolved cleanly; scripts/release_artifacts.py confirmed unchanged at 977/1000 lines. One doc-accuracy finding (below).

Independent verification (quality-mgr)

  • Worktree clean, HEAD a847d581141d90767fc9978cce2c4489f7db78e5 matches PR head — no drift.
  • python3 -m pytest scripts/tests/test_release_artifacts.py -q36 passed, confirming the Blocking finding from last round is genuinely fixed.
  • git diff --stat f26cc8a..a847d581 → exactly the 3 stated files (.claude/agents/publisher-channel-protocol.md, scripts/tests/test_release_artifacts.py, docs/sprints/publish-kit-agent-eval-hardening.md), no scope creep.
  • gh pr checks 507 (opportunistic, not gating): Format/clippy/manifest-validation green; platform test jobs pending at check time, not waited on.

Non-blocking follow-up (Important, arch-qa, independently confirmed)

docs/sprints/publish-kit-agent-eval-hardening.md:105-109's Validation Evidence text reads "Commit f26cc8a... The publisher and every role-specific channel worker now share that schema" — but f26cc8a did not update publisher-channel-protocol.md (that landed in this commit, a847d581). Confirmed via direct diff. The attribution should be corrected to credit a847d581 for the schema-sharing closure, but this doesn't reopen the checklist item and doesn't block this round.

Merge-readiness: Code/test/doc gate clear. Pending: platform test CI jobs to finish green, the doc-attribution follow-up (non-blocking, can land in a future commit), and explicit human/team-lead merge approval.

@randlee

randlee commented Aug 17, 2026

Copy link
Copy Markdown
Owner Author

QA verdict: PR #507 @ 747d513 (publisher 1.6.3) — FAIL

Reviewed as a new deliverable (full standard reviewer set: req-qa, arch-qa, rust-qa-agent, simplification-reviewer), against the branch feature/publish-kit-preflight-hardening, worktree sc-compose-worktrees/feature/publish-kit-preflight-hardening.

Review chain note: review was dispatched against 19d0726 (publisher 1.6.2 — "closed-world fixtures" + "named-recipient routing"). Mid-review, comp pushed 747d513 (1.6.3 — "forbid inferred synthetic evidence"), which is now the actual PR head. I independently diffed 747d513 and confirmed it only tightens the closed-world/no-inference language (adds "workflow" to the forbidden-invented-facts list; adds a new "don't derive a check from another fixture fact" rule) — it does not touch any of the lines implicated in the finding below. All findings below were re-verified against current HEAD (747d513479103552ea03d9077d245831b8ae2292, matches PR head, worktree clean).

Reviewer results

  • req-qa: FAIL. 2 Blocking, 3 Important/Minor. deliverable_completion_percent: 42.9.
  • arch-qa: FAIL. 1 Blocking, 1 Important.
  • simplification-reviewer: CONDITIONAL. Same routing defect (classified as redundant-path) + 1 minor (brittle literal-wrap test assertions).
  • rust-qa-agent: PASS, 0 findings. No Rust source in scope for this commit (docs/agent-contract + Python test only). cargo fmt --all --check clean, cargo clippy --all-targets --all-features -- -D warnings clean, cargo test -p sc-compose --test cli 182/182, cargo test --workspace all green.

Blocking finding (3 independent reviewers converged)

Completion-routing contradiction within publisher.md.
publisher.md:38-40 (Output Format) now reads: "Send the assignment's named recipient one concise ATM completion message... Production assignments name team-lead; evaluation assignments may name their evaluator." — a real, specific behavior change, not a naming tweak.

But three other sections of the same file were left unchanged and still hardcode an unconditional team-lead recipient:

  • publisher.md:~113-114 (Non-Negotiable Rules) — "report only its channel and sanitized diagnostic to team-lead"
  • publisher.md:~254-256 (Error Handling) — "send the sanitized failure to team-lead"
  • publisher.md:~279-283 (Completion Report) — "Send team-lead the release tag and commit plus the complete per-channel JSON result set"
  • publisher.md:18 (Inputs) — still states assignments are received from team-lead only, never reconciled with an evaluator-originated eval assignment

A publisher instance following the document literally gets two contradictory instructions for who receives an evaluation assignment's completion/failure report — exactly the scenario 1.6.2/1.6.3 was supposed to fix. The new regression assertions in test_release_artifacts.py (lines ~1425-1428) only assert the Output Format language is present; none assert anything about the Completion Report section, so they cannot catch (and did not catch) this contradiction.

Required fix: update the Non-Negotiable Rules, Error Handling, and Completion Report sections (plus the Inputs section's origin language) to reference the assignment's named recipient, consistent with Output Format — and add a regression assertion that the Completion Report section does not contain an unconditional hardcoded team-lead sentence bypassing the named-recipient contract.

Important findings

  1. (arch-qa, ARCH-002) .claude/skills/publishing/preflight.xml.j2:40 and publish.xml.j2:39 hardcode "Send team-lead a fenced JSON completion envelope" with no recipient/evaluator template variable — these are the actual templates that render assignments for the eval harness (evals/publisher-preflight.md, publisher-recovery.md), which use disposable evaluator identities. The new "evaluation assignments may name their evaluator" language currently has no mechanism to take effect for real eval runs; it's presently dead/misleading in that path. Either thread a recipient variable through the templates, or narrow the publisher.md claim until that plumbing exists.
  2. (req-qa, ATM-QA-002) docs/sprints/publish-kit-agent-eval-hardening.md remains status: complete; its Validation Evidence trail stops at f26cc8a. Neither the closed-world/named-recipient deliverable, commit 19d0726/747d513, nor the 1.6.3 version bump is recorded. Not independently blocking, but should be closed alongside the routing fix.
  3. (simplification-reviewer) New regression assertions in test_release_artifacts.py (~1426-1427, 1441) match full line-wrapped literal spans (e.g. embedded \n mid-sentence) rather than minimal content-bearing phrases — a harmless rewrap would break them. Non-blocking; flag for the same fix pass.

Independent verification (quality-mgr, direct)

  • python3 -m pytest scripts/tests/test_release_artifacts.py -q at current HEAD (747d513): 36 passed — confirms comp's claim, independently re-run.
  • Worktree/branch drift: none — git status --short clean, HEAD = 747d513479103552ea03d9077d245831b8ae2292, matches gh pr view 507 --json headRefOid.
  • scripts/release_artifacts.py line count: unchanged at 977/1000 (arch-qa confirmed, RULE-003 headroom stable).
  • CI (opportunistic, not gating): Format check, clippy, manifest-validation all pass; the three test (*) matrix jobs are still pending at time of this check — not treated as blocking the verdict, will be rechecked at merge time.
  • No scope creep detected by any reviewer; diff stays tightly scoped to the two stated behaviors plus required version/test sync.

Gate

FAIL — 1 Blocking finding (converged across req-qa, arch-qa, simplification-reviewer), independently corroborated by direct reading of current HEAD. Not merge-ready. Routing this to comp now; will re-review the fix commit against this exact contradiction plus the two Important items above.

@randlee

randlee commented Aug 17, 2026

Copy link
Copy Markdown
Owner Author

QA verdict: PR #507 @ 2089c5c (publisher 1.6.5, "align eval recipients and fixtures" + "render eval recipient contracts") — FAIL (documentation-completeness gate only)

Covers two commits reviewed together: 1577a0c (the fix round, reviewed below) and 2089c5c (pushed immediately after, while this verdict was being drafted — adds explicit recipient values to both eval docs plus a new test test_publishing_task_templates_render_recipient_contract that renders both .xml.j2 templates with Jinja2+StrictUndefined and asserts the rendered XML's <recipient> element and completion-step text match the supplied value). 2089c5c is now the actual PR head; drift-checked clean (git status --short empty, HEAD matches gh pr view 507 --json headRefOid).

Narrow recheck dispatched against the exact FAIL findings from the 747d513 round: req-qa (routing consistency + sprint doc) and arch-qa (routing + eval-harness template plumbing).

Both prior Blocking/Important findings: CONFIRMED CLOSED

  • req-qa: independently re-read the full publisher.md — Inputs (:18-22), Non-Negotiable Rules (:127), Error Handling (:269), and Completion Report (:294) now all route through "the named recipient"/"the named coordinator". Only 2 remaining team-lead mentions (lines 20, 40) are the intended production-default explanatory form, not stray hardcodes. Closed.
  • arch-qa: independently confirmed the same, plus verified preflight.xml.j2 and publish.xml.j2 now declare recipient as a required_variable, render <recipient>{{ recipient }}</recipient>, and step c sends to {{ recipient }} instead of a hardcoded team-lead. Closed. merge_ready: true from arch-qa's own gate (before the sprint-doc gap below is factored in).
  • New regression assertion assert "Send \team-lead`" not in publisher_text(test file, ~line 1432) scans the whole file — covers Completion Report, the actual site of the original violation, not just Output Format. Verified no false-negative risk against the two legitimateteam-lead` occurrences.

Remaining gap (why this isn't a clean PASS)

(Blocking per quality-mgr's 100%-deliverable-completion standing rule, not a functional defect)
docs/sprints/publish-kit-agent-eval-hardening.md Validation Evidence still stops at commit 747d513; commit 1577a0c did not append a paragraph documenting the recipient-routing consistency fix, the version bump to 1.6.5, or the new "Synthetic-evaluation response checklist" section. Repo-wide grep (req-qa) found no other doc mentioning this commit either. The doc remains status: complete while its own evidence trail is stale — deliverable_completion_percent: 75%.

Required fix: append a Validation Evidence paragraph for 1577a0c covering the routing-consistency fix, the 1.6.5 version bump, and the new synthetic-evaluation checklist.

Minor (non-blocking, batch with the doc fix)

publisher.md's Synthetic-evaluation response checklist item 1 requires data.commit to match the fixture, but neither JSON envelope schema example in the same file (~:45-51, :65-71) formally defines a data.commit field, even though Completion Report says commit is sent. Add data.commit to the schema examples or note it's carried outside the shown envelope.

2089c5c note

This commit substantively strengthens arch-qa's soft note from the 1577a0c recheck (the eval docs didn't previously pin down whether recipient actually renders correctly end-to-end) with real render-time proof via a new Jinja2+XML-parse test. It does not touch publisher.md, so the sprint-doc gap and the data.commit schema-example gap below are both still open and unaffected by this commit.

Independent verification (quality-mgr, direct)

  • python3 -m pytest scripts/tests/test_release_artifacts.py -q at 2089c5c: 37 passed.
  • Worktree/HEAD: git status --short clean, HEAD = 2089c5cd8c44354cb27dd0d35b7f6ac86a811ace, matches PR head.
  • scripts/release_artifacts.py: 977/1000 lines, unchanged.
  • CI (opportunistic) at 2089c5c: Format check and clippy pass; manifest-validation and the test matrix still running — not gating, will recheck at merge.

Gate

FAIL — 1 Blocking (sprint-doc completeness gap, standing 100%-completion rule), 1 Minor. The functional defect from the prior round (routing contradiction) is fully resolved and independently confirmed by two reviewers. This is effectively a documentation-only close-out away from PASS.

@randlee

randlee commented Aug 17, 2026

Copy link
Copy Markdown
Owner Author

QA verdict: PR #507 @ cbc1362 (publisher 1.6.5 doc close-out) — FAIL (CI regression, independently found)

req-qa's final recheck confirmed 100% deliverable completion, zero open Blocking/Important findings on the documentation/content side: the sprint-doc Validation Evidence paragraph for 1577a0c is adequate, publisher.md's two JSON envelope examples now both include data.commit, and the eval-doc rewording ("the separate named evaluator/coordinator identity as recipient, not the evaluated publisher teammate") is a genuine, coherent fix, consistent with the .xml.j2 templates. One new cosmetic Minor was raised (a vacuous test assertion at test_release_artifacts.py:1607 that only checks a hardcoded fixture string against itself, enforcing nothing) — non-blocking.

However, an opportunistic CI check surfaced a real, root-caused regression that overrides the otherwise-clean review:

manifest-validation (ubuntu) failed at cbc1362 (run 32082425533), cascading to skip python-wheels, sc-sha-python wheel, and test. Root cause (gh run view --log-failed):

ImportError while importing test module '.../scripts/tests/test_release_artifacts.py'.
scripts/tests/test_release_artifacts.py:13: in <module>
    from jinja2 import Environment, StrictUndefined
E   ModuleNotFoundError: No module named 'jinja2'

The test_publishing_task_templates_render_recipient_contract test added in 2089c5c imports jinja2 to render .xml.j2 templates for the recipient-contract check. This passes locally (and passed in every prior direct-verification run I did in this worktree) only because jinja2 happens to be present in the ambient dev/worktree Python environment — it is not an actual project dependency. .github/workflows/ci.yml:70-71 installs only python3 -m pip install pytest for the manifest-validation job; there is no requirements.txt/pyproject.toml covering scripts/tests/ that pulls in jinja2. On a clean CI runner the import fails immediately, so the entire test module fails to collect — meaning all 37 tests in this file, not just the new one, do not run in CI, despite comp's "37 passed" claim (which reflects the local worktree, where jinja2 is coincidentally installed) and despite just test not catching it (confirmed earlier this sprint that just test is a report-render recipe, not a test runner).

Required fix: add jinja2 to the CI install step (.github/workflows/ci.yml:71, e.g. python3 -m pip install pytest jinja2), or declare it in a scripts/tests requirements file, or avoid the dependency in the test. Then re-push and confirm manifest-validation goes green.

Independent verification (quality-mgr, direct)

  • python3 -m pytest scripts/tests/test_release_artifacts.py -q locally: 37 passed (this environment has jinja2 installed — does not reflect what CI actually runs, which is the point of this finding).
  • Worktree/HEAD: clean, HEAD = cbc13623b0007daefa0e1d2cf2fa3ebd99cc252e, matches PR head.
  • CI (opportunistic, this time genuinely blocking per the concrete-root-caused-regression exception to the no-poll policy): Format check and clippy pass; manifest-validation fails as above; python-wheels, sc-sha-python wheel, test all skipped as a direct consequence.

Gate

FAIL — the documentation/content side of this round is fully closed (req-qa: 100% complete, 0 Blocking/Important), but a genuine CI-breaking regression was independently found and root-caused. Not merge-ready until the CI install step (or the test's dependency) is fixed and the pipeline goes green.

@randlee

randlee commented Aug 18, 2026

Copy link
Copy Markdown
Owner Author

QA verdict: PR #507 @ 0e55e67 (CI dependency fix) — PASS

Closes the sole remaining item from the cbc1362 FAIL: .github/workflows/ci.yml:70-71's install step is now python3 -m pip install pytest jinja2 (was pytest only), which was the exact root cause of manifest-validation's collection failure. The commit also drops the vacuous test assertion flagged as Minor in that same verdict (test_release_artifacts.py:1607, assert not context["recipient"].startswith("publisher-eval-"), which only checked a hardcoded fixture string against itself).

Status of the full review chain on this deliverable (19d0726747d5131577a0c2089c5ccbc13620e55e67)

  • Content/doc completeness: 100%, confirmed by req-qa's final recheck (0 open Blocking/Important; sprint-doc Validation Evidence entry, data.commit schema fields, and eval-doc recipient/identity wording all closed).
  • Routing contradiction (original Blocking, 747d513 round): confirmed closed by req-qa + arch-qa independently.
  • Eval-harness template plumbing (Important, 747d513 round): confirmed closed by arch-qa, later strengthened with a real render-time test (2089c5c).
  • CI regression (cbc1362, independently found via opportunistic CI check): root-caused to a missing jinja2 CI dependency; fixed here with the correct one-line change.
  • Minor cosmetic finding (vacuous test assertion): dropped in this commit.

No open findings remain across the entire chain.

Independent verification (quality-mgr, direct)

  • Worktree/HEAD: clean, HEAD = 0e55e67f7259e6675ee9ef76b8ce7b78646eec70, matches PR head.
  • python3 -m pytest scripts/tests/test_release_artifacts.py -q: 37 passed.
  • CI: fresh push, no checks reported yet at time of this verdict (not gating per standing policy — will be confirmed green opportunistically before any merge).
  • scripts/release_artifacts.py: 977/1000 lines, unchanged.

Gate

PASS. Merge-readiness still requires CI to actually go green on this commit (in particular manifest-validation, which was the failing job) and human/team-lead merge approval per standing policy — but no further QA rounds are needed for this deliverable.

@randlee

randlee commented Aug 18, 2026

Copy link
Copy Markdown
Owner Author

QA verdict: PR #507 @ 823ccd5 (test-fidelity fix: render via real CLI) — PASS

Narrow recheck against this single commit only (nothing else reopened; the rest of the chain remains closed per prior rounds).

What changed: test_publishing_task_templates_render_recipient_contract (in scripts/tests/test_release_artifacts.py) previously rendered .claude/skills/publishing/preflight.xml.j2/publish.xml.j2 with a hand-built Python jinja2.Environment(undefined=StrictUndefined) — a generic third-party Jinja2 environment, not sc-compose's actual rendering pipeline. This commit switches it to the pre-existing render_release_template() helper (already used by 2 other tests in the same file), which shells out to the real sc-compose CLI (cargo run --bin sc-compose -- render --mode file ...). The jinja2 CI dependency (added in 0e55e67 specifically to make the old approach work in CI) is now removed, reverting .github/workflows/ci.yml's install step back to pytest only.

Reviewer results

  • req-qa: PASS, 0 findings, deliverable_completion_percent: 100. Confirmed: recipient-contract assertions preserved verbatim; removal of the old .split("---", 2)[2] frontmatter-stripping step is correct (sc-composer's file-mode render output is frontmatter-free by design — independently corroborated by two other pre-existing passing tests in the same file that already consume unstripped CLI stdout); no doc references the old jinja2-based approach requiring an update.
  • arch-qa: PASS, 0 findings, merge_ready: true. Confirmed no crate-boundary violation (subprocess invocation of the compiled binary from scripts/tests/ isn't a Cargo/package dependency edge); confirmed precedent (this reuses an established in-file helper pattern, not a new one); confirmed no orphaned jinja2 imports remain anywhere in the repo after removal.

Net effect: this is a genuine improvement, not just a fix — the recipient-contract test now exercises sc-compose's actual composition/delimiter pipeline instead of a generic Jinja2 stand-in, and does so without a CI-only dependency gap.

Independent verification (quality-mgr, direct)

  • Worktree/HEAD: clean, HEAD = 823ccd5b373f1d88855f97542fb0f74437319c22, matches PR head.
  • CI (opportunistic): Format check, clippy, and manifest-validation (the job that was previously failing) all pass. test (ubuntu/macos/windows) still pending at time of check — not gating.

Gate

PASS. No open findings anywhere across the full review chain on this deliverable. Merge-readiness still requires the remaining pending CI jobs to finish green and team-lead's approval.

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