From 992dfa2598c748f1d6379643cdf9a936b7eb9a3f Mon Sep 17 00:00:00 2001 From: James Estevez Date: Thu, 14 May 2026 09:48:07 -0700 Subject: [PATCH 1/4] docs(triage/v5): add CCI v5 triage evidence pack Pushable evidence from a triage of 142 open issues in SFDO-Tooling/CumulusCI: - README.md: methodology, results table, AI-assistance disclosure, spec basis, Tranche 1 candidate list - proposals.md: per-issue classification + proposed pass-1 action for all 142 issues - repro-results.{md,csv}: narrative + machine-readable evidence for the 115 issues that went through the reproducibility pass (80 REPRODUCED, 23 NOT-REPRODUCED, 11 INCONCLUSIVE, 1 duplicate) - themes.md: 12 theme clusters, duplicate detection, Tranche 1 list Phase 1 GitHub state mutations (gh issue close / label) are NOT executed by this PR. Maintainer approval gate applies. --- docs/triage/v5/README.md | 126 + docs/triage/v5/proposals.md | 247 ++ docs/triage/v5/repro-results.csv | 116 + docs/triage/v5/repro-results.md | 4464 ++++++++++++++++++++++++++++++ docs/triage/v5/themes.md | 528 ++++ 5 files changed, 5481 insertions(+) create mode 100644 docs/triage/v5/README.md create mode 100644 docs/triage/v5/proposals.md create mode 100644 docs/triage/v5/repro-results.csv create mode 100644 docs/triage/v5/repro-results.md create mode 100644 docs/triage/v5/themes.md diff --git a/docs/triage/v5/README.md b/docs/triage/v5/README.md new file mode 100644 index 0000000000..03ea1d7c84 --- /dev/null +++ b/docs/triage/v5/README.md @@ -0,0 +1,126 @@ +# CCI v5 Issue Triage Evidence (May 2026) + +This directory contains the results of an AI-assisted triage of the 142 +open issues in `SFDO-Tooling/CumulusCI` as part of preparation for +CumulusCI v5. + +## Contents + +| File | Purpose | +| ---------------------------- | ------------------------------------------------------------------------------------------- | +| `README.md` | This file. | +| `proposals.md` | Per-issue classification + proposed pass-1 action (kept-open, close-with-reason, etc.). | +| `repro-results.md` | Per-issue narrative evidence for the 115 issues that went through the reproducibility pass. | +| `repro-results.csv` | Machine-readable matrix backing the narrative (one row per issue). | +| `themes.md` | Theme clusters, duplicate detection, and Tranche-1 candidate list. | +| `fix-sketches/issue_NNNN.md` | One fix sketch per `REPRODUCED` issue not slated for an immediate fix-PR. | + +## Methodology + +1. **Classification**: All 142 open issues were evaluated against a + hygiene policy covering staleness (>24mo no activity), missing + reproducer information, and known-resolved status. Output: + `proposals.md`. + +2. **Theme clustering**: Issues were grouped into 12 themes + (`packaging`, `metadata-etl`, `cli`, `bulkdata`, `dependencies`, + `ci-integration`, `robotframework`, `scratch-org-config`, `auth`, + `keychain`, `docs`, `python-modernization`) with cross-theme + duplicate detection. Output: `themes.md`. + +3. **Reproducibility pass**: 115 of 142 issues were verified in + isolated git worktrees against CumulusCI v4.10.0 or `origin/dev`. + The 27 `closed:pre-v4.0.0` issues were excluded from the repro pass + (they're tagged separately for close). Verdicts: + + | Verdict | Count | + | ---------------------------------- | ------: | + | `REPRODUCED-on-v4.10.0` | 56 | + | `REPRODUCED-on-dev` | 24 | + | `NOT-REPRODUCED-on-v4.10.0` | 18 | + | `NOT-REPRODUCED-on-dev` | 5 | + | `INCONCLUSIVE-needs-*` (kept-open) | 11 | + | `closed:duplicate-of-#3544` | 1 | + | **Total** | **115** | + + Output: `repro-results.md`, `repro-results.csv`. + +4. **Failing-test capture**: For each `REPRODUCED-on-*` issue with a + code-level assertion target, a `@pytest.mark.xfail(strict=False)` + regression test was committed to `cumulusci/tests/triage/`. The + xfail marker is intentionally non-strict so a bug that resolves + independently surfaces as `XPASS` rather than as a CI failure. + Fix-PRs remove the marker. + +5. **Fix sketches**: For every `REPRODUCED` issue not slated for an + immediate fix-PR, `fix-sketches/issue_NNNN.md` captures the + proposed approach, target `file:line`, size estimate, and risk. + +6. **Tranche 1 fix PRs**: A small slate of recent regressions + (`#3852`, `#3854`, `#3886`, `#3938`, `#3939`) receives immediate + fix-PRs against `dev` with the xfail marker removed and a + corresponding passing unit test. + +## AI assistance disclosure + +This triage was conducted with AI assistance. Specifically: + +- Initial classification, theme clustering, and reproducibility + verification were performed by Claude Opus 4.7 with isolated + subagents. +- Each subagent ran in a dedicated `git` worktree with hard-coded + constraints: no source mutation outside scope, no live-org access, + no scratch-org creation outside DevHub-aliased orgs, no GitHub + state mutation, no `git push`. +- The xfail tests are intentionally `strict=False`; an `XPASS` + surfaces a verdict that no longer holds (e.g. the bug was fixed + independently) rather than crashing CI. +- All proposed pass-1 mutations against GitHub issues (close / + label) are gated on explicit maintainer approval before execution + — they are NOT executed by this PR. + +The full session evidence (subagent dispatch logs, anomaly notes, +intermediate CSV consolidation steps) lives in a separate local +branch and is intentionally not included here. + +## Spec basis + +Pass-1 vocabulary used in `proposals.md`: + +- `closed:stale-24mo` — no activity >24 months, no maintainer label. +- `closed:pre-v4.0.0` — body declares CumulusCI 3.x; no reporter + reconfirmation against v4+. +- `closed:missing-fields` — issue lacks repro / cci-version / + expected behaviour. +- `closed:pr-resolved-#NNNN` — fix already on dev via specified PR. +- `closed:not-reproducible-on-v4.10.0` — bug not reproducible on + v4.10.0; close with explicit verdict. +- `closed:not-reproducible-on-dev` — bug not reproducible on `dev`; + close with explicit verdict. +- `closed:feature-implemented` — feature ask already shipped. +- `closed:duplicate-of-#NNNN` — pointer to canonical issue. +- `closed:pr-pending-#NNNN` — fix exists in an open PR ready to + land; close once that PR merges. +- `kept-open` — confirmed REPRO; rescue from close. + +Pass-2 vocabulary (selected): `target:v4-patch`, `v5-candidate:yes|no`, +`severity:{critical,major,minor,trivial}`, `area:{packaging,bulkdata, +cli,robotframework,...}`. + +## Tranche 1 candidate list + +Recent regressions slated for immediate fix-PR against `dev`: + +| Issue | Title | Estimated diff | +| ----- | ------------------------------------------------------------ | -------------- | +| #3852 | sarge cosmetic warning under Python 3.13 | ~5-15 LOC | +| #3854 | extract-validation regression from PR #3741 | ~5-10 LOC | +| #3886 | `cumulusci[select]` warning fires at every `extract_dataset` | ~3-5 LOC | +| #3938 | (see fix-sketches/issue_3938.md) | TBD | +| #3939 | (see fix-sketches/issue_3939.md) | TBD | + +Two adjacent fix-already-on-dev issues that close without a fix-PR +needed here: + +- `#3610` → `closed:pr-resolved-#3681` (already on dev). +- `#3910` → `closed:pr-pending-#3911` (PR #3911 ready to land). diff --git a/docs/triage/v5/proposals.md b/docs/triage/v5/proposals.md new file mode 100644 index 0000000000..1ad054bab0 --- /dev/null +++ b/docs/triage/v5/proposals.md @@ -0,0 +1,247 @@ +# CCI Issue Triage Proposals + +Classification matrix for the 142 open issues, with proposed pass-1 actions. +Mutations are gated on explicit maintainer approval; NONE of the GitHub state changes +described here are executed by this PR. + +## Class summary + +By proposed-pass1: + +- kept-open: 70 +- closed:stale-24mo: 30 +- closed:pre-v4.0.0: 28 +- closed:not-reproducible-on-v4.10.0: 6 +- closed:feature-implemented: 4 +- closed:missing-fields: 1 +- closed:pr-resolved-#3361: 1 +- closed:pr-resolved-#3651: 1 +- closed:pr-resolved-#3681: 1 + +By risk: + +- low: 97 +- medium: 0 +- medium-high: 45 +- high: 0 + +## Repro pass updates (Task 2.5c) + +Two rounds of subagents verified 98 of 142 open issues against v4.10.0 +source on `origin/main` (see `repro-results.md` and `repro-results.csv`): + +- **Round 1**: packaging + metadata-etl (45 issues, subagents 1-6). +- **Round 2**: cli + bulkdata + dependencies + ci-integration (53 issues, subagents 7-12). + +This file integrates Round 1 + Round 2 verdicts. Proposed-pass1 was changed for **62 rows**; **24 rows** were confirmed by repro and marked in `rule-rationale`. Untouched themes (44 issues): `robotframework`, `scratch-org-config`, `auth`, `keychain`, `docs`, `python-modernization`, plus all `closed:pre-v4.0.0` rows. + +### New proposed-pass1 vocabulary introduced by repro pass + +The repro pass introduces three pass1 values that are not yet in the spec section 7 vocabulary; they are proposed here for spec amendment in the closeout: + +- `closed:not-reproducible-on-v4.10.0`: bug already fixed (or feature already shipped) on v4.10.0; close with explicit verdict citation rather than the generic stale-24mo template. +- `closed:feature-implemented`: feature ask already shipped (separate from PR-resolved because no specific PR can be cited in the close comment, just a confirmation that the requested behaviour exists). +- `closed:pr-resolved-#NNNN`: same as the existing spec value but reused for repro-discovered fixes (e.g. #3283 -> PR #3361, #3605 -> PR #3651). The PR was found via repro, not via GitHub linkage. + +### Repro pass cross-cutting findings (relevant to Phase 2 execution and v5 planning) + +- **Same-file pairs / triplets** (worth bundling as one fix epic each): + - #2153 + #3471: both touch `cumulusci/tasks/github/merge.py` (`MergeBranch`). + - #3506 + #3570 + #3663: flow `when:` evaluator in `cumulusci/core/flowrunner.py:510-516` and missing propagation in the flow branch (lines 660-697). + - #3349 + #2013: shared root cause in `MappingStep` table-naming (uses `sf_object` not `table`). + - #3603 + #3604 + #3619: dependency-resolution UX gaps (404 leak, missing pin password env, missing sfdx-project.json writeback). +- **Recent regressions still active** (Tranche 1 candidates for v4.10.x patch): + - #3852 (sarge cosmetic, Py 3.13). + - #3854 (PR #3741 / commit `2c5d0056e` introduced a still-active validation error in `cumulusci/tasks/bulkdata/extract.py:371-374`). + - #3938, #3939 (already in Round 1; reaffirmed REPRO). +- **Wrong-repo report**: + - #3612: `cci robot ...` issue belongs in `cci-vscode`, not cci core. Recommend new spec vocab `closed:wrong-repo` and a one-line "filed-in-wrong-repo" close comment. +- **Cross-room duplicate confirmation** (Round 1): + - #3762 -> closed:duplicate-of-#3544 (Cluster A canonical). +- **Unchanged INCONCLUSIVE-needs-X** (kept-open with informational note in narrative; no proposals.md row change required): + - #3418 + #3717: both `INCONCLUSIVE-needs-cumulus-actions-workflow` (cci has zero GitHub Actions env auto-detect; structural gap). + - #3542: needs 2GP CI pipeline. + - #3936: flaky-network read-timeout; intermittent. +- **Adjacent-finding** surfaced but not blocking: + - `TypeError` in `cumulusci/utils/__init__.py:229` when `namespaced_org=True` is supplied against a project with `namespace=None` (Round 1). + - `cumulusci[select]` warning at module-import time in `cumulusci/tasks/bulkdata/select_utils.py` (#3886, fires on every `extract_dataset`). + +### Approval-gate hint + +Most `closed:stale-24mo -> kept-open` rescues warrant a `target:v4-patch` or `v5-candidate` pass2 label, but those columns were left unchanged here so the next user gate can attach labels deliberately. + +## Round 3 updates (2026-05-13 → 2026-05-14) + +Round 3 added 17 issues across 6 themes (`robotframework`, `scratch-org-config`, `auth`, `keychain`, `docs`, `python-modernization`) against `origin/dev` (NOT v4.10.0). Each updated row in the proposal table is annotated with `+repro Task 2.5c R3: {verdict}`. + +- **12 REPRODUCED-on-dev**: #675, #710, #773, #2500, #3407, #3464, #3541, #3602, #3849, #3873, #3910, #3955. +- **5 NOT-REPRODUCED-on-dev**: #987, #2126, #2667, #3306, #3610. + +R3 rescues from prior closure verdicts: + +- **From `closed:missing-fields` (5 issues)**: + - `#2126`, `#2667` → `closed:stale-24mo` (NOT-REPRO on dev; ancient). + - `#2500` → `kept-open` (REPRO; documentation gap, not stale). + - `#3306` confirmed kept-open (NOT-REPRO, but real reporter). + - `#3873` confirmed kept-open (REPRO; feature ask, not stale). +- **From `closed:stale-24mo` (5 issues)**: + - `#710`, `#773` → `kept-open` (REPRO on dev; surface as v5 candidates). + - `#987` confirmed `closed:stale-24mo` (NOT-REPRO; ancient). + - `#675` confirmed `closed:stale-24mo` (REPRO but robot-runner-only with no python test path). + - `#3407` confirmed kept-open. +- **New PR-resolved (1 issue)**: + - `#3610` → `closed:pr-resolved-#3681` (fixed on dev by commit 84389d998; regression tests already on dev). + +Notable R3 findings (also captured in repro-results.md narrative): + +- `#3910` (REPRO on dev) has an open PR `#3911` that fixes it; suggest `closed:pr-pending-#3911` close vocab once PR merges. Until then, keep open. +- `#3849` (REPRO on dev) is a urllib3 v2 / Selenium 3 ABI conflict on a fresh `pip install`; `.venv` only survives via the `uv.lock` pin. Surface as a dependency-modernization candidate for v5. +- `#3955` and `#3602` (REPRO on dev) are RF-theme bugs with pytest-stubbable repros — first proof that the parent plan's no-RF-inspection rule is too broad for evidence/test work (addressed in plan's "RF scope clarification" subsection). +- `#3541` (REPRO on dev) is a keychain corruption when the password is missing — reproducible via test stubbing the encryption layer. + +## Proposal table + +| issue# | title | last-activity | proposed-pass1 | proposed-pass2 | proposed-v5 | rule-rationale | risk | approval | +| -----: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------- | ---------------------------------- | -------------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------- | ----------- | -------- | +| #675 | Show full traceback for Python exceptions in robot keywords | 2018-09-11 | closed:stale-24mo | n/a | n/a | rule 1: updated 2018-09-11, no maintainer label; +repro Task 2.5c R3: REPRO-on-dev | low | | +| #710 | Allow disabling default scratch org configs | 2018-11-02 | kept-open | n/a | n/a | rule 1: updated 2018-11-02, no maintainer label; +repro Task 2.5c R3: REPRO-on-dev | low | | +| #733 | Prompt to delete scratch org when creating one that already exists | 2018-09-11 | closed:stale-24mo | n/a | n/a | rule 1: updated 2018-09-11, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | +| #773 | Document task return values and results | 2018-11-19 | kept-open | n/a | n/a | rule 1: updated 2018-11-19, no maintainer label; +repro Task 2.5c R3: REPRO-on-dev | low | | +| #808 | deploy_packaging flow runs uninstall_packaged_incremental with wrong package name | 2018-10-09 | kept-open | n/a | n/a | rule 1: updated 2018-10-09, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #987 | Last week this test worked, now I get a javascriptexception message. | 2022-06-16 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-06-16, no maintainer label; +repro Task 2.5c R3: NOT-REPRO-on-dev | low | | +| #1348 | Multiple Git Provider Support | 2022-11-07 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-11-07, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | +| #1350 | Unable to run tasks in remote projects | 2022-07-07 | closed:not-reproducible-on-v4.10.0 | n/a | n/a | rule 1: updated 2022-07-07, no maintainer label; +repro Task 2.5c: NOT-REPRO | low | | +| #1432 | CCI Inconsistencies in validating arguments | 2020-01-03 | closed:stale-24mo | n/a | n/a | rule 1: updated 2020-01-03, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | +| #1769 | Unusual case in test_load | 2020-08-07 | closed:stale-24mo | n/a | n/a | rule 1: updated 2020-08-07, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | +| #2013 | Mapping files with steps that are not 1-1 with SObjects are unreliable for extraction | 2020-09-13 | kept-open | n/a | n/a | rule 1: updated 2020-09-13, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #2096 | REST dataloads throw errors that Bulk loads do not. | 2020-10-15 | closed:not-reproducible-on-v4.10.0 | n/a | n/a | rule 1: updated 2020-10-15, no maintainer label; +repro Task 2.5c: NOT-REPRO | low | | +| #2126 | Support task to encrypt all possible fields with probabilistic encryption | 2022-01-28 | closed:stale-24mo | n/a | n/a | rule 3: missing cci-version; updated 2022-01-28; +repro Task 2.5c R3: NOT-REPRO-on-dev | medium-high | | +| #2140 | Prompt Org Configs when Org Does Not Exist and Command Runs Against It | 2022-05-20 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-05-20, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | +| #2153 | Add comment to original PR which tags all branch subscribers when a merge conflict auto-generated PR is created ("Merge master into ") | 2020-11-11 | kept-open | n/a | n/a | rule 1: updated 2020-11-11, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #2325 | Task to turn off validation rules to allow data insert | 2021-01-19 | kept-open | n/a | n/a | rule 1: updated 2021-01-19, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #2402 | Create a --rebuild-org parameter for cci flow run | 2022-01-28 | closed:stale-24mo | n/a | n/a | rule 3: missing repro, cci-version; updated 2022-01-28; +repro Task 2.5c: REPRO | medium-high | | +| #2440 | add_permission_set_perms throws 'string indices must be integers' error | 2022-01-28 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #2500 | ignore_failure is not documented | 2022-03-28 | kept-open | n/a | n/a | rule 3: missing repro, cci-version; updated 2022-03-28; +repro Task 2.5c R3: REPRO-on-dev | medium-high | | +| #2505 | Filtering records to be extracted | 2021-06-02 | closed:feature-implemented | n/a | n/a | rule 1: updated 2021-06-02, no maintainer label; +repro Task 2.5c: NOT-REPRO | low | | +| #2506 | Bulk Operations should have a --debug mode which maintains logs and tempfiles | 2021-03-27 | kept-open | n/a | n/a | rule 1: updated 2021-03-27, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #2507 | Undo mode for CumulusCI Insert | 2021-03-27 | closed:stale-24mo | n/a | n/a | rule 1: updated 2021-03-27, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | +| #2508 | Manual load retries | 2021-03-27 | kept-open | n/a | n/a | rule 1: updated 2021-03-27, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #2667 | `cci org connect` should output the name of the connected app it is using, especially if it is non-default | 2022-01-28 | closed:stale-24mo | n/a | n/a | rule 3: missing repro, cci-version; updated 2022-01-28; +repro Task 2.5c R3: NOT-REPRO-on-dev | medium-high | | +| #2697 | Initialization issue with 'namespaced' field in 'cci org info' after updating from a non-namespaced scratch org to namespaced | 2021-06-25 | closed:stale-24mo | n/a | n/a | rule 1: updated 2021-06-25, no maintainer label; +repro Task 2.5c: INCONCL:scratch-slot (confirms) | low | | +| #2826 | The deploy_unmanaged flow is supposed to silently do nothing if there's not actually a package directory | 2021-08-25 | kept-open | n/a | n/a | rule 1: updated 2021-08-25, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #2930 | Exception in task load_dataset | 2022-01-28 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #2951 | Error in task load_dataset - Standard_price_not_defined | 2021-11-11 | kept-open | n/a | n/a | rule 1: updated 2021-11-11, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #2973 | cumulusci.tasks.salesforce.CreateCommunity has no option to set authentication mode for LWR Community | 2022-01-28 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #2979 | deploy task should deploy from the default entry in packageDirectories in sfdx-project.json if the project is using sfdx format. | 2021-11-17 | kept-open | n/a | n/a | rule 1: updated 2021-11-17, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3015 | Request to have the ability to remove an imported dx org from cci org list without deleting the actual scratch org. | 2022-01-28 | closed:stale-24mo | n/a | n/a | rule 3: missing repro, cci-version; updated 2022-01-28; +repro Task 2.5c: REPRO | medium-high | | +| #3024 | Order of flow groups in cumulusci/cumulusci.yml reflects in the Flows box in CCI VSCode extension, but order is not natural | 2022-01-05 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-01-05, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | +| #3045 | create_bulk_data_permission_set errors on multiple runs | 2022-01-28 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3047 | Open Test Browser TypeError: 'NoneType' object is not callable when using useralias param | 2022-01-28 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3089 | task run_tests not including namespace in query | 2022-02-21 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3100 | uninstall_post is not substituting %%%NAMESPACE%%% | 2023-10-02 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3134 | Running flow always needs a default org or org defined | 2022-04-18 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3137 | cci task run update_package_xml and Salesforce Case Custom Object | 2022-05-18 | kept-open | n/a | n/a | rule 3: missing repro; updated 2022-05-18; +repro Task 2.5c: REPRO | medium-high | | +| #3161 | Ability to Hide Option Values When Using Task Options In a Task or Flow Run | 2022-04-21 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-04-21, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | +| #3165 | Update Admin Profile task fails when specifying records types without custom package.xml | 2022-04-19 | kept-open | n/a | n/a | rule 1: updated 2022-04-19, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3167 | Add ability to define page layout assignments with record types using the update_admin_profile task | 2022-04-20 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-04-20, no maintainer label; +repro Task 2.5c: NOT-REPRO (confirms) | low | | +| #3182 | "Error: 'utf-8' codec can't decode byte 0x80 in position 0: invalid start byte" when running any CCI command after connecting Github service | 2025-02-19 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3203 | generate_and_load_from_yaml task record type extraction fails for namespaced custom objects | 2023-01-09 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3283 | json parser error when empty string passed for date field during upsert or update | 2022-09-16 | closed:pr-resolved-#3361 | n/a | n/a | rule 1: updated 2022-09-16, no maintainer label; +repro Task 2.5c: NOT-REPRO | low | | +| #3306 | Preview Toggle for Scratch org def file | 2023-09-13 | kept-open | n/a | n/a | rule 3: missing repro, cci-version; updated 2023-09-13; +repro Task 2.5c R3: NOT-REPRO-on-dev | medium-high | | +| #3307 | Project Template Support for initialisation | 2022-07-25 | closed:stale-24mo | n/a | n/a | rule 3: missing repro, cci-version; updated 2022-07-25; +repro Task 2.5c: REPRO | medium-high | | +| #3320 | Metadata ETL task to Deactivate a Flow | 2023-02-15 | closed:feature-implemented | n/a | n/a | rule 3: missing repro, cci-version; updated 2023-02-15; +repro Task 2.5c: NOT-REPRO | medium-high | | +| #3331 | Task update_package_xml does not write correct package.xml for AssignmentRules | 2022-10-11 | kept-open | n/a | n/a | rule 1: updated 2022-10-11, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3347 | Cannot release an unlocked beta package with release_unlocked_beta flow | 2022-08-29 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-08-29, no maintainer label; +repro Task 2.5c: NOT-REPRO (confirms) | low | | +| #3349 | Make generated dataset recordType tables unique based on table instead of sf_object | 2022-09-26 | kept-open | n/a | n/a | rule 3: missing repro, cci-version; updated 2022-09-26; +repro Task 2.5c: REPRO | medium-high | | +| #3353 | Enable Snowfakery task to use recipes from other repositories | 2024-08-20 | kept-open | n/a | n/a | rule 3: missing repro, cci-version; updated 2024-08-20; +repro Task 2.5c: REPRO | medium-high | | +| #3360 | Read Only Object Lookup for Load_Dataset | 2022-09-15 | closed:feature-implemented | n/a | n/a | rule 1: updated 2022-09-15, no maintainer label; +repro Task 2.5c: NOT-REPRO | low | | +| #3376 | extract_dataset sql error | 2022-10-03 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3407 | `set_service(service_config)` type signature is wrong | 2022-10-19 | kept-open | n/a | n/a | rule 1: updated 2022-10-19, no maintainer label; +repro Task 2.5c R3: REPRO-on-dev | low | | +| #3418 | Error creating 1gp release | 2022-11-01 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-11-01, no maintainer label; +repro Task 2.5c: INCONCL:cumulus-actions-workflow (confirms) | low | | +| #3429 | Support overriding `cumulusci.yml` to be used for configuration | 2022-11-08 | kept-open | n/a | n/a | rule 1: updated 2022-11-08, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3440 | Enhance default_package_path to serve multi package projects better | 2022-11-17 | kept-open | n/a | n/a | rule 1: updated 2022-11-17, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3441 | "cci task run create_package_version" should allow option "version_base: default" in cumulusci.yml | 2023-12-15 | kept-open | n/a | n/a | rule 1: updated 2023-12-15, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3446 | CCI task "push_qa" crashes for Unlocked package with no namespace | 2022-12-13 | kept-open | n/a | n/a | rule 1: updated 2022-12-13, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3464 | Provide concise documentation of cumulusci.yml `project` configuration options | 2022-12-12 | kept-open | n/a | n/a | rule 1: updated 2022-12-12, no maintainer label; +repro Task 2.5c R3: REPRO-on-dev | low | | +| #3466 | Ability to specify a test suite to run instead of just test_name_match in the run_tests task | 2022-12-13 | closed:feature-implemented | n/a | n/a | rule 3: missing repro, cci-version; updated 2022-12-13; +repro Task 2.5c: NOT-REPRO | medium-high | | +| #3470 | Rename `ci_master` flow to a `ci_main` or at least create a new duplicate `ci_main` flow | 2022-12-16 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-12-16, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | +| #3471 | `Merged 0 commits into branch:` message displays when a non-Source Code change is made in `github_automerge_feature` task | 2022-12-16 | kept-open | n/a | n/a | rule 1: updated 2022-12-16, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3479 | Error with "cci org import" in github action | 2023-02-22 | closed:not-reproducible-on-v4.10.0 | n/a | n/a | rule 1: updated 2023-02-22, no maintainer label; +repro Task 2.5c: NOT-REPRO | low | | +| #3485 | "cci task run run_tests" generates incorrect test_results.xml format output | 2024-01-28 | kept-open | n/a | n/a | rule 1: updated 2024-01-28, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3492 | Enhance the "-o" option of "cci flow run" to accept "project\_\_custom" attribute values | 2023-01-17 | kept-open | n/a | n/a | rule 1: updated 2023-01-17, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3506 | when clause support for flow steps which call other flows | 2023-01-25 | kept-open | n/a | n/a | rule 1: updated 2023-01-25, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3512 | `namespace` does not display when running `cci org info` on a packaging org (does work when you add `--json` flag) | 2023-02-03 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3518 | Task add_picklist_entries always sets a default value for record types | 2023-02-03 | kept-open | n/a | n/a | rule 1: updated 2023-02-03, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3541 | Getting None\_\_dev as SFDX Alias | 2023-07-07 | kept-open | n/a | n/a | rule 1: updated 2023-07-07, no maintainer label; +repro Task 2.5c R3: REPRO-on-dev | low | | +| #3542 | 2GP flows fail in the local environment to test: `ci_feature_2gp` or `qa_org_2gp` with error: Could not find package version id | 2023-02-22 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-02-22, no maintainer label; +repro Task 2.5c: INCONCL:2GP-CI-pipeline (confirms) | low | | +| #3543 | New Option `load_sfdx_project_paths` for dx_convert_from Task | 2023-03-30 | kept-open | n/a | n/a | rule 1: updated 2023-03-30, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3544 | Task `update_admin_profile` errors when the org has person accounts and a namespace | 2025-05-07 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation; +repro Task 2.5c: INCONCL:namespaced-project (confirms) | medium-high | | +| #3546 | password_env_name bleeding over to next package | 2024-09-13 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3549 | Deploy to Salesforce does not create a test output | 2023-04-05 | kept-open | n/a | n/a | rule 1: updated 2023-04-05, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3561 | Retrieve_unpackaged unusable in MetaDeploy | 2023-03-15 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-03-15, no maintainer label; +repro Task 2.5c: NOT-REPRO (confirms) | low | | +| #3563 | Unmanaged Metadata not deploying during 2GP Package Create | 2024-06-21 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3570 | Feature Request: Flow "finally" or "error" path | 2023-04-04 | kept-open | n/a | n/a | rule 1: updated 2023-04-04, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3585 | Error Occurs when Using `update_package_xml` on object with `xsi:nil="true"` | 2023-04-19 | kept-open | n/a | n/a | rule 1: updated 2023-04-19, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3587 | Warning message when attempting to set `--install_class` or `--uninstall_class` flag on `update_package_xml` and `--managed` is `false` or null (defaults to true) | 2023-04-23 | kept-open | n/a | n/a | rule 1: updated 2023-04-23, no maintainer label; +repro Task 2.5c: NOT-REPRO | low | | +| #3589 | "Workflow" and "MatchingRules" are removed from package.xml after running "update_package_xml" task | 2023-04-25 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3592 | release_unlocked_beta doesn't work when an install key is specified | 2023-08-02 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3593 | `dx` task doesn't work for some commands like `project convert source` | 2023-05-03 | kept-open | n/a | n/a | rule 1: updated 2023-05-03, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3600 | Allow install_managed to use environment variables | 2023-05-25 | kept-open | n/a | n/a | rule 1: updated 2023-05-25, no maintainer label; +repro Task 2.5c: NOT-REPRO | low | | +| #3602 | Need Chrome/Firefox options(browser options/capabilities) in 'Open Test Browser' Keyword | 2023-05-26 | kept-open | n/a | n/a | rule 1: updated 2023-05-26, no maintainer label; +repro Task 2.5c R3: REPRO-on-dev | low | | +| #3603 | Any issue with git results in the unhelpful "404 not found" error | 2023-05-30 | kept-open | n/a | n/a | rule 1: updated 2023-05-30, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3604 | Task request: Update sfdx-project.json dependencies based off of computed cumulusci dependencies | 2023-05-30 | kept-open | n/a | n/a | rule 3: missing repro, cci-version; updated 2023-05-30; +repro Task 2.5c: REPRO | medium-high | | +| #3605 | Ability to Increment Major Versions when running `upload_production` | 2023-05-31 | closed:pr-resolved-#3651 | n/a | n/a | rule 1: updated 2023-05-31, no maintainer label; +repro Task 2.5c: NOT-REPRO | low | | +| #3607 | The `retry_failures` from the task `run_tests` is not working for me. | 2023-06-01 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-06-01, no maintainer label; +repro Task 2.5c: INCONCL:org-with-managed-package (confirms) | low | | +| #3609 | Command 'cci task run dx --command "plugins:install sfdx-browserforce-plugin"' fails | 2023-06-05 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-06-05, no maintainer label; +repro Task 2.5c: INCONCL:live-cli-test (confirms) | low | | +| #3610 | Error running `run_tests` task | 2023-06-05 | closed:pr-resolved-#3681 | n/a | n/a | rule 1: updated 2023-06-05, no maintainer label; +repro Task 2.5c R3: NOT-REPRO-on-dev (fixed on dev by PR #3681) | low | | +| #3612 | Maintain the CumulusCI for VSCode Extension | 2023-06-23 | closed:not-reproducible-on-v4.10.0 | n/a | n/a | rule 1: updated 2023-06-23, no maintainer label; +repro Task 2.5c: NOT-REPRO | low | | +| #3613 | AddFieldsToPageLayout | 2023-06-23 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-06-23, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | +| #3615 | update_dependencies does not honor resolution strategy | 2023-07-06 | closed:not-reproducible-on-v4.10.0 | n/a | n/a | rule 1: updated 2023-07-06, no maintainer label; +repro Task 2.5c: NOT-REPRO | low | | +| #3618 | Allow for list when using deleting/removing CumulusCI orgs (`cci org remove` and `cci org scratch_delete`) | 2023-07-13 | kept-open | n/a | n/a | rule 1: updated 2023-07-13, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3619 | Dependency_pins does not honor passwords | 2023-08-02 | kept-open | n/a | n/a | rule 1: updated 2023-08-02, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3641 | Prevent Downgrade of dependencies | 2024-05-17 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3649 | Support serial loads with update_data task | 2023-09-08 | kept-open | n/a | n/a | rule 1: updated 2023-09-08, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3663 | When clause | Ability to pass in prior task response values | 2023-09-21 | kept-open | n/a | n/a | rule 1: updated 2023-09-21, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3692 | No parser configuration found for subdirectory digitalExperiences | 2023-10-30 | kept-open | n/a | n/a | rule 1: updated 2023-10-30, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3699 | Sort of the data during extraction | 2023-11-10 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-11-10, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | +| #3700 | Trying to do an upsert on a master-detail child object gets an error around permission | 2023-11-10 | kept-open | n/a | n/a | rule 1: updated 2023-11-10, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3701 | set a mapping to the id instead of it being either a number or the salesforce id | 2023-11-10 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-11-10, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | +| #3717 | Github automerge feature task not working when running through Github Flows | 2023-12-08 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-12-08, no maintainer label; +repro Task 2.5c: INCONCL:cumulus-actions-workflow (confirms) | low | | +| #3721 | create_package_version version_name default should be version number, not "Release" | 2024-02-12 | kept-open | n/a | n/a | rule 1: updated 2024-02-12, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3733 | `cci org remove` doesn't remove org | 2025-02-01 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3734 | Exception in cci task upload_production - Malformed Request Error: The version number must be greater than the last Managed - Released version number | 2024-02-15 | kept-open | n/a | n/a | rule 1: updated 2024-02-15, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3745 | cci flow run ci_beta AND cci task install_managed_beta DO not use the latest beta | 2024-02-13 | closed:stale-24mo | n/a | n/a | rule 1: updated 2024-02-13, no maintainer label; +repro Task 2.5c: NOT-REPRO (confirms) | low | | +| #3746 | Deleted Versions used for determining next version | 2024-02-09 | kept-open | n/a | n/a | rule 1: updated 2024-02-09, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3754 | Enable configuration for cci version update sources | 2024-05-16 | kept-open | n/a | n/a | rule 3: missing repro, cci-version; updated 2024-05-16; +repro Task 2.5c: REPRO | medium-high | | +| #3758 | Flow "push_upgrade_org" is incorrectly defined | 2024-02-28 | kept-open | n/a | n/a | rule 1: updated 2024-02-28, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3762 | `update_admin_profile` task fails on namespaced org with Person Accounts enabled | 2024-03-06 | closed:stale-24mo | n/a | n/a | rule 1: updated 2024-03-06, no maintainer label; +repro Task 2.5c: closed:duplicate-of-#3544 (confirms) | low | | +| #3763 | Namespace not being added into Flow references in minority of cases | 2024-06-18 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3768 | Snowfakery Batch Size and Just Once | 2024-03-27 | kept-open | n/a | n/a | rule 1: updated 2024-03-27, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3770 | Error during cci task run retrieve_changes | 2024-08-05 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3771 | find_replace transforms on XPath with predicates does not work | 2024-04-12 | kept-open | n/a | n/a | rule 1: updated 2024-04-12, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3773 | retrieve_profile task seems to be missing some Metadata | 2024-04-30 | kept-open | n/a | n/a | rule 1: updated 2024-04-30, no maintainer label; +repro Task 2.5c: REPRO | low | | +| #3781 | Package Versions Starting with 0 (0.1,0.2,0.3, etc.) Cause "does not exist" error When Referenced in cumulusci.yml Dependencies | 2024-06-13 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3784 | Can't run test suites if project**test**name_match is defined | 2024-05-13 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3796 | cci task run get_installed_packages/uninstall_managed do not see 2GP beta | 2024-06-03 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3810 | Github tasks fail when using github enterprise | 2024-07-12 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3849 | Installing CumulusCI v 4 installs the latest version of urllib3 which seems to be incompatable with running ROBOT tests | 2025-09-04 | kept-open | severity:minor,area:robotframework,v5-candidate:no,needs-repro | no | kept-open: bug, area:robotframework; +repro Task 2.5c R3: REPRO-on-dev | low | | +| #3852 | CumulusCI 4 refresh token error | 2025-06-09 | kept-open | severity:minor,area:auth,v5-candidate:no | no | kept-open: bug, area:auth; +repro Task 2.5c: REPRO (confirms) | low | | +| #3854 | Issue while Capturing Data | 2025-02-03 | kept-open | severity:minor,area:cli,v5-candidate:no | no | kept-open: bug, area:cli; +repro Task 2.5c: REPRO (confirms) | low | | +| #3873 | Standalone Robot Framework Library for Selenium-Based Salesforce Automation (Inspired by Copado QForce) | 2025-01-24 | kept-open | n/a | n/a | rule 3: missing cci-version; updated 2025-01-24; +repro Task 2.5c R3: REPRO-on-dev | medium-high | | +| #3884 | Running a Dev_Org flow goes through re-install of the the same package version again. | 2025-02-26 | closed:missing-fields | n/a | n/a | rule 3: missing cci-version; updated 2025-02-26; +repro Task 2.5c: INCONCL:project-with-managed-deps (confirms) | medium-high | | +| #3885 | Versioning in CumulusCI Releases Does Not Support Full Versioning with Build Numbers | 2025-03-21 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 1.x; no reporter v4+ reconfirmation | medium-high | | +| #3886 | Required Dependencies? | 2025-03-06 | kept-open | severity:minor,area:bulkdata,v5-candidate:no | no | kept-open: bug, area:bulkdata; +repro Task 2.5c: REPRO (confirms) | low | | +| #3887 | Version comparison bug: 0.10.0.1 incorrectly compared as less than 0.9.0.1 | 2025-03-06 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3889 | Uninstall 2GP task request | 2025-03-21 | kept-open | n/a | n/a | rule 3: missing repro, cci-version; updated 2025-03-21; +repro Task 2.5c: REPRO | medium-high | | +| #3899 | Getting following Exception in task deploy_packaging.unschedule_apex | 2025-05-15 | kept-open | severity:minor,area:packaging,v5-candidate:no | no | kept-open: bug, area:packaging; +repro Task 2.5c: INCONCL:1gp-packaging-org (confirms) | low | | +| #3902 | Task install_managed security_type not being respected with 04t ID | 2025-06-03 | kept-open | severity:minor,area:packaging,v5-candidate:no | no | kept-open: bug, area:packaging; +repro Task 2.5c: INCONCL:managed-package-04t (confirms) | low | | +| #3910 | JSON Schema incorrectly defines namespaced field as string instead of boolean for scratch org configuration | 2025-07-14 | kept-open | severity:minor,area:keychain,v5-candidate:no | no | kept-open: bug, area:keychain; +repro Task 2.5c R3: REPRO-on-dev (open PR #3911 ready to land) | low | | +| #3919 | uninstall_packaged_incremental was purged even though it was set to "not" | 2025-08-15 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3929 | cci task run create_community (and sf community create) Appears to Loop/Timeout During Community Creation | 2025-10-22 | closed:not-reproducible-on-v4.10.0 | severity:minor,area:cli,v5-candidate:no,needs-repro | no | kept-open: bug, area:cli; +repro Task 2.5c: NOT-REPRO | low | | +| #3931 | Specifying a profile in cumulusci.tasks.salesforce.ProfileGrantAllAccess results in an error | 2025-10-17 | kept-open | severity:minor,area:metadata-etl,v5-candidate:no | no | kept-open: bug, area:metadata-etl; +repro Task 2.5c: REPRO (confirms) | low | | +| #3936 | Error: HTTPSConnectionPool(host='yoursite.scratch.my.salesforce.com', port=443): Read timed out. (read timeout=None) | 2025-12-03 | kept-open | severity:minor,area:bulkdata,v5-candidate:no | no | kept-open: bug, area:bulkdata; +repro Task 2.5c: INCONCL:flaky-network (confirms) | low | | +| #3938 | Rest_Deploy ignores errors | 2025-12-16 | kept-open | severity:minor,area:other,v5-candidate:no | no | kept-open: bug, area:other; +repro Task 2.5c: REPRO (confirms) | low | | +| #3939 | Deploy task can't parse SOAP Response | 2025-12-16 | kept-open | severity:minor,area:other,v5-candidate:no | no | kept-open: bug, area:other; +repro Task 2.5c: REPRO (confirms) | low | | +| #3951 | set_duplicate_rule_status broken | 2026-02-03 | kept-open | severity:minor,area:metadata-etl,v5-candidate:no | no | kept-open: bug, area:metadata-etl; +repro Task 2.5c: REPRO (confirms) | low | | +| #3953 | add_picklist_entries never works through CLI | 2026-02-13 | kept-open | severity:minor,area:metadata-etl,v5-candidate:no | no | kept-open: bug, area:metadata-etl; +repro Task 2.5c: REPRO (confirms) | low | | +| #3955 | Open Test Browser - SalesforcePlaywright.robot | 2026-03-05 | kept-open | severity:minor,area:robotframework,v5-candidate:no,needs-repro | no | kept-open: bug, area:robotframework; +repro Task 2.5c R3: REPRO-on-dev | low | | diff --git a/docs/triage/v5/repro-results.csv b/docs/triage/v5/repro-results.csv new file mode 100644 index 0000000000..918d85954c --- /dev/null +++ b/docs/triage/v5/repro-results.csv @@ -0,0 +1,116 @@ +number,theme,bucket,repro_type,verdict,evidence_summary,repro_test_path,recommended_pass1,recommended_pass2_labels,verdict_source,notes +675,robotframework,feature-request,feature,REPRODUCED-on-dev,cumulusci/tasks/robotframework/robotframework.py does not configure traceback logging; rg 'traceback|format_exc|format_tb' in cumulusci/robotframework returns 0 matches. Default robot output shows only the exception's str(); full Python tracebacks require --loglevel TRACE or a custom listener which cumulusci does not provide.,,closed:stale-24mo,"cli-usability,robotframework,stale",dev,"Issue from 2018-07, last activity 2018-09, no activity for ~8 years. Two pragmatic workarounds exist today: (1) users can pass options=loglevel:TRACE to the robot task; (2) python keywords can wrap with traceback.format_exc() and log themselves. Workarounds make this low-priority. Close as stale." +710,scratch-org-config,feature,unit-pytest,REPRODUCED-on-dev,"The four+ default scratch org configs in cumulusci/cumulusci.yml:1559 cannot be disabled by a project. `merge_config` (cumulusci/core/utils.py:158, via dictmerge) drops ``None`` overrides, and BaseProjectKeychain._load_scratch_orgs (cumulusci/core/keychain/base_project_keychain.py:149) iterates every key unconditionally. Two XFAIL assertions added showing the issue's proposed `config_file: None` syntax has no effect today.",cumulusci/tests/triage/test_issue_710.py,keep-open,"enhancement,needs-spec",dev,"API question: should disabling use `config_file: None`, an explicit `disabled: true` flag, or sentinel removal? Tests assert end-state (`dev not in keychain.orgs`) so any of those implementations would pass." +733,cli,A,feature,REPRODUCED-on-v4.10.0,runtime.py:131-133 still raises ClickException with same hard error message; no interactive prompt path,,closed:stale-24mo,"enhancement,cli-usability,stale",v4.10.0,Stale 7yr feature request; confirm dry-run proposal stands +773,docs,feature-with-doc-component,doc-gap,REPRODUCED-on-dev,"cdcarter (2018) asked for tasks to declare ``return_values``/``result`` and for ``cci task info`` plus the web docs to surface them. On dev (1925a3083), ``BaseTask`` (``cumulusci/core/tasks.py:51``) only declares ``return_values`` as a runtime dict (line 64, populated as ``self.return_values = {}`` at line 92) — no declarative schema attribute. ``doc_task()`` in ``cumulusci/utils/__init__.py:354`` walks ``task_options`` and a free-form ``task_docs`` string but emits no ""Return Values"" / ""Returns"" section. The docs themselves admit the gap: ``docs/config.md:740-744`` literally says ""Current task return values are _not_ documented, so finding return values set by a specific task (if any) requires you to read the source code"". 8 years stale but still 100% accurate.",/tmp/repro/17/tests/test_issue_773.py,keep-open,"area/docs,area/tasks,type/enhancement",dev,"Pass-2: still actionable. Fix sketch: add a class attr like ``return_values_schema: Dict[str, str]`` (key -> one-line description) on BaseTask, extend ``doc_task`` to render a ""Return Values"" RST section when the attr is non-empty, and backfill the common return-value-emitting tasks (PackageUpload, GithubRelease, PromotePackageVersion, etc.). Same convention can power web docs since web docs use the same ``doc_task``." +808,metadata-etl,B,bug,REPRODUCED-on-dev,UninstallPackaged._init_options (cumulusci/tasks/salesforce/UninstallPackaged.py:25) defaults the 'package' option to project__package__name only; project__package__name_managed is never consulted (compare InstallPackageVersion which does fall back through name_managed -> name -> namespace at install_package_version.py:75-79). uninstall_packaged_incremental therefore retrieves the wrong package when name_managed is set,,keep-open,"bug,good-first-issue",dev,"Static-analysis confirmation; live repro needs a packaging org with a managed package whose name differs from project__package__name. Minimal fix: in UninstallPackaged._init_options, do `self.project_config.project__package__name_managed or self.project_config.project__package__name`. Also revisit jlantz's 2018 follow-up about deprecating name_managed entirely.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d)." +987,robotframework,user-error-or-stale,bug,NOT-REPRODUCED-on-dev,"Issue is Spring 19 Salesforce + Chromedriver 2.46 + Selenium ~3.x shadow-DOM-specific. Reporter explicitly stated workaround works (""I figured out a work-around. Use firefox with geckodriver. Everything works as intended now."") and the underlying Chrome/Selenium/Salesforce stack has changed substantially. cumulusci/robotframework/Salesforce.py:154 click_object_button still uses _jsclick but the upstream shadow-DOM bug it depends on no longer manifests the same way.",,closed:stale-24mo,"stale,user-error",dev,"Reporter found workaround within days; last meaningful activity 2022-06. Spring 19 UI no longer exists. 7 years stale, ineligible for repro without specific reproducible scenario." +1348,cli,A,feature,REPRODUCED-on-v4.10.0,No 'gitlab' or 'bitbucket' references anywhere in cumulusci/; ci_feature flow still uses github_parent_pr_notes/github_automerge_feature tasks,,closed:stale-24mo,"enhancement,stale,wontfix-candidate",v4.10.0,Architectural change scoped to GitHub only; stale 6yr +1350,cli,A,bug,NOT-REPRODUCED-on-v4.10.0,project_config.py:52-57 sets up synthetic 'tasks' namespace package; include_source() at line 662 calls _add_tasks_directory_to_python_path() which extends tasks.__path__ for each loaded source,,closed:not-reproducible-on-v4.10.0,fixed,v4.10.0,Original ModuleNotFoundError fixed via tasks namespace package; collision concern raised in 2022 comments is separate +1432,cli,A,bug,REPRODUCED-on-v4.10.0,core/tasks.py:186-196 _validate_options() only checks required; old-style task_options dict path silently accepts unknown keys (test passed). Pydantic Options class path now rejects extras.,/tmp/repro/7/tests/test_1432_options_validation.py,closed:stale-24mo,"bug,stale,partially-fixed",v4.10.0,Partially mitigated for tasks using new Pydantic Options class; old task_options dict still vulnerable +1769,bulkdata,A,bug,REPRODUCED-on-v4.10.0,"Test code-smell: `lookups[""Id""] = MappingLookup(name=""Id"", table=""accounts"", key_field=""sf_id"")` pattern still present in test_load.py:736 (was line 352 in 2020). davidmreed acknowledged ""horrible hack"" but never refactored. Pattern repeats at lines 754, 773, 801. Used to express UPDATE-on-Id dependency in `_expand_mapping` after_steps fixtures.",,closed:stale-24mo,"test-cleanup,low-priority",v4.10.0,"Issue is a test-fixture style question, never escalated to bug. 6 yrs old." +2013,bulkdata,A,bug,REPRODUCED-on-v4.10.0,"`create_table_if_needed` (utils.py:133-139) calls `Table(tablename, metadata, *fields)` then checks `inspector.has_table()` for the BulkDataException. SQLAlchemy raises `InvalidRequestError: Table 'X' is already defined for this MetaData instance` BEFORE the inspector check fires. Reproduced exact 2020 traceback verbatim with two MappingStep(sf_object=Account, table=Account) entries.",/tmp/repro/9/tests/test_2013_multistep.py,keep-open,"bug,bulkdata,extract_dataset,error-handling",v4.10.0,"Trivial fix: try/except around Table() to convert to BulkDataException, or use `extend_existing=True`. Or detect the duplicate-table case in mapping_parser at validation time." +2096,bulkdata,A,bug,NOT-REPRODUCED-on-v4.10.0,REST DML (`step.py:778-784 RestApiDmlOperation._record_to_json`) calls `process_bool_arg` for boolean fields. `process_bool_arg` (core/utils.py:53-83) accepts the full Salesforce Data Loader spectrum: yes/y/true/on/1 -> True; no/n/false/off/0 -> False (case-insensitive). Tested all 20 spectrum values; all pass.,/tmp/repro/9/tests/test_2096_rest_booleans.py,closed:not-reproducible-on-v4.10.0,"resolved,bulkdata",v4.10.0,Fix predates v4.10.0; the spec referenced in the issue is now followed. +2126,keychain,feature,feature,NOT-REPRODUCED-on-dev,"Feature request for `encrypt_all_encryptable_fields` Metadata-ETL task using probabilistic Shield encryption. Author (davidmreed, 2022-01-28) wrote ""feature has been developed but is blocked by bugs in the underlying platform functionality"". No matching task exists in cumulusci/ today (grep for `encryptionScheme`/`encrypt_all_encryptable`/`probabilistic` returns 0 hits in cumulusci/). 5+ years stale, still labelled `blocked`. Not a keychain bug \u2014 theme misclassification (encryption-via-Shield, not encryption-at-rest).",,closed:stale-24mo,"area/metadata-etl,blocked",dev,"Theme mislabel: this is metadata-etl/Shield, not keychain. Pass-2: relabel before closing; if owner still wants it, keep-open with `blocked`." +2140,cli,A,feature,REPRODUCED-on-v4.10.0,runtime.py get_org() calls keychain.get_org which raises OrgNotFound; cli/org.py:530-531 just shows 'Org X does not exist'; no interactive prompt offering scratch configs,,closed:stale-24mo,"enhancement,cli-usability,stale",v4.10.0,Stale 5yr feature request +2153,ci-integration,A,feature,REPRODUCED-on-dev,"Code scan of cumulusci/tasks/github/merge.py shows _create_conflict_pull_request (lines 264-288) only calls self.repo.create_pull(...) for the new auto-generated ""Merge into "" PR. There is no call to comment on the original (source) PR or its branch's open PR. Repo-wide grep for ""create_comment"" / ""issue_comment"" in cumulusci/tasks/github returns no matches in production code (only in test fixture util_github_api.py). Feature is still unimplemented on v4.10.0.",,keep-open,"enhancement,github,merge-conflict",dev,"Small enhancement; could be implemented inside _create_conflict_pull_request after pull = self.repo.create_pull(...). Need design decision on how to find the ""original PR"" (search open PRs whose head==branch_name?).; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d)." +2325,bulkdata,A,feature,REPRODUCED-on-v4.10.0,"No `set_validation_rule_status` or `disable_validation_rules` task in cumulusci.yml. Analogs exist for triggers (`disable_tdtm_trigger_handlers`/`restore_tdtm_trigger_handlers` lines 738-747) and DuplicateRules (`set_duplicate_rule_status` -> tasks/metadata_etl/duplicate_rules.py). Implementation pattern is established: a `MetadataSingleEntityTransformTask` subclass with `entity = ""ValidationRule""` would satisfy this.",,keep-open,"enhancement,bulkdata,metadata_etl,good-first-issue",v4.10.0,Clear pattern to follow from SetDuplicateRuleStatus. Small implementation effort. +2402,cli,A,feature,REPRODUCED-on-v4.10.0,cli/flow.py:119-145 flow_run only has --delete-org flag; no --rebuild-org option; no rg matches anywhere,,closed:stale-24mo,"enhancement,stale",v4.10.0,Stale 5yr; tracked as W-10502624 +2500,docs,feature-with-doc-component,doc-gap,REPRODUCED-on-dev,"prescod (2021) flagged that ``ignore_failure`` is not documented. On dev, the option is real and supported: ``Step.ignore_failure: bool = False`` (``cumulusci/utils/yaml/cumulusci_yml.py:45``), used in ``flowrunner.py:667`` as ``allow_failure=step_config.get(""ignore_failure"", False)``, and present in the JSON schema (``cumulusci/schema/cumulusci.jsonschema.json:149``). In the docs directory, the only mentions are (a) a single example YAML at ``docs/config.md:800`` (in a release-flow snippet) and (b) a one-line changelog blurb at ``docs/history.md:5993``. The ""Flow Configurations"" chapter has subsections for ""Add a Flow Step"", ""Skip a Flow Step"", ""Replace a Flow Step"", ""Conditionally Run a Flow Step"" (``when:``), but no parallel subsection for ``ignore_failure``. The follow-up GUS ticket W-10908655 (davidmreed, 2022-03-28) was created but nothing landed.",/tmp/repro/17/tests/test_issue_2500.py,keep-open,"area/docs,area/flows,good-first-issue",dev,"Pass-2: trivial documentation PR. Fix sketch: add a ``### Ignore a Failed Step`` (or ``Continue on Step Failure``) subsection under ``## Flow Configurations`` in ``docs/config.md``, parallel to ""Conditionally Run a Flow Step"". Cover: (1) what the option does (don't raise the task's exception; the flow continues with the next step); (2) interaction with ``result`` / ``return_values`` for downstream steps that conditioned on success; (3) when NOT to use it (silently swallowing failures hides regressions in CI); (4) link to the ``when:`` mechanism for branching instead of swallowing." +2505,bulkdata,A,feature,NOT-REPRODUCED-on-v4.10.0,"`MappingStep.soql_filter` field added (mapping_parser.py:120). `extract.py:142-147` applies it via `append_filter_clause` (extract.py:420). Also surfaced in extract-mapping generator (extract_mapping_file_generator.py:26 reads `where:` from declarations into `soql_filter`). Tests cover plain filter, filter prefixed with WHERE, and no-record-type variants (test_extract.py:1216,1248,1280).",,closed:feature-implemented,"resolved,bulkdata,extract_dataset",v4.10.0,WHERE-clause filtering for extraction is implemented via `soql_filter` per mapping step. +2506,bulkdata,A,feature,REPRODUCED-on-v4.10.0,"Snowfakery task DOES respect `get_debug_mode()` (snowfakery.py:241,355,385,565) and prints the working tempdir on each loop iteration. But the core bulk operations (extract.py, load.py, step.py) have no `--debug` mode that retains tempfiles or logs their paths. extract.py and step.py have ZERO matches for debug_mode/get_debug_mode/delete=False.",,keep-open,"enhancement,bulkdata,extract_dataset,load_dataset,debugging",v4.10.0,Partial: Snowfakery only. Could be extended to load_dataset/extract_dataset by wiring `get_debug_mode` and using TemporaryDirectory(delete=False) when set. +2507,cli,A,feature,REPRODUCED-on-v4.10.0,"No undo_insert task in repo; bulkdata/load.py and snowfakery have enable_rollback option but only triggers on error, not the requested ad-hoc undo",,closed:stale-24mo,"enhancement,stale,partially-fixed",v4.10.0,Partial mitigation via enable_rollback (rollback on error); standalone undo task still missing +2508,bulkdata,A,feature,REPRODUCED-on-v4.10.0,"No retry-only-failed-records feature in v4.10.0. `cci task list` shows zero retry-named tasks. There is an `enable_rollback` option on load_dataset (load.py:97-98, RollbackType enum at load.py:1051) but that performs the OPPOSITE: undoes successful inserts when failures occur. RowErrorChecker (utils.py:158) only logs/raises; it does not persist failed rows for retry.",,keep-open,"enhancement,bulkdata,load_dataset,reliability",v4.10.0,Distinct from rollback. Would require persisting failed-record CSV/SQL output and a new task that consumes it. +2667,auth,enhancement,cli-output,NOT-REPRODUCED-on-dev,"cumulusci/cli/org.py:204 already emits ""Connecting org using the {connected_app_name} connected app..."" before connecting. Implemented by commit 40520bee4 (2022-01-31, post-issue-filing). Existing tests at cumulusci/cli/tests/test_org.py:135 and :191 assert the connected-app name is present in CLI output for both default (""built-in"") and non-default (""other"") connected apps. All 10 org_connect tests pass on dev (1925a3083). Issue description requested ""Using connected_app 'xyzzy'""; current implementation produces functionally equivalent message.",,close-stale,"resolved,implemented",dev,"Originally requested by prescod 2021-06-08; davidmreed noted W-9863651 covering on 2022-01-28. Implementation landed shortly after. davisagli's follow-up suggestions (storing connected_app on OrgConfig, configurable login URLs per connected app) are partially addressed: org_config.config[""connected_app""] is now stored (line 155). Login-URL-per-connected-app remains a separate concern not blocking close." +2697,cli,B,bug,INCONCLUSIVE-needs-scratch-slot,namespaced field is sourced from cci config not auto-derived from SFDX qa.json; keychain create_scratch_org defaults namespaced=False (base_project_keychain.py:74). Requires scratch org to confirm cli/org.py 'org info' output behavior matches reporter's expectation,,closed:stale-24mo,"bug,stale,needs-info",v4.10.0,User expectation conflicts with cci design; field is cci-controlled not derived from SFDX def. Scratch creation skipped (DevHub limit prudence); behavior likely unchanged +2826,metadata-etl,B,bug,REPRODUCED-on-dev,PackageXmlGenerator.parse_types (cumulusci/tasks/metadata/package.py:107) calls os.listdir(self.directory) without a pre-check; UpdatePackageXml._run_task (line 612) does not guard. Unit repro raises FileNotFoundError when path is missing rather than silently no-opping the way the issue title says deploy_unmanaged 'is supposed to',/tmp/repro/5/tests/issue-2826/repro_unit.py,keep-open,"bug,good-first-issue",dev,"Behavior unchanged from 2021. Smallest change: in UpdatePackageXml._init_task (or _run_task) skip with logger.info('No package directory at {path}; skipping') when not Path(path).exists(). Could also be done at the deploy_unmanaged flow level via a `when:` clause, e.g. when: project_config.has_package_directory.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d)." +2951,bulkdata,A,bug,REPRODUCED-on-v4.10.0,"Loader has no special PricebookEntry sequencing logic. Within a single Insert PricebookEntry mapping step, records (whether targeting Standard Price Book or custom) are sent to Bulk/REST in mixed order, hitting STANDARD_PRICE_NOT_DEFINED. Mitigation: hardcoded_default_declarations.py:14-18 filters out Standard Price Book during extract_dataset by default, so the typical extract->load round-trip avoids this. But manually-authored mappings (like reporter's) still hit it.",,keep-open,"bug,bulkdata,load_dataset,pricebook,documentation",v4.10.0,"Could be addressed by either (a) auto-splitting PricebookEntry into two implicit steps (standard first, custom second), or (b) documenting that PricebookEntries against Standard pricebook must be in a separate, earlier mapping step." +2979,packaging,A,feature,REPRODUCED-on-v4.10.0,deploy task in cumulusci.yml still hardcodes path: src; default_package_path exists but is not wired into Deploy task,,keep-open,"severity:low,area:packaging,area:sfdx,state:needs-design",v4.10.0,default_package_path is wired only into create_package_version; would need backwards-compat design (per davisagli comment) +3015,cli,A,feature,REPRODUCED-on-v4.10.0,cli/org.py:519-543 org_remove always calls delete_org() if can_delete; no --keep-org or -o flag,,closed:stale-24mo,"enhancement,stale",v4.10.0,Stale 4yr; tracked as W-10502512; davisagli workaround (delete .org file directly) still applies +3024,cli,A,feature,REPRODUCED-on-v4.10.0,Flow groups in cumulusci/cumulusci.yml still appear in original order: Metadata Transformations first; Continuous Integration appears at position ~23. User-requested 'Org Setup' group does not exist (uses 'Setup' instead),,closed:stale-24mo,"enhancement,stale",v4.10.0,Stale 4yr cosmetic VS Code extension request +3137,metadata-etl,A,feature,REPRODUCED-on-v4.10.0,CustomObjectParser at package.py:443-461 still skips non-__c/__mdt/__e/__b objects; no opt-in option added to UpdatePackageXml,,keep-open,"severity:low,area:metadata-etl,type:enhancement,state:needs-design",v4.10.0,Maintainer agreed in 2022 it's by-design; needs design for an include_standard_objects option +3161,cli,A,feature,REPRODUCED-on-v4.10.0,flowrunner.py:317-320 _obfuscate_if_sensitive masks if task_options info.sensitive==True; partial implementation. No CLI-time hide flag for ad-hoc values like robot__vars; robot vars option not marked sensitive,,closed:stale-24mo,"enhancement,stale,partially-implemented",v4.10.0,Infrastructure exists for sensitive task option metadata; user's ad-hoc CLI -o hiding still missing +3165,metadata-etl,B,bug,REPRODUCED-on-v4.10.0,"_expand_package_xml_objects (which adds objects referenced by record_types to the retrieve package.xml) is only invoked from inside _expand_package_xml, which is gated on include_packaged_objects=True (update_profile.py:137-138 and 182). When include_packaged_objects is False (the default unless project's minimum_cumulusci_version >= 3.9.0), record_types referencing standard objects not already in admin_profile.xml (e.g. Case) are never added to the retrieve, the retrieved Admin profile lacks those recordTypeVisibilities, and _set_record_types raises TaskOptionsError 'Record Type X not found in retrieved Admin.profile'. Existing test test_init_options__include_packaged_objects asserts _expand_package_xml.assert_not_called() in that branch (test_ProfileGrantAllAccess.py:609-615) which proves the gating",/tmp/repro/5/tests/issue-3165/repro_unit.py,keep-open,bug,v4.10.0,"Smallest fix: in update_profile.py:137 always call self._expand_package_xml_objects(package_xml) (regardless of include_packaged_objects), and only call self._expand_package_xml when include_packaged_objects is True. _expand_package_xml_objects only walks the user-supplied record_types option; it does not need a Tooling API query." +3167,metadata-etl,B,feature,NOT-REPRODUCED-on-v4.10.0,"page_layout key on record_types is fully implemented in ProfileGrantAllAccess._set_record_types (update_profile.py:280-298). Documented in the record_types task option description (update_profile.py:32-34). Landed in PR #3243 (commit f2ff04bd5) in June 2022, well before v4.10.0",,close-as-implemented,enhancement,v4.10.0,Feature is shipped; documentation is in cci task info `update_admin_profile`. Could add a CHANGES note or a docs example showing the page_layout usage. +3283,bulkdata,A,bug,NOT-REPRODUCED-on-v4.10.0,"PR #3361 (commit b0bfb70e0, ""Support updates and upserts with blank dates represented by strings"") is in v4.10.0 (verified via `git merge-base --is-ancestor`). Fix at step.py:795-796: for UPDATE/UPSERT, empty strings are converted to None. Repro test confirms empty Birthdate -> JSON null for both UPDATE and UPSERT, and is dropped entirely for INSERT.",/tmp/repro/9/tests/test_3283_empty_date.py,closed:fixed-by-pr-#3361,"resolved,bulkdata,load_dataset",v4.10.0,"Reporter's own last comment (""Fixed in #3361"") confirms this; repro test now verifies behavior on v4.10.0 source." +3306,scratch-org-config,feature,no-test-feature-request,NOT-REPRODUCED-on-dev,"`cci org scratch ... --release preview` exists in cumulusci/cli/org.py:567 but `cci flow run` has no `--release`/`--preview` flag (cumulusci/cli/flow.py 119-150). Internally tracked as W-11486409; no PR landed. Issue is a never-implemented enhancement, not a regression.",,keep-open,"enhancement,needs-spec",dev,"Workaround today is `cci org scratch --release preview` then `cci flow run dev_org --org `. No test written — API/UX (--preview vs --release flag, semantics for non-scratch orgs) not yet specced." +3307,cli,A,feature,REPRODUCED-on-v4.10.0,cli/project.py project_init only renders internal Jinja templates from cumulusci/files/templates/project; no --template option exists,,closed:stale-24mo,"enhancement,stale",v4.10.0,Stale 4yr; user marked 'low priority/nice to have' +3320,metadata-etl,A,feature,NOT-REPRODUCED-on-v4.10.0,deactivate_flow task is shipped in cumulusci/cumulusci.yml:10-15 using ActivateFlow class with status:False,,closed:feature-implemented,"area:metadata-etl,type:enhancement,resolution:already-implemented",v4.10.0,Reporter likely missed that deactivate_flow exists; ActivateFlow.status:False does the work +3331,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,metadata_map.yml line 46 maps assignmentRules folder to type AssignmentRule (singular); MDAPI requires AssignmentRules plural,/tmp/repro/2/tests/test_issues_bucket_a.py::test_issue_3331_assignment_rules_metadata_type_plural,keep-open,"severity:medium,area:metadata-etl,type:bug,good-first-issue",v4.10.0,One-line fix in metadata_map.yml; reporter offered a PR; cross-cutting hint: autoResponseRules already plural in same file +3347,release-unlocked-beta-typeerror,C,code-only,NOT-REPRODUCED-on-v4.10.0,create_package_version.py:158-159 now raises TaskOptionsError(PERSISTENT_ORG_ERROR) early when org_config.config_file is None; replaces the cryptic TypeError reported. Fix landed in commit 2a9cadcb1 on 2023-10-12. Existing test at cumulusci/tasks/tests/test_create_package_version.py::TestPackageConfig::test_org_config validates the new behavior (passes on HEAD).,cumulusci/tasks/tests/test_create_package_version.py::TestPackageConfig::test_org_config,close-with-comment,resolved-by-clear-error-message,v4.10.0,Cryptic TypeError replaced by clear actionable TaskOptionsError. Underlying limitation (cannot use persistent org for 2GP package upload) is documented now. +3349,bulkdata,A,bug,REPRODUCED-on-v4.10.0,"mapping_parser.py:177-179 still names recordtype tables as f""{self.sf_object}_rt_mapping"" (and ""_rt_target_mapping""). Two MappingStep entries for the same sf_object (e.g. Account business vs PersonAccount) collide on the same SQLite table when extracted/loaded together. load.py:552 and extract.py:259/393 both use the sf_object-derived names with no per-step disambiguation.",/tmp/repro/10/tests/test_3349_recordtype_table_collision.py,keep-open,"keep-open,bug,area:bulkdata,severity:major,v5-candidate:yes",v4.10.0,"Has maintainer label wi-created (W-11466074). Real bug, fix would change get_source/destination_record_type_table to use self.table when present. Active community impact (Person Accounts + Business Accounts a common case)." +3353,bulkdata,B,feature,REPRODUCED-on-v4.10.0,snowfakery.py:159-162 validates recipe via Path(recipe).exists() with no SOURCE_NAME:path resolution. No call to project_config.sources / source_url anywhere in snowfakery.py. Recipe string is passed straight to Snowfakery as a filesystem path.,none — code-only,keep-open,"keep-open,enhancement,area:bulkdata,severity:minor,v5-candidate:maybe",v4.10.0,"Community resurfaced this in 2024-08 (davidjray, jnesong). Workaround: cci org import. Fix would resolve SOURCE_NAME:path via project_config.get_source(name).fetch().path before Path() validation." +3360,bulkdata,A,feature,NOT-REPRODUCED-on-v4.10.0,"action: select was added by commit b15945203 (Aug 2024) — well before v4.10.0. select_utils.py + step.py SELECT branch + mapping_select.yml fixture confirm full implementation. select_options supports strategy/filter/priority_fields. This is exactly the requested ""read-only object lookup"" feature — populates the lookup table from existing org records without DML.",none — code-only,closed:feature-implemented,"closed:feature-implemented,enhancement,area:bulkdata",v4.10.0,SELECT action lets you reference existing records by similarity / external-id without inserting. Documented in mapping_select.yml. Issue should be closed citing select feature. +3407,keychain,bug,type-bug,REPRODUCED-on-dev,"`BaseProjectKeychain.set_service` (base_project_keychain.py:202-209) annotates `service_config: ServiceConfig`, but `EncryptedFileProjectKeychain._load_service_files` (encrypted_file_project_keychain.py:717) calls it with a raw `str` (encrypted file body) plus `config_encrypted=True`. `_set_service` (line 583-605) explicitly branches on `config_encrypted` and stores the raw blob without ever constructing a ServiceConfig. Annotation is therefore wrong. Two-test repro xfails on dev: (a) annotation-vs-caller introspection; (b) runtime call with a string succeeds, contradicting the type.",/tmp/repro/16/tests/test_issue_3407.py,keep-open,"area/keychain,good-first-issue,type/typing",dev,"Trivial fix: change annotation to `Union[ServiceConfig, str]` or `ServiceConfig | bytes | str` and update docstring. Optionally split into `set_service` (validated ServiceConfig) and `set_encrypted_service` (raw blob) for cleaner API." +3418,packaging,B,bug,INCONCLUSIVE-needs-cumulus-actions-workflow,cci has no auth:sfdxurl:store path; error originates from SFDO-Community/standard-workflows action; comment from davidmreed in 2022 indicated planned external fix,,unchanged,"needs-info,needs-repro",v4.10.0,"Bug is in the third-party github action (SFDO-Community/standard-workflows production-1gp.yml), not in cci. davidmreed promised to address externally; verify SFDO-Community fix landed before triaging." +3429,packaging,A,feature,REPRODUCED-on-v4.10.0,No CUMULUSCI_YML env var or --config-file CLI flag in v4.10.0; config_filename hardcoded; PR #3969 (extra-yaml-cli-flag) is in flight but not merged,,keep-open,"severity:medium,area:packaging,area:cli,state:in-progress",v4.10.0,PR #3969 on branch extra-yaml-cli-flag adds --extra-yaml + CUMULUSCI_EXTRA_YAML; not yet in v4.10.0; close once #3969 merges +3440,packaging,A,feature,REPRODUCED-on-v4.10.0,default_package_path in project_config.py:517 only honors first packageDirectory with default:true; no name-based lookup or multi-package warnings,,keep-open,"severity:low,area:packaging,area:sfdx,area:multi-package",v4.10.0,Same multi-package theme as #2979 and #3429; could be solved jointly with a multi-package config story +3441,packaging,A,feature,REPRODUCED-on-v4.10.0,version_base accepts None / 'latest_github_release' / literal version; no syntax to reset back to default after a flow override; CCI lacks generic null-override mechanism,,keep-open,"severity:low,area:packaging,area:flow-overrides,area:cli",v4.10.0,yippie's comment generalizes the request to a CCI-wide null-override feature; could be solved by a 'default' sentinel string in create_package_version._get_base_version_number +3446,packaging,B,bug,REPRODUCED-on-v4.10.0,_parse_version(None) raises NoneType.split when push_qa is run with --metadata_package_id but no --version/--version_id; user comment about Push API activation is a downstream concern,/tmp/repro/3/tests/repro_3446_push_qa_no_version.py,keep-open,"bug,good-first-issue",v4.10.0,Two-part fix is wanted: (1) validate that version or version_id is required in _init_options; (2) wrap MetadataPackage SOQL in a check that surfaces a friendlier error if Push API is not activated on the org. +3464,docs,feature-with-doc-component,doc-gap,REPRODUCED-on-dev,"yippie (2022) asked for ALL ``cumulusci.yml`` ``project:`` keys to be defined with at least one sentence each in https://cumulusci.readthedocs.io/en/stable/config.html. On dev, the ``Project`` Pydantic model (``cumulusci/utils/yaml/cumulusci_yml.py:135``) declares 9 fields: ``name``, ``package``, ``test``, ``git``, ``dependencies``, ``dependency_resolutions``, ``dependency_pins``, ``source_format``, ``custom``. ``docs/config.md`` shows ONE example YAML block at line 281 covering only ``name`` + ``package``. Substring scan of the file: ``dependency_resolutions`` 0 hits, ``dependency_pins`` 0 hits — those are documented only in ``docs/dev.md`` (lines 499, 509, 535, 596, 724, 727), which is precisely the ""docs are scattered to the wind"" complaint in the issue. ``source_format`` is mentioned in flow examples but not as a project-level key reference. Sub-models (``Package``, ``Git``, ``Test``, ``DependencyResolutions``) have additional second-level fields with no reference at all in ``config.md``. jstvz acknowledged the gap in 2022.",/tmp/repro/17/tests/test_issue_3464.py,keep-open,"area/docs,type/enhancement",dev,"Pass-2: still actionable; significant doc work. Fix sketch: add a ``## Project Configuration Reference`` (or expand the existing ``### Project Configurations`` at line 673) to ``docs/config.md`` that enumerates every ``project:`` key with one-sentence semantics. Source the enumeration from the ``Project``/``Package``/``Git``/``Test``/``DependencyResolutions`` Pydantic models so it stays in sync. Alternative low-effort path: generate the reference from the Pydantic ``__fields__`` + field descriptions at docs-build time (Sphinx extension) — this requires backfilling ``Field(description=...)`` calls on each model attribute, but produces an always-accurate page. Cross-link to the in-depth dependency pages in ``docs/dev.md`` rather than duplicating their content." +3466,packaging,A,feature,NOT-REPRODUCED-on-v4.10.0,RunApexTests in cumulusci/tasks/apex/testrunner.py exposes test_suite_names option (line 173); fully wired through _get_test_classes_from_test_suite_names,/tmp/repro/1/tests/test_issue_3466.py,closed:feature-implemented,"area:packaging,area:apex,state:resolved",v4.10.0,Implemented at some point after the 2022-12 request; W-12214520 backlog item appears completed +3470,cli,A,feature,REPRODUCED-on-v4.10.0,cumulusci.yml:823 only ci_master flow defined; no ci_main alias. davidmreed acknowledged backlog need for flow aliasing first,,closed:stale-24mo,"enhancement,stale,inclusive-language",v4.10.0,Naming/inclusivity request; needs flow aliasing infra +3471,ci-integration,A,bug,REPRODUCED-on-dev,"cumulusci/tasks/github/merge.py line 251 still emits f""Merged {compare.behind_by} commits into branch: {branch_name}"" using github3's compare.behind_by. ""behind_by"" is computed by GitHub's compare-commits API and reflects how many commits the merged commit is behind the destination tip after the comparison ref-point; for some merges (e.g. when the merge target shares an ancestor at the same ref or when GitHub's compare picks the same head), this can return 0 even though the merge POST at line 249 succeeded and shipped a real commit. git log shows the line was last touched as part of the original MergeBranch implementation; no fix has landed since the issue was filed (2022-12). Pattern reported (README/test.txt vs source-code changes) is consistent with how GitHub's compare API treats ""effectively no-op"" merges where the file content already matches downstream content via merge-base.",,keep-open,"bug,github,merge,low-priority",dev,"Fix: replace compare.behind_by with len(list(compare.commits)) or report the actual merged commit SHA returned from self.repo.merge(...). Existing test_merge.py asserts ""Merged 1 commits"" in normal cases but has no test for the behind_by=0 case.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d)." +3479,ci-integration,A,bug,NOT-REPRODUCED-on-v4.10.0,"Reported error ""Expecting value: line 1 column 1 (char 0)"" is the bare json.JSONDecodeError. In v4.10.0 cumulusci/core/config/sfdx_org_config.py lines 38-55 wrap both nonzero return codes AND JSON parse failures from `sfdx org display --json` in SfdxOrgException with explicit ""Failed to parse json from output. Exception: ... Output: ..."" message (wrapping landed in commit 017bc49f4 on 2020-11-24, predating the 2023-01 issue, so the symptom may have come from a different code path or be a regression in the user's specific 3.71.0 environment). davidmreed's only reply (2023-02-22) correctly diagnoses the root cause as shell-expansion of the multiline GHA secret (echo ${{ secrets.DEV_AUTH_URL }} without quotes). Reporter never responded. The issue is a user CI/workflow-config problem; cci's only contribution is the wrapper message, which is already in place on v4.10.0.",,closed:not-reproducible-on-v4.10.0,"awaiting-more-details,external-config",v4.10.0,"No reporter response in 3+ years; root cause is in user's GHA workflow (unquoted multiline secret), not cci. Improved SfdxOrgException wrapping is already in v4.10.0." +3485,cli,A,bug,REPRODUCED-on-dev,cumulusci/tasks/apex/testrunner.py:803-834 still writes a single tag with no declaration and no wrapper; matches user-reported invalid JUnit format exactly.,,keep-open,"bug,area:apex,good-first-issue",dev,Fix is mechanical: prepend XML declaration and wrap in . Old issue but bug still reproducible against v4.10.0.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). +3492,cli,A,feature,REPRODUCED-on-dev,cumulusci/cli/flow.py:152-162 splits -o key on '__' into exactly 2 parts; passing project__custom__attr would actually error with 'too many values to unpack'. No project-level option override path exists from -o.,,keep-open,"enhancement,area:cli",dev,Feature still missing. Would need new -p / --project-option flag or smarter -o parser.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). +3506,cli,A,feature,REPRODUCED-on-dev,"cumulusci/core/flowrunner.py:660-672 sets when=step_config.get('when') only on the task: branch. The flow: branch at lines 674-697 never reads when from step_config, so when on a flow-call step is silently ignored.",,keep-open,"enhancement,area:flows",dev,Confirmed silent-ignore behavior the user complained about.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). +3518,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,picklists.py:177 stores str.lower bound method (not call) so if-default check at line 214 always truthy; every entry overrides record-type default,/tmp/repro/2/tests/test_issues_bucket_a.py::test_issue_3518_picklist_record_type_default_logic_bug,keep-open,"severity:high,area:metadata-etl,type:bug",v4.10.0,Two-line fix at picklists.py:177 (call .lower()) plus rewrite assignment to avoid shadowing +3541,keychain,bug,bug,REPRODUCED-on-dev,"`BaseProjectKeychain.create_scratch_org` (base_project_keychain.py:77-79) builds `sfdx_alias = f""{project_config.project__name}__{org_name}""`. When `project__name` is None (no `project.name` in cumulusci.yml, or project not yet resolved during the eager `_load_scratch_orgs` pass invoked at keychain init, line 45), the resulting alias is the literal string ""None__dev"" \u2014 exactly matching the reporter. Repro builds a BaseProjectConfig without project.name, calls create_scratch_org, asserts alias doesn't contain literal 'None'; xfails on dev. Second test exercises the eager-load path via __init__.",/tmp/repro/16/tests/test_issue_3541.py,keep-open,"area/keychain,area/scratch-orgs,bug",dev,Issue currently labelled `cannot-reproduce` \u2014 evidence here contradicts that label. Recommend removing it. Fix: guard against None (raise CumulusCIException with clear message OR fall back to org_name). Mind the upgrade path \u2014 existing keychains may already contain `None__*` aliases needing migration. +3542,packaging,B,bug,INCONCLUSIVE-needs-2GP-CI-pipeline,github_package_data uses self.project_config.repo_commit (local SHA) verbatim; if the upstream workflow recorded version_id under a merge-commit SHA from pull_request trigger; locally checked-out PR head SHA will not match; cci-side code path unchanged on v4.10.0,,unchanged,"needs-repro,2gp",v4.10.0,Root cause is workflow-vs-local SHA mismatch. May need a docs/CI fix in cumulus-actions/standard-workflows rather than cci. Could add a fallback: search by SHA on parent commits. +3543,metadata-etl,A,feature,REPRODUCED-on-v4.10.0,DxConvertFrom in cumulusci/tasks/dx_convert_from.py only exposes extra and src_dir options; no load_sfdx_project_paths or resolve_sfdx_package_dirs,,keep-open,"severity:low,area:metadata-etl,type:enhancement",v4.10.0,Reporter offered draft PR; could be folded into multi-path support across deploy/uninstall_packaged_incremental too +3544,update-admin-profile-person-accounts-namespaced,C,e2e-config-required,INCONCLUSIVE-needs-namespaced-project,Provisioned scratch org repro-special-c-pa from orgs/person_accounts.json (PersonAccounts + Communities + ContactsToMultipleAccounts features). update_admin_profile task ran SUCCESSFULLY against this non-namespaced person_accounts org on v4.10.0. Bug condition requires BOTH PersonAccounts AND namespaced:true on the project; CumulusCI itself has no project namespace so the second condition cannot be satisfied without registering a namespace in CCIDevHub. No code fix found referencing #3544 or W-12589033 in update_profile.py / admin_profile.xml since 2023.,,needs-info,needs-namespaced-project,v4.10.0,Tracked internally as W-12589033 per davidmreed comment 2023-02-22. Discovered adjacent latent bug at cumulusci/utils/__init__.py:229 where namespaced_org=True with no project namespace raises TypeError: unsupported operand type(s) for + 'NoneType' and 'str' — distinct from #3544 but worth a separate ticket. +3549,cli,A,feature,REPRODUCED-on-v4.10.0,"cumulusci/tasks/salesforce/Deploy.py exposes test_level/specified_tests but does not capture or write JUnit/JSON test output (no junit_output option, no _write_output for tests).",,keep-open,"enhancement,area:metadata-deploy",v4.10.0,Related to #3564. Reasonable feature ask; not implemented. +3561,metadata-etl,B,bug,NOT-REPRODUCED-on-v4.10.0,"Bug was reported by yippie (who is also the PR author). Fix landed in commit 56e10665e (PR #3566, May 2024) by the original reporter. RetrieveUnpackaged._init_options now stores file content under options['package_xml_content'] and leaves the file-path option intact (RetrieveUnpackaged.py:29-31), so the second _init_options invocation in MetaDeploy no longer corrupts the path",,close-as-fixed,,v4.10.0,Suggest closing with a back-reference to PR #3566 in case the original reporter never got back to flip the issue state. +3570,cli,A,feature,REPRODUCED-on-dev,cumulusci/core/flowrunner.py supports per-step ignore_failure (StepSpec.allow_failure) but has no concept of finally:/on_error:/cleanup: steps in a flow definition. No 'always-run' or post-error step type exists.,,keep-open,"enhancement,area:flows",dev,Big design change; unlikely to ship without strong demand.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). +3585,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,PackageXmlGenerator on .object containing unbound xsi:nil='true' raises XML parse error; no namespace shim added,/tmp/repro/2/tests/test_issues_bucket_a.py::test_issue_3585_xsi_nil_true_breaks_update_package_xml,keep-open,"severity:medium,area:metadata-etl,type:bug,sfdx-compat",v4.10.0,Fix: register xsi namespace before parsing or pre-strip xsi:nil attributes; also fixes #3692 class of issues +3587,packaging,B,feature,NOT-REPRODUCED-on-v4.10.0,PackageXmlGenerator only emits / when self.managed is truthy; no warning is logged when install_class set with managed=False; live cci task run update_package_xml --install_class X confirms silent drop,/tmp/repro/3/tests/repro_3587_update_package_xml_no_warning.py,keep-open,"enhancement,good-first-issue",v4.10.0,Feature still missing. Smallest implementation: in UpdatePackageXml._init_task; if install_class/uninstall_class set but not self.options.get('managed'); emit self.logger.warning(...). +3593,packaging,A,bug,REPRODUCED-on-dev,SFDXOrgTask._get_command in cumulusci/tasks/sfdx.py:50 unconditionally appends ' -o ' for ScratchOrgConfig; no opt-out option,/tmp/repro/1/tests/test_issue_3593.py,keep-open,"severity:medium,area:packaging,area:sfdx,area:dx-task,state:needs-design",dev,Repro test confirms command becomes 'sf project convert source ... -o test@example.com'; sf cli rejects -o for subcommands like 'project convert source'; suggested fix is an opt-out option or auto-detect; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). +3600,packaging,B,feature,NOT-REPRODUCED-on-v4.10.0,cci task option processing only substitutes $project_config. via PROJECT_CONFIG_RE; YAML loader uses plain yaml.safe_load with no env-var resolver; live install_managed --version '${MY_FAKE_VERSION}' shows literal string in interactive prompt,/tmp/repro/3/tests/repro_3600_install_managed_no_env_var.py,keep-open,enhancement,v4.10.0,Feature not implemented. Scope likely larger than install_managed (would touch all task options); design decision needed: $env:VAR vs ${VAR} syntax; backwards-compat impact on literal $-strings. +3602,robotframework,feature-request,feature,REPRODUCED-on-dev,"cumulusci/robotframework/SalesforcePlaywright.py:60 open_test_browser signature is (self, size=None, useralias=None, wait=True, record_video=None) — no kwarg accepts browser options or **kwargs. cumulusci/robotframework/Salesforce.robot:103 ""Open Test Browser"" robot keyword only takes size/alias/wait/useralias. Chrome options are constructed by Get Chrome Options (Salesforce.robot:157) which hard-codes --disable-notifications with no extension hook.",cumulusci/tests/triage/test_issue_3602.py,keep-open,"enhancement,robotframework,playwright,good-second-issue",dev,"Small-medium feature: add browser_options/extra_options kwarg to both Selenium and Playwright open_test_browser implementations, forward to webdriver options / new_browser kwargs. Pytest asserts signature exposes such a hook." +3603,dependencies,A,bug,REPRODUCED-on-v4.10.0,"Source ref/tag not found leaks raw `404 [No message]` from GitHubSource.resolve() (cumulusci/core/source/github.py L126). Repo-not-found cases (1,2) and `release:` strategy fail (case 5) are already wrapped in DependencyResolutionError; ref-not-found case (3) is not, and dep strategy fall-through (case 4) names the dep but not the strategies tried.",/tmp/repro/11/tests/test_3603_404_messages.py,keep-open,"theme:dependencies,error-handling,good-first-issue",v4.10.0,"Partial repro. Cases 1,2,5 were addressed by commit 738d4a8a4 (2021); cases 3 and 4 remain." +3604,dependencies,A,feature,REPRODUCED-on-v4.10.0,No CCI task exists to write computed dependencies into `sfdx-project.json`. Confirmed via `cci task list` and grep: zero references to writing/updating sfdx-project.json. W-13504384 was filed by maintainer in 2023 but no implementation has shipped through v4.10.0.,,keep-open,"theme:dependencies,enhancement,wi-created",v4.10.0,Pure feature request; gap persists. wi-created label already present. +3605,packaging,A,feature,NOT-REPRODUCED-on-v4.10.0,PackageUpload (upload_production backing class) exposes major_version and minor_version options (cumulusci/tasks/salesforce/package_upload.py:39-46); _validate_versions handles major bump,/tmp/repro/1/tests/test_issue_3605.py,closed:fixed-by-pr-#3651,"area:packaging,area:1gp,state:resolved",v4.10.0,Implemented in commit 87b94440e (PR #3651 'Deploy Major and Minor Version option in upload_production task') +3607,cli,A,bug,INCONCLUSIVE-needs-org-with-managed-package,"Code path traced in cumulusci/tasks/apex/testrunner.py: retry_failures regex compiled at line 209-222, _is_retriable_failure (line 405) checks Message and StackTrace via re.search. Repro test at /tmp/repro/8/tests/test_3607_retry.py confirms 'UNABLE_TO_LOCK_ROW' regex DOES match the user's quoted message in pure Python. Likely user-side: wrapped exception so Message lacks the literal token, or managed-class symbol-table skip at line 448-452.",/tmp/repro/8/tests/test_3607_retry.py,closed:stale-24mo,"bug,area:apex,needs-info",v4.10.0,Code logic is correct as written. To definitively reproduce we need a managed package and an org producing the exact failure shape. 30+ months no follow-up from reporter. +3609,cli,A,bug,INCONCLUSIVE-needs-live-cli-test,"cumulusci/tasks/sfdx.py is now a thin shell wrapper around 'sf {command}' (SFDX_CLI = 'sf' in v4.x; was 'sfdx' in 3.76.0 when reported). The user's syntax 'plugins:install ...' is sfdx-style with colon; 'sf' uses 'plugins install' (space). Underlying timeout originates from the sfdx/sf CLI itself, not CCI.",,closed:stale-24mo,"bug,upstream:sf-cli",v4.10.0,"Not a CCI bug. CCI faithfully shells out. Old issue, CLI changed substantially since." +3610,apex,Fixed-on-dev,negative-test,NOT-REPRODUCED-on-dev,Fixed by PR #3681 (commit 84389d998); cumulusci/tasks/apex/testrunner.py:500-510 handles None method name; regression tests already exist on dev,,closed:pr-resolved-#3681,,dev,"Fixed by PR #3681 (commit 84389d998b4783ddd2ff062f486a2366709cac27, ""Handling exception when the Tooling API returns a test result with a null method name""). cumulusci/tasks/apex/testrunner.py lines 500-510 detect None in method_names, remove the None key, enqueue the affected class for retry, and bump counts['Retriable']. Regression tests test_run_task_None_methodname_fail / test_run_task_None_methodname_pass pass on origin/dev@1925a3083." +3612,cli,A,feature,NOT-REPRODUCED-on-v4.10.0,"Issue is about the SFDO-Tooling/cci-vscode VSCode extension repo, not CumulusCI itself. Out of scope for this repository.",,closed:not-reproducible-on-v4.10.0,"enhancement,wontfix,wrong-repo",v4.10.0,Should be filed against SFDO-Tooling/cci-vscode. +3613,metadata-etl,B,bug,REPRODUCED-on-v4.10.0,Live repro: `cci task run add_page_layout_fields --org repro-etl-b-dev -o api_names Account` -> 'Cannot find metadata file ...layouts/Account.layout' from MetadataSingleEntityTransformTask (base.py:332). Same task with correct API name format `Account-Account Layout` succeeds. Underlying functionality works; the user-visible bug is the unhelpful error when the api_name does not match the Layout file naming convention -,/tmp/repro/5/tests/issue-3613/output-just-object.txt,improve-error-message,"bug,good-first-issue",v4.10.0,"Original report has no log of the exact api_names value passed; the cropped screenshot only shows 'page layouts'. Two improvements would help: (1) in _transform; if path does not exist, log the list of files actually retrieved into source_metadata_dir to help users identify naming mismatch; (2) in AddFieldsToPageLayout._init_options; warn when api_name does not contain '-'." +3615,dependencies,A,bug,NOT-REPRODUCED-on-v4.10.0,"`--resolution_strategy preproduction` is documented in cumulusci.yml as an alias for `latest_release` (which contains [tag, latest_release, unmanaged] and intentionally omits `latest_beta`). User wanted `include_beta`. Tests confirm preproduction == production == latest_release stack. Working as documented.",/tmp/repro/11/tests/test_3615_preproduction_strategy.py,closed:not-reproducible-on-v4.10.0,"theme:dependencies,docs",v4.10.0,"Naming is confusing -- ""preproduction"" sounds like ""beta-friendly"" but it isn't. Docs-improvement candidate; no code bug." +3618,cli,A,feature,REPRODUCED-on-dev,"cumulusci/cli/org.py:519-545 (org_remove) and 605-625 (org_scratch_delete) accept a single org_name argument via orgname_option_or_argument. No comma-separated list, no batch mode.",,keep-open,"enhancement,area:cli,good-first-issue",dev,Modest feature; could be implemented by accepting nargs=-1 or comma-split arg.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). +3619,dependencies,A,bug,REPRODUCED-on-v4.10.0,"Two-part bug confirmed. (A) `parse_pins()` raises DependencyParseError if a `dependency_pins` entry includes `password_env_name:` -- because GitHubDependencyPin only declares `github` and `tag`. (B) When a dynamic dep has `password_env_name` and a pin matches, `pin.pin()` calls GitHubTagResolver().resolve() directly, bypassing resolve_dependency()'s password-propagation logic; resulting `package_dependency.password_env_name` is None.",/tmp/repro/11/tests/test_3619_pin_password.py,keep-open,"theme:dependencies,bug",v4.10.0,Strong repro. Fix needs both (A) add password_env_name field to GitHubDependencyPin and (B) propagate it onto package_dependency in pin.pin() -- mirroring resolvers.py L644-654. +3649,bulkdata,A,feature,REPRODUCED-on-v4.10.0,"update_data.py:184 and :211 both pass api_options={} hardcoded to get_dml_operation. No task option exposes bulk job concurrency mode (Serial/Parallel). step.py BulkApiDmlOperation honors api_options[""bulk_mode""] but UpdateData never sets it. Other tasks (snowfakery, load_dataset) DO let users pick bulk_mode; update_data is the gap.",none — code-only,keep-open,"keep-open,enhancement,area:bulkdata,severity:minor,good-first-issue,v5-candidate:yes",v4.10.0,Author offered to contribute. Small fix: add bulk_mode option to UpdateData.task_options and pipe it through to api_options. Mirrors LoadData pattern. +3663,cli,A,feature,REPRODUCED-on-dev,cumulusci/core/flowrunner.py:510-516 _run_step builds the when Jinja context from only project_config and org_config. No prior-task return values are exposed to the when expression.,,keep-open,"enhancement,area:flows",dev,Would need to thread results dict (or ^^ resolver) into the when context.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). +3692,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,digitalExperiences key absent from metadata_map.yml; PackageXmlGenerator raises MetadataParserMissingError on Enhanced LWR sites,/tmp/repro/2/tests/test_issues_bucket_a.py::test_issue_3692_digital_experiences_in_metadata_map,keep-open,"severity:medium,area:metadata-etl,type:bug",v4.10.0,Add digitalExperiences/digitalExperienceConfigs entries to metadata_map.yml; needed for Winter '24+ LWR sites +3699,bulkdata,A,feature,REPRODUCED-on-v4.10.0,"extract.py _soql_for_mapping does not append ORDER BY. mapping_parser MappingStep has no order_by/sort field. soql_filter however allows arbitrary trailing SOQL so users CAN write soql_filter: ""Name != 'X' ORDER BY CreatedDate"" — this works because append_filter_clause just concatenates after WHERE. So a workaround exists; an explicit field would be a UX win.",none — code-only,closed:stale-24mo,"closed:stale-24mo,enhancement,area:bulkdata",v4.10.0,Workaround via soql_filter ORDER BY makes this lower priority. Author hasn't followed up. Closing as stale is fine; can reopen if explicit order_by becomes a v5 ask. +3700,bulkdata,A,bug,REPRODUCED-on-v4.10.0,"mapping_parser.py:373-377 _get_required_permission_types returns (""updateable"", ""createable"") for any UPSERT. Master-detail lookup fields in Salesforce are createable but NOT updateable, so _check_field_permission rejects them, raising ""Field xxx__c does not have the correct permissions ('updateable', 'createable') for this operation."" Repro test confirms with simulated MD describe.",/tmp/repro/10/tests/test_3700_master_detail_upsert_perm.py,keep-open,"keep-open,bug,area:bulkdata,severity:major,good-first-issue,v5-candidate:yes",v4.10.0,"Real bug, applies to any upsert involving an MD child. Fix should detect master-detail fields (relationshipName + cascadeDelete) and require only createable for those, OR loosen the upsert lookup-field check to ""createable OR updateable""." +3701,bulkdata,A,feature,REPRODUCED-on-v4.10.0,"mapping_parser.py:171/190/228/241/422 special-case ""Id"" — it always represents the SF Id and goes to sf_id-typed columns. There is no mechanism to make a different field (e.g. an external-id like BCM_Unique_Id__c) act as the row primary key in the extracted SQLite. The ""Id : OtherField"" mapping the user wrote is interpreted as ""extract SF Id into column OtherField"", not ""make OtherField the primary key"".",none — code-only,closed:stale-24mo,"closed:stale-24mo,enhancement,area:bulkdata",v4.10.0,"Closely tied to #3699 (sort/diff motivation). Author hasn't followed up. Workaround: extract SF Id into a chosen column, then post-process. The deeper PK-replacement feature would touch many places." +3717,ci-integration,A,bug,INCONCLUSIVE-needs-cumulus-actions-workflow,"cumulusci/core/config/project_config.py repo_info property (lines 220-255) only auto-detects from environment when CUMULUSCI_AUTO_DETECT is set, and only handles Heroku CI (HEROKU_TEST_RUN_ID/BRANCH/COMMIT_VERSION). Repo-wide grep for ""GITHUB_REF"" / ""GITHUB_HEAD_REF"" / ""GITHUB_SHA"" / ""GITHUB_ACTIONS"" returns ZERO matches in cci source. So when run inside a GitHub Actions job the only way for repo_branch to be populated is (a) CUMULUSCI_REPO_BRANCH env var set by the workflow, or (b) git inference via current_branch(self.repo_root). On push events GHA checks out a detached HEAD, so (b) returns None. The reporter's symptom (repo_branch=None for push-triggered ci_feature, but works on workflow_dispatch where the branch ref is checked out by name) is exactly what this code path produces. The fix lives in the cumulus-actions/standard-workflows YAMLs (set CUMULUSCI_REPO_BRANCH from github.event.ref or github.head_ref before invoking cci) — not in the cci codebase. Same precedent as #3418.",,unchanged,"external-config,cumulus-actions,needs-info",v4.10.0,"Mirrors #3418 precedent (INCONCLUSIVE-needs-cumulus-actions-workflow). Could optionally be addressed inside cci by adding GitHub Actions auto-detection in repo_info (similar to Heroku block), reading GITHUB_REF/GITHUB_SHA — that would be a separate enhancement." +3721,packaging,A,feature,REPRODUCED-on-v4.10.0,create_package_version.py:184 still defaults version_name to literal 'Release'; upload_production hardcodes name: Release in cumulusci.yml:685,,keep-open,"severity:low,area:packaging,area:1gp,area:2gp",v4.10.0,muselab-d2x fork commit 7aaf348f3 implements jinja2 templating for PackageUpload; not merged upstream; would need port + design for create_package_version too +3734,packaging,B,bug,REPRODUCED-on-v4.10.0,PackageUpload._validate_versions SOQL ORDER BY ... PatchVersion DESC; ReleaseState DESC LIMIT 1 returns a Beta patch (e.g. 6.13.1 Beta) as latest; then minor_version is set to the patch's MinorVersion (13); colliding with already-Released 6.13 server-side,/tmp/repro/3/tests/repro_3734_upload_production_beta_patch.py,keep-open,bug,v4.10.0,User's own analysis in last 3 comments is correct; current 'cannot-reproduce' label is stale; should be removed. Fix candidates: filter out Beta+Patch from the latest-version query; or filter ReleaseState='Released' for minor-detection and use a separate query for Beta. +3745,packaging,B,code-review,NOT-REPRODUCED-on-v4.10.0,latest_beta resolver looks up GitHub Releases (include_beta strategy) per install_package_version.py L96-100; reporter ran create_package_version standalone without release_2gp_beta which publishes the beta tag. Working as designed; reporter accepted the explanation 2024-02-13 and indicated closure intent.,/tmp/repro/4/evidence/3745-source-and-design.txt,closed:stale-24mo,n/a,v4.10.0,"No code defect; doc-improvement opportunity. Original closed:stale-24mo proposal stands. Could optionally add closed:not-a-bug if that vocabulary exists, but stale-24mo is fine." +3746,packaging,B,code-review,REPRODUCED-on-dev,"create_package_version._get_base_version_number SOQL at L535-541 of cumulusci/tasks/create_package_version.py selects highest Package2Version with no IsDeprecated filter. The same file at L297 DOES filter IsDeprecated=FALSE for Package2 lookups, confirming the omission at L535 is asymmetric and matches the report verbatim.",/tmp/repro/4/evidence/3746-source-soql.txt,kept-open,"severity:medium,area:packaging,target:v4-patch,needs-fix-trivial",dev,Trivial 1-line fix (add 'AND IsDeprecated = false' to the SOQL WHERE clause). Currently proposed closed:stale-24mo; recommend flip to kept-open + target:v4-patch given low fix cost and clear customer impact (wrong version numbers on next package version create after a delete).; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). +3754,cli,A,feature,REPRODUCED-on-v4.10.0,cumulusci/cli/utils.py:65-79 hardcodes 'https://pypi.org/pypi/cumulusci/json' with no env-var override or config flag. check_latest_version (line 82) cannot be disabled or redirected.,,keep-open,"enhancement,area:cli",v4.10.0,"User-suggested options (env flag to disable, custom URL) are all viable." +3758,packaging,A,bug,REPRODUCED-on-v4.10.0,push_upgrade_org flow in cumulusci/cumulusci.yml:1161-1177 still calls 'flow: config_qa' as final step; should be config_managed per bug report,/tmp/repro/1/tests/test_issue_3758.py,keep-open,"severity:medium,area:packaging,area:flows,good-first-issue",v4.10.0,Single-line YAML fix; both flows have same steps so behavior is currently equivalent but semantically wrong +3762,metadata-etl,B,bug,closed:duplicate-of-#3544,"Reporter (noahisapilot) explicitly self-identifies as duplicate of #3544 in their first comment on 2024-03-06. Both report the same root cause: update_admin_profile fails on a namespaced scratch org with PersonAccounts because the retrieved profile contains 'Account.Business_Account' record type with no namespace, but the namespace gets injected onto recordType references. The reporter's analysis even links the offending line at update_profile.py L238 (now L236 in v4.10.0)",,close-as-duplicate,,v4.10.0,Self-confirmed duplicate. No live repro performed per dup-confirm protocol. Canonical #3544 is still OPEN at v4.10.0 with a 'wi-created' label (W-12589033). +3768,bulkdata,B,bug,REPRODUCED-on-v4.10.0,"snowfakery.py architecturally creates a separate working dir per batch via shutil.copytree(template_path, data_dir) (queue_manager.py:322). _cleanup_object_tables (snowfakery.py:721) drops every non-sf_ids table from the template before it is copied to subsequent batch dirs, so just_once Account rows are gone from batch_2+. random_reference: Account in batch_2+ would resolve only against rows generated within that batch; with just_once: true, no Accounts are generated, so the random_reference cannot pick anything. The user's observed first-batch-works / later-batches-don't matches this exactly.",none — code-only,keep-open,"keep-open,bug,area:bulkdata,severity:major,v5-candidate:maybe",v4.10.0,Mixed CCI/Snowfakery responsibility. Could be fixed in CCI by preserving just_once-referenced object data (not just sf_ids) in the template carried to subsequent batches. Coordination with snowfakery dev branch likely needed. +3771,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,transforms.py transform_xpath() wraps tags in *[local-name()=...] but leaves predicate inner refs (e.g. price>40) namespace-bound; PR #3772 from leboff fork not merged,/tmp/repro/2/tests/test_issues_bucket_a.py::test_issue_3771_xpath_predicate_with_xmlns_resolves,keep-open,"severity:medium,area:source-transforms,type:bug,has-pr",v4.10.0,PR #3772 from external fork rewrites approach to strip xmlns; consider rebasing or implementing reporter's suggested 'remove xmlns then re-add' approach +3773,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,retrieve_profile_api.py _queries_retrieve_permissions never queries FieldPermissions table; only ObjectPermissions/SetupEntityAccess/PermissionSetTabSetting,/tmp/repro/2/tests/test_issues_bucket_a.py::test_issue_3773_retrieve_profile_queries_field_permissions,keep-open,"severity:medium,area:retrieve-profile,type:bug",v4.10.0,Architectural gap; field perms on standard objects without object perms are silently dropped; would benefit from org-side end-to-end verification but code evidence is conclusive +3849,python-modernization,Active-regression,import-only,REPRODUCED-on-dev,pyproject.toml pins selenium<4 + robotframework-seleniumlibrary<6 with no urllib3<2 cap; fresh pip resolves urllib3>=2 and breaks selenium 3.141.0,/tmp/repro/18/tests/test_issue_3849.py,keep-open,"needs:dependency-modernization,target:v5",dev,"pyproject.toml still pins selenium<4 and robotframework-seleniumlibrary<6 (lines 50, 54) with no urllib3 upper bound; requests permits urllib3<3,>=1.26 so a fresh pip install picks urllib3>=2.x. Selenium 3.141.0's connection pool uses the pre-2.0 Timeout sentinel API and breaks at Robot import. The local .venv survives only because uv.lock pins urllib3==1.26.20. The modernization (drop selenium<4 / robotframework-seleniumlibrary<6 OR add explicit urllib3<2) has not landed." +3852,cli,A,bug,REPRODUCED-on-v4.10.0,"pyproject.toml:52 still pins 'sarge' unconstrained; installed sarge 0.1.7.post1 lacks Capture.flush (verified: hasattr(sarge.Capture,'flush')==False). cumulusci/core/config/sfdx_org_config.py:212 still calls self.sfdx_info inside refresh_oauth_token, which triggers the AttributeError on Python 3.13 logging path.",,keep-open,"bug,upstream:sarge,py313",v4.10.0,"Per maintainer note in thread: cosmetic only (no functional impact), waiting on sarge 0.1.8 release. Could pin sarge to a git rev (gabrielrholl's note) but not preferred." +3854,cli,A,bug,REPRODUCED-on-v4.10.0,cumulusci/tasks/bulkdata/extract.py:371-374 still raises ConfigError 'Total mapping operations (X) do not match total non-empty rows (Y) for lookup_key' identical to user report. Validation introduced in PR #3741 / commit 2c5d0056e per swirkens' comment is still active in v4.10.0.,,keep-open,"bug,area:bulkdata,regression",v4.10.0,Workaround in thread: downgrade to 3.84.1. Real fix needed for polymorphic lookups. +3873,robotframework,feature-request,feature,REPRODUCED-on-dev,"cumulusci/robotframework/Salesforce.py and SalesforcePlaywright.py both subclass BaseLibrary (base_library.py) which imports cumulusci-internal services (CumulusCI, SalesforceAPI); the libraries cannot be used standalone without a CumulusCI project context",,keep-open,"enhancement,robotframework,scope-large",dev,Large architectural ask. No PR submitted in 16 months. Would require decoupling FakerMixin/BaseLibrary/Salesforce from cumulusci.core. No concrete API to test; tagging as feature-still-missing. Reasonable to keep open for future Copado-QForce-style refactor or close as wont-fix if scope is out-of-charter. +3884,packaging,B,partial-runtime,INCONCLUSIVE-needs-project-with-managed-deps,"Source review: PackageNamespaceVersionDependency.install (dependencies.py L437-475) and PackageVersionIdDependency.install (L499-528) BOTH guard with skip-if-already-at-this-or-newer-version logic. CumulusCI repo itself has no project__dependencies block, so end-to-end dev_org rerun cannot exercise the path. Likely the report conflates 'Resolving dependencies...' log noise or unmanaged-metadata redeploys with reinstalls.",/tmp/repro/4/evidence/3884-source-skip-logic.txt,closed:missing-fields,n/a,v4.10.0,"Original closed:missing-fields (rule 3 missing cci-version) is appropriate. Source review shows skip logic is in place; report may reflect unmanaged-metadata redeploy or user perception of log output. Without a customer project to reproduce on, no further action." +3886,dependencies,A,bug,REPRODUCED-on-v4.10.0,"Warning ""Optional dependencies are missing... cumulusci[select]"" emits at import time of cumulusci/tasks/bulkdata/select_utils.py whenever numpy/pandas/annoy/sklearn aren't installed. extract.py -> mapping_parser/step -> select_utils import chain triggers it on every extract_dataset run, even when no select strategy is configured. Behavior added in PR #3858 (89a5b5ddb) and unchanged through v4.10.0. Extraction itself works fine; only the noise persists.",/tmp/repro/11/tests/test_3886_select_warning.py,keep-open,"theme:dependencies,bulkdata,ux,log-noise",v4.10.0,"Dual-themed (bulkdata + dependencies); classified under dependencies per the bundle instructions. Fix candidates: defer warning until select strategy is actually used, or downgrade to debug-level." +3889,packaging,A,feature,REPRODUCED-on-v4.10.0,UninstallPackage only accepts namespace (1GP); UninstallPackageZipBuilder uses InstalledPackage destructive changes; no 04t/SubscriberPackageVersion-based uninstall task,,keep-open,"severity:medium,area:packaging,area:2gp,area:unlocked-package",v4.10.0,sf cli 'package uninstall -p 04t...' is the underlying API; new UninstallPackageVersion task could wrap Tooling API SubscriberPackageVersion delete +3899,packaging,B,partial-runtime,INCONCLUSIVE-needs-1gp-packaging-org,"unschedule_apex (cumulusci.yml L646-651) sends 1 line of trivial Apex via Tooling API: 'for (CronTrigger t : [SELECT Id FROM CronTrigger]) { System.abortJob(t.Id); }'. Ran cleanly on scratch org repro-pkg-b2-dev. Reporter's error references Salesforce platform-internal Java classes (system.scheduler.cron.JobType, common.udd.constants.CronJobTypeEnum) — root cause is upstream Salesforce platform NPE, not CCI.",/tmp/repro/4/evidence/3899-task-and-error-analysis.txt,kept-open,"severity:minor,area:packaging,external/upstream-salesforce,v5-candidate:no",v4.10.0,CCI sends correct trivial Apex; the System.UnexpectedException originates inside Salesforce's scheduler subsystem. Cannot fix in CCI. Recommend annotating with external/upstream-salesforce label (or equivalent) and considering close-as-not-our-bug after a brief look for any Salesforce known-issue reference. +3902,install-managed-security-type-04t,C,code-only,INCONCLUSIVE-needs-managed-package-04t,v4.10.0 install_package_version.py:162-167 routes 04t versions through PackageVersionIdDependency.install -> install_package_by_version_id -> _install_package_by_version_id which posts {'SecurityType': options.security_type} to the Tooling API PackageInstallRequest (package_install.py:170). Verified runtime serialization: SecurityType.ADMIN serializes to JSON 'NONE'. Both 04t and namespace+version paths pass security_type identically. No code-side defect found.,,needs-info,needs-managed-package-fixture,v4.10.0,"Could not provision a real managed package 04t to validate runtime API behavior. Code path is correct; observed user behavior (tab visible to non-admins) likely originates from Salesforce Tooling API treatment of SecurityType=NONE for upgrades or from package metadata, not from CumulusCI." +3910,scratch-org-config,bug,unit-pytest,REPRODUCED-on-dev,"ScratchOrg.namespaced declared as ``str`` in cumulusci/utils/yaml/cumulusci_yml.py:150; auto-generated cumulusci/schema/cumulusci.jsonschema.json:424 has ""type"": ""string""; ScratchOrg.parse_obj({""namespaced"": True}) silently coerces to ""True"" string. Open PR #3911 fixes both. Six XFAIL assertions added.",cumulusci/tests/triage/test_issue_3910.py,keep-open,"bug,has-open-pr",dev,Fixing the schema alone is insufficient because make schema regenerates it from the Pydantic model. PR #3911 correctly updates both files; recommend nudging it through review. +3929,packaging,B,runtime,NOT-REPRODUCED-on-v4.10.0,"Ran create_community with name=TestWebsite template='Customer Service' url_path_prefix=testwebsite against scratch org repro-pkg-b2-dev (orgs/dev.json with Communities feature). Community 0DBRK000000QtNR4A0 created in ~117s with normal polling escalation (1->2->3->...->8s) and exited the poll loop cleanly — no 300s timeout, no retry. Matches OP comment 2025-10-22 that the underlying SF CLI/server-side issue is fixed.",/tmp/repro/4/evidence/3929-create_community.log,closed:not-reproducible-on-v4.10.0,n/a,v4.10.0,Currently kept-open with needs-repro label; recommend flip to closed:not-reproducible-on-v4.10.0 (NEW vocabulary per spec amendment). Confirmed working end-to-end. Original cause was upstream SF CLI/Communities API bug now fixed. +3931,metadata-etl,B,bug,REPRODUCED-on-v4.10.0,Unit repro (with synthetic profile XML containing a layoutAssignments element that has a child but no child) raises 'AttributeError: NoneType object has no attribute text' at update_profile.py:291 inside _set_record_types. The buggy line is `if elem.find('recordType').text == rt['record_type']:` which assumes every layoutAssignments element has a recordType child; this is not true (a layoutAssignments without recordType applies to records without a record-type binding),/tmp/repro/5/tests/issue-3931/repro_unit.py,keep-open,bug,v4.10.0,Reported on cci 4.6.0 and reproduces unchanged on 4.10.0. Minimal fix at update_profile.py:290-293: change to `rt_elem = elem.find('recordType'); if rt_elem is not None and rt_elem.text == rt['record_type']: ...`. Also worth scanning sibling code in _set_record_types for similar None-deref patterns on optional children. +3936,bulkdata,B,bug,INCONCLUSIVE-needs-flaky-network,"salesforce_api/utils.py get_simple_salesforce_connection (lines 30-43) constructs Salesforce() with no timeout kwarg and only retries 502/503/504 via Retry(total=5). No CCI-side option exposes connect/read timeout for SF API calls. The reported error ""HTTPSConnectionPool ... Read timed out. (read timeout=None)"" with timeout=None usually means the proxy/VPN closed the socket; CCI cannot mitigate without exposing a configurable timeout AND a retry policy for read timeouts.",none — code-only,unchanged,"keep-open,bug,area:bulkdata,severity:major,needs-repro,v5-candidate:yes",v4.10.0,Already kept-open by maintainer (recent 2025-12-03). Environment-specific reproduction (corporate VPN). Confirmed structural gap: no exposed timeout option. v5 candidate: add timeout option + read-timeout retry to get_simple_salesforce_connection and to bulk job HTTP polling. +3938,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,rest_deploy.py _monitor_deploy_status (line 119) returns silently on Failed; __call__ also only logs on non-201 status_code; no exception raised,/tmp/repro/2/tests/test_issues_bucket_a.py::test_issue_3938_rest_deploy_failure_does_not_raise,keep-open,"severity:critical,area:rest-deploy,type:bug,silent-failure",v4.10.0,CRITICAL: rest_deploy:True silently passes failed deploys; flows continue thinking deploy succeeded. Recently filed (2025-12-16). Likely affects MetaDeploy plans +3939,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,metadata.py BaseMetadataApiCall.__call__ wraps every Exception from _process_response (incl. ApexTestException at line 540) in MetadataParseError losing original message,/tmp/repro/2/tests/test_issues_bucket_a.py::test_issue_3939_deploy_apex_test_failure_swallowed,keep-open,"severity:high,area:salesforce-api,type:bug,error-handling",v4.10.0,"Fix: re-raise CCI exception classes (MetadataApiError, MetadataComponentFailure, ApexTestException) without wrapping. Also recently filed; same reporter as #3938; both block production deploys" +3951,metadata-etl,B,bug,REPRODUCED-on-v4.10.0,Live repro: `cci task run set_duplicate_rule_status -o api_names Standard_Rule_for_Leads_with_Duplicate_Contacts -o active False` -> 'Cannot find metadata file .../duplicateRules/Standard_Rule_for_Leads_with_Duplicate_Contacts.duplicateRule'. Same command with the canonical API name format `Lead.Standard_Rule_for_Leads_with_Duplicate_Contacts` succeeds end-to-end (extract -> transform -> deploy -> Success). The functional task is not actually broken; the bug is the unhelpful error when the user omits the Object prefix that the Metadata API requires for DuplicateRule,/tmp/repro/5/tests/issue-3951/output-no-prefix.txt,improve-error-message,"bug,good-first-issue,documentation",v4.10.0,"Two improvements: (1) update set_duplicate_rule_status docs and task option help to show that api_names need the . format; (2) in MetadataSingleEntityTransformTask._transform (base.py:332), when the file is missing, list the files actually retrieved so users can spot the naming gap. Could also pre-validate api_names contain a dot for entity types that require it." +3953,metadata-etl,B,bug,REPRODUCED-on-v4.10.0,"Live CLI repro: `cci task run add_picklist_entries --org X -o picklists 'Account.Status__c' -o entries '[{""fullName"": ""TestValue"", ""label"": ""Test Value""}]'` -> 'The fullName key is required on all picklist values'. AddPicklistEntries._init_options (picklists.py:68) checks `'fullName' in entry for entry in self.options['entries']` directly, but no JSON parser is run on the CLI value first; the CLI passes 'entries' through as a string, so iteration walks the characters of the JSON string, none of which contain the substring 'fullName'. process_list_arg is run on 'picklists' but not on 'entries'",/tmp/repro/5/tests/issue-3953/output.txt,keep-open,"bug,good-first-issue",v4.10.0,"Minimal fix in AddPicklistEntries._init_options: if isinstance(self.options.get('entries'), str): self.options['entries'] = json.loads(self.options['entries']). Apply same pattern to record_types option for consistency. Same class of bug exists in AddFieldsToPageLayout (`fields` and `pages` options); see line 'value is not a valid list' from issue-3613 testing." +3955,robotframework,bug-in-source,bug,REPRODUCED-on-dev,"cumulusci/robotframework/SalesforcePlaywright.py:106 splits size with str.split('x', 1) yielding two strings, then passes them directly to browser.new_context(viewport={""width"": width, ""height"": height}) on line 109-111 without int casting; Playwright rejects strings with ""viewport.width: expected integer, got string""",cumulusci/tests/triage/test_issue_3955.py,keep-open,"bug,robotframework,playwright,good-first-issue",dev,Trivial 1-line fix: cast width/height to int. Pytest stubs the Browser library and asserts new_context receives int dimensions. diff --git a/docs/triage/v5/repro-results.md b/docs/triage/v5/repro-results.md new file mode 100644 index 0000000000..33e22273e2 --- /dev/null +++ b/docs/triage/v5/repro-results.md @@ -0,0 +1,4464 @@ +# Reproducibility Pass Results — Task 2.5c + +## Scope + +Two rounds of subagents: + +- **Round 1** (subagents 1-6): packaging + metadata-etl themes (45 issues; pre-v4.0.0 dropped per user; #3544 included as Cluster A canonical). +- **Round 2** (subagents 7-12): cli + bulkdata + dependencies + ci-integration themes (53 issues; pre-v4.0.0 dropped; cross-theme dups assigned to one subagent). +- **Total**: 98 of 142 open issues triaged via live v4.10.0 verification. +- Method: each subagent in an isolated git worktree pinned to `origin/main` (= release v4.10.0 at commit `129238663`); per-bucket org provisioning via DevHub `CCIDevHub`. +- See `themes.md` for the prior dry-run baseline; this file augments those proposals with v4.10.0 verdicts. + +## Totals (98 issues) + +| Verdict | Count | +| ---------------------------------------------- | ----: | +| `REPRODUCED-on-v4.10.0` | 68 | +| `NOT-REPRODUCED-on-v4.10.0` | 18 | +| `INCONCLUSIVE-needs-cumulus-actions-workflow` | 2 | +| `INCONCLUSIVE-needs-1gp-packaging-org` | 1 | +| `INCONCLUSIVE-needs-2GP-CI-pipeline` | 1 | +| `INCONCLUSIVE-needs-flaky-network` | 1 | +| `INCONCLUSIVE-needs-live-cli-test` | 1 | +| `INCONCLUSIVE-needs-managed-package-04t` | 1 | +| `INCONCLUSIVE-needs-namespaced-project` | 1 | +| `INCONCLUSIVE-needs-org-with-managed-package` | 1 | +| `INCONCLUSIVE-needs-project-with-managed-deps` | 1 | +| `INCONCLUSIVE-needs-scratch-slot` | 1 | +| `closed:duplicate-of-#3544` | 1 | + +## Per-round tally + +### Round 1 (packaging+metadata-etl, 45 issues) + +| Verdict | Count | +| ---------------------------------------------- | ----: | +| `REPRODUCED-on-v4.10.0` | 28 | +| `NOT-REPRODUCED-on-v4.10.0` | 10 | +| `INCONCLUSIVE-needs-1gp-packaging-org` | 1 | +| `INCONCLUSIVE-needs-2GP-CI-pipeline` | 1 | +| `INCONCLUSIVE-needs-cumulus-actions-workflow` | 1 | +| `INCONCLUSIVE-needs-managed-package-04t` | 1 | +| `INCONCLUSIVE-needs-namespaced-project` | 1 | +| `INCONCLUSIVE-needs-project-with-managed-deps` | 1 | +| `closed:duplicate-of-#3544` | 1 | + +### Round 2 (cli+bulkdata+dependencies+ci-integration, 53 issues) + +| Verdict | Count | +| --------------------------------------------- | ----: | +| `REPRODUCED-on-v4.10.0` | 40 | +| `NOT-REPRODUCED-on-v4.10.0` | 8 | +| `INCONCLUSIVE-needs-cumulus-actions-workflow` | 1 | +| `INCONCLUSIVE-needs-flaky-network` | 1 | +| `INCONCLUSIVE-needs-live-cli-test` | 1 | +| `INCONCLUSIVE-needs-org-with-managed-package` | 1 | +| `INCONCLUSIVE-needs-scratch-slot` | 1 | + +## Quick-action shortlist (high-confidence — proposed-pass1 deviates from dry-run baseline) + +Subagents surfaced the following items where the v4.10.0 verdict suggests a clear change from the dry-run proposed action: + +| # | Theme | Verdict | Subagent recommendation | Note | +| ----- | ------------------------------- | ---------------------------------------------- | ------------------------------------ | -------------------------------------------------------------------------------------------- | +| #733 | cli | `REPRODUCED-on-v4.10.0` | `closed:stale-24mo` | runtime.py:131-133 still raises ClickException with same hard error message; no interactiv… | +| #1348 | cli | `REPRODUCED-on-v4.10.0` | `closed:stale-24mo` | No 'gitlab' or 'bitbucket' references anywhere in cumulusci/; ci_feature flow still uses g… | +| #1350 | cli | `NOT-REPRODUCED-on-v4.10.0` | `closed:not-reproducible-on-v4.10.0` | project_config.py:52-57 sets up synthetic 'tasks' namespace package; include_source() at l… | +| #1432 | cli | `REPRODUCED-on-v4.10.0` | `closed:stale-24mo` | core/tasks.py:186-196 \_validate_options() only checks required; old-style task_options dic… | +| #1769 | bulkdata | `REPRODUCED-on-v4.10.0` | `closed:stale-24mo` | Test code-smell: `lookups["Id"] = MappingLookup(name="Id", table="accounts", key_field="sf… | +| #2096 | bulkdata | `NOT-REPRODUCED-on-v4.10.0` | `closed:not-reproducible-on-v4.10.0` | REST DML (`step.py:778-784 RestApiDmlOperation._record_to_json`) calls `process_bool_arg` … | +| #2140 | cli | `REPRODUCED-on-v4.10.0` | `closed:stale-24mo` | runtime.py get_org() calls keychain.get_org which raises OrgNotFound; cli/org.py:530-531 j… | +| #2402 | cli | `REPRODUCED-on-v4.10.0` | `closed:stale-24mo` | cli/flow.py:119-145 flow_run only has --delete-org flag; no --rebuild-org option; no rg ma… | +| #2505 | bulkdata | `NOT-REPRODUCED-on-v4.10.0` | `closed:feature-implemented` | `MappingStep.soql_filter` field added (mapping_parser.py:120). `extract.py:142-147` applie… | +| #2507 | cli | `REPRODUCED-on-v4.10.0` | `closed:stale-24mo` | No undo_insert task in repo; bulkdata/load.py and snowfakery have enable_rollback option b… | +| #2697 | cli | `INCONCLUSIVE-needs-scratch-slot` | `closed:stale-24mo` | namespaced field is sourced from cci config not auto-derived from SFDX qa.json; keychain c… | +| #3015 | cli | `REPRODUCED-on-v4.10.0` | `closed:stale-24mo` | cli/org.py:519-543 org_remove always calls delete_org() if can_delete; no --keep-org or -o… | +| #3024 | cli | `REPRODUCED-on-v4.10.0` | `closed:stale-24mo` | Flow groups in cumulusci/cumulusci.yml still appear in original order: Metadata Transforma… | +| #3161 | cli | `REPRODUCED-on-v4.10.0` | `closed:stale-24mo` | flowrunner.py:317-320 \_obfuscate_if_sensitive masks if task_options info.sensitive==True; … | +| #3167 | metadata-etl | `NOT-REPRODUCED-on-v4.10.0` | `close-as-implemented` | page*layout key on record_types is fully implemented in ProfileGrantAllAccess.\_set_record*… | +| #3283 | bulkdata | `NOT-REPRODUCED-on-v4.10.0` | `closed:fixed-by-pr-#3361` | PR #3361 (commit b0bfb70e0, "Support updates and upserts with blank dates represented by s… | +| #3307 | cli | `REPRODUCED-on-v4.10.0` | `closed:stale-24mo` | cli/project.py project_init only renders internal Jinja templates from cumulusci/files/tem… | +| #3320 | metadata-etl | `NOT-REPRODUCED-on-v4.10.0` | `closed:feature-implemented` | deactivate_flow task is shipped in cumulusci/cumulusci.yml:10-15 using ActivateFlow class … | +| #3347 | release-unlocked-beta-typeerror | `NOT-REPRODUCED-on-v4.10.0` | `close-with-comment` | create_package_version.py:158-159 now raises TaskOptionsError(PERSISTENT_ORG_ERROR) early … | +| #3360 | bulkdata | `NOT-REPRODUCED-on-v4.10.0` | `closed:feature-implemented` | action: select was added by commit b15945203 (Aug 2024) — well before v4.10.0. select_util… | +| #3466 | packaging | `NOT-REPRODUCED-on-v4.10.0` | `closed:feature-implemented` | RunApexTests in cumulusci/tasks/apex/testrunner.py exposes test_suite_names option (line 1… | +| #3470 | cli | `REPRODUCED-on-v4.10.0` | `closed:stale-24mo` | cumulusci.yml:823 only ci_master flow defined; no ci_main alias. davidmreed acknowledged b… | +| #3479 | ci-integration | `NOT-REPRODUCED-on-v4.10.0` | `closed:not-reproducible-on-v4.10.0` | Reported error "Expecting value: line 1 column 1 (char 0)" is the bare json.JSONDecodeErro… | +| #3561 | metadata-etl | `NOT-REPRODUCED-on-v4.10.0` | `close-as-fixed` | Bug was reported by yippie (who is also the PR author). Fix landed in commit 56e10665e (PR… | +| #3605 | packaging | `NOT-REPRODUCED-on-v4.10.0` | `closed:fixed-by-pr-#3651` | PackageUpload (upload_production backing class) exposes major_version and minor_version op… | +| #3607 | cli | `INCONCLUSIVE-needs-org-with-managed-package` | `closed:stale-24mo` | Code path traced in cumulusci/tasks/apex/testrunner.py: retry_failures regex compiled at l… | +| #3609 | cli | `INCONCLUSIVE-needs-live-cli-test` | `closed:stale-24mo` | cumulusci/tasks/sfdx.py is now a thin shell wrapper around 'sf {command}' (SFDX_CLI = 'sf'… | +| #3612 | cli | `NOT-REPRODUCED-on-v4.10.0` | `closed:not-reproducible-on-v4.10.0` | Issue is about the SFDO-Tooling/cci-vscode VSCode extension repo, not CumulusCI itself. Ou… | +| #3615 | dependencies | `NOT-REPRODUCED-on-v4.10.0` | `closed:not-reproducible-on-v4.10.0` | `--resolution_strategy preproduction` is documented in cumulusci.yml as an alias for `late… | +| #3699 | bulkdata | `REPRODUCED-on-v4.10.0` | `closed:stale-24mo` | extract.py \_soql_for_mapping does not append ORDER BY. mapping_parser MappingStep has no o… | +| #3701 | bulkdata | `REPRODUCED-on-v4.10.0` | `closed:stale-24mo` | mapping_parser.py:171/190/228/241/422 special-case "Id" — it always represents the SF Id a… | +| #3745 | packaging | `NOT-REPRODUCED-on-v4.10.0` | `closed:stale-24mo` | latest*beta resolver looks up GitHub Releases (include_beta strategy) per install_package*… | +| #3762 | metadata-etl | `closed:duplicate-of-#3544` | `close-as-duplicate` | Reporter (noahisapilot) explicitly self-identifies as duplicate of #3544 in their first co… | +| #3884 | packaging | `INCONCLUSIVE-needs-project-with-managed-deps` | `closed:missing-fields` | Source review: PackageNamespaceVersionDependency.install (dependencies.py L437-475) and Pa… | +| #3929 | packaging | `NOT-REPRODUCED-on-v4.10.0` | `closed:not-reproducible-on-v4.10.0` | Ran create_community with name=TestWebsite template='Customer Service' url_path_prefix=tes… | + +## Per-subagent SUMMARY chunks + +#### Bucket A — Packaging triage summary + +Subagent 1 (`pkg-bucket-a`). Worktree pinned at `v4.10.0` / commit `129238663`. +10 issues processed; no GitHub mutations; no Salesforce org used. + +#### Verdict counts + +| Verdict | Count | Issues | +| ------------------------- | ----- | ------------------------------------------------------ | +| REPRODUCED-on-v4.10.0 | 8 | #2979, #3429, #3440, #3441, #3593, #3721, #3758, #3889 | +| NOT-REPRODUCED-on-v4.10.0 | 2 | #3466, #3605 | +| INCONCLUSIVE-\* | 0 | — | +| SKIPPED | 0 | — | + +#### Repro tests written (under `/tmp/repro/1/tests/`) + +| Test file | Purpose | Result on v4.10.0 | +| -------------------- | ------------------------------------------------------------------------ | ---------------------------- | +| `test_issue_3466.py` | confirms `test_suite_names` option exists on `RunApexTests` | passes (feature implemented) | +| `test_issue_3593.py` | demonstrates `SFDXOrgTask` still appends `-o ` unconditionally | fails (bug present) | +| `test_issue_3605.py` | confirms `major_version`/`minor_version` exist on `PackageUpload` | passes (feature implemented) | +| `test_issue_3758.py` | asserts `push_upgrade_org` final step calls `config_managed` | fails (bug present) | + +`#2979`, `#3429`, `#3440`, `#3441`, `#3721`, `#3889` are all features whose absence is verifiable purely by code inspection (no test scaffolding needed); see `narrative.md` for `path:line` evidence. + +#### Pass-1 recommended actions + +| Recommendation | Issues | +| ---------------------------- | ------------------------------------------------------ | +| `keep-open` | #2979, #3429, #3440, #3441, #3593, #3721, #3758, #3889 | +| `closed:feature-implemented` | #3466 | +| `closed:fixed-by-pr-#3651` | #3605 | + +#### Cross-cutting findings + +1. **Multi-package SFDX umbrella (#2979, #3429, #3440)** — three open enhancements all point at the same gap: CumulusCI assumes a single package per repo. `default_package_path` exists but is only consumed by `create_package_version`. A single small design refactor (Deploy gets a `path: $project_config.default_package_path` default, `default_package_path` becomes name-aware, and a `cumulusci.yml` override mechanism is added) could resolve all three. Worth folding them into one umbrella issue or theme on the pass-2 labeling pass. + +2. **Null/sentinel overrides in flow steps (#3441)** — yippie's comment generalizes the request: CCI lacks any way to "unset" or "reset to default" an option that a flow step has set. This is a CCI-wide ergonomics gap (not just `version_base`), and probably belongs as its own meta-issue. + +3. **PR #3969 (`extra-yaml-cli-flag`) is in flight for #3429** — adds `--extra-yaml` and `CUMULUSCI_EXTRA_YAML`. Not yet in v4.10.0. Recommend the parent agent flip #3429 to `closed:fixed-by-pr-#3969` once that PR merges; until then `keep-open` is correct. + +4. **muselab-d2x fork has a fix for #3721** — commit `7aaf348f3` ("Change version naming on PackageUpload task to use the predicted version number and a jinja2 template expression") implements jinja2 templating for `PackageUpload.version_name`. Lives only on `d2x/*` remotes. Could be ported upstream as a small PR; would also need a sibling change in `create_package_version.py:184` for 2GP coverage. + +5. **One-line YAML fix candidate (#3758)** — `push_upgrade_org` last step should be `config_managed`, not `config_qa`. Currently both expand to the same task list, so it's not a behavior regression today, but the docs link customers to the wrong page. Excellent `good-first-issue` for an external contributor; explicitly out of scope for this triage pass. + +6. **`SFDXOrgTask` org-flag append (#3593)** — recurring pain point as sf cli surface evolves; a generic `pass_org` / `no_org` opt-out option (or a curated whitelist of no-org subcommands) is a more durable fix than the user's `#` workaround. Verifying actual sf cli behavior of `project convert source` would need an org/sf cli; the CCI side of the bug is unchanged on v4.10.0. + +7. **2GP unlocked uninstall (#3889)** — natural shape is a new `UninstallPackageVersion` task that calls Tooling API `SubscriberPackageVersion` delete directly, avoiding the sf cli stability concern the user calls out. Aligns with broader 2GP investment. + +#### Bucket A — metadata-etl summary (Subagent 2) + +**Worktree**: `/Users/jestevez/work/rel/CumulusCI/.worktrees/repro-etl-bucket-a` +**Pinned commit**: `129238663` (Release v4.10.0) +**Issues processed**: 11 / 11 + +#### Verdict counts + +| verdict | count | issues | +| ------------------------- | ----- | -------------------------------------------------------------------- | +| REPRODUCED-on-v4.10.0 | 10 | #3137, #3331, #3518, #3543, #3585, #3692, #3771, #3773, #3938, #3939 | +| NOT-REPRODUCED-on-v4.10.0 | 1 | #3320 | +| INCONCLUSIVE | 0 | — | +| SKIPPED | 0 | — | + +#### Severity / urgency picks (most worth flagging in pass-1) + +- **#3938 (CRITICAL, recently filed 2025-12-16)** — `rest_deploy: True` silently + swallows failed deployments and reports success. Affects MetaDeploy plans + and any flow using `rest_deploy`. Same reporter as #3939; likely both + blocking the same production-deploy workflow. +- **#3939 (HIGH, recently filed 2025-12-16)** — Even SOAP-path deploys lose + their actual error text because `BaseMetadataApiCall.__call__` wraps every + exception in the generic "Could not process MDAPI response" message. + Apex test failures, component failures, and API errors are all clobbered. +- **#3518 (HIGH)** — `add_picklist_entries` always marks a default for record + types because of a missing `()` after `.lower` (picklists.py:177); blocks + any non-default picklist additions on objects with record types. + +#### Cross-cutting findings + +- **Error-handling pattern (#3938 + #3939)**: Both critical bugs come from + the same anti-pattern — an outer try/except at the orchestration layer + swallows exceptions raised by inner code that was correctly trying to + surface a user-actionable error. Worth a single PR that audits both + code paths and keeps `CumulusCIException` subclasses unwrapped. +- **`metadata_map.yml` accuracy (#3331 + #3692 + arguably #3585)**: Three + separate bugs trace back to the YAML metadata-name registry being + out-of-date or inconsistent: wrong type name (`AssignmentRule` vs + `AssignmentRules`), missing entry (`digitalExperiences`), and lack of + parser robustness against newer SFDX-emitted XML quirks (`xsi:nil="true"`). + A single sweep against the current MDAPI catalog would close all three. +- **External fork PR for #3771**: Commit `2bf6ce6a3` ("Improve namespace + handling in find_replace") exists on `remotes/leboff/...` but never + landed on origin/main. Bringing that PR back through review would close + the issue. +- **#3320 mismatch**: Reporter asked for a `deactivate_flow` task; one is + already shipped in `cumulusci/cumulusci.yml:10-15`. Likely a docs / + discoverability issue rather than a code one — worth flagging in pass-2 + as `closed:feature-implemented` plus a small doc improvement. +- **Architectural gap for #3773**: `RetrieveProfileApi._queries_retrieve_permissions` + doesn't query `FieldPermissions` at all. This is a class-of-omission + bug: any object that has profile field-perms but no object-perms + (very common for standard objects like `AccountContactRelation`) is + silently dropped. Likely there are other under-queried permission + surfaces too — worth a focused review. + +#### Output artifacts + +- `/tmp/repro/2/repro-results.csv` — machine-readable results (12 rows) +- `/tmp/repro/2/narrative.md` — per-issue evidence and recommended actions +- `/tmp/repro/2/tests/test_issues_bucket_a.py` — 11 throwaway repro tests; + all 11 currently fail on v4.10.0 (= bugs reproduced). + +#### Constraint compliance + +- No `git push` from worktree. +- No GitHub mutations (only read-only inspection of bundled JSON). +- No writes under `cumulusci/robotframework/`. +- All repro tests live under `/tmp/repro/2/tests/`, not in the worktree + source tree. +- No third-party packages added; tests use only `pytest`, `pyyaml`, and + in-tree CCI modules. +- `uv run pytest ...` used for test execution. + +# + +**Theme**: packaging +**Bucket**: B (scratch-org-required) +**Worktree**: `.worktrees/repro-pkg-bucket-b1` @ `129238663` (release v4.10.0) +**Issues processed**: 6 / 6 + +#### Verdict tally + +| Verdict | Count | Issues | +| ------------------------------------------------- | ----- | ------------ | +| REPRODUCED-on-v4.10.0 | 2 | #3446, #3734 | +| NOT-REPRODUCED-on-v4.10.0 (feature unimplemented) | 2 | #3587, #3600 | +| INCONCLUSIVE-needs-cumulus-actions-workflow | 1 | #3418 | +| INCONCLUSIVE-needs-2GP-CI-pipeline | 1 | #3542 | +| **Total** | **6** | | + +#### Recommended pass1 actions + +| Issue | Action | Reasoning | +| ----- | --------- | ------------------------------------------------------------------ | +| #3418 | unchanged | external github action; needs cross-repo investigation | +| #3446 | keep-open | reproduced; simple fix (validate version) + UX (Push API guidance) | +| #3542 | unchanged | external CI/CD; needs reporter info on workflow SHA semantics | +| #3587 | keep-open | feature still missing; small enhancement | +| #3600 | keep-open | feature still missing; needs design decision on syntax | +| #3734 | keep-open | reproduced; remove stale `cannot-reproduce` label | + +#### Cross-cutting findings + +1. **Two clear bugs reproducing on v4.10.0 (#3446, #3734)** with well-localized root causes: + - #3446 is a missing-validation bug in `cumulusci/tasks/push/tasks.py` `_run_task` / `_parse_version`. + - #3734 is a logic bug in `cumulusci/tasks/salesforce/package_upload.py` `_validate_versions` where a Beta patch on a previous minor is treated as the latest version. +2. **Two unimplemented features (#3587, #3600)** suitable for "good-first-issue" tagging: + - #3587 wants a one-line warning in `UpdatePackageXml._init_task`. + - #3600 wants env-var substitution in task options — broader scope (touches all options, not just `install_managed`); needs design. +3. **Two issues that escape cci's repo boundary (#3418, #3542)**: + - #3418 is in `SFDO-Community/standard-workflows`; cci has no `auth:sfdxurl:store` code path. + - #3542 is a SHA-mismatch problem between the workflow that posts a commit status and the local checkout that reads it; could be fixed in `cumulus-actions/standard-workflows` or by adding a parent-commit fallback in `get_version_id_from_commit`. +4. **Mislabeled triage state on #3734**: the user's last three comments contain a correct, fully-localized root-cause analysis. The `cannot-reproduce` and `awaiting-more-details` labels are stale and should be dropped in pass2 in favor of `bug`. +5. **Code stability**: none of the relevant code paths for these six issues have changed materially between the issue dates and v4.10.0 (verified via `git log` for `cumulusci/tasks/push/`, `cumulusci/tasks/salesforce/package_upload.py`, `cumulusci/tasks/github/commit_status.py`, `cumulusci/tasks/metadata/package.py`, `cumulusci/utils/yaml/safer_loader.py`, `cumulusci/core/tasks.py`). + +#### Scratch orgs used + +- `repro-pkg-b1-dev` (cci alias) / `CumulusCI__repro-pkg-b1-dev` (sf alias) — config `dev`, used for live `install_managed` and `push_qa` invocations. + +No second alias was needed; `feature` config was not required. + +#### Cleanup status + +**Cleanup completed successfully**. Verified at end of session: + +``` +$ uv run cci org list 2>&1 | grep -i 'pkg-b1' + (no rows match) +$ sf org list 2>&1 | grep -i 'pkg-b1' + (no rows match) +``` + +Steps taken: + +1. `uv run cci org scratch_delete repro-pkg-b1-dev` — sf-side org deleted via `sf org delete scratch -p -o test-ra9moqy3oqup@example.com`. +2. `uv run cci org remove repro-pkg-b1-dev` — cci keychain alias removed (cci was still listing the alias even after `scratch_delete` because the alias entry persists locally). + +#### Output files (under `/tmp/repro/3/`) + +- `repro-results.csv` — one row per issue (header + 6 data rows). +- `narrative.md` — per-issue method/evidence/recommendation. +- `tests/repro_3446_push_qa_no_version.py` — reproduces NoneType.split. +- `tests/repro_3587_update_package_xml_no_warning.py` — confirms install_class silently dropped. +- `tests/repro_3600_install_managed_no_env_var.py` — confirms no env-var substitution. +- `tests/repro_3734_upload_production_beta_patch.py` — confirms Beta-patch sets colliding minor. + +#### Deviations from constraints + +None. + +# + +#### Verdict tally (5 issues processed) + +| Verdict | Count | Issues | +| ---------------------------------------------- | ----- | ------------ | +| `REPRODUCED-on-v4.10.0` | 1 | #3746 | +| `NOT-REPRODUCED-on-v4.10.0` | 2 | #3745, #3929 | +| `INCONCLUSIVE-needs-project-with-managed-deps` | 1 | #3884 | +| `INCONCLUSIVE-needs-1gp-packaging-org` | 1 | #3899 | +| `SKIPPED-policy-*` | 0 | — | + +Total: 5 / 5 (100%). + +#### Cross-cutting findings + +1. **Two of five issues had already self-resolved upstream**: #3745 (user-confusion about ci_beta requiring release_2gp_beta to publish the GitHub release tag — accepted by the reporter in-thread) and #3929 (an upstream Salesforce CLI / Communities API bug that is now fixed per OP comment 2025-10-22 and confirmed end-to-end against scratch org). The triage policy's stale-24mo and needs-repro proposals respectively were defensible at proposal time but #3929 should now flip to `closed:not-reproducible-on-v4.10.0`. + +2. **One real, trivially-fixable v4.10 bug surfaced**: #3746 (`create_package_version._get_base_version_number` SOQL has no `IsDeprecated = false` filter). The same file has the filter on a parallel `Package2` lookup at line 297, so the omission at line 535 is asymmetric and the fix is one clause. This is a `target:v4-patch` candidate hidden under a stale-24mo proposal. + +3. **One issue is provably an upstream Salesforce platform bug, not CCI**: #3899. The reported error (`system.scheduler.cron.JobType.getJobImplementation()` being null) references Salesforce-internal Java classes; CCI sends correct Apex; trivial Apex runs cleanly on a fresh scratch org. The triage labelling vocabulary should grow an `external/upstream-salesforce` Pass-2 label so future triage can disposition this class of report quickly. + +4. **One issue is plausibly user-misperception of log noise**: #3884 (dev_org "reinstalls" same package version). Source review confirms skip-if-already-installed logic is present in v4.10.0 for both managed-package install paths. Without a customer project that has managed deps, we cannot disprove a corner case, but the proposed `closed:missing-fields` (rule 3) is the right disposition because the report lacks the `cumulusci.yml` excerpt that would let us identify which dependency type they observed. + +5. **Methodology note**: 2 of 5 verdicts were reachable by code review alone (#3745, #3746), 1 required a brief scratch-org runtime check that succeeded (#3899 partial; #3929 full), and 1 required a runtime check that fully resolved the question (#3929). The scratch org was reused across all runs — quota cost: 1 dev-config scratch (already provisioned, not torn down per "Scratch org cleanup" below since other subagents may still be relying on the DevHub quota math). + +#### Scratch org aliases used + +- `repro-pkg-b2-dev` (config: `orgs/dev.json`, expires 2026-05-15 08:51 PT, instance `customization-java-47-dev-ed.scratch`). + - Used for: #3899 unschedule_apex runtime check, #3929 create_community runtime check. + - Already existed at session start (presumably from a prior controller run); reused, not recreated, so no fresh DevHub-create quota was consumed by this subagent. + +#### Output files written + +- [`/tmp/repro/4/repro-results.csv`](/tmp/repro/4/repro-results.csv) — 5 rows + header, full triage CSV schema per plan §2.5c step 5. +- [`/tmp/repro/4/narrative.md`](/tmp/repro/4/narrative.md) — per-issue narrative, sorted by verdict (REPRODUCED first). +- [`/tmp/repro/4/SUMMARY.md`](/tmp/repro/4/SUMMARY.md) — this file. +- [`/tmp/repro/4/evidence/`](/tmp/repro/4/evidence/) — 5 evidence files, one per issue, referenced from `repro-results.csv` and `narrative.md`. + +#### Deviations from the prompt + +- The scratch org `repro-pkg-b2-dev` was already provisioned at session start (left over from a prior run, healthy and unexpired). Reused it directly rather than creating a new one. Documented above; conserves DevHub quota. +- Cleanup decision deferred to the controller — see "Scratch org cleanup" note below. + +#### Scratch org cleanup (executed) + +``` +$ uv run cci org scratch_delete repro-pkg-b2-dev +[05/14/26 02:07:26] Deleting scratch org with command: sf org delete scratch -p + -o test-qu66hqqypnu3@example.com +[05/14/26 02:07:28] (success) + +$ uv run cci org remove repro-pkg-b2-dev +(silently removes the cci keychain entry) + +$ sf org list scratch --target-dev-hub CCIDevHub | grep qu66hqqypnu3 || echo "absent" +absent + +$ uv run cci org list | grep repro-pkg-b2 || echo "absent" +absent +``` + +DevHub `CCIDevHub` quota slot returned. No worktree branch pushed. No GitHub mutations performed. No files written under `cumulusci/robotframework/`. + +# + +Theme: **metadata-etl** · Bucket **B** · Worktree `.worktrees/repro-etl-bucket-b` @ commit `129238663` (release v4.10.0) + +#### Verdict tally (10 issues processed) + +| Verdict | Count | Issues | +| ------------------------------------------- | ----- | ------------------------------------------------ | +| REPRODUCED-on-v4.10.0 | 7 | #808, #2826, #3165, #3613, #3931, #3951, #3953 | +| NOT-REPRODUCED-on-v4.10.0 (already fixed) | 1 | #3561 (fix in PR #3566, May 2024) | +| NOT-REPRODUCED-on-v4.10.0 (feature shipped) | 1 | #3167 (PR #3243, June 2022) | +| closed:duplicate | 1 | #3762 (dup of #3544; self-confirmed by reporter) | + +Of the 7 REPRODUCED: + +- 4 are real correctness bugs (#808, #2826, #3165, #3931) +- 2 are UX/error-message bugs (#3613, #3951) — underlying functionality works with correct input +- 1 is a CLI option-parsing bug (#3953) — task is unusable from CLI + +#### Cross-cutting findings + +##### 1. CLI doesn't auto-parse JSON list options for several ETL tasks + +`AddPicklistEntries.entries`, `AddFieldsToPageLayout.fields/pages`, and likely other dict-list options can be set in `cumulusci.yml` (where the YAML loader parses them into lists/dicts) but break from the CLI when passed as JSON strings. Each task currently has to re-implement parsing if it wants to support CLI use. + +Issues affected: **#3953** (confirmed) and **add_page_layout_fields** (found while testing #3613). + +Likely fix venues: + +- One-line `json.loads` in each affected task's `_init_options`. Cheap, low risk. +- Or: a generic helper on `BaseTask._init_options` that walks `task_options` declared as list/dict and JSON-parses string values. Higher impact, deeper change. +- Or: leverage Pydantic-validated `task_options` (already used in `AddFieldsToPageLayout` for `AddFieldsToLayoutOptions`) to coerce strings -> JSON via a validator. + +##### 2. `MetadataSingleEntityTransformTask` "Cannot find metadata file" error is unhelpful + +`MetadataSingleEntityTransformTask._transform` (base.py:332) raises a generic message when the user-provided `api_names` value doesn't match any retrieved file. Shared root cause behind **#3613** (Layout) and **#3951** (DuplicateRule), and probably also explains user confusion with other entities like `Profile`, `Flow`, `RecordType` whose Metadata API names follow non-obvious patterns. + +Suggested fix: when the file is missing, also log the list of files actually retrieved into `source_metadata_dir`. Single change, multi-issue improvement. + +##### 3. `update_admin_profile`'s `record_types` plus `_expand_package_xml` gating is fragile + +The `record_types` -> `_expand_package_xml_objects` dependency is buried inside `_expand_package_xml`, which is gated on `include_packaged_objects=True`. This means a user who specifies `record_types` for an object outside the default `admin_profile.xml` package list — without also setting `include_packaged_objects: true` — silently skips the package.xml expansion needed for their record types. + +Issues affected: **#3165** (record_type for Case fails). Probably also a contributing factor in **#3544 / #3762** (the namespaced-org Person Accounts crash). + +The fix is a one-line refactor: always call `_expand_package_xml_objects` (which only walks the user's options); only call the full `_expand_package_xml` (Tooling API query) when `include_packaged_objects=True`. + +##### 4. Several issues are "long-tail" enhancement requests still open + +**#808** (2018), **#2826** (2021), **#3167** (2022, now implemented), **#3561** (2023, now fixed). The pattern suggests value in periodic dup/staleness sweeps that pair issues with PRs (#3167 ↔ #3243, #3561 ↔ #3566) — both were closed by a PR but the issue was never auto-closed. + +#### Scratch org aliases used + +- `repro-etl-b-dev` — used for live repros of #3613, #3951, #3953. Pre-existed from a prior subagent setup; reused as instructed. Will be deleted in the cleanup step. Created 2026-05-14 with `dev.json`, expires 2026-05-15. + +No additional scratch orgs created. + +#### Output files + +- `/tmp/repro/5/repro-results.csv` — verdict CSV (10 rows + header) +- `/tmp/repro/5/narrative.md` — per-issue narrative (10 sections) +- `/tmp/repro/5/SUMMARY.md` — this file +- `/tmp/repro/5/tests/issue-2826/repro_unit.py` — Python repro (FileNotFoundError) +- `/tmp/repro/5/tests/issue-3165/repro_unit.py` — Python repro (package.xml expansion gap) +- `/tmp/repro/5/tests/issue-3613/output-just-object.txt` — CLI output (Cannot find metadata file) +- `/tmp/repro/5/tests/issue-3613/output-good-name.txt` — CLI output (success with correct API name) +- `/tmp/repro/5/tests/issue-3931/repro_unit.py` — Python repro (NoneType.text) +- `/tmp/repro/5/tests/issue-3931/repro-output.txt` — captured output +- `/tmp/repro/5/tests/issue-3951/output-no-prefix.txt` — CLI output (Cannot find metadata file) +- `/tmp/repro/5/tests/issue-3953/output.txt` — CLI output (fullName key required) + +#### Deviations + +None. All 10 issues processed within the protocol. No GitHub mutations. No commits to the worktree. No edits to `cumulusci/robotframework/`. No `git push`. No package additions to `pyproject.toml`/`uv.lock`. + +# + +#### Verdict tally + +| Verdict | Count | Issues | +| ---------------------------------------- | ----- | ------ | +| `NOT-REPRODUCED-on-v4.10.0` | 1 | #3347 | +| `INCONCLUSIVE-needs-managed-package-04t` | 1 | #3902 | +| `INCONCLUSIVE-needs-namespaced-project` | 1 | #3544 | +| `REPRODUCED-on-v4.10.0` | 0 | — | +| **Total processed** | **3** | | + +#### Scratch org aliases used + +| Alias | Config | DevHub | Status | +| -------------------- | ----------------- | --------- | ------------------------------------------------------------------------------ | +| `repro-special-c-pa` | `person_accounts` | CCIDevHub | Created (existed at session start, reused), used for #3544, slated for cleanup | + +No other aliases created. #3902 and #3347 were code-only investigations. + +#### Per-issue outcomes + +##### #3347 — `release_unlocked_beta` TypeError → fixed + +Cryptic `TypeError: expected str, bytes or os.PathLike object, not NoneType` is replaced on v4.10.0 by an early `TaskOptionsError(PERSISTENT_ORG_ERROR)` at `cumulusci/tasks/create_package_version.py:158-159`, fix landed in commit `2a9cadcb1` (2023-10-12). Existing test `test_create_package_version.py::TestPackageConfig::test_org_config` validates the new behavior and passes. **Recommend close-with-comment.** + +##### #3902 — `install_managed` security_type with 04t → code looks correct, runtime not validatable + +Code path inspection on v4.10.0 confirms `install_managed` faithfully passes `security_type` to the Salesforce Tooling API `PackageInstallRequest.SecurityType` for both 04t and namespace+version code paths. `SecurityType.ADMIN` correctly serializes to JSON `"NONE"`. No CumulusCI defect identified; observed user behavior likely originates from Salesforce platform behavior (upgrade vs fresh install, App-level tab visibility, etc.). **Cannot fully validate without a reusable managed package 04t fixture — verdict INCONCLUSIVE-needs-managed-package-04t.** + +##### #3544 — `update_admin_profile` with PersonAccounts + namespacing → not validatable in CumulusCI repo + +Bug requires the intersection of PersonAccounts AND a namespaced project. CumulusCI itself has no project namespace, so the repro condition cannot be fully satisfied without registering a namespace in CCIDevHub (out of scope). Partial repro: `update_admin_profile` ran SUCCESSFULLY against a non-namespaced PersonAccounts scratch on v4.10.0, confirming the bug is specific to the namespaced+PersonAccounts intersection. No code-level fix found referencing #3544 / W-12589033 in `update_profile.py` since 2023. **Verdict INCONCLUSIVE-needs-namespaced-project.** + +#### Per-issue blocker explanations + +| Issue | Blocker | Mitigation | +| ----- | ----------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | +| #3347 | None — code-only verifiable | Existing pytest passes on HEAD | +| #3902 | No reusable managed package 04t fixture available within CCIDevHub workflow | Recommend Pass 2 label `needs-managed-package-fixture` | +| #3544 | CumulusCI repo has no project namespace; cannot satisfy `namespaced:true` repro condition | Recommend Pass 2 label `needs-namespaced-project` and ask reporter to retest on v4.10.0 | + +#### Adjacent finding (not in scope but worth recording) + +While exercising `-o namespaced_org True` on a non-namespaced project for #3544, surfaced a latent `TypeError: unsupported operand type(s) for +: 'NoneType' and 'str'` at `cumulusci/utils/__init__.py:229`: + +```229:229:cumulusci/utils/__init__.py + namespaced_org = namespace + "__" if namespaced_org else "" +``` + +Distinct from #3544 (init-time vs deploy-time). Suggest a separate small cleanup ticket. + +#### Outputs + +- `/tmp/repro/6/repro-results.csv` — header-conforming CSV with 3 rows +- `/tmp/repro/6/narrative.md` — per-issue narrative sections +- `/tmp/repro/6/SUMMARY.md` — this file +- `/tmp/repro/6/tests/` — directory created but no new test files written (used existing in-repo test for #3347; manual cci command for #3544; pure code inspection for #3902) + +#### Constraints honored + +- No `git push` from worktree. +- No GitHub mutations. +- No edits under `cumulusci/robotframework/`. +- No edits to `pyproject.toml`/`uv.lock`. +- All commands run via `uv run …` from the worktree. +- DevHub: `CCIDevHub` only. +- Scratch alias prefix: `repro-special-c-`. + +# + +Worktree: `.worktrees/repro-cli-part1` @ `129238663` = release v4.10.0. + +#### Verdict tally (13 issues) + +| Verdict | Count | Issues | +| ------------------------------- | ----- | -------------------------------------------------------------------------- | +| REPRODUCED-on-v4.10.0 | 11 | #733, #1348, #1432, #2140, #2402, #2507, #3015, #3024, #3161, #3307, #3470 | +| NOT-REPRODUCED-on-v4.10.0 | 1 | #1350 | +| INCONCLUSIVE-needs-scratch-slot | 1 | #2697 | + +By type: 10 features, 3 bugs (one of which is partially-fixed: #1432; one fully-fixed: #1350; one inconclusive: #2697). + +#### Recommended pass1 labels + +| Recommendation | Count | Issues | +| ----------------------------------------------- | ----- | ---------------- | +| `closed:stale-24mo` (confirms dry-run proposal) | 12 | all except #1350 | +| `closed:not-reproducible-on-v4.10.0` | 1 | #1350 | + +So **12 of 13 dry-run `closed:stale-24mo` proposals stand**. One should be re-categorised as `closed:not-reproducible-on-v4.10.0` (#1350). + +#### Cross-cutting findings + +1. **Most of the bundle is stable feature requests with very little movement** (#733 from 2018, #1348 from 2019, #2140 from 2020, etc.). The `closed:stale-24mo` action is appropriate; the work-items in some cases (W-028291, W-10502624, W-10502512) have been tracked for years without delivery. + +2. **#1350 is the only clear "we shipped a fix" issue**: a synthetic `tasks` namespace package was added (`cumulusci/core/config/project_config.py:52-57`) plus `_add_tasks_directory_to_python_path()` so cross-project task imports now resolve. The follow-up _name-collision_ concern raised by `prescod` in 2022 is a separate concern and would warrant its own issue if anyone hit it again. + +3. **#1432 and #2507 and #3161 each show "partial mitigation"** — infrastructure has landed but the original ergonomic request is not fully satisfied. Worth flagging in `notes` so these don't get re-triaged as still-open feature debt without context. Adding `partially-fixed` / `partially-implemented` labels in pass2 surfaces this. + +4. **Inclusive-language angle (#3470)**: the rename remains undone but the underlying need (flow aliasing) is acknowledged. If pass2 includes a `inclusive-language` label, this is the only candidate. + +5. **No issues should remain open** — all 13 are either fixed, stale, or design-as-intended (the design-as-intended one, #2697, is best closed with a `needs-info` framing if anyone reopens). + +#### Scratch org aliases used + +**No scratch needed**. All 13 issues were resolved via code-scan (Bucket A) plus one unit test. #2697 was the only candidate for Bucket B and the code reading was conclusive enough to defer scratch provisioning (DevHub-slot conservation per instructions). + +#### Output files + +- `/tmp/repro/7/repro-results.csv` — 13 rows, header included. +- `/tmp/repro/7/narrative.md` — H3 section per issue. +- `/tmp/repro/7/SUMMARY.md` — this file. +- `/tmp/repro/7/tests/test_1432_options_validation.py` — unit repro for #1432 (passes on v4.10.0). + +#### Deviations + +None. + +# + +**Pinned commit**: `129238663` (Release v4.10.0) +**Branch**: `worktree/repro/cli-part2` +**Worktree**: `.worktrees/repro-cli-part2` +**Issues processed**: 13 / 13 +**Scratch orgs provisioned**: none — all repros completed via Bucket A (code-scan + one isolated unit test) + +#### Verdict tally + +| Verdict | Count | Issues | +| ------------------------------------------- | ----- | -------------------------------------------------------------------- | +| REPRODUCED-on-v4.10.0 | 10 | #3485, #3492, #3506, #3549, #3570, #3618, #3663, #3754, #3852, #3854 | +| INCONCLUSIVE-needs-org-with-managed-package | 1 | #3607 | +| INCONCLUSIVE-needs-live-cli-test | 1 | #3609 | +| NOT-REPRODUCED-on-v4.10.0 | 1 | #3612 | + +#### Pass-1 recommendation tally + +| Recommendation | Count | Issues | +| ------------------------------------ | ----- | -------------------------------------------------------------------- | +| `keep-open` | 10 | #3485, #3492, #3506, #3549, #3570, #3618, #3663, #3754, #3852, #3854 | +| `closed:stale-24mo` | 2 | #3607, #3609 | +| `closed:not-reproducible-on-v4.10.0` | 1 | #3612 | + +Both kept-open issues from the dry-run (#3852, #3854) remain `keep-open` here — verdicts confirm the maintainer's label. + +#### Cross-cutting findings + +1. **Flow `when:` clause is structurally limited.** Three issues in this batch (#3506, #3570, #3663) all expose the same surface: the `when:` evaluator at `cumulusci/core/flowrunner.py:510-516` only sees `project_config` + `org_config`, and `when:` is only honored on `task:` steps (line 669) — never on `flow:` steps (lines 674-697). A single epic could absorb #3506 + #3663 and is adjacent to #3570's "finally/error path" request. + +2. **`-o` / option-parsing surface is rigid.** #3492 (project-level overrides) and #3618 (multi-org operations) are both small CLI parser improvements. Both landed in this batch with `keep-open` and `good-first-issue`-eligible scope. + +3. **JUnit/test-output story for Apex is half-done.** #3485 (malformed JUnit from `run_tests`) and #3549 (no test output from `deploy`) both concern producing CI-consumable test results. A consistent JUnit emitter shared by both tasks would close both. + +4. **Update-check / network-dependence concerns.** #3754 (no way to disable PyPI ping) is small and self-contained. Adding a `CUMULUSCI_DISABLE_VERSION_CHECK` env var around `cumulusci/cli/utils.py:check_latest_version` (line 82) closes it in one short PR. + +5. **Two genuine regressions are still active**: + + - #3852 (sarge `Capture.flush`) is upstream-dependent (sarge 0.1.8 unreleased). Cosmetic only on Python 3.13. + - #3854 (`capture_sample_data` validation) is a regression introduced by PR #3741 / `2c5d0056e`. Workaround documented (downgrade to 3.84.1) but the bug is real for polymorphic-lookup users. + +6. **#3609 (dx plugins:install) is upstream-only.** `cumulusci/tasks/sfdx.py` is now a 5-line shell wrapper around `sf {command}`; any `Timed out` error originates in the SF CLI itself. + +7. **#3612 belongs in a different repo** (`SFDO-Tooling/cci-vscode`) and should be transferred or closed as wrong-repo. + +#### Output files + +- `/tmp/repro/8/repro-results.csv` — 13 rows, header validated, parses cleanly. +- `/tmp/repro/8/narrative.md` — H3 section per issue with verdict + evidence + pass-1/pass-2 recs. +- `/tmp/repro/8/SUMMARY.md` — this file. +- `/tmp/repro/8/tests/test_3607_retry.py` — one repro test (passes, confirming retry regex logic is correct in isolation). + +#### Scratch-org cleanup + +No scratch orgs provisioned — Bucket A sufficed for all 13. Nothing to delete. + +#### Deviations + +None. + +# + +**Theme**: bulkdata · **Bucket**: B (org-eligible) · **Pinned commit**: `129238663` (= release v4.10.0) · **Issues processed**: 9 / 9 + +#### Verdict tally + +| Verdict | Count | Issues | +| ------------------------- | ----- | ---------------------------------------- | +| REPRODUCED-on-v4.10.0 | 6 | #1769, #2013, #2325, #2506, #2508, #2951 | +| NOT-REPRODUCED-on-v4.10.0 | 3 | #2096, #2505, #3283 | +| INCONCLUSIVE | 0 | — | + +#### Pass-1 recommendations + +| Recommendation | Count | Issues | +| ---------------------------------- | ----- | --------------------------------- | +| keep-open | 5 | #2013, #2325, #2506, #2508, #2951 | +| closed:not-reproducible-on-v4.10.0 | 1 | #2096 | +| closed:feature-implemented | 1 | #2505 | +| closed:fixed-by-pr-#3361 | 1 | #3283 | +| closed:stale-24mo | 1 | #1769 | + +#### Bug vs. feature + +- 5 bugs: #1769 (test code-smell), #2013 (extract multi-step duplicate table), #2096 (REST booleans), #2951 (Pricebook sequencing), #3283 (empty date). +- 4 features: #2325 (validation rule toggle), #2505 (extract WHERE), #2506 (debug tempfiles), #2508 (manual retries). + +#### Cross-cutting findings + +1. **Pattern of extending metadata-toggle tasks is fertile**: `disable_tdtm_trigger_handlers`, `restore_tdtm_trigger_handlers`, `set_duplicate_rule_status` form a clear template (`MetadataSingleEntityTransformTask` subclass). #2325 (ValidationRule), and historical asks for similar toggles, can all be solved by ~25-line additions following this pattern. +2. **`MappingStep.soql_filter` is mature**: per-step WHERE-clause filtering is now first-class, used by extract.py, the new declarative extract generator, and the hardcoded extract defaults. This closes #2505 cleanly and could be a reusable answer for any future "filter at extract time" requests. +3. **`hardcoded_default_declarations.py` quietly mitigates several historic data-shape bugs**: PricebookEntry filtering (#2951), sample-account exclusion, business hours, etc. Worth surfacing this file to triage doc readers — many "I extracted my org and it broke" issues are now invisibly handled here. +4. **Snowfakery has a working `get_debug_mode` integration; load/extract do not**: #2506 is half-complete. Wiring `get_debug_mode()` into `load.py`/`extract.py` and conditionally retaining tempdirs would close the gap with negligible risk. +5. **Rollback ≠ retry**: `enable_rollback` (added since 2021) is sometimes confused with the retry asked for in #2508. They are orthogonal: rollback undoes successful inserts on failure; retry would re-attempt failed records. Both have value. +6. **REST loader has caught up with Bulk on type coercion** (`process_bool_arg` is now used by `RestApiDmlOperation._record_to_json`); the empty-string→null fix (#3361) for upsert/update is also in place. Several "REST is stricter than Bulk" historic complaints are likely resolved by these two changes alone. + +#### Scratch org aliases used + +**None.** All 9 issues were classifiable from source-code reading and small in-process unit tests; no `cci org scratch` invocation was needed. + +#### Repro test artifacts + +- `/tmp/repro/9/tests/test_2013_multistep.py` — confirms #2013 SQLAlchemy error +- `/tmp/repro/9/tests/test_2096_rest_booleans.py` — confirms #2096 spec compliance (20/20) +- `/tmp/repro/9/tests/test_3283_empty_date.py` — confirms #3283 fix in v4.10.0 (3/3) + +All three test files run green against the v4.10.0 source via `uv run pytest ` from this worktree. + +#### Deviations + +None. No GitHub mutations. No git pushes. No edits under `cumulusci/robotframework/`. No edits inside main worktree at `/Users/jestevez/work/rel/CumulusCI`. No package additions to pyproject/lock. + +# + +- **Theme**: bulkdata +- **Worktree**: `.worktrees/repro-bulk-part2` @ `129238663` (= v4.10.0) +- **Issues processed**: 9 / 9 +- **Scratch orgs provisioned**: 1 — `repro-bulk-p2-dev` (created 2026-05-14 09:48:57 UTC, username `test-9oxwkamse2zq@example.com`, Org Id `00DRt00000Q7HYE`). Provisioned during initial triage but ultimately not needed because all 9 issues turned out to be conclusive from code review and/or in-process unit tests against `cumulusci/tasks/bulkdata/`. Already cleaned up — see "Scratch org cleanup" section below. + +#### Verdict tally + +| Verdict | Count | Issues | +| ---------------------------------- | ----: | ----------------------------------------------- | +| `REPRODUCED-on-v4.10.0` | 7 | #3349, #3353, #3649, #3699, #3700, #3701, #3768 | +| `NOT-REPRODUCED-on-v4.10.0` | 1 | #3360 | +| `INCONCLUSIVE-needs-flaky-network` | 1 | #3936 | +| `closed:duplicate-of-#NNNN` | 0 | — | + +#### Pass-1 recommendations + +| Recommendation | Count | Issues | +| ---------------------------- | ----: | ------------------------------------ | +| `keep-open` | 5 | #3349, #3353, #3649, #3700, #3768 | +| `closed:stale-24mo` | 2 | #3699, #3701 | +| `closed:feature-implemented` | 1 | #3360 | +| `unchanged` | 1 | #3936 (already maintainer kept-open) | + +#### Bug vs feature breakdown + +- **Bugs** (4): #3349, #3700, #3768, #3936 + - All four still present in v4.10.0 (with #3936 environment-dependent for the actual timeout, but the underlying missing-timeout-config gap is confirmed). + - 2 are good-first-issue candidates (#3700 small fix; #3349 medium). +- **Features** (5): #3353, #3360, #3649, #3699, #3701 + - 1 already implemented and should close: #3360 (`action: select`). + - 1 small good-first-issue: #3649 (add `bulk_mode` option to `update_data`). + - 1 active community ask: #3353 (cross-source recipe paths). + - 2 low-priority with workarounds: #3699 (workaround via `soql_filter ORDER BY`), #3701 (related to #3699). + +#### Cross-cutting findings + +1. **`api_options={}` is hardcoded in multiple bulkdata tasks.** `update_data.py:184/211` is the case in #3649, but the same pattern appears in `extract.py:156`. A small refactor to make `api_options` (specifically `bulk_mode`) a first-class task option across all bulk tasks would resolve #3649 and similar friction. + +2. **`MappingStep._get_required_permission_types` is too conservative for upserts.** #3700 is the master-detail variant; the same logic also affects formula fields (read-only) and other intentionally-non-updateable fields used as upsert lookups. A field-shape-aware permission check (using `cascadeDelete` / `relationshipName` / `nillable` from describe) would handle multiple field categories at once. + +3. **RecordType-table naming derives from `sf_object` not `table` (#3349) and the same problem caused #2013 (Subagent 9).** Both bugs share a root cause: the code assumes a 1:1 mapping between `sf_object` and SQLite table within an extract run. A v5 refactor of mapping_parser to make the `table:` key the unambiguous primary key would fix both. + +4. **Snowfakery `just_once` + `batch_size` (#3768) reflects a deliberate cleanup choice.** `_cleanup_object_tables` drops all object tables from the template before propagating it to subsequent batches, keeping only `_sf_ids`. To fix #3768, CCI needs to detect which objects are referenced via `random_reference`+`just_once` and preserve their rows in the template DB. This is non-trivial and intersects with the Snowfakery dev cutover (see master plan `snowfakery-coordination`). + +5. **No timeout configuration anywhere (#3936).** `get_simple_salesforce_connection` and bulk-job polling never expose a timeout. For corporate-VPN users this manifests as `Read timed out. (read timeout=None)` from a server-side socket close. A v5 fix should add `org.timeout` config and read-timeout retry. + +6. **`action: select` (added Aug 2024) resolves #3360 and likely overlaps several closed enhancement requests not in this bundle.** A grep of historical issues for "lookup existing records" / "reference existing data" might find more candidates to close. + +#### Repro tests written (under `/tmp/repro/10/tests/`) + +- `test_3349_recordtype_table_collision.py` — proves `MappingStep` collides record-type table names for two steps sharing `sf_object`. +- `test_3700_master_detail_upsert_perm.py` — proves `_check_field_permission` rejects MD lookup fields under UPSERT. + +Both tests exercise `cumulusci.tasks.bulkdata.mapping_parser` only, no org needed, ~0.3s each. + +#### Scratch org cleanup + +`repro-bulk-p2-dev` was provisioned (see `scratch-info.log`) and has been confirmed cleaned up at the end of the session: + +- `uv run cci org list` shows no `repro-bulk-p2-*` entries. +- `uv run cci org scratch_delete repro-bulk-p2-dev` returns `Org with name 'repro-bulk-p2-dev' does not exist.` (= already cleaned). +- `sf data query --query "SELECT Id, ScratchOrg, SignupUsername FROM ActiveScratchOrg" --target-org CCIDevHub` returns one row whose username does NOT match `test-9oxwkamse2zq@example.com` — i.e. our scratch org is no longer active on the DevHub. +- `sf org list --json` filtered for `repro-bulk-p2` / `test-9oxwkamse2zq` returns `[]`. + +No `repro-bulk-p2-*` aliases or scratch orgs remain. + +#### Deviations + +None. + +# + +- **Worktree**: `/Users/jestevez/work/rel/CumulusCI/.worktrees/repro-deps` +- **HEAD SHA**: `12923866380211161c309f3afb55e67ef18a8890` (= v4.10.0 pin) +- **Total processed**: 5 / 5 +- **Scratch orgs provisioned**: 0 (all issues resolved via Bucket A code-scan + unit-level repro) + +#### Verdict tally + +| Verdict | Count | Issues | +| ------------------------- | ----- | -------------------------- | +| REPRODUCED-on-v4.10.0 | 4 | #3603, #3604, #3619, #3886 | +| NOT-REPRODUCED-on-v4.10.0 | 1 | #3615 | +| INCONCLUSIVE | 0 | — | +| closed:duplicate-of-#NNNN | 0 | — | + +Note: #3604 is a feature request; "REPRODUCED" here means the requested +capability is still missing in v4.10.0. + +#### Recommended pass1 actions + +| Recommendation | Issues | +| ---------------------------------- | -------------------------- | +| keep-open | #3603, #3604, #3619, #3886 | +| closed:not-reproducible-on-v4.10.0 | #3615 | + +#### Cross-cutting findings + +1. **Dependency error messages are inconsistent**. `cumulusci/core/source/github.py` + wraps repo-not-found and release-not-found cases in + `DependencyResolutionError`, but lets ref-not-found leak as raw + `github3.exceptions.NotFoundError` (`'404 [No message]'`). Similarly + `resolvers.py:663`'s "Unable to resolve dependency" message names the dep + but not the strategies tried. Both surface in #3603. A short follow-up + ticket "wrap remaining github3 NotFoundError leaks in dependency code" + would resolve this cleanly. + +2. **Pin model is missing fields that are routine on dependencies**. + `GitHubDependencyPin` (#3619) only carries `github`/`tag` — but a real + pinned dep often needs `password_env_name`. The pin-resolution path + (`pin.pin()`) also bypasses the password-propagation block in + `resolve_dependency()`, so even when a dep declares the password, it gets + silently dropped. Fix is small (add field, propagate in `pin.pin()`). + +3. **Resolution-strategy alias names are confusing**. (#3615) `preproduction` + sounds like "pre-prod = beta" but is in fact an alias for `latest_release`. + This is a documentation/UX problem, not a code bug. Worth a cross-link in + `docs/data.md` or release notes. + +4. **Module-import-time log warnings produce noise on every cci run**. + `select_utils` (#3886) emits at module import; because `extract.py` pulls + it in transitively, the warning fires regardless of whether the user + actually invokes `select` functionality. Common pattern fix: lazy-emit at + first use of optional code path. + +5. **None of these 5 issues required org access**. All were resolvable via + targeted unit tests against in-process mocks. This generalizes the + triage-cost estimate downward for future "dependencies" buckets. + +#### Scratch org aliases used + +None. + +#### Cleanup + +No scratch orgs were provisioned; no cleanup required. + +#### Output files + +- `/tmp/repro/11/repro-results.csv` +- `/tmp/repro/11/narrative.md` +- `/tmp/repro/11/SUMMARY.md` +- `/tmp/repro/11/tests/test_3603_404_messages.py` (4 tests, all passing) +- `/tmp/repro/11/tests/test_3615_preproduction_strategy.py` (3 tests, all passing) +- `/tmp/repro/11/tests/test_3619_pin_password.py` (4 tests, all passing) +- `/tmp/repro/11/tests/test_3886_select_warning.py` (2 tests, all passing) + +#### Deviations + +None against bundle constraints. Two observations worth noting: + +1. Mid-session, `git status -sb` briefly showed the branch label as + `worktree/repro/bulk-part2`; by end-of-session it had updated to the + expected `worktree/repro/deps`. The HEAD SHA was always `129238663` + (= v4.10.0), so all repro evidence is valid against the intended source + state. + +2. `/tmp/repro/11/tests/` already contained 3 stale repro files from a prior + subagent run (`test_3603_404_messaging.py`, `test_3619_pin_no_password.py`, + `test_3886_select_optional_deps_warning.py`) that conflicted with my own + tests by sharing module-level imports of `select_utils`. I deleted those + stale files and re-ran my tests cleanly (13/13 passing). Other subagents' + outputs in adjacent `/tmp/repro//` directories were not touched. + +#### Final test verification + +``` +$ uv run pytest /tmp/repro/11/tests/ -v +======================== 13 passed, 1 warning in 0.35s ========================= +``` + +# + +Worktree: `/Users/jestevez/work/rel/CumulusCI/.worktrees/repro-ci-int` @ `129238663` (= v4.10.0) +Theme: `ci-integration` (mixed bucket — issues span Heroku/CI workflow, GitHub Actions, sfdx CLI integration) +Issues processed: 4 (all 4 in bundle-12.json) + +#### Verdict tally + +| Verdict | Count | Issues | +| --------------------------------------------- | ----: | ------------ | +| `REPRODUCED-on-v4.10.0` | 2 | #2153, #3471 | +| `NOT-REPRODUCED-on-v4.10.0` | 1 | #3479 | +| `INCONCLUSIVE-needs-cumulus-actions-workflow` | 1 | #3717 | +| **Total** | **4** | | + +Bug vs feature breakdown: + +- 1 feature (#2153) — REPRODUCED (still unimplemented) +- 3 bugs (#3471 REPRODUCED, #3479 NOT-REPRODUCED, #3717 INCONCLUSIVE) + +#### Recommended pass1 actions + +| Issue | Action | Reasoning | +| ----- | ------------------------------------ | ------------------------------------------------------------------------------------------- | +| #2153 | `keep-open` | Small, well-scoped enhancement to `MergeBranch._create_conflict_pull_request`; still wanted | +| #3471 | `keep-open` | Real bug; replace `compare.behind_by` at `merge.py:251` with a count of merged commits | +| #3479 | `closed:not-reproducible-on-v4.10.0` | Root cause is user GHA shell expansion; cci already wraps the JSON parse error in v4.10.0 | +| #3717 | `unchanged` | Lives at cci ↔ cumulus-actions boundary; mirrors #3418 precedent | + +#### Cross-cutting findings + +1. **`MergeBranch` (`cumulusci/tasks/github/merge.py`) is the locus of two of the four issues** (#2153 and #3471). Both have small, well-localized fixes: + + - #2153: After `self.repo.create_pull(...)` in `_create_conflict_pull_request`, look up open PRs whose `head==branch_name` (the conflicted child branch) and post a comment linking back to the auto-generated conflict PR with resolution steps. + - #3471: Replace `compare.behind_by` in the success log line with `len(list(compare.commits))` (or report the merge SHA returned by `self.repo.merge`). Add a unit test in `test_merge.py` that mocks a `compare` with `behind_by=0` but `files=[…]` to lock in the new behavior. + +2. **cci has no GitHub Actions environment auto-detection.** `project_config.py::repo_info` only handles Heroku CI plus generic `CUMULUSCI_REPO_*` overrides. Repo-wide grep for `GITHUB_REF|GITHUB_HEAD_REF|GITHUB_SHA|GITHUB_ACTIONS` returns zero matches. This is the structural cause behind #3717 (and a contributing factor any time a `push`-triggered GHA job runs cci against a detached HEAD). Two viable directions, both out of scope for triage: + + - Fix in `cumulus-actions/standard-workflows`: set `CUMULUSCI_REPO_BRANCH` from `${{ github.head_ref || github.ref_name }}` and `CUMULUSCI_REPO_COMMIT` from `${{ github.sha }}` before invoking cci. + - Add a `# GitHub Actions` block in `repo_info` parallel to the existing Heroku block. + +3. **Stale 2023-era user-config issues with no reporter follow-up** (#3479) are good `closed:not-reproducible-on-v4.10.0` candidates when (a) the symptom is improved or wrapped in v4.10.0 and (b) the reviewer's clarifying question went unanswered for 2+ years. #3479 fits both criteria. + +4. **Code stability for this theme is high.** Between the issue dates (2020-2023) and v4.10.0: + - `cumulusci/tasks/github/merge.py` has had only refactors (ruff migration, `create_pull_request_on_conflict` option, `skip_future_releases` fixes) — no change to the `compare.behind_by` reporting line or to PR-creation behavior on conflict. + - `cumulusci/core/config/sfdx_org_config.py` has had the JSON-error wrapper since 2020-11-24. + - `cumulusci/core/config/project_config.py::repo_info` still only auto-detects Heroku. + +#### Scratch org aliases used + +**No scratch needed** — all 4 issues resolved by code-scan against the worktree (Bucket A). DevHub `CCIDevHub` was not touched. + +#### Deviations from instructions + +None. No GitHub mutations, no pushes, no edits under `cumulusci/robotframework/`, no work in the main worktree, no `pyproject.toml`/`uv.lock` changes, no scratch orgs provisioned. + +#### Output files + +- `/tmp/repro/12/repro-results.csv` +- `/tmp/repro/12/narrative.md` +- `/tmp/repro/12/SUMMARY.md` + +## Per-issue narratives + +Concatenated from each subagent's `narrative.md`. Sorted by issue number. Headings normalized to `### #NNNN`. + + + +### #733: Prompt to delete scratch org when creating one that already exists + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature +**Method**: code-scan + +**Evidence**: + +```126:140:cumulusci/cli/runtime.py + def check_org_overwrite(self, org_name): + try: + org = self.keychain.get_org(org_name) + if org.scratch: + if org.created: + raise click.ClickException( + f"Scratch org has already been created. Use `cci org scratch_delete {org_name}`" + ) + else: + raise click.ClickException( + f"Org {org_name} already exists. Use `cci org remove` to delete it." + ) + except OrgNotFound: + pass + return True +``` + +Behaviour identical to the 2018 report — hard error, no interactive Y/N prompt. + +**Recommended action**: + +- pass1: `closed:stale-24mo` — 7-year-old `cli-usability` enhancement, no traction, original tracking W-028291. +- pass2 labels: `enhancement,cli-usability,stale` + +--- + + + +### #808: deploy_packaging flow runs uninstall_packaged_incremental with wrong package name + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug +**Org used**: none (static analysis; live repro requires a real packaging org with a managed package whose name differs from `project__package__name`). + +**Method**: +Read `cumulusci/tasks/salesforce/UninstallPackaged.py` and compared with `cumulusci/tasks/salesforce/install_package_version.py`. + +**Evidence**: + +- `UninstallPackaged._init_options` (UninstallPackaged.py:22-25): + +```22:25:cumulusci/tasks/salesforce/UninstallPackaged.py + def _init_options(self, kwargs): + super(UninstallPackaged, self)._init_options(kwargs) + if "package" not in self.options: + self.options["package"] = self.project_config.project__package__name +``` + +- Compare to `InstallPackageVersion._init_options` (install_package_version.py:75-79) which DOES use the fall-back chain `name_managed -> name -> namespace`. The asymmetry is the bug. +- Bug pattern is unchanged since 2018; no fix has landed. + +**Recommended action**: + +- pass1: `keep-open` — small, contained fix. +- pass2 labels: `bug`, `good-first-issue` + +**Notes**: jlantz's 2018 follow-up about deprecating `project__package__name_managed` (legacy NPSP-only feature) is a separate, larger conversation; for this triage the minimal symmetric fix is enough. + +--- + + + +### #1348: Multiple Git Provider Support + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature +**Method**: code-scan + +**Evidence**: + +`rg -li "gitlab" cumulusci/` and `rg -li "bitbucket" cumulusci/` both return zero matches. The `ci_feature` flow still hardcodes GitHub-specific tasks: + +```767:789:cumulusci/cumulusci.yml + ci_feature: + group: Continuous Integration + ... + steps: + 0.5: + task: github_parent_pr_notes + ... + 5: + task: github_automerge_feature +``` + +**Recommended action**: + +- pass1: `closed:stale-24mo` — large architectural change (multi-VCS abstraction); 6yr no traction; user `zenibako` confirmed using cci on GitLab via custom flows is feasible. +- pass2 labels: `enhancement,stale,wontfix-candidate` + +--- + + + +### #1350: Unable to run tasks in remote projects + +**Verdict**: NOT-REPRODUCED-on-v4.10.0 +**Repro type**: bug +**Method**: code-scan + +**Evidence**: + +The original `ModuleNotFoundError: No module named 'tasks'` is fixed via a synthetic `tasks` namespace package and per-source path extension: + +```52:57:cumulusci/core/config/project_config.py +sys.modules.setdefault( + "tasks", types.ModuleType("tasks", "Synthetic package for all repo tasks") +) +import tasks + +tasks.__path__ = [] +``` + +```657:679:cumulusci/core/config/project_config.py + # If I can't load remote code, make sure that my + # included repos can't either. + if not self.allow_remote_code: + spec.allow_remote_code = False + else: + project_config._add_tasks_directory_to_python_path() + + return project_config + + def _add_tasks_directory_to_python_path(self): + # https://stackoverflow.com/a/2700924/113477 + if not self.allow_remote_code: + return False + + directory = str(Path(self.repo_root) / "tasks") + if directory not in tasks.__path__: + self.logger.debug(f"Adding {directory} to tasks.__path__") + tasks.__path__.append(directory) +``` + +The follow-up name-collision concern raised by `prescod` in 2022 (NPSP and EDA both registering `tasks.is_rd2_enabled`) is a **separate** issue from the original report. + +**Recommended action**: + +- pass1: `closed:not-reproducible-on-v4.10.0` — original bug is fixed. +- pass2 labels: `fixed` + +--- + + + +### #1432: CCI Inconsistencies in validating arguments + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug +**Method**: code-scan + unit test + +**Evidence**: + +Old-style `task_options` dict still does not validate unknown keys: + +```186:196:cumulusci/core/tasks.py + def _validate_options(self): + missing_required = [] + for name, config in list(self.task_options.items()): + if config.get("required") is True and name not in self.options: + missing_required.append(name) + + if missing_required: + required_opts = ",".join(missing_required) + raise TaskOptionsError( + f"{self.__class__.__name__} requires the options ({required_opts}) and no values were provided" + ) +``` + +Repro test passes (= unknown `colour` typo is silently accepted via YAML/Python path): + +``` +$ uv run pytest /tmp/repro/7/tests/test_1432_options_validation.py -q +. [100%] +1 passed in 0.25s +``` + +Test path: `/tmp/repro/7/tests/test_1432_options_validation.py`. + +**Mitigation**: Tasks that opted into the new Pydantic `Options` class (lines 159-184) now reject extras with `"extra options"`. So the bug is partially fixed for new-style tasks but persists for legacy ones. + +**Recommended action**: + +- pass1: `closed:stale-24mo` — 5yr; partial mitigation in place; full fix would require reworking every legacy `task_options` dict task. +- pass2 labels: `bug,stale,partially-fixed` + +--- + + + +### #1769: Unusual case in test_load + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug (test code-smell) +**Org used**: none — code-only +**Method**: `git show` of the original 2020 commit referenced in the issue + grep of the current `test_load.py`. + +**Evidence**: +The original line 352 in `158a2d4356f` (May 2020) was: + +```python +lookups["Id"] = {"table": "accounts", "key_field": "sf_id"} +``` + +In v4.10.0 the same pattern survives, just wrapped in `MappingLookup`: + +```736:739:cumulusci/tasks/bulkdata/tests/test_load.py + lookups["Id"] = MappingLookup(name="Id", table="accounts", key_field="sf_id") + lookups["Primary_Contact__c"] = MappingLookup( + table="contacts", name="Primary_Contact__c" + ) +``` + +The pattern repeats at lines 754, 773, 801, 1119, 1187, 1255 — declaring `Id` as a "lookup" key inside the `lookups` dict so `_expand_mapping` can express the after-step's UPDATE-on-Id dependency. davidmreed acknowledged in 2020 it was "a horrible hack" he intended to clean up, but six years later it is still there, with zero downstream complaints. + +**Recommended action**: + +- pass1: `closed:stale-24mo` — pure test-fixture nit; never escalated to a real bug; original commenters have moved on. +- pass2 labels: `test-cleanup, low-priority` + +--- + + + +### #2013: Mapping files with steps that are not 1-1 with SObjects are unreliable for extraction + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug +**Org used**: none — code-only +**Method**: Direct unit test against `cumulusci.tasks.bulkdata.utils.create_table` with two `MappingStep` instances both named `Account`. + +**Evidence**: +`create_table_if_needed` (`utils.py:133-139`) tries to detect duplicate tables but the SQLAlchemy `Table()` constructor raises first: + +```133:139:cumulusci/tasks/bulkdata/utils.py +def create_table_if_needed(tablename, metadata, fields: T.List[Column]) -> Table: + t = Table(tablename, metadata, *fields) + inspector = inspect(metadata.bind) + if inspector.has_table(tablename): + raise BulkDataException(f"Table already exists: {tablename}") + t.create(metadata.bind) + return t +``` + +Reproduction (`/tmp/repro/9/tests/test_2013_multistep.py`) yields the exact 2020 traceback: + +``` +Exception type: InvalidRequestError +Exception message: Table 'Account' is already defined for this MetaData instance. +Specify 'extend_existing=True' to redefine options and columns on an existing +Table object. +``` + +**Recommended action**: + +- pass1: `keep-open` — bug is real, easy to reproduce, easy to fix (catch the SQLAlchemy error and re-raise as `BulkDataException`, or validate at mapping-parse time). +- pass2 labels: `bug, bulkdata, extract_dataset, error-handling` + +--- + + + +### #2096: REST dataloads throw errors that Bulk loads do not + +**Verdict**: NOT-REPRODUCED-on-v4.10.0 +**Repro type**: bug +**Org used**: none — code-only +**Method**: Inspect `RestApiDmlOperation._record_to_json` and `process_bool_arg`; parametric unit test against the full Data Loader spectrum. + +**Evidence**: +REST DML pre-converts boolean columns: + +```778:784:cumulusci/tasks/bulkdata/step.py + def _record_to_json(self, rec): + result = dict(zip(self.fields, rec)) + for boolean_field in self.boolean_fields: + try: + result[boolean_field] = process_bool_arg(result[boolean_field] or False) + except TypeError as e: + raise BulkDataException(e) +``` + +`process_bool_arg` (`core/utils.py:75-83`) accepts the entire spectrum from the Data Loader guide cited in the issue (yes/y/true/on/1 → True; no/n/false/off/0 → False; case-insensitive). Test `/tmp/repro/9/tests/test_2096_rest_booleans.py` confirms 20/20 spectrum values pass. + +**Recommended action**: + +- pass1: `closed:not-reproducible-on-v4.10.0` +- pass2 labels: `resolved, bulkdata` + +--- + + + +### #2140: Prompt Org Configs when Org Does Not Exist and Command Runs Against It + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature +**Method**: code-scan + +**Evidence**: + +```95:104:cumulusci/cli/runtime.py + def get_org(self, org_name=None, fail_if_missing=True): + if org_name: + org_config = self.keychain.get_org(org_name) + else: + org_name, org_config = self.keychain.get_default_org() + if org_config: + org_config = self.check_org_expired(org_name, org_config) + elif fail_if_missing: + raise click.UsageError("No org specified and no default org set.") + return org_name, org_config +``` + +`keychain.get_org` raises `OrgNotFound` -> `cli/org.py:530-531` shows `"Org {name} does not exist in the keychain"`. No interactive prompt offering available scratch configs. + +**Recommended action**: + +- pass1: `closed:stale-24mo` — 5yr `cli-usability` enhancement with no traction. +- pass2 labels: `enhancement,cli-usability,stale` + +--- + + + +### #2153: Add comment to original PR which tags all branch subscribers when a merge + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature +**Method**: Bucket A — code-scan against `cumulusci/tasks/github/merge.py` and grep for `create_comment` / `issue_comment` across `cumulusci/tasks/github`. + +**Evidence**: + +`cumulusci/tasks/github/merge.py` `_create_conflict_pull_request` (the only place an auto-merge PR is created): + +```264:288:cumulusci/tasks/github/merge.py + def _create_conflict_pull_request(self, branch_name, source): + """Attempt to create a pull request from source into branch_name if merge operation encounters a conflict""" + if branch_name in self._get_existing_prs( + self.options["source_branch"], self.options["branch_prefix"] + ): + self.logger.info( + f"Merge conflict on branch {branch_name}: merge PR already exists" + ) + return + + try: + pull = self.repo.create_pull( + title=f"Merge {source} into {branch_name}", + base=branch_name, + head=source, + body="This pull request was automatically generated because " + "an automated merge hit a merge conflict", + ) + self.logger.info( + f"Merge conflict on branch {branch_name}: created pull request #{pull.number}" + ) + except github3.exceptions.UnprocessableEntity as e: + self.logger.error( + f"Error creating merge conflict pull request to merge {source} into {branch_name}:\n{e.response.text}" + ) +``` + +The method only creates the conflict PR; it never opens a comment on any PR (the original child PR or otherwise). Repo-wide grep for `create_comment|issue_comment|pr.create_comment|comment.*pull_request` under `cumulusci/tasks/github` returns no hits in production code (only test fixtures). Davis Agli's response in the thread agreed with the issue reporter that the appropriate place would be a comment on the original PR. Feature is unimplemented in v4.10.0. + +**Recommended action**: + +- pass1: `keep-open` — small, well-scoped enhancement; reasonable "good-second-issue". +- pass2 labels: `enhancement, github, merge-conflict` + +--- + + + +### #2325: Task to turn off validation rules to allow data insert + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature +**Org used**: none — code-only +**Method**: Grep cumulusci.yml + `cci task list` for any `validation_rule` / `disable_*` task. + +**Evidence**: + +- Trigger analog: `disable_tdtm_trigger_handlers` / `restore_tdtm_trigger_handlers` (`cumulusci.yml:738-747`). +- DuplicateRule analog: `set_duplicate_rule_status` → `cumulusci.tasks.metadata_etl.duplicate_rules.SetDuplicateRuleStatus` (a 25-line `MetadataSingleEntityTransformTask` subclass with `entity = "DuplicateRule"`). +- ValidationRule equivalent: **none.** `cci task list | grep -i -E "validation|rule"` returns only `set_duplicate_rule_status`. + +The pattern to copy is trivially established. The user's specific use case (relative-date hearings during dataset insert) is exactly what `disable_tdtm_trigger_handlers` solves for triggers; ValidationRule needs the same. + +**Recommended action**: + +- pass1: `keep-open` — feature still missing, clear implementation pattern, modest scope. +- pass2 labels: `enhancement, bulkdata, metadata_etl, good-first-issue` + +--- + + + +### #2402: Create a --rebuild-org parameter for cci flow run + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature +**Method**: code-scan + +**Evidence**: + +```119:145:cumulusci/cli/flow.py +@flow.command(name="run", help="Runs a flow") +@click.argument("flow_name") +@click.option("--org", help="Specify the target org. By default, runs against the current default org") +@click.option("--delete-org", is_flag=True, help="If set, deletes the scratch org after the flow completes") +@click.option("--debug", is_flag=True, help="Drops into pdb, the Python debugger, on an exception") +@click.option("-o", nargs=2, multiple=True, help="...") +@click.option("--no-prompt", is_flag=True, help="...") +@pass_runtime(require_keychain=True) +def flow_run(runtime, flow_name, org, delete_org, debug, o, no_prompt): +``` + +Only `--delete-org` exists. `rg -i "rebuild.org"` returns zero hits. + +**Recommended action**: + +- pass1: `closed:stale-24mo` — 5yr; tracked W-10502624 (no movement); user can accomplish via `cci org scratch_delete X && cci flow run`. +- pass2 labels: `enhancement,stale` + +--- + + + +### #2505: Filtering records to be extracted + +**Verdict**: NOT-REPRODUCED-on-v4.10.0 +**Repro type**: feature +**Org used**: none — code-only +**Method**: Grep `mapping_parser.py` and `extract.py` for `soql_filter` / WHERE-clause support. + +**Evidence**: +Per-step SOQL filter is now first-class: + +```120:120:cumulusci/tasks/bulkdata/mapping_parser.py + soql_filter: Optional[str] = None # soql_filter property +``` + +```142:147:cumulusci/tasks/bulkdata/extract.py + if mapping.soql_filter is not None: + soql = self.append_filter_clause( + soql=soql, filter_clause=mapping.soql_filter + ) +``` + +The new extract-mapping generator wires user-declared `where:` into `soql_filter` (`extract_mapping_file_generator.py:26`), and the existing hardcoded extract declarations (`extract_dataset_utils/hardcoded_default_declarations.py`) already use this for per-sObject filtering. Tests exercise the plain filter, the WHERE-prefixed variant, and combinations with record_type (`test_extract.py:1216, 1248, 1280`). + +**Recommended action**: + +- pass1: `closed:feature-implemented` +- pass2 labels: `resolved, bulkdata, extract_dataset` + +--- + + + +### #2506: Bulk Operations should have a --debug mode which maintains logs and tempfiles + +**Verdict**: REPRODUCED-on-v4.10.0 (partial) +**Repro type**: feature +**Org used**: none — code-only +**Method**: Grep all bulkdata modules for `get_debug_mode` / `delete=False` / `TemporaryDirectory` usage. + +**Evidence**: + +- Snowfakery task (`snowfakery.py:241,355,385,565`) calls `get_debug_mode()` and at `:386` logs `f"Working Directory: {tempdir}"` per loop iteration. +- `extract.py`, `step.py` — **zero** references to `debug_mode` or `get_debug_mode`. +- `load.py:283` uses `tempfile.TemporaryFile` with no debug-mode override; the file is auto-deleted on context exit regardless of debug. + +So the ask is half-met: Snowfakery cooperates with debug mode; the workhorse `load_dataset` / `extract_dataset` tasks do not. + +**Recommended action**: + +- pass1: `keep-open` — partial implementation; remaining work is straightforward (wire `get_debug_mode()` into load/extract, conditionally use `TemporaryDirectory(delete=False)` and emit path). +- pass2 labels: `enhancement, bulkdata, extract_dataset, load_dataset, debugging` + +--- + + + +### #2507: Undo mode for CumulusCI Insert + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature +**Method**: code-scan + +**Evidence**: + +No `undo_insert` task exists (`rg -l undo_insert` returns nothing). Closest functionality is `enable_rollback` on `load_dataset` and `snowfakery` tasks: + +```97:99:cumulusci/tasks/bulkdata/load.py + "enable_rollback": { + "description": "When True, performs rollback operation incase of error. Defaults to False" + }, +``` + +That only triggers rollback on error during the load; it does not provide the post-hoc "delete everything we ever inserted" capability the requester described. + +**Recommended action**: + +- pass1: `closed:stale-24mo` — 4yr feature with partial mitigation already shipped. +- pass2 labels: `enhancement,stale,partially-fixed` + +--- + + + +### #2508: Manual load retries + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature +**Org used**: none — code-only +**Method**: `cci task list | grep -i retry` and grep load.py for retry/failed-record persistence. + +**Evidence**: + +- `cci task list` returns no retry-named task. +- `load.py` has an `enable_rollback` option (`:97-98`, `RollbackType` enum at `:1051`) but rollback **undoes successful inserts when failures occur** — the opposite of "retry the failures." +- `RowErrorChecker` (`utils.py:158`) only logs and optionally raises; it does not persist a failed-rows artifact that could be replayed. + +**Recommended action**: + +- pass1: `keep-open` — distinct from rollback; would need (a) failed-row CSV/SQL persistence + (b) a new `retry_failed_load` task that consumes it. +- pass2 labels: `enhancement, bulkdata, load_dataset, reliability` + +--- + + + +### #2697: 'namespaced' field stale in `cci org info` after switching org def + +**Verdict**: INCONCLUSIVE-needs-scratch-slot +**Repro type**: bug +**Method**: code-scan (no scratch provisioned) + +**Evidence**: + +The cci `namespaced` field is set from the cci YAML config, not derived from the SFDX scratch def file: + +```57:75:cumulusci/core/keychain/base_project_keychain.py + def create_scratch_org( + self, org_name, config_name, days=None, set_password=True, release=None + ): + """Adds/Updates a scratch org config to the keychain from a named config""" + scratch_config = self.project_config.lookup(f"orgs__scratch__{config_name}") + ... + scratch_config["scratch"] = True + scratch_config.setdefault("namespaced", False) +``` + +This means `cci org info` reflects the cci `orgs__scratch__qa.namespaced` value, not whatever the SFDX `qa.json` says. Since the user changed only the SFDX `qa.json` (not the cci YAML), cci's view of `namespaced` is unchanged. This is **likely working as designed** but conflicts with the user's mental model. + +I did not provision a scratch org to confirm because (a) the code reading is unambiguous and (b) DevHub-slot conservation. Marking inconclusive only because final verification of the `cci org info` output panel was not exercised live. + +**Recommended action**: + +- pass1: `closed:stale-24mo` — 5yr stale; design/docs friction rather than a defect; request more info if reopened. +- pass2 labels: `bug,stale,needs-info` + +--- + + + +### #2826: deploy_unmanaged flow is supposed to silently do nothing if there's not actually a package directory + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug (enhancement-flavored) +**Org used**: none (purely local task) + +**Method**: +Inspected `cumulusci/tasks/metadata/package.py`: + +- `PackageXmlGenerator.parse_types` (line 107) calls `os.listdir(self.directory)` without checking existence. +- `UpdatePackageXml._init_task` (line 590) and `_run_task` (line 612) do not guard for missing path. + +Wrote a unit-level repro at `/tmp/repro/5/tests/issue-2826/repro_unit.py` that instantiates `UpdatePackageXml` against a temp dir containing no `src/`. Result: raises `FileNotFoundError: [Errno 2] No such file or directory: '/var/.../src'`. Bug present. + +**Recommended action**: + +- pass1: `keep-open` — small, contained fix. +- pass2 labels: `bug`, `good-first-issue` + +**Notes**: Could be fixed at the task layer (skip with logger.info when path missing) or at the flow layer (`when:` guard on the deploy_unmanaged steps). Task-layer is more defensible because the same task may be referenced from custom flows. + +--- + + + +### #2951: Error in task load_dataset - Standard_price_not_defined + +**Verdict**: REPRODUCED-on-v4.10.0 (with mitigation) +**Repro type**: bug +**Org used**: none — code-only +**Method**: Grep load.py / step.py for any PricebookEntry-specific sequencing logic; inspect `hardcoded_default_declarations.py`. + +**Evidence**: +No special handling exists in the loader to sequence Standard-Price-Book PricebookEntries before custom-pricebook PricebookEntries within a single mapping step. Within one Bulk job, records are processed in parallel within batches and Salesforce throws `STANDARD_PRICE_NOT_DEFINED` when a custom price is created before the matching standard price. + +Mitigation already in place for the `extract_dataset` → `load_dataset` round-trip: + +```14:18:cumulusci/tasks/bulkdata/extract_dataset_utils/hardcoded_default_declarations.py + ExtractDeclaration( + sf_object="PricebookEntry", + where="Pricebook2.Id != NULL and Pricebook2.Name != 'Standard Price Book'", + ), + ExtractDeclaration(sf_object="Pricebook2", where="Name != 'Standard Price Book'"), +``` + +So default extracts skip the Standard Price Book entirely, and the typical flow doesn't hit the bug. But the reporter built a mapping by hand that included both, and that path is still broken. + +**Recommended action**: + +- pass1: `keep-open` — bug is latent. Fix options: (a) loader auto-splits PricebookEntry into two implicit batches (standard pricebook first); (b) document the requirement and validate at parse time that PricebookEntry steps are not "mixed." +- pass2 labels: `bug, bulkdata, load_dataset, pricebook, documentation` + +--- + + + +### #2979: deploy task should deploy from default entry in packageDirectories + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature + +**Method**: +Inspected the `deploy` task definition in `cumulusci/cumulusci.yml` and the `default_package_path` helper in `cumulusci/core/config/project_config.py`. Searched for `default_package_path` usages across the codebase to see whether any deploy/Deploy task consumes it. + +**Evidence**: + +- `cumulusci/cumulusci.yml:227-229` — the `deploy` task still hard-codes `path: src` for `cumulusci.tasks.salesforce.Deploy`. +- `cumulusci/core/config/project_config.py:517-525` — `default_package_path` correctly reads `packageDirectories[*].default` from `sfdx-project.json` when `project__source_format == "sfdx"`. +- The only consumer of `default_package_path` is `cumulusci/tasks/create_package_version.py:230`. The Deploy task does not consult it. + +**Recommended action**: + +- pass1: `keep-open` — feature still missing; davisagli's 2021 design comment (3-tier fallback `path` -> sfdx default -> `src`) remains the natural plan. +- pass2 labels: `severity:low,area:packaging,area:sfdx,state:needs-design` + +--- + + + +### #3015: Remove imported dx org from cci list without deleting actual scratch + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature +**Method**: code-scan + +**Evidence**: + +```519:543:cumulusci/cli/org.py +@org.command(name="remove", help="Removes an org from the keychain") +@orgname_option_or_argument(required=True) +@click.option("--global-org", is_flag=True, help="...") +@pass_runtime(require_project=False, require_keychain=True) +def org_remove(runtime, org_name, global_org): + try: + org_config = runtime.keychain.get_org(org_name) + except OrgNotFound: + raise click.ClickException(f"Org {org_name} does not exist in the keychain") + + if org_config.can_delete(): + click.echo("A scratch org was already created, attempting to delete...") + try: + org_config.delete_org() + ... + runtime.keychain.remove_org(org_name, global_org) +``` + +No `--keep-org` flag. davisagli's manual workaround (delete `~/.cumulusci//.org` directly) still applies. + +**Recommended action**: + +- pass1: `closed:stale-24mo` — 4yr; tracked W-10502512. +- pass2 labels: `enhancement,stale` + +--- + + + +### #3024: Order of flow groups in `cumulusci/cumulusci.yml` + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature +**Method**: code-scan + +**Evidence**: + +Sequence of unique `group:` values in `cumulusci/cumulusci.yml` (first appearance): + +``` +Metadata Transformations +Salesforce Users +Salesforce +Salesforce Preflight Checks +Utilities +Data Operations +Salesforce Communities +Setup +Salesforce Packages +Salesforce Metadata +Marketing Cloud +OmniStudio +Salesforce DX +GitHub +Release Operations +Push Upgrades +Salesforce Bulk API +Robot Framework +NPSP/EDA +Continuous Integration +Post-Install Configuration +Dependency Management +``` + +`Continuous Integration` is buried near the bottom; `Org Setup` (the user's preferred name) does not exist (uses `Setup`); ordering does not match the user's request. + +**Recommended action**: + +- pass1: `closed:stale-24mo` — 4yr cosmetic VS Code extension request; the true fix is sorting at the consumer (the extension) rather than rearranging the canonical YAML. +- pass2 labels: `enhancement,stale` + +--- + + + +### #3137: cci task run update_package_xml and Salesforce Case Custom Object + +**Verdict**: REPRODUCED-on-v4.10.0 (treated as feature request) +**Repro type**: feature + +**Method**: +Inspected `cumulusci/tasks/metadata/package.py` `CustomObjectParser` (lines +443–482). It explicitly skips any object file that doesn't end in `__c`, +`__mdt`, `__e`, or `__b`. Inspected `UpdatePackageXml` task_options +(package.py:563–584) — no opt-in option such as `include_standard_objects`. +The maintainer's response on the issue agreed the behavior is by-design +(holdover from managed-package world) and committed only to "investigate"; +no design has landed. + +**Evidence**: + +- `cumulusci/tasks/metadata/package.py:451-458` skips standard objects. +- `cumulusci/tasks/metadata/package.py:562-584` `UpdatePackageXml.task_options` + has only `path`, `output`, `package_name`, `managed`, `delete`, + `install_class`, `uninstall_class`. + +**Recommended action**: + +- pass1: keep-open — a real product gap remains; mark for design discussion. +- pass2 labels: `severity:low,area:metadata-etl,type:enhancement,state:needs-design` + +--- + + + +### #3161: Ability to Hide Option Values When Using Task Options + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature +**Method**: code-scan + +**Evidence**: + +```300:320:cumulusci/core/flowrunner.py + def _log_options(self, task: "BaseTask"): + ... + for key, info in task.task_options.items(): + value = task.options.get(key) + if value is not None: + if type(value) is not list: + value = self._obfuscate_if_sensitive(value, info) + task.logger.info(f" {key}: {value}") + ... + + def _obfuscate_if_sensitive(self, value: str, info: dict) -> str: + if info.get("sensitive"): + value = 8 * "*" + return value +``` + +A masking infrastructure was added (task-option metadata can opt in via `sensitive: True`), but: + +1. The Robot `vars` option is not marked sensitive (`cumulusci/tasks/robotframework/robotframework.py:54-56`). +2. There's no CLI/Robot-side flag for the user to mark an ad-hoc `-o` value as sensitive. + +So the user's specific request (mask multi-line GitHub Actions secrets passed via `-o robot__vars …`) is **partially mitigated** but not fully solved. + +**Recommended action**: + +- pass1: `closed:stale-24mo` — 4yr; partial fix in place. +- pass2 labels: `enhancement,stale,partially-implemented` + +--- + + + +### #3165: Update Admin Profile task fails when specifying record types without custom package.xml + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug +**Org used**: none for the unit repro; live test would need a Case "Case" record type in the scratch org + +**Method**: +Read `cumulusci/tasks/salesforce/update_profile.py` carefully: + +- `_generate_package_xml(RETRIEVE)` calls `_expand_package_xml(package_xml)` only when `include_packaged_objects=True` (line 137-138). +- `_expand_package_xml` calls `_expand_package_xml_objects(package_xml)` (line 182). +- `_expand_package_xml_objects` (line 184-201) is what walks `record_types` and inserts each referenced object into `/`. +- Therefore: when `include_packaged_objects` is False (the default unless `minimum_cumulusci_version >= 3.9.0`), record_types referencing objects not in the default `cumulusci/files/admin_profile.xml` (e.g. `Case`) never get added. +- Confirmed by the existing test `test_init_options__include_packaged_objects` (test_ProfileGrantAllAccess.py:609-615) which explicitly asserts `task._expand_package_xml.assert_not_called()` in the False branch. + +Wrote `/tmp/repro/5/tests/issue-3165/repro_unit.py`. Output (key parts): + +``` +include_packaged_objects = False +--- generated package.xml --- + + + + * + Account + Campaign + ... + Opportunity + CustomObject + + ... + +--- end --- +REPRODUCED: 'Case' is NOT in CustomObject members. +``` + +**Recommended action**: + +- pass1: `keep-open` — single-line refactor. +- pass2 labels: `bug` + +**Notes**: Smallest fix at update_profile.py:137 — always call `self._expand_package_xml_objects(package_xml)` regardless of `include_packaged_objects`, and only call the broader `self._expand_package_xml` (which does the Tooling API query) when `include_packaged_objects=True`. `_expand_package_xml_objects` itself only walks the user-supplied options, no API call. + +--- + + + +### #3167: Add ability to define page layout assignments with record types using the update_admin_profile task + +**Verdict**: NOT-REPRODUCED-on-v4.10.0 (feature implemented) +**Repro type**: feature +**Org used**: none + +**Method**: +Read `cumulusci/tasks/salesforce/update_profile.py`: + +- `task_options['record_types']` description (lines 32-34) explicitly documents the `page_layout` key. +- `_set_record_types` lines 280-298 handle `page_layout`: locate any existing `` matching the record type and update its ``, or append a new `` block. + +`git log -S "page_layout" -- cumulusci/tasks/salesforce/update_profile.py` shows the feature landed in commit `f2ff04bd5` (PR #3243 by davidmreed, merged 2022-06-16) — well before v4.10.0. + +**Recommended action**: + +- pass1: `close-as-implemented` with reference to PR #3243. +- pass2 labels: `enhancement` + +**Notes**: Could also add a small docs example. + +--- + + + +### #3283: json parser error when empty string passed for date field during upsert or update + +**Verdict**: NOT-REPRODUCED-on-v4.10.0 +**Repro type**: bug +**Org used**: none — code-only +**Method**: Verify PR #3361 (commit `b0bfb70e0`) is in `129238663` via `git merge-base --is-ancestor`; small unit test against `RestApiDmlOperation._record_to_json` for UPDATE/UPSERT/INSERT operations. + +**Evidence**: +Fix is in place at `step.py:795-796`: + +```789:797:cumulusci/tasks/bulkdata/step.py + if self.operation is DataOperationType.INSERT: + result = { + k: result[k] + for k in result + if result[k] is not None and result[k] != "" + } + elif self.operation in (DataOperationType.UPDATE, DataOperationType.UPSERT): + result = {k: (result[k] if result[k] != "" else None) for k in result} +``` + +Repro test (`/tmp/repro/9/tests/test_3283_empty_date.py`) verifies: empty `Birthdate` becomes JSON null on UPDATE and UPSERT (no longer triggering JSON_PARSER_ERROR), and is omitted entirely for INSERT. The reporter's own final comment ("Fixed in #3361") aligns. + +**Recommended action**: + +- pass1: `closed:fixed-by-pr-#3361` +- pass2 labels: `resolved, bulkdata, load_dataset` + + + +### #3307: Project Template Support for `cci project init` + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature +**Method**: code-scan + +**Evidence**: + +`rg "template" cumulusci/cli/project.py` only finds references to internal Jinja templates rendered from `cumulusci/files/templates/project` (lines 220-329). No `--template` CLI option exists. `project_init` (line 41) takes no template-source argument. + +**Recommended action**: + +- pass1: `closed:stale-24mo` — 4yr; explicitly described by the requester as "low priority / nice to have". +- pass2 labels: `enhancement,stale` + +--- + + + +### #3320: Metadata ETL task to Deactivate a Flow + +**Verdict**: NOT-REPRODUCED-on-v4.10.0 +**Repro type**: feature + +**Method**: +Greped for `[Dd]eactivate.*[Ff]low|DeactivateFlow|deactivate_flow` across the +codebase and inspected `cumulusci/cumulusci.yml`. + +**Evidence**: + +- `cumulusci/cumulusci.yml:10-15` ships a `deactivate_flow` task that + reuses `cumulusci.tasks.salesforce.activate_flow.ActivateFlow` with + `status: False`. +- `cumulusci/tasks/salesforce/activate_flow.py:33-65` toggles + `activeVersionNumber` to 0 when `status` is falsy, i.e. real deactivation. + +**Recommended action**: + +- pass1: closed:feature-implemented — `cci task run deactivate_flow` is + shipped; reporter likely missed it. +- pass2 labels: `area:metadata-etl,type:enhancement,resolution:already-implemented` + +--- + + + +### #3331: Task update_package_xml does not write correct package.xml for AssignmentRules + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug + +**Method**: +Read `cumulusci/tasks/metadata/metadata_map.yml` and wrote two tests: one +that asserts the YAML mapping is correct, one that runs `PackageXmlGenerator` +on a sample `assignmentRules/Case.assignmentRules` fixture and asserts the +emitted `` element is `AssignmentRules` (plural). + +**Evidence**: + +- `cumulusci/tasks/metadata/metadata_map.yml:45-48` maps the + `assignmentRules` folder to `type: AssignmentRule` (singular). MDAPI + expects the plural type name (cf. `autoResponseRules:` at lines 60-63 + which is already correctly `AutoResponseRules`). +- Test output: both `test_issue_3331_*` tests fail; observed + `AssignmentRule` instead of `AssignmentRules`. + +**Recommended action**: + +- pass1: keep-open — one-line YAML fix; reporter offered a PR. +- pass2 labels: `severity:medium,area:metadata-etl,type:bug,good-first-issue` + +--- + + + +### #3347: Cannot release an unlocked beta package with `release_unlocked_beta` + +**Verdict:** `NOT-REPRODUCED-on-v4.10.0` + +### Original symptom + +User on CumulusCI 3.64.0 (2022-08) ran `cci flow run release_unlocked_beta` and the first task `create_package_version` died with a confusing low-level error: + +``` +TypeError: expected str, bytes or os.PathLike object, not NoneType + at create_package_version.py line 377: + with open(self.org_config.config_file, "r") as f: +``` + +Root cause: `org_config.config_file` is `None` for persistent orgs (DevHub, Developer Edition, etc.), but the user (likely) ran the flow against the DevHub directly. `release_unlocked_beta` requires a scratch target org; the old code fell through with an opaque error. + +### Evidence on v4.10.0 + +`cumulusci/tasks/create_package_version.py` lines 44–46 and 158–159: + +```44:46:cumulusci/tasks/create_package_version.py +PERSISTENT_ORG_ERROR = """ +Target org scratch org definition file missing. Persistent orgs like a Dev Hub can't be used for 2GP package uploads. +""" +``` + +```158:159:cumulusci/tasks/create_package_version.py + if not self.org_config.config_file: + raise TaskOptionsError(PERSISTENT_ORG_ERROR) +``` + +The early `_init_options` check raises a clear `TaskOptionsError` before any `open()` is attempted. Fix landed in commit `2a9cadcb1` on 2023-10-12 (`added_clear_error`), refined in `8f62d3153` and `8328bfb9d`. + +### Test verification + +```text +$ uv run pytest "cumulusci/tasks/tests/test_create_package_version.py::TestPackageConfig::test_org_config" -x +1 passed in 0.22s +``` + +The test (`test_create_package_version.py:159–167`) explicitly sets `org_config.config_file = None` and asserts that `CreatePackageVersion` raises `TaskOptionsError` matching `PERSISTENT_ORG_ERROR`. + +### Recommendation + +- **Pass 1:** close-with-comment ("Fixed by commit `2a9cadcb1` (PR adding clear error message). v4.10.0 raises a clear `TaskOptionsError` directing users to use a scratch org target.") +- **Pass 2 label:** `resolved-by-clear-error-message` +- The underlying limitation — cannot use a persistent (DevHub) org as the target for 2GP package upload — is preserved by design and now communicated clearly. + +--- + + + +### #3349: Make generated dataset recordType tables unique based on table instead of sf_object + +**Verdict:** `REPRODUCED-on-v4.10.0` — bug, structural + +`MappingStep.get_source_record_type_table()` and `get_destination_record_type_table()` in `cumulusci/tasks/bulkdata/mapping_parser.py:177-179` build the SQLite table name solely from `self.sf_object` (`f"{self.sf_object}_rt_mapping"` and `f"{self.sf_object}_rt_target_mapping"`). Two mapping steps targeting the same `sf_object` (the canonical case is `Account` Person vs Business with different `record_type:` values) thus produce the same table name. `load.py:552` and `extract.py:259/393` both use those names without per-step disambiguation. + +Repro test (`/tmp/repro/10/tests/test_3349_recordtype_table_collision.py`) constructs two `MappingStep` objects with `sf_object="Account"` and different `record_type` values and asserts that both source and target table names collide — assertion passes, confirming the bug. + +The maintainer label `wi-created` (W-11466074) is present, so this is exempt from the stale-24mo close. **Recommended pass1: `keep-open`.** Suggested fix: include `self.table` (or a hash of `record_type`+`filter`) in the generated table name when more than one mapping step shares an `sf_object`. + + + +### #3353: Enable Snowfakery task to use recipes from other repositories + +**Verdict:** `REPRODUCED-on-v4.10.0` — feature still unimplemented + +`Snowfakery._validate_options` in `cumulusci/tasks/bulkdata/snowfakery.py:159-162` validates the `recipe` option via `Path(recipe).exists()` only. There is no `SOURCE_NAME:path` parsing, and no call to `project_config.sources` / `project_config.get_source(...)` anywhere in `snowfakery.py`. The recipe string is passed straight to Snowfakery as a filesystem path. + +This is a documented community ask (resurfaced in 2024-08 by `davidjray` and `jnesong`), not just a single reporter. Workaround today is `cci org import` from inside the source repository. + +**Recommended pass1: `keep-open`.** Suggested fix: pre-process the `recipe` option to detect a `SOURCE_NAME:path` prefix and resolve it via `project_config.get_source(name).fetch().path` before existence check. + + + +### #3360: Read Only Object Lookup for Load_Dataset + +**Verdict:** `NOT-REPRODUCED-on-v4.10.0` — feature implemented + +The `action: select` mapping step (added by commit `b15945203`, "Core Logic for Selecting Records from Target Org", 2024-08-19, well before v4.10.0) provides exactly this behavior. It is fully wired through `cumulusci/tasks/bulkdata/select_utils.py`, the `SELECT` branch in `step.py`, and the `mapping_select.yml` test fixture. `select_options.strategy` (`similarity`, etc.), `select_options.filter`, and `select_options.priority_fields` allow the user to populate a lookup table from existing org records without DML, which is precisely the "read-only" semantic the issue requested. + +**Recommended pass1: `closed:feature-implemented`.** Close-comment should cite the SELECT action and `mapping_select.yml`. + + + +### #3418: Error creating 1gp release + +**Verdict**: INCONCLUSIVE-needs-cumulus-actions-workflow +**Repro type**: bug +**Org used**: none (no cci code path under test) + +**Method**: +Read the cci docs and source for any code that would invoke `auth:sfdxurl:store` or otherwise parse the `PACKAGING_ORG_AUTH_URL` secret. The error message in the issue is verbatim text from the sfdx CLI (`auth:sfdxurl:store`), invoked by the `SFDO-Community/standard-workflows/.github/workflows/production-1gp.yml` workflow before cci ever runs. Searched the repo for `sfdxurl|SFDX_AUTH_URL|PACKAGING_ORG_AUTH_URL` — only hit is `docs/github-actions.md` (documentation pointing users at the standard-workflows repo). + +**Evidence**: + +- `docs/github-actions.md:101-119` — examples reference `SFDO-Community/standard-workflows/.github/workflows/{beta,production}-1gp.yml@main` and the `packaging-org-auth-url` secret. +- No occurrence of `auth:sfdxurl:store` anywhere in the cci tree. +- davidmreed's 2022 comment on the issue: "I believe I know the issue here and I will seek to address it this evening" — implies the fix landed in the third-party workflow, not in cci. +- Issue is still OPEN on GitHub but no `closedByPullRequestsReferences`. + +**Recommended action**: + +- pass1: `unchanged` — keep open until we can confirm whether SFDO-Community fix is in place; transfer or cross-link there if appropriate. +- pass2 labels: `needs-info`, `needs-repro` + +--- + + + +### #3429: Support overriding `cumulusci.yml` to be used for configuration + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature + +**Method**: +Searched for `CUMULUSCI_YML`, `CUMULUSCI_EXTRA_YAML`, `extra_yaml`, `--extra-yaml`, `--configFile` across the v4.10.0 source. Inspected `BaseProjectConfig.__init__` and `_load_config` to see how YAML is layered. Verified the `extra-yaml-cli-flag` branch is NOT an ancestor of HEAD. + +**Evidence**: + +- `cumulusci/core/config/project_config.py:82` — `config_filename = "cumulusci.yml"` is hardcoded. +- `cumulusci/core/config/project_config.py:118-184` — only an `additional_yaml` kwarg (programmatic, used by MetaCI) is supported; no env var or CLI plumbing. +- `git merge-base --is-ancestor 9d650ace2 HEAD` returns non-zero — PR #3969 (commits prefixed `feat(cli): add resolve_extra_yaml helper for --extra-yaml flag`) is in flight on branch `extra-yaml-cli-flag` but not merged. +- Bundle records `closedByPullRequestsReferences = [#3969]`. + +**Recommended action**: + +- pass1: `keep-open` — feature is genuinely actionable on v4.10.0; auto-close once #3969 merges via `closed:fixed-by-pr-#3969`. +- pass2 labels: `severity:medium,area:packaging,area:cli,state:in-progress` + +--- + + + +### #3440: Enhance `default_package_path` to serve multi-package projects better + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature + +**Method**: +Re-read `default_package_path` against the request. The user wants name-based lookup with warnings when the package alias does not match the project name and a hard fail when no default and no `force-app` exist. + +**Evidence**: + +- `cumulusci/core/config/project_config.py:517-525` — implementation is the simple "first packageDirectory with `default: true`" pattern; falls back to `force-app`, then `src`. No name-based lookup, no multi-package warning, no hard fail when both are missing. + +**Recommended action**: + +- pass1: `keep-open` — same multi-package umbrella as #2979 / #3429; would best be solved together. +- pass2 labels: `severity:low,area:packaging,area:sfdx,area:multi-package` + +--- + + + +### #3441: `cci task run create_package_version` should allow `version_base: default` + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature + +**Method**: +Inspected `version_base` handling in `cumulusci/tasks/create_package_version.py` and the `release_unlocked_beta` flow definition in `cumulusci.yml`. + +**Evidence**: + +- `cumulusci/tasks/create_package_version.py:63-112` — `version_base: Optional[str]`; documented values are `None`, a literal version number, or `latest_github_release`. +- `cumulusci/tasks/create_package_version.py:529-563` — `_get_base_version_number` only branches on `None` (default) and `"latest_github_release"`; any other string is parsed as a literal version. There is no `"default"`/`"highest"` sentinel and no support for unsetting via flow override. +- `cumulusci/cumulusci.yml:1216-1225` — `release_unlocked_beta` hard-codes `version_base: latest_github_release` for `create_package_version`. Per yippie's comment, CCI lacks a generic null-override mechanism for flow steps. + +**Recommended action**: + +- pass1: `keep-open` — could be solved minimally with a `default`/`highest` sentinel in `_get_base_version_number`, or generalized as a CCI null-override feature. +- pass2 labels: `severity:low,area:packaging,area:flow-overrides,area:cli` + +--- + + + +### #3446: CCI task push_qa crashes for Unlocked package with no namespace + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug +**Org used**: `repro-pkg-b1-dev` (dev) — used to confirm push_qa even runs against a non-packaging org; the user's actual NoneType crash happens before the SOQL would succeed on a real packaging org. + +**Method**: +The user's command omitted `--version` and `--version_id`. Inspected `cumulusci/tasks/push/tasks.py` `_run_task`: when neither is set, it calls `self._get_version(package, self.options.get("version"))`, which calls `self._parse_version(version)` on `version=None`, which calls `version.split(".")`. This raises `AttributeError: 'NoneType' object has no attribute 'split'` — exactly the error from the linked gist in the issue. Verified by direct unit-style invocation: + +```python +BaseSalesforcePushTask._parse_version(None, None) # -> AttributeError +``` + +Also ran `cci task run push_qa --orgs /tmp/repro_pkg_orgs.txt --metadata_package_id 0337S000000DUMMY --org repro-pkg-b1-dev` against the scratch org; the path failed earlier on the org (no Push API on a dev scratch — `sObject type 'MetadataPackage' is not supported`), but on a real Push-API-enabled DevHub it would surface the NoneType crash. + +The user's follow-up comment ("Push API not activated by default") is a separate UX issue: when Push API is disabled, the SOQL `SELECT ... FROM MetadataPackage` fails with `INVALID_TYPE`. They'd like a friendlier error. + +**Evidence**: + +- `cumulusci/tasks/push/tasks.py:33` — `version_parts = version.split(".")` (no None-guard above). +- `cumulusci/tasks/push/tasks.py:283-297` — `_run_task` does not validate `version` before calling `_get_version`. +- Test: `/tmp/repro/3/tests/repro_3446_push_qa_no_version.py` passes on v4.10.0. +- Live invocation against scratch org: `Error: Malformed request ... sObject type 'MetadataPackage' is not supported` (orthogonal to the NoneType but illustrates the second comment). + +**Recommended action**: + +- pass1: `keep-open` — real bug, simple fix. +- pass2 labels: `bug`, `good-first-issue` + +--- + + + +### #3466: Ability to specify a test suite to run instead of just `test_name_match` + +**Verdict**: NOT-REPRODUCED-on-v4.10.0 +**Repro type**: feature + +**Method**: +Searched for `test_suite_names` in `cumulusci/tasks/apex/testrunner.py`. Wrote `/tmp/repro/1/tests/test_issue_3466.py` to assert the option exists, has a sensible description, and is mutually exclusive with `test_name_match`. + +**Evidence**: + +- `cumulusci/tasks/apex/testrunner.py:173-175` — `test_suite_names` is a documented `task_options` field accepting a comma-separated list of ApexTestSuite names. +- `cumulusci/tasks/apex/testrunner.py:188-190, 246-253, 308-376` — option is wired through `_init_options`, validated as mutually exclusive with `test_name_match`, and used by `_get_test_classes_from_test_suite_names` (queries ApexTestSuite + TestSuiteMembership). +- Repro test passes (2/2) on v4.10.0. + +**Recommended action**: + +- pass1: `closed:feature-implemented` — the request is fully covered. davidmreed's reply linked W-12214520; that backlog item appears to have shipped. +- pass2 labels: `area:packaging,area:apex,state:resolved` + +--- + + + +### #3470: Rename `ci_master` to `ci_main` (or alias) + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature +**Method**: code-scan + +**Evidence**: + +```823:835:cumulusci/cumulusci.yml + ci_master: + group: Continuous Integration + description: Deploy the package metadata to the packaging org and prepare for managed package version upload. Intended for use against main branch commits. + steps: + ... +``` + +`rg "ci_main"` returns no matches. davidmreed's 2022 reply indicated this requires flow-aliasing infrastructure first. + +**Recommended action**: + +- pass1: `closed:stale-24mo` — 4yr stale; preserve as `closed:stale-24mo` rather than dismiss; the inclusive-language motivation is real and could be revisited if flow aliasing lands. +- pass2 labels: `enhancement,stale,inclusive-language` + + + +### #3471: `Merged 0 commits into branch:` message displays when a non-Source Code change is + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug +**Method**: Bucket A — code-scan and `git log` against `cumulusci/tasks/github/merge.py`. + +**Evidence**: + +The reported log message originates from `_merge`: + +```241:262:cumulusci/tasks/github/merge.py + def _merge(self, branch_name, source, commit): + """Attempt to merge a commit from source to branch with branch_name""" + compare = self.repo.compare_commits(branch_name, commit) + if not compare or not compare.files: + self.logger.info(f"Skipping branch {branch_name}: no file diffs found") + return + + try: + self.repo.merge(branch_name, commit) + self.logger.info( + f"Merged {compare.behind_by} commits into branch: {branch_name}" + ) + except GitHubError as e: + if e.code != http.client.CONFLICT: + raise + + if self.options["create_pull_request_on_conflict"]: + self._create_conflict_pull_request(branch_name, source) + else: + self.logger.info( + f"Merge conflict on branch {branch_name}: skipping pull request creation" + ) +``` + +The log line at 251 reports `compare.behind_by` from github3's CompareCommits. `behind_by` is computed from the GitHub compare-commits endpoint and reflects how many commits the destination branch is behind the merged commit _as of the comparison's chosen merge-base_; for "effectively no-op" content merges (e.g. README/test.txt scenarios where downstream content already matches via merge-base), the API can return 0 even though `self.repo.merge(branch_name, commit)` at line 249 just shipped a real commit. The reporter's pattern (README and `test.txt` reproduce; cumulusci.yml / source-code changes do not) is consistent with this hypothesis. + +`git log --all --oneline -- cumulusci/tasks/github/merge.py` since 2023-01-01 shows only refactors (ruff migration, internal repo migration, the `create_pull_request_on_conflict` option, `skip_future_releases` fixes); the `compare.behind_by` reporting line has not changed since the original `MergeBranch` implementation. Existing `test_merge.py` only exercises the happy path where `behind_by == 1`; no test covers the misleading 0-case. + +**Recommended action**: + +- pass1: `keep-open` — small, well-localized fix (replace `compare.behind_by` with `len(list(compare.commits))` or report the SHA returned from `self.repo.merge(...)`); add a test covering the `behind_by=0` case. +- pass2 labels: `bug, github, merge, low-priority` + +--- + + + +### #3479: Error with "cci org import" in github action + +**Verdict**: NOT-REPRODUCED-on-v4.10.0 +**Repro type**: bug +**Method**: Bucket A — code-scan of `cumulusci/cli/org.py` `org_import`, `cumulusci/core/config/sfdx_org_config.py` `sfdx_info`, and `git log` for the relevant wrapping fix. + +**Evidence**: + +The reported error is the bare `Expecting value: line 1 column 1 (char 0)` (raw `json.JSONDecodeError`). The actual error path in v4.10.0: + +`cumulusci/cli/org.py`: + +```238:255:cumulusci/cli/org.py +@org.command(name="import", help="Import an org from Salesforce DX") +@click.argument("username_or_alias") +@orgname_option_or_argument(required=True) +@pass_runtime(require_keychain=True) +def org_import(runtime: CliRuntime, username_or_alias: str, org_name: str): + # Import the org from the SFDX keychain as an SfdxOrgConfig + # The `sfdx` key ensures we can reload using the right class. + org_config = SfdxOrgConfig( + {"username": username_or_alias, "sfdx": True}, + org_name, + runtime.keychain, + global_org=False, + ) + + # Determine if we received a locally-created scratch org + # or some other org (which we'll treat as persistent) + + info = org_config.sfdx_info +``` + +`cumulusci/core/config/sfdx_org_config.py`: + +```38:55:cumulusci/core/config/sfdx_org_config.py + if p.returncode: + self.logger.error(f"Return code: {p.returncode}") + for line in stderr_list: + self.logger.error(line) + for line in stdout_list: + self.logger.error(line) + message = f"\nstderr:\n{nl.join(stderr_list)}" + message += f"\nstdout:\n{nl.join(stdout_list)}" + raise SfdxOrgException(message) + + else: + try: + org_info = json.loads("".join(stdout_list)) + except Exception as e: + raise SfdxOrgException( + "Failed to parse json from output.\n " + f"Exception: {e.__class__.__name__}\n Output: {''.join(stdout_list)}" + ) +``` + +Both nonzero return codes and JSON parse failures from `sfdx org display --json` are wrapped in `SfdxOrgException` with explicit context (this wrapping landed in commit `017bc49f4` on 2020-11-24, well before the 2023-01-06 issue). The bare `Expecting value: line 1 column 1 (char 0)` symptom is therefore not what a v4.10.0 user would see for this scenario — they would get the `Failed to parse json from output. Exception: JSONDecodeError. Output: ...` message instead, which directly reveals the empty/garbled sfdx output and points to the upstream auth/shell problem. + +David Reed's only reply (2023-02-22, never answered by the reporter) correctly identifies the root cause as GHA shell interpolation: `echo ${{ secrets.DEV_AUTH_URL }} > sfdx_auth` without quotes mangles multiline secrets, so `sfdx force:auth:sfdxurl:store` either fails silently or produces an invalid auth — then `sfdx org display --json` returns empty/non-JSON. Fix is in the user's workflow, not in cci. + +**Recommended action**: + +- pass1: `closed:not-reproducible-on-v4.10.0` — root cause is user GHA workflow (unquoted multiline secret); cci's only relevant code path (`sfdx_info`) already wraps the error with a user-actionable message in v4.10.0; reporter never responded for 3+ years. +- pass2 labels: `awaiting-more-details, external-config` + +--- + + + +### #3485: "cci task run run_tests" generates incorrect test_results.xml format + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug +**Method**: code-scan + +**Evidence**: + +- `cumulusci/tasks/apex/testrunner.py:803-834` — `_write_output` opens `junit_output` and writes `'\n'` with no `` declaration and no enclosing `` element. +- The closing tag at line 834 is ``. This exactly matches the malformed XML the reporter showed. +- `junit_output` defaults to `test_results.xml` (line 201-203), unchanged. + +**Recommended action**: + +- pass1: `keep-open` — small mechanical fix, still affects users producing JUnit reports for CI. +- pass2 labels: `bug, area:apex, good-first-issue` + + + +### #3492: Enhance the "-o" option of "cci flow run" to accept "project\_\_custom" attribute values + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature +**Method**: code-scan + +**Evidence**: + +- `cumulusci/cli/flow.py:152-162` — parses `-o` pairs by splitting key on `"__"` and unpacking into exactly two parts (`task_name, option_name = key.split("__")`). +- A user passing `-o project__custom__myattr value` would actually error with "too many values to unpack" because the split yields three elements; even worded as `-o project__custom value` there is no codepath that writes into `project_config.config["project"]["custom"]`. +- `coordinator = runtime.get_flow(flow_name, options=options)` (line 166) receives a `{task_name: {option_name: value}}` dict; project-level overrides have no entry point here. + +**Recommended action**: + +- pass1: `keep-open` — legitimate usability gap for matrix-style CI. +- pass2 labels: `enhancement, area:cli` + + + +### #3506: when clause support for flow steps which call other flows + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature (silent ignore = bug-shaped) +**Method**: code-scan + +**Evidence**: + +- `cumulusci/core/flowrunner.py:660-672` — when the step has a `task:` key, the StepSpec is built with `when=step_config.get("when")`. +- `cumulusci/core/flowrunner.py:674-697` — the `flow:` branch recurses via `_visit_step(...)` passing only `parent_options`, `parent_ui_options`, and `from_flow`; it never reads or propagates `step_config.get("when")`. Any `when:` clause attached to a flow-call step is silently dropped. + +**Recommended action**: + +- pass1: `keep-open` — confirmed silent-failure foot-gun the user reported. +- pass2 labels: `enhancement, area:flows` + + + +### #3518: Task add_picklist_entries always sets a default value for record types + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug + +**Method**: +Read `cumulusci/tasks/metadata_etl/picklists.py`. The smoking gun is at +line 177: `default = str(process_bool_arg(entry.get("default", False))).lower` +— `.lower` is referenced as an attribute, not invoked. The resulting bound +method is truthy, so the `if default:` guard at line 214 always runs the +default-clobbering loop, marking the new entry as default for every record +type. Wrote two tests: a unit-level repro of the truthy bound-method, and a +function-level repro driving `_add_single_record_type_entries` directly via +`MetadataElement` to observe the mutated XML. + +**Evidence**: + +- `cumulusci/tasks/metadata_etl/picklists.py:177` missing `()` after `.lower`. +- `cumulusci/tasks/metadata_etl/picklists.py:214-221` unconditionally sets + defaults whenever `default` is truthy. +- Test output: `test_issue_3518_picklist_record_type_default_logic_bug` + asserts the value is callable (it is) — fails as expected. +- Test output: `test_issue_3518_record_type_default_not_set_when_default_false` + observed `true` on a value that was passed + `default: False`. + +**Recommended action**: + +- pass1: keep-open — small targeted fix. +- pass2 labels: `severity:high,area:metadata-etl,type:bug` + +--- + + + +### #3542: 2GP flows fail locally with "Could not find package version id" + +**Verdict**: INCONCLUSIVE-needs-2GP-CI-pipeline +**Repro type**: bug +**Org used**: none (cannot easily fabricate a github status posted under a different SHA) + +**Method**: +Read `cumulusci/tasks/github/commit_status.py` `GetPackageDataFromCommitStatus._run_task` and `cumulusci/core/github.py:get_version_id_from_commit`. The lookup uses `self.project_config.repo_commit` (the local checkout's git HEAD SHA) verbatim, then iterates `commit.status().statuses` for one matching the configured context. No fallback to parent commits or to `pull_request.head.sha`. If the upstream workflow posted the status under a different SHA — most commonly the synthetic merge SHA used by `actions/checkout` on `pull_request` triggers — the local lookup returns no version_id and the user sees the exact error from the issue. + +git log shows several "github_package_data" commits since 2022 (last directly related: `33bb24197 Update default API version to v59.0`; `7686731b2 Use commit_status resolution strategy when building non-SkipValidation 2GPs`) but none change the SHA-resolution semantics. The cci-side code path is **unchanged** at v4.10.0. + +Cannot fully reproduce in this run because that requires (a) a private repo configured to use a 2GP feature build workflow that records the version_id, (b) a PR build that has actually completed, (c) local checkout of that PR. Out-of-scope for a fresh scratch org repro. + +**Evidence**: + +- `cumulusci/tasks/github/commit_status.py:20` — `commit_sha = self.project_config.repo_commit` +- `cumulusci/core/github.py:361-368` — `get_version_id_from_commit` only checks the exact SHA's statuses; no fallback. + +**Recommended action**: + +- pass1: `unchanged` — needs the reporter (or someone with a 2GP CI pipeline) to confirm whether their workflow posts under merge-commit SHA vs head-commit SHA. If the latter, this is a cci bug; if the former, it's a workflow alignment bug in `cumulus-actions`. +- pass2 labels: `needs-repro`, `2gp` + +--- + + + +### #3543: New Option `load_sfdx_project_paths` for dx_convert_from Task + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature + +**Method**: +Read `cumulusci/tasks/dx_convert_from.py` end to end (27 lines). Greped for +`load_sfdx_project_paths|resolve_sfdx_package_dirs|sfdx_project` across the +codebase. + +**Evidence**: + +- `cumulusci/tasks/dx_convert_from.py:7-14` exposes only `extra` and + `src_dir`; no `load_sfdx_project_paths` / `resolve_sfdx_package_dirs`. +- The grep hits in `project_config.py` and `cli/project.py` are unrelated + (general sfdx-project.json reading); they aren't wired into + `DxConvertFrom`. + +**Recommended action**: + +- pass1: keep-open — feature still unimplemented; reporter offered a draft PR. +- pass2 labels: `severity:low,area:metadata-etl,type:enhancement` + +--- + + + +### #3544: `update_admin_profile` errors when org has Person Accounts AND a namespace + +**Verdict:** `INCONCLUSIVE-needs-namespaced-project` + +### Original symptom + +When `cci flow run dev_org --org dev` is run against a scratch org that has both: + +1. `PersonAccounts` in `features` array of the scratch_def +2. `namespaced: true` set under `orgs/scratch/` in `cumulusci.yml` + +…then the `update_admin_profile` step of `config_dev` fails. The reporter cited stackoverflow Q 206310 noting "Entity of type 'RecordType' named 'Account.Business_Account' cannot be found", indicating the deployed Profile XML references a record type that has been renamed or removed by SFDX/MetadataAPI behavior in PersonAccounts orgs. + +Internal tracking: davidmreed filed W-12589033 (2023-02-22) but stated "I can't make any promises about delivering a behavior change." + +### Provisioning attempted + +```text +$ uv run cci org info repro-special-c-pa +config_file: orgs/person_accounts.json +config_name: person_accounts +namespaced: False +features: Communities, PersonAccounts, ContactsToMultipleAccounts +instance_url: https://drive-inspiration-9525.scratch.my.salesforce.com +``` + +CumulusCI's own `cumulusci.yml` declares no `project__package__namespace`. Setting `namespaced: true` on the scratch config has no effect without a registered namespace, and registering a CumulusCI namespace in CCIDevHub is out of scope for this triage pass. + +### Partial repro on v4.10.0 + +```text +$ uv run cci task run update_admin_profile --org repro-special-c-pa +Beginning task: ProfileGrantAllAccess +Extracting existing metadata... +[Done] +Loading transformed metadata... +Beginning task: Deploy +[InProgress]: Processing Type: Profile +[Done] +[Success]: Succeeded +``` + +The task **succeeded** against a non-namespaced PersonAccounts scratch org — confirming that the bug requires the _intersection_ of PersonAccounts + namespacing, not PersonAccounts alone. + +### Code search for fixes + +- `git log --since=2023-02-01 -- cumulusci/tasks/salesforce/update_profile.py cumulusci/files/admin_profile.xml` shows only one commit (entrypoints refactor 23295c0a2) — no functional change to PersonAccounts handling. +- `git log --grep "person.account|business_account|3544|W-12589033" -i` returns nothing relevant in `update_profile.py`. +- `update_profile.py` retains a generic `person_account_default` option (line 242, 277) for explicit recordType configuration but no automatic detection or filtering of `Account.Business_Account` for PersonAccounts orgs. + +### Adjacent finding (not the same bug) + +`cumulusci/utils/__init__.py:229`: + +```229:229:cumulusci/utils/__init__.py + namespaced_org = namespace + "__" if namespaced_org else "" +``` + +Passing `-o namespaced_org True` against a project with `namespace=None` raises `TypeError: unsupported operand type(s) for +: 'NoneType' and 'str'`. Distinct from #3544's bug (which is a deploy-time RecordType-not-found error, not an init-time TypeError). Worth filing as a separate cleanup issue. + +### Recommendation + +- **Pass 1:** needs-info — ask reporter to validate against v4.10.0 with their namespaced project and confirm whether the issue persists. Include `wi-created` already on the issue (W-12589033). +- **Pass 2 label:** `needs-namespaced-project` — repro requires a namespaced project that this triage pipeline cannot synthesize. +- Alternative: consider treating as `wontfix` per davidmreed's recommendation (use `flows.config_dev.steps.2: task: None` workaround) until SFDC fixes the underlying SFDX/MetadataAPI Account.Business_Account renaming issue. + + + +### #3549: Deploy to Salesforce does not create a test output + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature +**Method**: code-scan + +**Evidence**: + +- `cumulusci/tasks/salesforce/Deploy.py:49-94` — exposes `test_level` and `specified_tests` options and validates them. +- `cumulusci/tasks/salesforce/Deploy.py:150-154` — passes them through to the metadata API call but never captures `runTestResult`/`runTestsResult` from the response. +- `rg "junit_output|test_results"` against `cumulusci/tasks/salesforce/Deploy.py` and `cumulusci/salesforce_api/metadata.py` returns no test-output writer for the deploy path. + +**Recommended action**: + +- pass1: `keep-open` — natural feature; tracks #3564. +- pass2 labels: `enhancement, area:metadata-deploy` + + + +### #3561: Retrieve_unpackaged unusable in MetaDeploy + +**Verdict**: NOT-REPRODUCED-on-v4.10.0 (fix landed) +**Repro type**: bug +**Org used**: none + +**Method**: +Read `cumulusci/tasks/salesforce/RetrieveUnpackaged.py`. Current code: + +```26:36:cumulusci/tasks/salesforce/RetrieveUnpackaged.py + def _init_options(self, kwargs): + super(RetrieveUnpackaged, self)._init_options(kwargs) + + if "package_xml" in self.options: + with open(self.options["package_xml"], "r") as f: + self.options["package_xml_content"] = f.read() + + def _get_api(self): + return self.api_class( + self, self.options["package_xml_content"], self.options.get("api_version") + ) +``` + +`git log -S "package_xml_content" -- cumulusci/tasks/salesforce/RetrieveUnpackaged.py` -> commit `56e10665e` "Fix retrieve unpackaged so it is usable in metadeploy (#3566)" merged 2024-05-20 by yippie (the original issue reporter). The fix introduces `package_xml_content` as a separate option so the path-typed `package_xml` is preserved across multiple `_init_options` invocations. + +**Recommended action**: + +- pass1: `close-as-fixed` with link to PR #3566. +- pass2 labels: (none) + +**Notes**: yippie shipped their own fix; the issue was just never closed. + +--- + + + +### #3570: Feature Request: Flow "finally" or "error" path + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature +**Method**: code-scan + +**Evidence**: + +- `cumulusci/core/flowrunner.py` — only `ignore_failure` (mapped to `StepSpec.allow_failure`, line 122/144) and the `finally:` Python clause inside `flow.run()` (line 500) handle failures. There is no flow-step type for `finally:` / `on_error:` / `cleanup:` / `always_run`. `rg "finally|on_error|on_failure|always_run"` confirms. +- `_run_step` (line 503-536) re-raises on `result.exception` if not `allow_failure`, which is the only failure handling. + +**Recommended action**: + +- pass1: `keep-open` — design-level feature, but problem is real (rollback, notify on partial failure). +- pass2 labels: `enhancement, area:flows` + + + +### #3585: Error Occurs when Using `update_package_xml` on object with `xsi:nil="true"` + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug + +**Method**: +Wrote a test that places a `.object` file containing +`` (with no `xmlns:xsi` +declared) and invokes `PackageXmlGenerator`. The underlying parser raises a +parse error because the `xsi:` prefix is unbound. + +**Evidence**: + +- `cumulusci/tasks/metadata/package.py:115-130` — when a folder has objects + it instantiates the registered parser; for `objects/` the parser uses the + metadata tree which is strict about namespaces. +- Test output: `test_issue_3585_xsi_nil_true_breaks_update_package_xml` fails + with the exact "not well-formed (invalid token)" class of error reported + by the user. + +**Recommended action**: + +- pass1: keep-open — needs either a namespace-shim before parsing or + pre-stripping of `xsi:nil` attributes. +- pass2 labels: `severity:medium,area:metadata-etl,type:bug,sfdx-compat` + +--- + + + +### #3587: Warning when install_class/uninstall_class set with managed=false on update_package_xml + +**Verdict**: NOT-REPRODUCED-on-v4.10.0 (feature still unimplemented) +**Repro type**: feature +**Org used**: none (update_package_xml is a local task) + +**Method**: +Inspected `cumulusci/tasks/metadata/package.py`: + +- `PackageXmlGenerator.render_xml()` lines 142-152: emits `/` only when `self.managed and self.install_class` / `self.managed and self.uninstall_class`. No warning if managed is False. +- `UpdatePackageXml._init_options` line 587-588: only normalizes `managed` to bool. No validation/warning. +- `UpdatePackageXml._init_task` line 590-610: passes options through without checking the install_class+managed=False combination. + +Confirmed live by running: + +```bash +uv run cci task run update_package_xml --install_class MyInstall --uninstall_class MyUninstall +``` + +Output (full): `Beginning task: UpdatePackageXml; Generating src/package.xml from metadata in src` — **no warning**. (src/package.xml ended up empty because src/ has no metadata in the cci repo, but the relevant signal is the absence of any warning about install_class being silently dropped.) + +Also confirmed via direct generator test (`/tmp/repro/3/tests/repro_3587_update_package_xml_no_warning.py`): + +- `managed=False, install_class="X"` → output XML has neither `` nor ``. +- `managed=True, install_class="X"` → output XML has them. + +**Evidence**: + +- `cumulusci/tasks/metadata/package.py:142-152` +- `cumulusci/tasks/metadata/package.py:578-610` +- Live cci output: no warning when invoked with --install_class but no --managed. + +**Recommended action**: + +- pass1: `keep-open` — feature still missing. +- pass2 labels: `enhancement`, `good-first-issue` + +--- + + + +### #3593: `dx` task doesn't work for some commands like `project convert source` + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug + +**Method**: +Read `cumulusci/tasks/sfdx.py` end-to-end. Wrote `/tmp/repro/1/tests/test_issue_3593.py` that constructs an `SFDXOrgTask` with command `"project convert source -r src -d force-app"` and a `ScratchOrgConfig`, then asserts the resulting command would not append a target-org flag. + +**Evidence**: + +- `cumulusci/tasks/sfdx.py:46-51` — `SFDXOrgTask._get_command` unconditionally appends `" -o {username}"` for any `ScratchOrgConfig`, regardless of whether the underlying sf subcommand accepts a target-org flag. +- Repro test FAILS with the resulting command: `sf project convert source -r src -d force-app -o test@example.com` — the same shape that the issue reporter said sf cli rejects. +- Note: `cumulusci/tasks/dx_convert_from.py` (which backs the OOTB `dx_convert_from` task) was switched to extend `SFDXBaseTask` (no org), so the OOTB task is fine; the bug remains for any user-defined task that uses `SFDXOrgTask` with a no-org sf subcommand. + +**Recommended action**: + +- pass1: `keep-open` — needs an opt-out option (e.g. `pass_org: False` or a `no_org_command` whitelist). Verifying actual sf cli rejection of `-o` for `project convert source` would need an org/sf cli; the CCI side of the bug is unchanged. +- pass2 labels: `severity:medium,area:packaging,area:sfdx,area:dx-task,state:needs-design` + +--- + + + +### #3600: Allow install_managed to use environment variables + +**Verdict**: NOT-REPRODUCED-on-v4.10.0 (feature still unimplemented) +**Repro type**: feature +**Org used**: `repro-pkg-b1-dev` (dev) — used to confirm cci accepts the literal `${VAR}` value at runtime. + +**Method**: +Inspected the option-processing path: + +- `cumulusci/core/tasks.py:35` — `PROJECT_CONFIG_RE = re.compile(r"\$project_config.(\w+)")`. This is the only substitution pattern. +- `cumulusci/core/tasks.py:127-157` — `_init_options.process_options` only calls `PROJECT_CONFIG_RE.sub(...)`; no env-var lookup. +- `cumulusci/utils/yaml/safer_loader.py:60` — uses plain `yaml.safe_load(...)` with no custom resolver. +- `cumulusci/tasks/salesforce/install_package_version.py:31-34` — `version` option description does not mention env-var support. + +Confirmed live by: + +```bash +export MY_FAKE_VERSION='1.2.3' +uv run cci task run install_managed --version '${MY_FAKE_VERSION}' \ + --namespace npsp --org repro-pkg-b1-dev --interactive True +``` + +Interactive prompt printed: `Package to install: npsp ${MY_FAKE_VERSION}` — literal, **not** expanded. + +**Evidence**: + +- `cumulusci/core/tasks.py:35` — only substitution pattern. +- `cumulusci/utils/yaml/safer_loader.py:60` — plain yaml load. +- Test: `/tmp/repro/3/tests/repro_3600_install_managed_no_env_var.py` passes. +- Live interactive output: `Package to install: npsp ${MY_FAKE_VERSION}`. + +**Recommended action**: + +- pass1: `keep-open` — feature still missing. Note design decision required: `$env:VAR` (consistent with `$project_config.X`) vs `${VAR}` (POSIX) vs `os.path.expandvars` semantics; backwards-compat for any literal `$`-strings. +- pass2 labels: `enhancement` + +--- + + + +### #3603: Any issue with git results in the unhelpful "404 not found" error + +**Bucket**: A. **Type**: bug. **Verdict**: REPRODUCED-on-v4.10.0 (partial). + +The user enumerated five situations (1) source repo missing, (2) dep repo +missing, (3) source ref/tag/branch missing, (4) dep resolution strategy fails, +(5) source resolution strategy fails — all collapsing into a generic 404 with +no source/URL/ref context. Code-scan + targeted unit test confirm: + +- Cases **1, 2** are already wrapped: both `cumulusci/core/dependencies/github.py::get_repo` + and `cumulusci/core/source/github.py::GitHubSource.__init__` catch `NotFoundError` + and raise `DependencyResolutionError("We are unable to find the repository at {url}...")`. + Fixed long ago by commit `738d4a8a4` (2021). +- Case **5** for the `release:` source spec is wrapped at + `source/github.py:103` ("Could not find release {self.spec.release}."). +- Case **3** is **NOT** wrapped. `source/github.py:126` + `self.commit = self.repo.ref(ref).object.sha` lets a raw `NotFoundError` + bubble out. The repro test (`test_case3_source_ref_not_found_message_quality`) + prints the actual exception: + + ``` + Exception type: NotFoundError + Message: '404 [No message]' + ``` + + Neither the repo URL nor the missing ref/tag is present. + +- Case **4** raises `DependencyResolutionError(f"Unable to resolve dependency {dependency}")` + (resolvers.py:663). The dependency description is included, but the list of + attempted strategies is not — so the user can't immediately tell which + strategy fell through. + +Recommendation: keep-open. Two clean, scoped fixes available (wrap `repo.ref()` +in `source/github.py`; enrich the resolvers.py:663 message with strategy +names). Good-first-issue territory. + +Repro: `/tmp/repro/11/tests/test_3603_404_messages.py` (4 tests; all pass). + +--- + + + +### #3604: Task request: Update sfdx-project.json dependencies based off of computed cumulusci dependencies + +**Bucket**: A. **Type**: feature. **Verdict**: REPRODUCED-on-v4.10.0 (gap still +present). + +`uv run cci task list` returns 0 tasks that write `sfdx-project.json`. A +project-wide grep for `unpackagedMetadata` returns no matches. Maintainer +acknowledged the request as W-13504384 in a 2023 reply, label `wi-created` +already on the issue, but no implementation has shipped through v4.10.0. + +Recommendation: keep-open (`enhancement`, `wi-created` already attached). + +Repro: code-scan only; no test file (feature gap, nothing to assert against). + +--- + + + +### #3605: Ability to Increment Major Versions when running `upload_production` + +**Verdict**: NOT-REPRODUCED-on-v4.10.0 +**Repro type**: feature + +**Method**: +Inspected `cumulusci/tasks/salesforce/package_upload.py`. Wrote `/tmp/repro/1/tests/test_issue_3605.py` to assert `major_version` and `minor_version` task options exist and the major-bump branch is wired in `_validate_versions`. + +**Evidence**: + +- `cumulusci/tasks/salesforce/package_upload.py:39-46` — `major_version` and `minor_version` are documented `task_options`. +- `cumulusci/tasks/salesforce/package_upload.py:101-140` — `_validate_versions` honors a major-version bump, defaulting `minor_version` to `"0"` when the user supplies a higher major. +- Repro test passes (3/3). +- Closing PR identified by `git log` history: commit `87b94440e` — "Deploy Major and Minor Version option in upload_production task (#3651)". + +**Recommended action**: + +- pass1: `closed:fixed-by-pr-#3651` — feature shipped; user can run `cci task run upload_production -o major_version 34 -o minor_version 0`. +- pass2 labels: `area:packaging,area:1gp,state:resolved` + +--- + + + +### #3607: The `retry_failures` from the task `run_tests` is not working for me + +**Verdict**: INCONCLUSIVE-needs-org-with-managed-package +**Repro type**: bug +**Method**: code-scan + unit test + +**Evidence**: + +- `cumulusci/tasks/apex/testrunner.py:209-222` — `retry_failures` strings are compiled into regexes at task init. +- `cumulusci/tasks/apex/testrunner.py:400-408` — `_is_retriable_failure` checks both `Message` and `StackTrace` via `re.search`. +- `cumulusci/tasks/apex/testrunner.py:475-490` — increments `counts["Retriable"]` for each matching failure. +- `cumulusci/tasks/apex/testrunner.py:548` — printed as `Retried: {Retriable}`. +- Repro test `/tmp/repro/8/tests/test_3607_retry.py` confirms in pure Python that `re.compile("UNABLE_TO_LOCK_ROW").search(user_message)` returns a match for the exact message body the user pasted. Both tests pass. +- One escape hatch in code: `cumulusci/tasks/apex/testrunner.py:448-452` — for class-level errors with `managed: true` (which the user has), retries are explicitly skipped. The user's failure shows per-test details, so this should not have been the cause. + +**Recommended action**: + +- pass1: `closed:stale-24mo` — code logic is correct as written; reporter has not engaged in 30+ months; cannot reproduce without their managed package + org. +- pass2 labels: `bug, area:apex, needs-info` + + + +### #3609: Command 'cci task run dx --command "plugins:install ..."' fails + +**Verdict**: INCONCLUSIVE-needs-live-cli-test +**Repro type**: bug +**Method**: code-scan + +**Evidence**: + +- `cumulusci/tasks/sfdx.py:20` — `SFDX_CLI = "sf"` (changed from `sfdx` in the v4.x cutover; reporter was on 3.76.0). +- `cumulusci/tasks/sfdx.py:34-40` — `_get_command` is a thin wrapper: `f"sf {self.options['command']}"`. The CCI layer adds nothing that could introduce the "Timed out after 30000 ms" error the user saw. +- `cumulusci/cumulusci.yml:273-275` — `dx` task is registered as `cumulusci.tasks.sfdx.SFDXOrgTask` with description "Execute an arbitrary Salesforce DX command". +- Reporter's literal command `--command "plugins:install ..."` uses the colon syntax that `sfdx` accepted; `sf` typically wants `plugins install`. Different CLI now. + +**Recommended action**: + +- pass1: `closed:stale-24mo` — not a CCI bug; CCI faithfully shells out. CLI in question has changed substantially since. +- pass2 labels: `bug, upstream:sf-cli` + + + +### #3612: Maintain the CumulusCI for VSCode Extension + +**Verdict**: NOT-REPRODUCED-on-v4.10.0 +**Repro type**: feature (wrong repo) +**Method**: code-scan + +**Evidence**: + +- Issue body explicitly references `https://github.com/SFDO-Tooling/cci-vscode`. That is a separate repository; nothing in this CumulusCI tree is responsible for it. + +**Recommended action**: + +- pass1: `closed:not-reproducible-on-v4.10.0` — should be re-filed against `SFDO-Tooling/cci-vscode`. +- pass2 labels: `enhancement, wontfix, wrong-repo` + + + +### #3613: AddFieldsToPageLayout — "Cannot find metadata file" + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug (UX/error-message) +**Org used**: `repro-etl-b-dev` + +**Method**: +Live repro: `uv run cci task run add_page_layout_fields --org repro-etl-b-dev -o api_names "Account"` against the scratch org. Saved at `/tmp/repro/5/tests/issue-3613/output-just-object.txt`. Result: `Error: Cannot find metadata file /var/.../retrieve/layouts/Account.layout`. Same task with `-o api_names "Account-Account Layout"` succeeds end-to-end (deploy succeeds). The functionality is intact; the user-visible bug is the unhelpful error when the api_name does not match the Metadata API's `-` file naming convention. + +The error originates from `MetadataSingleEntityTransformTask._transform` (base.py:332): `if not path.exists(): raise CumulusCIException(f"Cannot find metadata file {path}")`. The retrieve actually succeeded (the user's report says "metadata is getting downloaded"), but `_transform` looks for the user's typed api_names verbatim as filenames. + +**Recommended action**: + +- pass1: `improve-error-message` — keep open as a UX bug. +- pass2 labels: `bug`, `good-first-issue` + +**Notes**: Two complementary improvements would help: + +1. In `_transform` (base.py:332), include the actual list of files retrieved into `source_metadata_dir` in the error message so the user can spot the naming mismatch. +2. In `AddFieldsToPageLayout._init_options`, warn when an api_name does not contain `-` (Layout API names always do). + +The user was on Windows in 2023 — note that the user might also have been hitting a backslash path issue, but the underlying class of bug is the same: api_name format mismatch. + +--- + + + +### #3615: update_dependencies does not honor resolution strategy + +**Bucket**: A. **Type**: bug (filed). **Verdict**: NOT-REPRODUCED-on-v4.10.0. + +The user expected `cci task run update_dependencies --resolution_strategy preproduction` +to install a beta of an Unlocked dependency. In `cumulusci/cumulusci.yml`: + +```yaml +dependency_resolutions: + preproduction: latest_release + production: latest_release + resolution_strategies: + latest_release: [tag, latest_release, unmanaged] # no latest_beta + include_beta: [tag, latest_beta, latest_release, unmanaged] +``` + +So `preproduction` is an alias for the `latest_release` stack and intentionally +omits `latest_beta`. To install the beta unlocked package, the correct +invocation is `--resolution_strategy include_beta`. The repro test confirms +all three properties: `preproduction` lacks `latest_beta`, `include_beta` has +it, and `preproduction == production`. Working as documented. + +Recommendation: closed:not-reproducible-on-v4.10.0. Possible follow-up: docs/UX +improvement (the name `preproduction` is misleading; consider clarifying in +docs/data.md or renaming to `release_only` in a future major). + +Repro: `/tmp/repro/11/tests/test_3615_preproduction_strategy.py` (3 tests; all +pass). + +--- + + + +### #3618: Allow for list when deleting/removing CumulusCI orgs + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature +**Method**: code-scan + +**Evidence**: + +- `cumulusci/cli/org.py:519-545` — `org_remove` decorated with `@orgname_option_or_argument(required=True)`, takes a single `org_name`. +- `cumulusci/cli/org.py:605-625` — `org_scratch_delete` same pattern, single `org_name`. +- No `nargs=-1`, no comma-split helper; passing `org1,org2` would be treated as a single literal alias and fail keychain lookup. + +**Recommended action**: + +- pass1: `keep-open` — legitimately useful for cleanup workflows; small implementation surface. +- pass2 labels: `enhancement, area:cli, good-first-issue` + + + +### #3619: Dependency_pins does not honor passwords + +**Bucket**: A. **Type**: bug. **Verdict**: REPRODUCED-on-v4.10.0. + +Two distinct reproducible defects in `cumulusci/core/dependencies/dependencies.py`: + +1. **Parsing error (Part A)**: `GitHubDependencyPin` (L81-101) declares only + `github: str` and `tag: str`. Adding `password_env_name:` to a + `dependency_pins:` entry triggers + `DependencyParseError: Unable to parse dependency pin: {...}` from + `parse_dependency_pin()`. + +2. **Silent password drop (Part B)**: When a dynamic dependency carries a + `password_env_name`, the pin path at L171-187 short-circuits to + `pin.pin(self, context)`, which (L100) calls + `GitHubTagResolver().resolve(d, context)` directly — bypassing + `resolve_dependency()`'s password-propagation block (resolvers.py L644-654). + The resulting `package_dependency.password_env_name` is `None`, so + `PackageNamespaceVersionDependency.install()`'s + `os.environ.get(self.password_env_name)` runs against `None` and the + install-key is never sent. + +The contrast test confirms the non-pinned path _does_ propagate the password, +isolating the defect to `pin.pin()`. + +Recommendation: keep-open. Two-line fix sketch: + +- Add `password_env_name: Optional[str] = None` to `GitHubDependencyPin`. +- In `pin.pin()`, after `d.ref, d.package_dependency = ...`, mirror the + block from resolvers.py L644-654 to copy + `d.password_env_name` (or the pin's own) onto `d.package_dependency`. + +Repro: `/tmp/repro/11/tests/test_3619_pin_password.py` (4 tests; all pass). + +--- + + + +### #3649: Support serial loads with update_data task + +**Verdict:** `REPRODUCED-on-v4.10.0` — feature still unimplemented + +`UpdateData.load_data` and the rollback path in `cumulusci/tasks/bulkdata/update_data.py:184` and `:211` both call `get_dml_operation(..., api_options={}, ...)` with the `api_options` dict hardcoded empty. `BulkApiDmlOperation` in `step.py` honors `api_options["bulk_mode"]` for Serial/Parallel selection, but `UpdateData` never sets it. `LoadData` and the snowfakery channel runner DO let users pick `bulk_mode`; `update_data` is the gap. + +The author offered to implement. Fix is small (~10 lines): add `bulk_mode` (or `api_options`) to `UpdateData.task_options` and pipe it into both `get_dml_operation` calls. + +**Recommended pass1: `keep-open`** with `good-first-issue` label. + + + +### #3663: When clause | Ability to pass in prior task response values + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature +**Method**: code-scan + +**Evidence**: + +- `cumulusci/core/flowrunner.py:510-516` — the `when` Jinja context is hardcoded to `{"project_config": ..., "org_config": ...}`. Prior step results (`self.results`) are not exposed. +- The `^^task.return_value` resolver lives elsewhere (option resolution path) and is not threaded into the `when` evaluator. + +**Recommended action**: + +- pass1: `keep-open` — natural extension of `when`; complements #3506. +- pass2 labels: `enhancement, area:flows` + + + +### #3692: No parser configuration found for subdirectory digitalExperiences + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug + +**Method**: +Greped `digitalExperiences|digitalExperience` across the codebase — zero +hits. Wrote two tests: a static one asserting `digitalExperiences` is a key +in `metadata_map.yml`, and a runtime one that creates the folder structure +and runs `PackageXmlGenerator`. + +**Evidence**: + +- `cumulusci/tasks/metadata/metadata_map.yml` has no `digitalExperiences` + key. +- `cumulusci/tasks/metadata/package.py:115-118` raises + `MetadataParserMissingError("No parser configuration found for +subdirectory %s")`. +- Test output: `test_issue_3692_digital_experiences_in_metadata_map` fails + on the missing key; runtime test reproduces the exact error message from + the user report. + +**Recommended action**: + +- pass1: keep-open — add `digitalExperiences` (and likely + `digitalExperienceConfigs`) entries to `metadata_map.yml` with + appropriate parser classes (probably a bundle parser). +- pass2 labels: `severity:medium,area:metadata-etl,type:bug` + +--- + + + +### #3699: Sort of the data during extraction + +**Verdict:** `REPRODUCED-on-v4.10.0` — feature missing, but workaround exists + +`ExtractData._soql_for_mapping` (extract.py:133-147) builds the SOQL with `WHERE` only — no `ORDER BY`. `MappingStep` has no `order_by`/`sort` field. However, `append_filter_clause` strips a leading `WHERE` from `soql_filter` and concatenates the remainder onto the query, which means a user can write `soql_filter: "Active__c = true ORDER BY CreatedDate"` and it produces valid SOQL. So the missing capability is "first-class `order_by` field for parity with `where`", not "ability to sort at all". + +The author hasn't followed up since 2023-11; with a working workaround, this is low-priority. + +**Recommended pass1: `closed:stale-24mo`.** Reopen later if a v5 effort wants explicit `order_by` for declaration ergonomics. + + + +### #3700: Trying to do an upsert on a master-detail child object gets an error around permission + +**Verdict:** `REPRODUCED-on-v4.10.0` — bug + +`MappingStep._get_required_permission_types(operation)` in `mapping_parser.py:373-377` returns `("updateable", "createable")` for any operation in `(UPSERT, ETL_UPSERT)` (or any mapping action of the same). Master-detail lookup fields in Salesforce are `createable: True` but `updateable: False` (you cannot reparent a master-detail child after creation). `_check_field_permission` therefore returns `False` for the MD lookup field on an upsert mapping, and `_validate_field_dict` errors out with the exact message the user reported: "Field xxx\_\_c does not have the correct permissions ('updateable', 'createable') for this operation." + +Repro test (`/tmp/repro/10/tests/test_3700_master_detail_upsert_perm.py`) constructs an `UPSERT` mapping for an `Order__c` with an `Account__c` master-detail lookup, simulates a `{createable: True, updateable: False}` describe, and asserts that `_check_field_permission` returns `False` — assertion passes. + +**Recommended pass1: `keep-open`** with `good-first-issue`. Fix: when validating an MD lookup field for an upsert, accept `createable` alone (the lookup never gets updated post-insert anyway). A field-shape detector can use `relationshipName` + `cascadeDelete: True` from describe. + + + +### #3701: set a mapping to the id instead of it being either a number or the salesforce id + +**Verdict:** `REPRODUCED-on-v4.10.0` — feature gap + +`MappingStep` and the extract/load pipeline special-case the literal field name `"Id"` in many places (`mapping_parser.py:171/190/228/241/422`); it always represents the Salesforce Id and lands in an `sf_id` column. There is no mechanism to make a different field (an external-id like `BCM_Unique_Id__c`) act as the row's primary key in the extracted SQLite. The user's example yaml `Id : BCM_Unique_Id__c` is currently interpreted as "extract the SF Id into the column named `BCM_Unique_Id__c`", not "make `BCM_Unique_Id__c` the row primary key". + +This is closely tied to #3699 (motivated by sortable git diffs of dataset extracts). The deeper PK-replacement feature would touch many places in extract / load / lookup-resolution. + +**Recommended pass1: `closed:stale-24mo`.** Reporter hasn't followed up since 2023-11. Workarounds are available (extract Id into a known column and post-process). Could revisit if a v5 effort tackles dataset diff-ability holistically. + + + +### #3717: Github automerge feature task not working when running through Github Flow + +**Verdict**: INCONCLUSIVE-needs-cumulus-actions-workflow +**Repro type**: bug +**Method**: Bucket A — code-scan of `cumulusci/core/config/project_config.py` `repo_info` / `repo_branch` and repo-wide grep for GitHub Actions env-var auto-detection. + +**Evidence**: + +The reporter notes that `project_config.repo_branch` and `project_config.project__git__prefix_feature` are `None` when `ci_feature` / `github_automerge_feature` is triggered by a merge event in a GitHub Actions workflow, but populated when triggered manually via the Actions tab. + +`cumulusci/core/config/project_config.py` shows that cci's only CI auto-detection is for Heroku: + +```220:255:cumulusci/core/config/project_config.py + def repo_info(self) -> Dict[str, Any]: + if self._repo_info is not None: + return self._repo_info + + # Detect if we are running in a CI environment and get repo info + # from env vars for the environment instead of .git files + info = {"ci": None} + + # Make sure that the CUMULUSCI_AUTO_DETECT environment variable is + # set before trying to auto-detect anything from the environment + if not os.environ.get("CUMULUSCI_AUTO_DETECT"): + self._repo_info = info + return self._repo_info + + # Heroku CI + heroku_ci = os.environ.get("HEROKU_TEST_RUN_ID") + if heroku_ci: + info = { + "branch": os.environ.get("HEROKU_TEST_RUN_BRANCH"), + "commit": os.environ.get("HEROKU_TEST_RUN_COMMIT_VERSION"), + "ci": "heroku", + "root": "/app", + } + + # Other CI environment implementations can be implemented here... + + self._apply_repo_env_var_overrides(info) +``` + +A repo-wide grep (`Grep` over `cumulusci/`) for `GITHUB_REF|GITHUB_HEAD_REF|GITHUB_SHA|GITHUB_ACTIONS` returns **zero matches** — there is no GitHub Actions environment auto-detection in cci. The fallback path in `repo_branch` (line 394-402) calls `current_branch(self.repo_root)` which reads `.git/HEAD`. On a `push`-triggered GHA workflow the standard `actions/checkout@v4` checkout puts the working copy in a detached HEAD state, so `current_branch` returns `None`. On `workflow_dispatch` triggered manually, the action receives a `ref` input that resolves to a named branch checkout, so `current_branch` works. + +Net: the reporter's symptom is exactly what cci produces unless the workflow sets `CUMULUSCI_REPO_BRANCH` (and friends) explicitly before invoking `cci flow run`. That responsibility lives in the `cumulus-actions/standard-workflows` YAMLs, not in cci. This matches the precedent established in #3418 (also `INCONCLUSIVE-needs-cumulus-actions-workflow`). + +**Recommended action**: + +- pass1: `unchanged` — issue is at the cci ↔ cumulus-actions boundary; needs investigation in `cumulus-actions/standard-workflows` to confirm/fix `CUMULUSCI_REPO_BRANCH` plumbing for `push`-triggered child-feature merges. +- pass2 labels: `external-config, cumulus-actions, needs-info` + +> Optional follow-up enhancement (not part of triage): add a `# GitHub Actions` block in `repo_info` parallel to the Heroku block, reading `GITHUB_HEAD_REF` (PR) / `GITHUB_REF_NAME` (push) and `GITHUB_SHA`. Would close a class of "branch=None in CI" reports including this one, but is a behavior-change to a long-stable contract and merits its own design discussion. + + + +### #3721: `create_package_version` `version_name` default should be version number, not "Release" + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature + +**Method**: +Searched for `version_name` defaults in `create_package_version.py` and `package_upload.py`, and for any jinja2 templating in PackageUpload. Verified the muselab-d2x commit that implements the requested behavior is not an ancestor of HEAD. + +**Evidence**: + +- `cumulusci/tasks/create_package_version.py:184` — `version_name=self.options.get("version_name") or "Release"`. Default is still the literal string `"Release"`. +- `cumulusci/cumulusci.yml:684-686` — `upload_production` hard-codes `name: Release`. +- `cumulusci/tasks/salesforce/package_upload.py:147-154` — passes `VersionName` straight through; no jinja2/template support. +- `git merge-base --is-ancestor 7aaf348f3 HEAD` returns non-zero. Commit `7aaf348f3` ("Change version naming on PackageUpload task to use the predicted version number and a jinja2 template expression") lives only on the `d2x/*` remotes (muselab-d2x fork), per jlantz's 2024 comment. + +**Recommended action**: + +- pass1: `keep-open` — needs upstream port + design (templating? plain version number? both 1GP and 2GP?). +- pass2 labels: `severity:low,area:packaging,area:1gp,area:2gp` + +--- + + + +### #3734: upload_production fails with FIELD_INTEGRITY_EXCEPTION when latest is Beta patch + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug +**Org used**: none (would require a 1GP packaging org with both 6.13 Released and 6.13.1 Beta — too large to fabricate) + +**Method**: +Read `cumulusci/tasks/salesforce/package_upload.py` `PackageUpload._validate_versions`. The "latest version" SOQL query orders `MajorVersion DESC, MinorVersion DESC, PatchVersion DESC, ReleaseState DESC LIMIT 1`. When the user has the pattern they describe (release 6.13, then create patch 6.13.1 Beta as a safety net), the query returns the patch row with `ReleaseState='Beta'`. + +Then at line 134-135: + +```python +if version["ReleaseState"] == "Beta": + self.options["minor_version"] = str(version["MinorVersion"]) +``` + +This sets `minor_version=13`, identical to the already-Released minor. The PackageUploadRequest is then created with major=6, minor=13, which Salesforce rejects with `FIELD_INTEGRITY_EXCEPTION: The version number must be greater than the last Managed - Released version number: 6.13`. Exactly the error in the issue. + +The user's own analysis in their last 3 comments is correct and matches the code. The current `cannot-reproduce`/`awaiting-more-details` labels are stale. + +Confirmed via mocked unit test `/tmp/repro/3/tests/repro_3734_upload_production_beta_patch.py`: + +- With `{Major=6, Minor=13, Patch=1, ReleaseState=Beta}` → `_validate_versions` sets `minor_version='13'` (the bug). +- With `{Major=6, Minor=13, Patch=None, ReleaseState=Released}` → `_validate_versions` sets `minor_version='14'` (the desired behavior). + +git log shows `87b94440e Deploy Major and Minor Version option in upload_production task (#3651)` (2023-09-19) added the major/minor options but did not change the latest-version query or the Beta-branch logic. v4.10.0 still has this code as-is. + +**Evidence**: + +- `cumulusci/tasks/salesforce/package_upload.py:80-98` — SOQL query, `ORDER BY MajorVersion DESC, MinorVersion DESC, PatchVersion DESC, ReleaseState DESC LIMIT 1`. +- `cumulusci/tasks/salesforce/package_upload.py:134-137` — Beta branch sets `minor_version` to the same minor. +- Test passes on v4.10.0 with mocked `_get_one_record`. + +**Recommended action**: + +- pass1: `keep-open` — confirmed real bug; remove the stale `cannot-reproduce`/`awaiting-more-details` labels. +- pass2 labels: `bug` + +--- + +## Summary cross-cutting findings + +1. **Two feature requests (#3587, #3600)** are easy "good-first-issue" candidates whose semantics are clear from the issue body. Both are independently verifiable with no org needed (`update_package_xml` is local; env-var support is a parser-level concern). +2. **Two real bugs (#3446, #3734)** still reproduce on v4.10.0 with stable, well-understood root causes. #3734 is mislabeled `cannot-reproduce` — that label should be removed in pass2. +3. **Two cross-stack issues (#3418, #3542)** point at the boundary between cci and the `cumulus-actions/standard-workflows` repo. They cannot be triaged from cci alone; they need either a workflow-side check or a request to the reporter for the workflow file/SHAs they're using. + + + +### #3745: ci_beta and install_managed_beta do not use the latest beta + +**Verdict:** `NOT-REPRODUCED-on-v4.10.0` (working as designed) + +**Evidence:** [`/tmp/repro/4/evidence/3745-source-and-design.txt`](/tmp/repro/4/evidence/3745-source-and-design.txt) + +The `install_managed_beta` task (cumulusci.yml line 408) sets `version: latest_beta`, which `InstallPackageVersion` (lines 96–100 of `cumulusci/tasks/salesforce/install_package_version.py`) resolves via a GitHub Releases lookup using the `include_beta` resolver strategy — NOT a direct DevHub query for the latest `Package2Version`: + +```96:101:cumulusci/tasks/salesforce/install_package_version.py + if version in ["latest", "latest_beta"]: + strategy = "include_beta" if version == "latest_beta" else "production" + dependency = GitHubDynamicDependency(github=github) + dependency.resolve( + self.project_config, get_resolver_stack(self.project_config, strategy) + ) +``` + +The reporter (kayla-hager, 2024-02-07) ran `create_package_version` standalone — bypassing `release_2gp_beta` — so no GitHub release with the beta tag was ever created, hence `ci_beta` correctly fell back to the latest production tag (1.27). Comments resolve this as a documentation/usability issue; the reporter accepted the explanation 2024-02-13 and indicated they would close. v4.10.0 has not changed this behavior. + +**Recommendation:** keep `closed:stale-24mo` (rule 1). No code defect. + +--- + + + +### #3746: Deleted Versions used for determining next version + +**Verdict:** `REPRODUCED-on-v4.10.0` (code-level confirmation) + +**Evidence:** [`/tmp/repro/4/evidence/3746-source-soql.txt`](/tmp/repro/4/evidence/3746-source-soql.txt) + +The reporter (yippie, 2024-02-09) flagged that `create_package_version._get_base_version_number()` does not filter `IsDeprecated = true` when picking the highest existing `Package2Version` to increment from. The bug is present verbatim in v4.10.0 source at `cumulusci/tasks/create_package_version.py` lines 535–541: + +```529:545:cumulusci/tasks/create_package_version.py + def _get_base_version_number( + self, version_base: Optional[str], package_id: str + ) -> PackageVersionNumber: + """Determine the "base version" of the package (existing version to be incremented)""" + if version_base is None: + # Default: Get the highest existing version of the package + res = self.tooling.query( + "SELECT MajorVersion, MinorVersion, PatchVersion, BuildNumber, IsReleased " + "FROM Package2Version " + f"WHERE Package2Id='{package_id}' " + "ORDER BY MajorVersion DESC, MinorVersion DESC, PatchVersion DESC, BuildNumber DESC " + "LIMIT 1" + ) + if res["size"]: + return PackageVersionNumber( + **res["records"][0], package_type=PackageType.SECOND_GEN + ) +``` + +The same file at line 297 DOES include `IsDeprecated = FALSE` for `Package2` lookups, so the project knows about the column — the omission at line 535 is asymmetric and matches the report exactly. End-to-end repro on a real packaging org would require creating two Package2Version records and deleting one (sf package version delete), which is outside this triage's scope. Code-level confirmation is sufficient. + +**Recommendation:** flip currently-proposed `closed:stale-24mo` → `kept-open` with `severity:medium`, `area:packaging`, `target:v4-patch`. Trivial 1-line fix (add `AND IsDeprecated = false` to the SOQL WHERE clause). + +--- + + + +### #3754: Enable configuration for cci version update sources + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature +**Method**: code-scan + +**Evidence**: + +- `cumulusci/cli/utils.py:65-79` — `get_latest_final_version` hits `https://pypi.org/pypi/cumulusci/json` literally, no env-var, no kwarg. +- `cumulusci/cli/utils.py:82-101` — `check_latest_version` cannot be disabled via flag/env. Workaround in the comments (touch `~/.cumulusci/cumulus_timestamp` to a far-future epoch) confirmed by inspecting the timestamp logic at lines 38-50, 86-89. + +**Recommended action**: + +- pass1: `keep-open` — easy add (e.g. `CUMULUSCI_DISABLE_VERSION_CHECK` env), helps offline/restricted environments. +- pass2 labels: `enhancement, area:cli` + + + +### #3758: Flow `push_upgrade_org` is incorrectly defined + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug + +**Method**: +Read the `push_upgrade_org` flow in `cumulusci/cumulusci.yml`. Wrote `/tmp/repro/1/tests/test_issue_3758.py` to load the YAML and assert the final step calls `config_managed` (not `config_qa`). + +**Evidence**: + +- `cumulusci/cumulusci.yml:1161-1177` — final step is `flow: config_qa`. The bug report (correctly, in my view) argues this should be `config_managed` because push upgrades target managed-package orgs (UAT sandboxes), not QA scratch orgs. +- Repro test FAILS with `config_qa` != `config_managed`. +- Both flows currently expand to the same steps (`deploy_post`, `update_admin_profile`, `load_sample_data`), so behavior is equivalent today, but semantics drift over time and the docs link customers to the wrong flow page. + +**Recommended action**: + +- pass1: `keep-open` — single-line YAML fix; great `good-first-issue` candidate. Out of scope for this triage pass per task constraints (do not fix bugs). +- pass2 labels: `severity:medium,area:packaging,area:flows,good-first-issue` + +--- + + + +### #3762: `update_admin_profile` task fails on namespaced org with Person Accounts enabled + +**Verdict**: closed:duplicate-of-#3544 +**Repro type**: bug +**Org used**: none (dup-confirm only per protocol) + +**Method**: +Read both #3762 and (via gh) #3544. The reporter (noahisapilot) explicitly self-identifies the duplicate in their first comment dated 2024-03-06: _"Apologies, this seems like a duplicate of #3544"_. Both report the same root cause: `update_admin_profile` errors when deploying to a namespaced scratch org with `PersonAccounts` enabled, because the retrieved profile contains record types like `Account.Business_Account` (no namespace) but the task injects the namespace prefix onto recordType references during deploy. + +The reporter's own analysis even pinpoints the offending code at `update_profile.py` line 238 (in v3.84.3; corresponds to `rt["record_type"] = rt["record_type"].format(**self.namespace_prefixes)` at line 236 in v4.10.0). + +#3544 is still OPEN at v4.10.0 with `wi-created` label `W-12589033`. + +**Recommended action**: + +- pass1: `close-as-duplicate` — link to #3544. +- pass2 labels: (n/a — duplicate) + +**Notes**: Per dup-confirm protocol, no live repro performed. + +--- + + + +### #3768: Snowfakery Batch Size and Just Once + +**Verdict:** `REPRODUCED-on-v4.10.0` — bug, structural + +The Snowfakery channel runner architecturally creates a separate working directory per batch via `shutil.copytree(template_path, data_dir)` (`queue_manager.py:322`). Before that copy, `Snowfakery._cleanup_object_tables` (`snowfakery.py:721-730`) drops every non-`sf_ids` table from the template. So when batch 2+ starts, the SQLite database carried in the template only contains `sf_ids` mapping tables — none of the actual `account`-row data created in the initial just_once batch. + +Snowfakery's `random_reference: Account` resolves at generation time against rows in the recipe-local database. Since `just_once: true` means batch 2+ does not regenerate the Accounts, and the carried-over database has no `account` rows (just the `account_sf_ids` map), `random_reference` has nothing to pick from in batch 2+. This matches the user's exact symptom: first 20 contacts (one batch) get the 5 just_once Accounts, the next 430 get nothing (or fall back to NPSP defaults). + +Verifying interactively against an org would require provisioning a scratch and running the recipe at `--batch_size 20 --num_records 450` — code-review evidence is conclusive without it. **Recommended pass1: `keep-open`**, severity major. Fix likely requires preserving rows of just_once-referenced objects (not just `_sf_ids`) in the template DB carried to subsequent batches; coordination with the Snowfakery dev branch is probably required. + + + +### #3771: find_replace transforms on XPath with predicates does not work + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug + +**Method**: +Read `cumulusci/core/source_transforms/transforms.py:415-485`. The +`transform_xpath` helper splits the XPath on `/`, wraps each tag in +`*[local-name()=...]`, and re-appends the predicate verbatim. The bug: tag +references INSIDE the predicate (e.g. `price` in `[price>40]`) are still +namespace-bound, so on default-`xmlns` documents they don't match. PR #3772 +(referenced in `closedByPullRequestsReferences`) lives only on the `leboff` +fork and was never merged into `main`. + +**Evidence**: + +- `cumulusci/core/source_transforms/transforms.py:420-435` — naive + predicate handling. +- `git log --all --oneline --grep="3772\|3771\|XPath.*predicate"` shows + only `2bf6ce6a3 Improve namespace handling in find_replace` on + `remotes/leboff/feature/improve-find-replace-ns-handling`; not on + origin/main. +- Test output: `test_issue_3771_xpath_predicate_with_xmlns_resolves` + observed 0 matches (or 5 wrong matches) for the user-supplied xpath on + namespaced XML. + +**Recommended action**: + +- pass1: keep-open — the leboff PR is a viable starting point; or implement + the reporter's "strip xmlns then re-add" approach for simplicity. +- pass2 labels: `severity:medium,area:source-transforms,type:bug,has-pr` + +--- + + + +### #3773: retrieve_profile task seems to be missing some Metadata + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug + +**Method**: +Read `cumulusci/salesforce_api/retrieve_profile_api.py` end to end. The +`_queries_retrieve_permissions` method (lines 164-195) builds queries for +`SetupEntityAccess`, `ObjectPermissions`, `PermissionSetTabSetting`, and a +flow-specific `SetupEntityAccess`. There is no `FieldPermissions` query. +Wrote a test that asserts `fieldpermissions` appears in the joined query +text. + +**Evidence**: + +- `cumulusci/salesforce_api/retrieve_profile_api.py:164-195` — no + `FieldPermissions` query. +- Greped `FieldPermission|field_permission|fieldPermission` — only the + `update_profile.py`, `permissions.py`, and `mapping_parser.py` files + reference field permissions; `retrieve_profile_api.py` does not. +- Test output: `test_issue_3773_retrieve_profile_queries_field_permissions` + shows the four queries built by the function and confirms none include + `FieldPermissions`. + +**Caveat**: This is a code-level repro. Final end-to-end confirmation +(profile XML actually missing AccountContactRelation field perms) would +require a real org with a profile that has only field-level (not +object-level) permissions on AccountContactRelation. Code evidence is +conclusive, however, because objects with no `ObjectPermissions` row never +make it into the package.xml requested for retrieve. + +**Recommended action**: + +- pass1: keep-open — needs additional `FieldPermissions` query plus + inclusion of those parent SObjectTypes in the `CustomObject` retrieve set. +- pass2 labels: `severity:medium,area:retrieve-profile,type:bug` + +--- + + + +### #3852: CumulusCI 4 refresh token error (sarge Capture.flush) + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug +**Method**: code-scan + runtime probe + +**Evidence**: + +- `pyproject.toml:52` — `"sarge"` pinned with no version constraint. +- `uv run python -c "import sarge; print(sarge.__version__)"` → `0.1.7.post1`. +- `uv run python -c "import sarge; print(hasattr(sarge.Capture, 'flush'))"` → `False`. The upstream fix (`def flush(self): pass`) sits unreleased on master. +- `cumulusci/core/config/sfdx_org_config.py:200-214` — `refresh_oauth_token` still calls `self.sfdx_info` at line 212. Per the maintainer comment in-thread, on Python 3.13 this triggers the `AttributeError: 'Capture' object has no attribute 'flush'` during interpreter shutdown logging path — cosmetic only, no functional regression. + +**Recommended action**: + +- pass1: `keep-open` — kept-open per maintainer label; track until sarge 0.1.8 ships or we vendor/swap the dependency. +- pass2 labels: `bug, upstream:sarge, py313` + + + +### #3854: Issue while Capturing Data (capture_sample_data lookup_key validation) + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug +**Method**: code-scan + +**Evidence**: + +- `cumulusci/tasks/bulkdata/extract.py:367-374` — the offending validation block is intact: + - `if total_mapping_operations != total_rows: raise ConfigError(f"Total mapping operations ({total_mapping_operations}) do not match total non-empty rows ({total_rows}) for lookup_key: {lookup_key}. Mention all related tables for lookup: {lookup_key}")` +- Error text matches the user's report verbatim. +- Per swirkens' comment, this validation was introduced in PR #3741 / commit `2c5d0056e` and remains unchanged in v4.10.0. +- Workaround in thread: pin to CCI 3.84.1 (pre-validation). + +**Recommended action**: + +- pass1: `keep-open` — kept-open per maintainer label; real bug for polymorphic-lookup users. +- pass2 labels: `bug, area:bulkdata, regression` + + + +### #3884: Running a Dev_Org flow goes through re-install of the same package version again + +**Verdict:** `INCONCLUSIVE-needs-project-with-managed-deps` + +**Evidence:** [`/tmp/repro/4/evidence/3884-source-skip-logic.txt`](/tmp/repro/4/evidence/3884-source-skip-logic.txt) + +The reporter (dipakparmar, 2025-02-26) describes that re-running `dev_org` reinstalls dependencies that are already installed. CumulusCI itself has no `project__dependencies` block, so end-to-end repro on this very repo is not possible. Source review against v4.10.0 shows that BOTH managed-package install paths in `cumulusci/core/dependencies/dependencies.py` already have a "skip if already at this or newer version" guard: + +```458:465:cumulusci/core/dependencies/dependencies.py + if org.has_minimum_package_version( + self.namespace, + version, + ): + context.logger.info( + f"{self} or a newer version is already installed; skipping." + ) + return +``` + +```513:520:cumulusci/core/dependencies/dependencies.py + if any( + self.version_id == v.id + for v in itertools.chain(*org.installed_packages.values()) + ): + context.logger.info( + f"{self} or a newer version is already installed; skipping." + ) + return +``` + +Likely the reporter conflated "Resolving dependencies..." log noise (which always prints) and the unconditional `deploy_unmanaged` / `config_dev` steps in the dev_org flow with managed-package reinstalls. Without a customer project that has managed deps to reproduce against, we cannot disprove a corner case (e.g., `installed_packages` cache invalidation across a particular path). + +**Recommendation:** keep the proposed `closed:missing-fields` (rule 3) verdict. The original report lacks the customer's `cumulusci.yml` excerpt that would let us see which dependency type they were observing reinstall. + +--- + + + +### #3886: Required Dependencies? + +**Bucket**: A. **Type**: bug (UX/log-noise). **Verdict**: +REPRODUCED-on-v4.10.0. + +The `[select]` extras (`numpy`, `pandas`, `annoy`, `scikit-learn`) are not in +the default install. `cumulusci/tasks/bulkdata/select_utils.py` L14-30 emits +`logger.warning("Optional dependencies are missing...")` at module-import time +in the `try/except ImportError`. Two transitive imports +(`mapping_parser` and `step`) pull in `select_utils`, and `extract.py` imports +both, so **every** `extract_dataset` invocation triggers the warning even when +no select strategy is configured. + +Behavior introduced in PR #3858 / commit `89a5b5ddb` (W-17427085) and +unchanged through v4.10.0. The reporter's quoted text mentioned +`pipx upgrade cumulusci[select]`; v4.10.0 now uses `get_cci_upgrade_command()` +which adapts to the install method (e.g. `pip install --upgrade cumulusci[select]`), +so that part of the message has been polished — but the noise persists. + +Recommendation: keep-open. Mitigations to consider: + +- Move the warning emission out of module-import and into the code path that + actually consumes optional deps (e.g. inside the relevant similarity + strategy or `Annoy`-using step), so it only fires when the user opts into + `select` strategies. +- Or downgrade to `logger.debug` and add a one-line + `logger.warning` only at the point of need. + +Repro: `/tmp/repro/11/tests/test_3886_select_warning.py` (2 tests; all pass). + +This issue was double-tagged in `themes.md` (bulkdata + dependencies); +classified under dependencies here per bundle instructions. + + + +### #3889: Uninstall 2GP task request + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: feature + +**Method**: +Listed all `Uninstall*` task definitions in `cumulusci.yml` and inspected `UninstallPackage.py` and `UninstallPackageZipBuilder` to see whether any task accepts a 04t SubscriberPackageVersionId. + +**Evidence**: + +- `cumulusci/cumulusci.yml:615-642` — Uninstall tasks: `uninstall_managed`, `uninstall_packaged`, `uninstall_packaged_incremental`, `uninstall_src`, `uninstall_pre`, `uninstall_post`. None take a 04t id. +- `cumulusci/tasks/salesforce/UninstallPackage.py:6-32` — `UninstallPackage` accepts only `namespace` (and `purge_on_delete`). Builds an `UninstallPackageZipBuilder` from the namespace. +- `cumulusci/salesforce_api/package_zip.py:290-301` — `UninstallPackageZipBuilder` writes destructiveChanges referencing `InstalledPackage` by namespace; no 04t code path. +- Tooling API `SubscriberPackageVersion` delete or sf cli `package uninstall -p 04t...` is the underlying API the user wants; not wrapped by any CCI task. + +**Recommended action**: + +- pass1: `keep-open` — needs a new `UninstallPackageVersion` task (or extend `UninstallPackage`) that calls Tooling API directly so it doesn't depend on sf cli stability (per the user's note about sf cli breaking changes). +- pass2 labels: `severity:medium,area:packaging,area:2gp,area:unlocked-package` + + + +### #3899: Exception in task deploy_packaging.unschedule_apex + +**Verdict:** `INCONCLUSIVE-needs-1gp-packaging-org` + +**Evidence:** [`/tmp/repro/4/evidence/3899-task-and-error-analysis.txt`](/tmp/repro/4/evidence/3899-task-and-error-analysis.txt) + +The `unschedule_apex` task (cumulusci/cumulusci.yml lines 646–651) runs one line of trivial Apex via the Tooling API: + +```650:650:cumulusci/cumulusci.yml + apex: "for (CronTrigger t : [SELECT Id FROM CronTrigger]) { System.abortJob(t.Id); }" +``` + +Ran cleanly against scratch org `repro-pkg-b2-dev` ("Anonymous Apex Executed Successfully!"). The reporter's error references Salesforce platform-internal Java classes (`system.scheduler.cron.JobType`, `common.udd.constants.CronJobTypeEnum`) — this is a Salesforce platform NullPointerException inside the scheduler subsystem when looking up a CronTrigger's job-type implementation. CCI sends correct Apex; the platform fails to execute it on certain 1GP packaging org configurations. Provisioning a 1GP packaging org via OAuth connected app is outside the scope of this triage. + +**Recommendation:** keep `kept-open`. Add a Pass-2 `external/upstream-salesforce` label (or equivalent) so future triage knows the root cause is upstream. Could also be a candidate for "close as not-our-bug" once a Salesforce known-issue reference is found. + +--- + + + +### #3902: `install_managed` `security_type` not respected with 04t ID + +**Verdict:** `INCONCLUSIVE-needs-managed-package-04t` + +### Original symptom + +User reports that running `install_managed` with `--version '04t…'` and `--security_type NONE` yields a tab visible to non-admin profiles, whereas the same install with `--version '1.11.2'` (namespace+version) honors `NONE`. + +### Code-only evidence on v4.10.0 + +`InstallPackageVersion._init_options` (cumulusci/tasks/salesforce/install_package_version.py) builds `PackageInstallOptions` from task options including `security_type`: + +```148:148:cumulusci/tasks/salesforce/install_package_version.py + self.install_options = PackageInstallOptions.from_task_options(self.options) +``` + +`PackageInstallOptions.from_task_options` (cumulusci/salesforce_api/package_install.py:67–92) parses `security_type` into the `SecurityType` enum where `SecurityType.ADMIN = "NONE"`. + +For 04t versions, `_run_task` routes to `PackageVersionIdDependency.install(...)` which calls `install_package_by_version_id(...)` -> `_install_package_by_version_id(...)`. The latter posts the option to the Tooling API: + +```165:175:cumulusci/salesforce_api/package_install.py + request = PackageInstallRequest.create( + { + "EnableRss": options.activate_remote_site_settings, + "NameConflictResolution": options.name_conflict_resolution, + "Password": options.password, + "SecurityType": options.security_type, + ... + } + ) +``` + +Runtime serialization confirmed in the venv: + +```text +$ uv run python -c "import json; from cumulusci.salesforce_api.package_install import SecurityType; print(json.dumps({'SecurityType': SecurityType.ADMIN}))" +{"SecurityType": "NONE"} +``` + +`SecurityType` is a `StrEnum` (cumulusci/core/enums.py) with `__str__ = str.__str__`, so JSON serializes via the string base — `SecurityType.ADMIN` -> `"NONE"`. This was hardened previously in commit `502290b8d` (Dec 2022) for Python 3.11 enum changes and again in `402b890e0` (StrEnum migration). + +The 04t and namespace+version paths each correctly pass `security_type` to their respective Salesforce APIs (Tooling API `PackageInstallRequest.SecurityType` for 04t, package install zip header for namespace+version). No defect identified in CumulusCI v4.10.0. + +### Why INCONCLUSIVE + +We do not have a known reusable managed package 04t Id installable into a CCIDevHub-derived scratch to verify the user's runtime observation. Per spec, this verdict is allowed when the prerequisite cannot be provisioned within budget. + +### Possible non-CumulusCI explanations (worth recording for the issue) + +- Salesforce Tooling API treatment of `SecurityType=NONE` may differ between fresh installs and upgrades: existing components retain their previously assigned profile permissions on upgrade. If the package was previously installed at a lower version with `SecurityType=FULL`, upgrading with `NONE` may not retroactively restrict access to existing tabs. +- Tab visibility for managed-package tabs can be controlled by App-level visibility (Profile `applicationVisibilities` / `tabVisibilities`) independent of object-level CRUD/FLS, which is what `SecurityType` governs. +- Package metadata may include `Profile` deltas that explicitly grant tab access regardless of the install-time SecurityType. + +### Recommendation + +- **Pass 1:** needs-info — request reporter to (a) confirm whether the package was being upgraded vs freshly installed, and (b) inspect Salesforce setup audit trail to see the actual `PackageInstallRequest.SecurityType` value at install time. +- **Pass 2 label:** `needs-managed-package-fixture` — without an internal reusable managed package 04t fixture, this class of issue can never be deterministically validated by maintainers. + +--- + + + +### #3929: create_community Loop/Timeout During Community Creation + +**Verdict:** `NOT-REPRODUCED-on-v4.10.0` + +**Evidence:** [`/tmp/repro/4/evidence/3929-create_community.log`](/tmp/repro/4/evidence/3929-create_community.log) + +Ran the exact reproduction command against scratch org `repro-pkg-b2-dev`: + +```bash +uv run cci task run create_community --org repro-pkg-b2-dev \ + -o name "TestWebsite" -o template "Customer Service" -o url_path_prefix "testwebsite" +``` + +Community `0DBRK000000QtNR4A0` was created in ~117 seconds with normal polling escalation (1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 seconds) and exited the poll loop cleanly. No 300-second timeout, no retry. This matches the OP-thread comment from dipakparmar (2025-10-22): "This issue is no longer happening" — referring to the upstream SF CLI / Communities API fix tracked at forcedotcom/cli#3419. + +**Recommendation:** flip currently-proposed `kept-open` → `closed:not-reproducible-on-v4.10.0` (NEW Pass-1 vocabulary per spec amendment). Confirmed working end-to-end with the very command the reporter said hung. + + + +### #3931: Specifying a profile in cumulusci.tasks.salesforce.ProfileGrantAllAccess results in an error + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug +**Org used**: none (Python unit repro is sufficient — code path is purely local XML transform) + +**Method**: +Read `cumulusci/tasks/salesforce/update_profile.py`. Spotted the suspect line: + +```290:292:cumulusci/tasks/salesforce/update_profile.py + for elem in tree.findall("layoutAssignments"): + if elem.find("recordType").text == rt["record_type"]: + elem.layout.text = layout_option +``` + +`elem.find("recordType")` returns `None` whenever a `layoutAssignments` element has no `recordType` child (which is valid metadata — a layoutAssignments without recordType applies to records lacking a record-type binding). The subsequent `.text` then raises `AttributeError: 'NoneType' object has no attribute 'text'` — exactly the user's reported error. + +Wrote `/tmp/repro/5/tests/issue-3931/repro_unit.py` that builds an in-memory profile XML matching that shape (one `` with `Account-Account Layout` and no recordType, plus one with both children) and calls `_set_record_types`. Output: + +``` +Traceback (most recent call last): + File "/tmp/repro/5/tests/issue-3931/repro_unit.py", line 64, in main + task._set_record_types(tree, "Admin") + File "...update_profile.py", line 291, in _set_record_types + if elem.find("recordType").text == rt["record_type"]: + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +AttributeError: 'NoneType' object has no attribute 'text' +REPRODUCED: AttributeError raised: 'NoneType' object has no attribute 'text' +``` + +**Recommended action**: + +- pass1: `keep-open` — small, contained fix. +- pass2 labels: `bug` + +**Notes**: Minimal fix at update_profile.py:290-293 — bind `rt_elem = elem.find("recordType")` and check `if rt_elem is not None and rt_elem.text == rt["record_type"]`. Worth a quick scan of sibling code in `_set_record_types` for similar None-deref patterns on optional XML children. + +--- + + + +### #3936: HTTPSConnectionPool Read timed out (kept-open) + +**Verdict:** `INCONCLUSIVE-needs-flaky-network` — but a structural gap is confirmed + +`get_simple_salesforce_connection` in `cumulusci/salesforce_api/utils.py:13-51` constructs `simple_salesforce.Salesforce(...)` with no timeout kwarg and only retries `502/503/504` via `Retry(total=5, backoff_factor=0.3)`. No CCI-side task option, project setting, or env var exposes connect / read timeout for Salesforce REST or Bulk API calls. `cumulusci.yml` has no `timeout` entry. + +The reported error `Read timed out. (read timeout=None)` with `timeout=None` typically means the proxy / VPN closed the socket while the client was waiting, not that a client-side timeout was hit. CCI cannot mitigate this without (a) exposing a configurable timeout to short-circuit zombie connections, and (b) extending the `Retry` to also cover read-timeout errors and bulk-job-polling failures. + +The structural gap (no exposed timeout) is REPRODUCED. The actual flaky behavior is environment-dependent (corporate VPN) and not reproducible in CI without that environment. + +This issue is already maintainer-labelled `kept-open`. **Recommended pass1: `unchanged`**. v5 candidacy: yes — add timeout option to `get_simple_salesforce_connection` and to bulk-job polling, plus a documented `cci org refresh` retry path for VPN-induced disconnects. + + + +### #3938: Rest_Deploy ignores errors + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug + +**Method**: +Read `cumulusci/salesforce_api/rest_deploy.py`. Wrote a test that constructs +a `RestDeploy` instance with mocked task/org_config and patches +`requests.get` to return a JSON payload with `deployResult.status == "Failed"` +and a `componentFailures` list. + +**Evidence**: + +- `cumulusci/salesforce_api/rest_deploy.py:101-120` — + `_monitor_deploy_status` logs `componentFailures` then `return`s without + raising. +- `cumulusci/salesforce_api/rest_deploy.py:75-85` — `__call__` only logs + when initial POST is non-201; never raises. +- Test output: `test_issue_3938_rest_deploy_failure_does_not_raise` exits + the patched call with no exception, confirming the silent-success bug. + +**Recommended action**: + +- pass1: keep-open — CRITICAL severity; should raise `MetadataApiError` / + `MetadataComponentFailure` on Failed status, mirroring the SOAP + `ApiDeploy` behavior. +- pass2 labels: `severity:critical,area:rest-deploy,type:bug,silent-failure` + +--- + + + +### #3939: Deploy task can't parse SOAP Response + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug + +**Method**: +Read `cumulusci/salesforce_api/metadata.py:67-78` (`BaseMetadataApiCall.__call__`) +and `cumulusci/salesforce_api/metadata.py:425-546` +(`ApiDeploy._process_response`). The parser correctly raises +`ApexTestException` on Apex test failures (line 540) and +`MetadataApiError`/`MetadataComponentFailure` for other failure shapes +(lines 509, 520, 544). But every one of those exceptions is caught by the +generic `except Exception as e:` at line 73 and re-raised as +`MetadataParseError("Could not process MDAPI response: ...")`. The wrapping +matches the exact message text in the user report. + +**Evidence**: + +- `cumulusci/salesforce_api/metadata.py:71-76` — wraps every exception + thrown inside `_process_response`. +- `cumulusci/salesforce_api/metadata.py:509,520,540,544` — places where + intentional MDAPI exceptions are raised inside `_process_response`. +- Test output: `test_issue_3939_deploy_apex_test_failure_swallowed` + observed final message + `Could not process MDAPI response: Apex Test Failure: Class.MyTestClass.testIt: line 12, column 1` + which is the exact bug pattern. + +**Recommended action**: + +- pass1: keep-open — the wrapping `except Exception` should re-raise CCI's + own `CumulusCIException` subclasses (`MetadataApiError`, + `MetadataComponentFailure`, `ApexTestException`) untouched and only wrap + truly unexpected errors. +- pass2 labels: `severity:high,area:salesforce-api,type:bug,error-handling` + + + +### #3951: set_duplicate_rule_status broken + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug (UX/error-message) +**Org used**: `repro-etl-b-dev` + +**Method**: +Live repro using the exact CLI from the bug report: + +``` +uv run cci task run set_duplicate_rule_status --org repro-etl-b-dev \ + -o api_names "Standard_Rule_for_Leads_with_Duplicate_Contacts" \ + -o active False +``` + +Result (saved at `/tmp/repro/5/tests/issue-3951/output-no-prefix.txt`): + +``` +Error: Cannot find metadata file /var/.../retrieve/duplicateRules/Standard_Rule_for_Leads_with_Duplicate_Contacts.duplicateRule +``` + +Identical error wording as the user's report. Then ran the same command with the canonical Metadata API format `Lead.Standard_Rule_for_Leads_with_Duplicate_Contacts` — the task succeeded end-to-end (extract → transform → deploy → Success). The `SetDuplicateRuleStatus` task itself is functional; the bug is the unhelpful error when the user omits the `.` prefix that DuplicateRule API names require. + +Same root cause as #3613 (api_name format mismatch surfaces as the generic `Cannot find metadata file` from `MetadataSingleEntityTransformTask._transform` base.py:332). + +**Recommended action**: + +- pass1: `improve-error-message` — keep open. +- pass2 labels: `bug`, `good-first-issue`, `documentation` + +**Notes**: Two improvements: + +1. Update the `set_duplicate_rule_status` task option help to call out the `.` format requirement. +2. Same as #3613 — improve the base.py:332 error to list the files actually retrieved. + +The `Cannot find metadata file` error is shared across most `MetadataSingleEntityTransformTask` subclasses, so a single base-class fix would benefit several issues at once. + +--- + + + +### #3953: add_picklist_entries never works through CLI + +**Verdict**: REPRODUCED-on-v4.10.0 +**Repro type**: bug +**Org used**: `repro-etl-b-dev` + +**Method**: +Live repro using the exact CLI from the bug report: + +``` +uv run cci task run add_picklist_entries --org repro-etl-b-dev \ + -o picklists "Account.Status__c" \ + -o entries '[{"fullName": "TestValue", "label": "Test Value"}]' +``` + +Result (saved at `/tmp/repro/5/tests/issue-3953/output.txt`): + +``` +Error: The 'fullName' key is required on all picklist values. +``` + +Identical to user's report. + +Root cause confirmed by reading `cumulusci/tasks/metadata_etl/picklists.py`: + +- Line 51: `process_list_arg(self.options["picklists"])` — runs through the list-arg parser. +- Line 68: `if not all(["fullName" in entry for entry in self.options["entries"]])` — iterates `entries` directly without parsing. +- The CLI passes `entries` through as a JSON string. Iteration walks characters of `'[{"fullName": "TestValue", ...}]'`; none of the characters contain the substring `"fullName"`; `all(...)` returns False; error raised. + +**Recommended action**: + +- pass1: `keep-open` — single-line fix. +- pass2 labels: `bug`, `good-first-issue` + +**Notes**: Minimal fix in `AddPicklistEntries._init_options`: `if isinstance(self.options.get("entries"), str): self.options["entries"] = json.loads(self.options["entries"])`. Apply same pattern to `record_types` for symmetry. The same class of bug exists in `AddFieldsToPageLayout` (encountered while investigating #3613): `cci task run add_page_layout_fields ... -o fields '[...]'` -> `pydantic.ValidationError: value is not a valid list`. A more general fix would be a helper in the CLI/task-base that auto-parses JSON strings for list-typed options, or schema-driven coercion via the new task_options Pydantic models. + +--- + +## Round 3 (2026-05-13 → 2026-05-14) + +Themes: robotframework (subagent 13), scratch-org-config (subagent 14), auth (subagent 15), keychain (subagent 16), docs (subagent 17), python-modernization (subagent 18). +Scope: 17 issues across 6 themes, all against `origin/dev` @ `1925a3083` (NOT v4.10.0 like Rounds 1+2). +Verdicts: 12 REPRODUCED-on-dev, 5 NOT-REPRODUCED-on-dev. 10 `xfail` tests staged at `/tmp/repro/{13..18}/tests/`. + + + +# Subagent 13 (rf) — Round 3 robotframework triage + +Worktree: `.worktrees/repro-rf` (`worktree/repro/rf` @ `1925a3083` on `origin/dev`). + +5 issues processed: #3955, #3873, #675, #987, #3602. + +--- + +### #3955: Open Test Browser - SalesforcePlaywright.robot + +**Verdict**: REPRODUCED-on-dev +**Repro type**: bug +**Method**: code-scan + pytest (mocked Browser library) + +**Evidence**: + +- `cumulusci/robotframework/SalesforcePlaywright.py:106` — `width, height = size.split("x", 1)` returns two `str` values. +- `cumulusci/robotframework/SalesforcePlaywright.py:109-111` — the strings are forwarded directly: + + ```python + context_id = self.browser.new_context( + viewport={"width": width, "height": height}, recordVideo=record_video + ) + ``` + +- Playwright contract requires `viewport.width` / `viewport.height` to be `int`, hence the runtime error `viewport.width: expected integer, got string` reported by the user (and confirmed by commenter @rasjani's pointer to lines 106-111). + +**Proposed fix sketch**: + +- Approach: cast both fragments to `int` immediately after splitting. +- Target: `cumulusci/robotframework/SalesforcePlaywright.py:106` +- Size: small (~1 line) — e.g. `width, height = (int(v) for v in size.split("x", 1))` +- Risk: low — preserves all existing call sites; users were already passing the documented `WxH` string format. +- API break: no. + +**Recommended action**: + +- pass1: `keep-open` — clear, low-risk, single-line bug fix; great good-first-issue candidate. +- pass2 labels: `bug, robotframework, playwright, good-first-issue` +- triage test: `cumulusci/tests/triage/test_issue_3955.py` + +--- + +### #3873: Standalone Robot Framework Library for Selenium-Based Salesforce Automation (Inspired by Copado QForce) + +**Verdict**: REPRODUCED-on-dev (feature still missing) +**Repro type**: feature +**Method**: code-scan + +**Evidence**: + +- `cumulusci/robotframework/base_library.py:1-39` — `BaseLibrary` lazily resolves `cumulusci.robotframework.CumulusCI`, `cumulusci.robotframework.Salesforce`, `cumulusci.robotframework.SalesforceAPI` libraries through Robot's `BuiltIn`, which require a CumulusCI project context. +- `cumulusci/robotframework/Salesforce.py:20-28` — imports `cumulusci.robotframework.locator_manager`, `faker_mixin`, `form_handlers`, plus the rest of the cci core that ships in the same package. +- There is no standalone distribution; the Salesforce/SalesforcePlaywright libraries cannot be installed without the full `cumulusci` wheel and project layout. + +**Proposed fix sketch**: + +- Approach: factor a UI-only subset out of `cumulusci.robotframework.*` into a sibling distribution (e.g. `salesforce-robot-library`) that depends only on Selenium/Playwright + the locator dictionaries; have CumulusCI's Robot task consume that subset. +- Target: package layout change spanning `cumulusci/robotframework/` and `pyproject.toml`. +- Size: large (>100 lines, design change + new distribution). +- Risk: medium — must not break existing tasks/keywords. +- API break: no (additive new distribution). + +**Recommended action**: + +- pass1: `keep-open` — reasonable architectural request, age <24mo, no community PR yet; worth retaining as roadmap signal. +- pass2 labels: `enhancement, robotframework, scope-large` +- triage test: n/a — no concrete API to xfail against. + +--- + +### #675: Show full traceback for Python exceptions in robot keywords + +**Verdict**: REPRODUCED-on-dev (feature still missing) +**Repro type**: feature (cli-usability) +**Method**: code-scan + +**Evidence**: + +- `cumulusci/tasks/robotframework/robotframework.py` configures listeners (`KeywordLogger`, `DebugListener`) but never sets `loglevel`/`logtitle`/`pythonpath` to surface Python tracebacks. `rg 'traceback|format_exc|format_tb' cumulusci/robotframework/` returns 0 matches; same for `cumulusci/tasks/robotframework/`. +- Robot Framework's default behaviour: when a Python keyword raises, only `str(exc)` is shown in the report; the full traceback requires either `--loglevel TRACE`, `--listener` overrides, or `error.ROBOT_CONTINUE_ON_FAILURE`/`error.ROBOT_EXIT_ON_FAILURE` plumbing. CumulusCI does none of this by default. + +**Proposed fix sketch**: + +- Approach: in `Robot._init_options`, default `options.loglevel` to include `TRACE`, OR install a small listener that captures `sys.exc_info()` in keyword-end events and emits a formatted traceback through `robot.api.logger.error`. +- Target: `cumulusci/tasks/robotframework/robotframework.py:104` (`_init_options`). +- Size: small (~10 lines). +- Risk: low — additive listener; opt-out via options if needed. +- API break: no. + +**Recommended action**: + +- pass1: `closed:stale-24mo` — issue opened 2018-07, last activity 2018-09, ~8 years inactivity. Two simple workarounds exist (`-o loglevel:TRACE`, `traceback.format_exc()` in keywords). Surface as a tip in docs rather than keep the bug open. +- pass2 labels: `cli-usability, robotframework, stale` +- triage test: n/a — observable only in a robot run. + +--- + +### #987: Last week this test worked, now I get a javascriptexception message. + +**Verdict**: NOT-REPRODUCED-on-dev +**Repro type**: bug (legacy) +**Method**: code-scan + history review + +**Evidence**: + +- Issue specifies Salesforce Spring 19, chromedriver 2.46.628411, chrome 72.0.3626.109 — all extinct. +- Reporter posted on 2019-02-18: _"@davisagli I figured out a work-around. Use firefox with geckodriver. Everything works as intended now."_ — i.e. accepted a working alternative. +- `cumulusci/robotframework/Salesforce.py:154` `click_object_button` still calls `_jsclick`, which has been the workaround pattern for shadow-DOM-aware clicks for years; current Selenium 4 / Salesforce Lightning UI no longer surfaces the original `Cannot read property 'defaultView' of undefined` error in the same form. +- Last comment 2022-06 (davidmreed asking if still impacted; no response). + +**Proposed fix sketch**: n/a — environment-specific historical bug. + +**Recommended action**: + +- pass1: `closed:stale-24mo` — reporter has a workaround, root cause was Spring 19 specific, 7+ years stale, last activity 2022-06 (still 4 years ago). +- pass2 labels: `stale, user-error` +- triage test: n/a — would require a live 2019 org snapshot. + +--- + +### #3602: Need Chrome/Firefox options(browser options/capabilities) in 'Open Test Browser' Keyword + +**Verdict**: REPRODUCED-on-dev (feature still missing) +**Repro type**: feature +**Method**: code-scan + pytest (signature assertion) + +**Evidence**: + +- `cumulusci/robotframework/SalesforcePlaywright.py:60-62` — `def open_test_browser(self, size=None, useralias=None, wait=True, record_video=None):` has no `browser_options`/`extra_options`/`**kwargs` hook. +- `cumulusci/robotframework/Salesforce.robot:103` — Selenium keyword signature `[Arguments] ${size}=... ${alias}=${NONE} ${wait}=True ${useralias}=${NONE}` — same gap. +- `cumulusci/robotframework/Salesforce.robot:157-168` `Get Chrome Options` hard-codes a single `--disable-notifications` argument with no extension hook. +- Users cannot load Chrome extensions, switch to incognito, change download directory or accept self-signed certs without a fork of `Salesforce.robot`. + +**Proposed fix sketch**: + +- Approach (Playwright): add a `browser_options: dict | None = None` kwarg; pass through to `new_browser` (browser-launch options) and a separate `context_options` dict merged into the `new_context` call. +- Approach (Selenium): expose a `${EXTRA_CHROME_OPTIONS}` variable / list argument honoured by `Get Chrome Options`; alternatively add an `extra_options` argument to `Open Test Browser` and pipe through to `Create Webdriver With Retry`. +- Target: `cumulusci/robotframework/SalesforcePlaywright.py:60-117`; `cumulusci/robotframework/Salesforce.robot:77-168`. +- Size: medium (~30-60 lines across both implementations + tests + docs). +- Risk: low — additive parameter with safe default. +- API break: no (default `None` preserves current behaviour). + +**Recommended action**: + +- pass1: `keep-open` — reasonable, scoped feature ask; age <36mo; no PR yet; tractable medium-sized contribution. +- pass2 labels: `enhancement, robotframework, playwright, good-second-issue` +- triage test: `cumulusci/tests/triage/test_issue_3602.py` + + + +# Subagent 14 — scratch-org-config theme, Round 3 + +Working tree: `.worktrees/repro-scratch` on `worktree/repro/scratch` off `origin/dev` at `1925a3083`. + +Triaged 3 issues (#3910, #3306, #710). All three remain actionable on dev: #3910 has an open fix PR; #3306 and #710 are never-implemented enhancements. + +### #3910: JSON Schema incorrectly defines namespaced field as string instead of boolean for scratch org configuration + +**Verdict:** `REPRODUCED-on-dev`. Bug. + +**Evidence:** + +- `cumulusci/utils/yaml/cumulusci_yml.py:150` declares `namespaced: str = None` on the `ScratchOrg` Pydantic v1 model. +- The auto-generated schema at `cumulusci/schema/cumulusci.jsonschema.json:424` reads `"type": "string"` (the test `cumulusci/tests/test_schema.py:test_schema_is_current` enforces that the saved schema matches the model output, so the two are locked together). +- `ScratchOrg.parse_obj({"namespaced": True})` silently coerces to the literal string `"True"`; `{"namespaced": False}` to `"False"`. Either value is non-empty, so a downstream `if not self.namespaced` check would flip its logic if the model output were used directly. +- The actual runtime path (`BaseProjectKeychain.create_scratch_org` at `cumulusci/core/keychain/base_project_keychain.py:74`, then `ScratchOrgConfig._build_org_create_args` at `cumulusci/core/config/scratch_org_config.py:143`) bypasses the Pydantic model via `project_config.lookup`, so booleans set in YAML survive at runtime. The user-visible impact is therefore: editors that consume the JSON schema reject `namespaced: true`/`false` (boolean) in `cumulusci.yml`, and `make schema` regenerates the same incorrect schema until the model is fixed. +- Open PR [#3911](https://github.com/SFDO-Tooling/CumulusCI/pull/3911) (base `main`, branch `fix/namespaced-config-value-type-in-schema`) correctly fixes both files. State on 2026-05-14: OPEN, not merged. + +**Repro test:** `/tmp/repro/14/tests/test_issue_3910.py` — 4 XFAILs against the schema JSON, the live Pydantic schema, and the model's coercion of booleans. + +**Proposed fix sketch** + +- Approach: land PR #3911 essentially as-is (one-line Pydantic field change in `cumulusci_yml.py` + `make schema` regenerated `cumulusci.jsonschema.json`). Both edits must ship together because `test_schema_is_current` would otherwise fail. +- Target file:line: `cumulusci/utils/yaml/cumulusci_yml.py:150` (`namespaced: str = None` → `namespaced: bool = None`); regenerate `cumulusci/schema/cumulusci.jsonschema.json`. +- Size: small. +- Risk: low. The only Pydantic consumers of `ScratchOrg.namespaced` are YAML-validation pathways; the runtime keychain path already uses booleans. +- API break: no (silent coercion was incidental and arguably already broken for users). + +### #3306: Preview Toggle for Scratch org def file + +**Verdict:** `NOT-REPRODUCED-on-dev`. Feature. + +**Evidence:** + +- `cci org scratch` already supports `--release preview|previous` (`cumulusci/cli/org.py:567-579`) and threads it through `BaseProjectKeychain.create_scratch_org` (`cumulusci/core/keychain/base_project_keychain.py:57-84`) to `ScratchOrgConfig._build_org_create_args` (`cumulusci/core/config/scratch_org_config.py:149-150`). +- `cci flow run` (`cumulusci/cli/flow.py:119-200`) has no `--release` / `--preview` flag. The flow path also auto-recreates expired scratch orgs in `cumulusci/cli/runtime.py:106-114` without forwarding any release argument. +- Internally tracked as W-11486409; no PR opened in 4 years. + +No test written — this is a clean enhancement request whose API surface (`--preview` vs `--release` flag, behaviour with non-scratch orgs, behaviour when `release` is already set in YAML) is not yet specced. + +### #710: Allow disabling default scratch org configs + +**Verdict:** `REPRODUCED-on-dev`. Feature. + +**Evidence:** + +- The universal config at `cumulusci/cumulusci.yml:1559` defines five default scratch orgs (`dev`, `qa`, `feature`, `beta`, `release`). +- `BaseProjectKeychain._load_scratch_orgs` (`cumulusci/core/keychain/base_project_keychain.py:149-159`) iterates every key under `orgs.scratch` and calls `create_scratch_org` unconditionally. +- `merge_config` (`cumulusci/core/utils.py:158`) calls `dictmerge`, which drops a `None` value from the project-side override (`{"orgs": {"scratch": {"dev": {"config_file": None}}}}` merged with the universal config still resolves to the universal's `config_file: orgs/dev.json`). The exact syntax proposed by the issue therefore has no effect. + +**Repro test:** `/tmp/repro/14/tests/test_issue_710.py` — 2 XFAILs. One asserts that the project-side `config_file: None` override survives `merge_config`; the other asserts the resulting keychain does not load `dev`. + +**Proposed fix sketch** + +- Approach: introduce a sentinel for "disabled" (recommend an explicit `disabled: true` flag on each scratch org config rather than relying on `config_file: None`, which has overloaded meaning) and skip disabled entries in `_load_scratch_orgs`. Optional: a stricter `merge_config` mode that preserves `None` overrides under `orgs.scratch.*`. +- Target file:line: `cumulusci/utils/yaml/cumulusci_yml.py:147` (add `disabled: bool = None` to `ScratchOrg`); `cumulusci/core/keychain/base_project_keychain.py:155` (skip when `config.get("disabled")`); regenerate `cumulusci/schema/cumulusci.jsonschema.json`. +- Size: small/medium. +- Risk: low. Existing keys remain compatible; only adds new opt-in behaviour. Needs a docs note (`docs/orgs/scratch.md`) on how to disable inherited defaults. +- API break: no (additive). The issue's literal `config_file: None` syntax would NOT be honoured under this proposal; if the team prefers that exact syntax instead, add a `dictmerge` exception so `None` overrides under `orgs.scratch.*` are preserved, then have `_load_scratch_orgs` skip entries with `config_file is None`. Either implementation satisfies the XFAIL test (`dev not in keychain.orgs`). + + + +### #2667 — `cci org connect` should output the name of the connected app it is using + +**Theme**: auth · **Bucket**: enhancement (cli-output) · **Verdict**: `NOT-REPRODUCED-on-dev` + +**Original ask (prescod, 2021-06-08)**: When connecting an org, print which connected app is being used, e.g. `"Using connected_app 'xyzzy'"`, so users get a hint when a connected-app mismatch is the source of a confusing Salesforce error. + +**Status on `origin/dev` @ `1925a3083`**: Implemented. `cumulusci/cli/org.py` `org_connect` resolves the connected-app name (CLI flag → keychain default) and emits, before initiating OAuth: + +```204:209:cumulusci/cli/org.py + click.echo(f"Connecting org using the {connected_app_name} connected app...") + connected_app = runtime.keychain.get_service("connected_app", connected_app_name) + sf_client = setup_client(connected_app, login_url, sandbox) + connect_org_to_keychain( + sf_client, runtime, global_org, org_name, connected_app_name + ) +``` + +The connected_app name is also persisted onto the new `OrgConfig` (`org_config.config["connected_app"] = connected_app`, line 155), addressing davisagli's follow-up that orgs should remember which connected app authorized them. + +**Implementation history** (via `git log -L`): + +- `8fe1910b1` "refactor into separate methods" — split out `connect_org_to_keychain` and `setup_client`. +- `40520bee4` "checkpoint" (2022-01-31) — introduced the `connected_app_name` resolution and the `click.echo` line. This is the commit that closes the loop on this issue. Matches davidmreed's 2022-01-28 comment "Covering in W-9863651". +- `719d40260` "more tests, use the stored connected_app" — added test coverage and passed `connected_app_name` through to `connect_org_to_keychain` so it is stored on the org. + +**Test coverage already present**: + +- `cumulusci/cli/tests/test_org.py::TestOrgCommands::test_org_connect` asserts `"Connecting org using the built-in connected app..." in result.output` (line 135). +- `cumulusci/cli/tests/test_org.py::TestOrgCommands::test_org_connect__non_default_connected_app` asserts `"Connecting org using the other connected app..." in result.output` (line 191), explicitly covering the non-default case the issue called out as most important. + +Both pass on dev (verified locally; 10/10 `test_org_connect*` tests pass). + +**Recommendation**: `close-stale` with labels `resolved,implemented`. The exact phrasing differs from the issue's mock-up (`"Connecting org using the X connected app..."` vs `"Using connected_app 'X'"`), but the substantive ask — surfacing the connected-app identity at connection time — is satisfied. davisagli's deeper suggestions (configurable production/sandbox login URLs per connected app; auto-pick connected_app from login URL) are out of scope for this ticket and can be filed separately if still wanted. + + + +# Subagent 16 (keychain) — Round 3 narrative + +Worktree: `.worktrees/repro-keychain` @ `1925a3083` (off `origin/dev`). +Issues processed: 3/3 (#2126, #3407, #3541). +Verdict tally: 1 NOT-REPRODUCED (feature/stale), 2 REPRODUCED-on-dev. + +### #2126 — Probabilistic-encryption task + +**Classification**: feature request, theme-mismatched (Shield Platform +Encryption, not keychain). + +**What dev shows**: no `encrypt_all_encryptable_fields` task exists. +`rg -i 'encryptionScheme|encrypt_all_encryptable|probabilistic' cumulusci/` +returns zero hits. The issue is labelled `blocked` since 2022-01-28 when +davidmreed wrote "this feature has been developed but is blocked by bugs in +the underlying platform functionality." No platform follow-up has surfaced +in the comments; the issue is 5+ years stale. + +**Verdict**: `NOT-REPRODUCED-on-dev` (feature scope; no bug to reproduce). + +**Pass-1 recommendation**: `closed:stale-24mo`. Pass-2 labels: `area/metadata-etl`, +`blocked` (theme correction). No fix sketch — close or hand off to the +metadata-ETL theme owner with a stale-feature ping. + +### #3407 — `set_service(service_config)` annotation lies + +**Classification**: typing/API-consistency bug, still present on dev. + +**Reproduction path**: + +- `cumulusci/core/keychain/base_project_keychain.py` lines 202-209 declare + `service_config: ServiceConfig` on `set_service`. +- `cumulusci/core/keychain/encrypted_file_project_keychain.py` line 717 + calls `set_service(service_type, name, config, save=False, config_encrypted=True)` + where `config` is the raw text body of a `.service` file read at line 712-713. +- `_set_service` (encrypted_file_project_keychain.py:583-605) explicitly + short-circuits when `self.key and config_encrypted` and treats + `service_config` as the already-serialised payload, so the call is + semantically correct — the annotation is what's wrong. + +The two-test repro (`/tmp/repro/16/tests/test_issue_3407.py`) introspects the +annotation, confirms a string call site exists in `_load_service_files`, and +exercises the runtime path with a string payload via a `BaseProjectKeychain` +subclass. Both xfail on dev. + +**Proposed fix sketch** + +- **Approach**: Widen the annotation. `set_service`'s `service_config` + parameter should be `Union[ServiceConfig, str]` (or `ServiceConfig | str | +bytes`) and the docstring updated to say "raw encrypted payload when + `config_encrypted=True`". The deeper refactor — splitting the API into + `set_service` (validated `ServiceConfig`) and `set_encrypted_service` + (raw blob) — is cleaner but breaks the public API and is out of scope + for this triage pass. +- **Target**: `cumulusci/core/keychain/base_project_keychain.py:202-219`. + Also add the same widened annotation on the abstract `_set_service` + (line 360) and propagate to `EncryptedFileProjectKeychain._set_service` + (line 583). +- **Size**: ~10 LOC plus a typing-import bump. Single-file change feasible. +- **Risk**: very low. Pure type-hint widening; no runtime behaviour change. + Downstream callers that already pass `ServiceConfig` keep working; + pyright/mypy users gain an accurate hint. +- **API break**: no. Widening a parameter type is non-breaking for + callers. + +### #3541 — `None__dev` SFDX alias + +**Classification**: real bug, mis-labelled `cannot-reproduce`. + +**Reproduction path**: + +- `cumulusci/core/keychain/base_project_keychain.py` lines 77-79: + + ```python + scratch_config["sfdx_alias"] = ( + f"{self.project_config.project__name}__{org_name}" + ) + ``` + +- When `project_config.project__name` is None (cumulusci.yml without a + `project.name`, or partially-loaded project_config), this f-string + serialises the singleton `None` to the literal text `"None"`. The alias + becomes `"None__dev"`. +- Eager `_load_scratch_orgs` (line 45 → line 149-159) runs on keychain + construction and creates these mis-aliased configs before the user ever + runs `cci org scratch`. Reporter's claim that `cci org scratch dev dev` + fixes it is consistent: the explicit call re-runs `create_scratch_org` + after the project has fully loaded. +- The poisoned alias is then passed to `sfdx force config set +target-org={alias}` at `base_project_keychain.py:99`, producing the + reporter's symptom. + +Two xfail tests in `/tmp/repro/16/tests/test_issue_3541.py` build a +`BaseProjectConfig` without `project.name`, drive both the direct +`create_scratch_org` path and the eager-init `_load_scratch_orgs` path, and +assert the resulting alias contains no literal `'None'` token. Both fail on +dev. + +**Proposed fix sketch** + +- **Approach**: Guard the alias construction. Two reasonable options: + (1) raise `CumulusCIException("Cannot build sfdx_alias: project.name is not set in cumulusci.yml")` — surfaces the misconfiguration at the earliest possible moment. + (2) Fall back to `f"{org_name}"` (no prefix) when `project__name` is None, with a `logger.warning`. Less disruptive for existing setups. + Option 2 is the safer change; option 1 is the more correct one. Pick based on willingness to break first-run UX. + +- **Target**: `cumulusci/core/keychain/base_project_keychain.py:77-79`. + Migration helper recommended to scan the keychain for `None__*` aliases + and rewrite them once a real `project.name` is available. + +- **Size**: ~10 LOC for the guard, ~30 LOC including a one-shot migration + pass on keychain load. + +- **Risk**: medium. Existing keychains in the wild may already contain + `None__dev` rows; option 2 silently writes a new alias on next run, + option 1 forces the user to fix cumulusci.yml. Document either way in + CHANGELOG. + +- **API break**: no public API change. The `OrgConfig.sfdx_alias` field + shape is preserved; only its derivation logic shifts. + +- **Bonus**: remove the `cannot-reproduce` label — the repro here is + deterministic. + + + +# Subagent 17 (docs) — Round 3 narrative + +Worktree: `.worktrees/repro-docs` @ `1925a3083` (off `origin/dev`). +Issues processed: 3/3 (#773, #2500, #3464). +Verdict tally: 3 REPRODUCED-on-dev (all pure doc-gaps with code-level +testable assertions). + +### #773 — Document task return values and results + +**Classification**: feature-with-doc-component (needs a small framework +hook + matching renderer + the docs themselves). + +**What dev shows**: + +- `BaseTask` (`cumulusci/core/tasks.py:51`) declares `return_values: dict` + as an instance attribute (line 64), initialised to `{}` in `__init__` + (line 92), populated at runtime by each task's `_run_task()`. There is + no declarative class attribute that would describe the _shape_ of those + return values. +- `doc_task()` (`cumulusci/utils/__init__.py:354`) walks `task_options` + and a free-form `task_docs` string and emits "Description", "Class", + "Command Syntax", and "Options" sections. There is no "Return Values" + or "Returns" section — and no plumbing to add one. +- `cci task info ` is implemented by `cumulusci/cli/task.py:99`, + which delegates straight to `doc_task`, so it has the same gap. +- The docs themselves admit this. `docs/config.md:740-744` includes an + `attention` admonition that reads: _"Current task return values are + not documented, so finding return values set by a specific task (if + any) requires you to read the source code for the given task."_ + +So 8 years after the issue was filed, the documented workaround in the +docs is still "read the source". The repro test (`/tmp/repro/17/tests/test_issue_773.py`) +runs `doc_task` against a real shipping task (`PackageUpload`, whose +`_set_return_values()` populates `version_number` / `version_id` / +`package_id`) and asserts the rendered RST mentions any of those keys. +It xfails today. + +**Verdict**: `REPRODUCED-on-dev`. + +**Proposed fix sketch**: + +1. Add a class attribute on `BaseTask`: + +```python +return_values_schema: ClassVar[Dict[str, str]] = {} +``` + +where each key is the return-values dict key and each value is a one-line +description (parallel to how `task_options` already works). + +2. Extend `doc_task()` in `cumulusci/utils/__init__.py` to render a + "Return Values" RST section (heading + bullet list) when + `task_class.return_values_schema` is non-empty. Update the matching + `get_task_*` helpers to surface the schema for web-doc generation. + +3. Backfill the schema on tasks that already emit return values — search + for `self.return_values\[` across `cumulusci/tasks/`: at minimum + `PackageUpload`, `PromotePackageVersion`, `GithubRelease`, + `CreatePackageVersion`, dependency-resolution tasks. Each gets a few + lines. + +4. Lift the `attention` admonition in `docs/config.md:740-744` once + coverage is broad enough. + +Estimated effort: 1-2 day PR for the framework + first wave of tasks; an +ongoing "every new task documents its return values" contributor +expectation thereafter (enforce in `requesting-code-review` skill). + +### #2500 — `ignore_failure` is not documented + +**Classification**: pure doc-gap (the feature exists and works; only the +docs are missing). + +**What dev shows**: + +- The option exists in three independent places, so it is a stable, + public, supported feature: + - `cumulusci/utils/yaml/cumulusci_yml.py:45` — `Step` Pydantic model + declares `ignore_failure: bool = False`. + - `cumulusci/core/flowrunner.py:667` — uses `step_config.get("ignore_failure", False)` + to drive the `allow_failure` flag passed into the step runner. + - `cumulusci/schema/cumulusci.jsonschema.json:149` — exported in the + JSON schema for IDE autocomplete. +- In `docs/`, total mentions are exactly two: a single-line example use + inside a release-flow snippet at `docs/config.md:800` + (`ignore_failure: True`) and a one-line changelog blurb at + `docs/history.md:5993` from when the feature shipped. +- The `## Flow Configurations` chapter (line 294) has subsections for + "Add a Custom Flow" (303), "Add a Flow Step" (330), "Skip a Flow Step" + (388), "Replace a Flow Step" (414), "Configure Options on Tasks in + Flows" (432) — and there is documentation prose for `when:` at line + 474+ — but no parallel subsection for `ignore_failure`. +- Davidmreed cut GUS W-10908655 on 2022-03-28 to track it; nothing has + landed in the 4+ years since. + +The repro test (`/tmp/repro/17/tests/test_issue_2500.py`) confirms the +option exists in the `Step` model and asserts `docs/config.md` has a +heading-level section matching `ignore[ _]failure|ignore a failed|continue.*failure`. +The heading assertion xfails today; the existence assertion passes. + +**Verdict**: `REPRODUCED-on-dev`. + +**Proposed fix sketch**: + +Add `### Ignore a Failed Step` (or `### Continue After a Failed Step`) +to `docs/config.md` immediately after the existing `### Skip a Flow Step` +section. Body should cover: + +- What it does: when `ignore_failure: True` is set on a step, an + exception raised by that step does not abort the flow; subsequent + steps still run. +- A minimal YAML example (the existing `release_unlocked_production` + snippet around line 783 already demonstrates it — link to it instead + of duplicating). +- Interaction with `^^step.return_value` references: downstream steps + that reference a failed step's return values must defend against + missing keys. +- When NOT to use it: in CI, silently ignoring a failure hides + regressions; prefer a `when:` clause for intentional conditional + branching. +- One sentence on the difference between `ignore_failure` (post hoc: + swallow the exception) and `when:` (a priori: skip the step entirely). + +This is a tiny, high-leverage docs PR — a strong candidate for a +`good-first-issue` label. + +### #3464 — Concise project-config documentation + +**Classification**: doc-gap with structural-fix implications (the most +sustainable fix changes how docs are generated, not just what they say). + +**What dev shows**: + +- The authoritative shape of `project:` is the `Project` Pydantic model + at `cumulusci/utils/yaml/cumulusci_yml.py:135`, with nine fields: + `name`, `package`, `test`, `git`, `dependencies`, + `dependency_resolutions`, `dependency_pins`, `source_format`, `custom`. + Each of those (except scalars) points at a further sub-model with its + own fields — `Package` has 7, `Git` has 10, `DependencyResolutions` + has 3, `Test` has 1. +- `docs/config.md` shows exactly one project-level YAML example at line + 281 (NPSP's `project` block) covering `name` + a partial `package`. + There is no reference subsection enumerating every `project:` key. +- Substring scans of `docs/config.md`: + - `dependency_resolutions` → 0 occurrences. + - `dependency_pins` → 0 occurrences. + - `source_format` → 6 occurrences, all inside flow-step `when:` + clauses, not as a project-level reference. + - `custom` → 29 occurrences but none are about `project.custom`. +- The keys that _are_ documented live in a separate page — `docs/dev.md` + has `dependency_resolutions` at lines 596, 727 and `dependency_pins` + at lines 499, 509, 535 — which is exactly the _"scattered to the + wind"_ complaint in the issue body. jstvz acknowledged the gap in the + one comment on the issue ("We've made improvements to the + documentation over time, but there is still work to be done to make + it easier for users to find what they need"). + +The repro test (`/tmp/repro/17/tests/test_issue_3464.py`) enumerates +every field of the `Project` Pydantic model and asserts each name +appears at least once in `docs/config.md`. Today it lists the missing +keys; xfails. + +**Verdict**: `REPRODUCED-on-dev`. + +**Proposed fix sketch**: + +Two-step path: + +1. **Tactical**: expand the `### Project Configurations` heading at + `docs/config.md:673` into a real reference subsection that lists + every `project:` top-level key with a one-sentence description and + one example value. Cross-link to `docs/dev.md` for in-depth treatment + of `dependencies` / `dependency_resolutions` / `dependency_pins` so + we are not duplicating the longer narratives, just providing a + central index. This alone closes the issue per the user's literal + ask. + +2. **Strategic** (separate, follow-up PR): backfill `Field(description=...)` + on every Pydantic attribute in `cumulusci_yml.py` and add a Sphinx + directive (or a `conf.py` autodoc hook) that emits the reference + table directly from the model at docs-build time. This keeps the + reference and the schema in lockstep — the same mechanism powers the + JSON schema (`cumulusci/schema/cumulusci.jsonschema.json`), so the + plumbing is straightforward. + +Step 1 is a single-day effort; step 2 is multi-day but pays back every +time a new field is added to `cumulusci.yml`. Recommend keep-open until +at least step 1 ships. + + + +# Subagent 18 (pymod) — Round 3 narrative + +Worktree: `.worktrees/repro-pymod` @ `worktree/repro/pymod` based on `origin/dev` (`1925a3083`). + +### #3849 — urllib3 v2 breaks Robot tests on a fresh pip install + +**Verdict**: `REPRODUCED-on-dev` → `keep-open`. + +**Code scan**: + +- `pyproject.toml` `[project].dependencies` (lines 26–59) declares no `urllib3` constraint. It still pins `selenium<4` (line 54) and `robotframework-seleniumlibrary<6` (line 50). Both of those pin chains force `selenium==3.141.0`, whose `urllib3` import-time use of the pre-2.0 `Timeout` sentinel object is what produces the user-reported `ValueError: Timeout value connect was `. +- `requests` (installed as a transitive runtime dep) declares `urllib3<3,>=1.26`, so a fresh `pip install cumulusci` resolves to whatever `urllib3` 2.x is current on PyPI. The local worktree happens to have `urllib3==1.26.20` because `uv sync` consumed `uv.lock`, but the lock is not what pip sees. Confirmed via `uv run python -c "import importlib.metadata as md; print(md.metadata('selenium').get_all('Requires-Dist'))"` → `selenium` declares `urllib3` with no version constraint. +- `git log --all --grep urllib3` shows only dependabot lock bumps (e6423311e, 05a904856) that never landed on `dev`. The original 2018 fix referenced in `docs/history.md` (`#832`) is not reflected in the modern dependency list. +- 6+ users have reported reblocking on this in 2024–2025 (Szandor72, dipakparmar, atran-agentsync, JonnyPower, elizabethrichardson-uw, kg345); the documented workaround is still `pip install urllib3==1.26.20` after installing cumulusci. + +**Repro test**: `/tmp/repro/18/tests/test_issue_3849.py` parses the worktree's `pyproject.toml` (located via `cumulusci.__file__`) and asserts the modernized state — either an explicit `urllib3<…` constraint OR removal of both the `selenium<4` and `robotframework-seleniumlibrary<6` pins. Verified `XFAIL` under `uv run pytest -v -rx` (reason surfaces the docs path). + +**Proposed fix sketch**: Two acceptable shapes. + +1. **Cheap, restores Robot reliability**: add `"urllib3<2"` to `[project].dependencies` in `pyproject.toml`. This makes pip honor what `uv.lock` already encodes. Drop the matching workaround note from #3849. +2. **Right long-term**: bump to `robotframework-seleniumlibrary>=6` and `selenium>=4`, which removes the Timeout-sentinel incompatibility entirely. Audit `cumulusci/robotframework/*` for Selenium 4 API drift (the comment on the original PR notes integration tests caught urllib3 issues last time). The two pin entries on lines 50 and 54 of `pyproject.toml` are the visible footgun. + +Either way, add a smoke test that imports `SeleniumLibrary` after a fresh resolve to keep the regression caught. + +### #3610 — `run_tests` crashes when `ApexTestResult.MethodName` is null + +**Verdict**: `NOT-REPRODUCED-on-dev` → `closed:fixed-by-pr-#3681`. + +**Code scan**: + +- The original issue points at `cumulusci/tasks/apex/testrunner.py` L417 (sort that explodes on `None`) and L346–348 (dict keyed by `MethodName`). On `origin/dev` today the same module's `_process_test_results` (lines 491–510) explicitly handles `None`: + +```500:510:cumulusci/tasks/apex/testrunner.py + if None in method_names: + class_id = self.classes_by_name[class_name] + self.retry_details.setdefault(class_id, []).append( + self._get_test_methods_for_class(class_name) + ) + del self.results_by_class_name[class_name][None] + self.logger.info( + f"Retrying class with id: {class_id} name:{class_name} due to `None` methodname" + ) + self.counts["Retriable"] += len(self.retry_details[class_id]) + self._attempt_retries() +``` + +- This landed in PR #3681 / commit `84389d998b4783ddd2ff062f486a2366709cac27` (“Handling exception when the Tooling API returns a test result with a null method name”), with regression coverage in `cumulusci/tasks/apex/tests/test_apex_tasks.py::test_run_task_None_methodname_fail` and `…_pass`. Both pass on this worktree (`uv run pytest cumulusci/tasks/apex/tests/test_apex_tasks.py -k None_methodname -v` → `2 passed`). + +No repro test added — the fix is in place and already has direct unit coverage. Closing the issue is a paperwork action. + +**Proposed fix sketch**: none required. Recommend closing #3610 with a comment that points at PR #3681 and the two `None_methodname` tests. diff --git a/docs/triage/v5/themes.md b/docs/triage/v5/themes.md new file mode 100644 index 0000000000..41b6c3a89c --- /dev/null +++ b/docs/triage/v5/themes.md @@ -0,0 +1,528 @@ +# CCI Open-Issue Themes and Duplicate Clusters + +Generated by Task 2.5b. Read-only analysis over the 142-issue snapshot +captured by Task 1. The current proposed-pass1 decisions live in +`proposals.md`; this document surfaces information the controller and +user can use to refine those decisions before Phase 2 execution. + +## How to read this document + +- A "theme" is a topical bucket: a coherent group of issues that share + a subject area, even if they are not duplicates of each other. A + theme may overlap with other themes; an issue can appear in multiple. +- A "duplicate cluster" is a set of two or more issues that report the + same underlying problem or request the same feature. Each cluster has + a "canonical" issue (the one to keep open if any) and one or more + "subsumed" issues (the ones to close as `duplicate-of-#NNNN` rather + than `stale-24mo`, `pre-v4.0.0`, or `missing-fields`). +- A "tranche" is a release-and-effort grouping: a recommendation for + how the canonical surviving issues should be sequenced if the user + wants to act on them in v5. + +## Theme summary + +| theme | issues | dup clusters | net unique signals | suggested-v5 | +| -------------------- | -----: | -----------: | -----------------: | ------------ | +| packaging | 34 | 0 | 34 | yes | +| metadata-etl | 28 | 1 | 27 | yes | +| cli | 37 | 0 | 37 | maybe | +| bulkdata | 23 | 0 | 23 | yes | +| dependencies | 8 | 0 | 8 | yes | +| robotframework | 6 | 0 | 6 | maybe | +| scratch-org-config | 6 | 0 | 6 | maybe | +| ci-integration | 5 | 0 | 5 | maybe | +| auth | 5 | 0 | 5 | yes | +| keychain | 5 | 0 | 5 | no | +| docs | 4 | 0 | 4 | no | +| python-modernization | 3 | 0 | 3 | yes | + +Note: "issues" counts every issue that mentions theme-defining keywords +strongly enough; an issue can appear in multiple theme rows because +primary and secondary theme membership are both included. The total of +the issues column therefore exceeds 142. The "net unique signals" +column subtracts only the issues subsumed by clusters anchored in this +theme. + +## Cross-theme duplicate cluster index + +Issues that duplicate across themes (rare but important). + +None. The single confirmed duplicate cluster (Cluster A) is fully +contained in the metadata-etl theme. No cluster has 5+ members. + +## Themes + +### Theme: packaging + +Description: Issues touching 1GP and 2GP package creation, version management, install and uninstall flows, beta promotion, and community creation. + +Issues (34): + +#2973, #2979, #3089, #3347, #3418, #3429, #3440, #3441, #3446, #3466, #3512, #3542, #3563, #3587, #3592, #3593, #3600, #3605, #3721, #3734, #3745, #3746, #3758, #3763, #3781, #3796, #3810, #3884, #3885, #3889, #3899, #3902, #3919, #3929 + +Singletons in theme (no dup): + +- #3899: Getting following Exception in task deploy_packaging.unschedule_apex; current proposed-pass1: `kept-open`. +- #3902: Task install_managed security_type not being respected with 04t ID; current proposed-pass1: `kept-open`. +- #3929: cci task run create_community (and sf community create) Appears to Loop/Timeout ; current proposed-pass1: `kept-open`. +- #3466: Ability to specify a test suite to run instead of just test_name_match in the ru; current proposed-pass1: `closed:missing-fields`. +- #3884: Running a Dev_Org flow goes through re-install of the the same package version a; current proposed-pass1: `closed:missing-fields`. +- #3889: Uninstall 2GP task request; current proposed-pass1: `closed:missing-fields`. +- #2973: cumulusci.tasks.salesforce.CreateCommunity has no option to set authentication m; current proposed-pass1: `closed:pre-v4.0.0`. +- #3089: task run_tests not including namespace in query; current proposed-pass1: `closed:pre-v4.0.0`. +- #3512: `namespace` does not display when running `cci org info` on a packaging org (doe; current proposed-pass1: `closed:pre-v4.0.0`. +- #3563: Unmanaged Metadata not deploying during 2GP Package Create; current proposed-pass1: `closed:pre-v4.0.0`. +- #3592: release_unlocked_beta doesn't work when an install key is specified; current proposed-pass1: `closed:pre-v4.0.0`. +- #3763: Namespace not being added into Flow references in minority of cases; current proposed-pass1: `closed:pre-v4.0.0`. +- #3781: Package Versions Starting with 0 (0.1,0.2,0.3, etc.) Cause "does not exist" erro; current proposed-pass1: `closed:pre-v4.0.0`. +- #3796: cci task run get_installed_packages/uninstall_managed do not see 2GP beta; current proposed-pass1: `closed:pre-v4.0.0`. +- #3810: Github tasks fail when using github enterprise; current proposed-pass1: `closed:pre-v4.0.0`. +- #3885: Versioning in CumulusCI Releases Does Not Support Full Versioning with Build Num; current proposed-pass1: `closed:pre-v4.0.0`. +- #3919: uninstall_packaged_incremental was purged even though it was set to "not"; current proposed-pass1: `closed:pre-v4.0.0`. +- #2979: deploy task should deploy from the default entry in packageDirectories in sfdx-p; current proposed-pass1: `closed:stale-24mo`. +- #3347: Cannot release an unlocked beta package with release_unlocked_beta flow; current proposed-pass1: `closed:stale-24mo`. +- #3418: Error creating 1gp release; current proposed-pass1: `closed:stale-24mo`. +- #3429: Support overriding `cumulusci.yml` to be used for configuration; current proposed-pass1: `closed:stale-24mo`. +- #3440: Enhance default_package_path to serve multi package projects better; current proposed-pass1: `closed:stale-24mo`. +- #3441: "cci task run create_package_version" should allow option "version_base: default; current proposed-pass1: `closed:stale-24mo`. +- #3446: CCI task "push_qa" crashes for Unlocked package with no namespace; current proposed-pass1: `closed:stale-24mo`. +- #3542: 2GP flows fail in the local environment to test: `ci_feature_2gp` or `qa_org_2gp; current proposed-pass1: `closed:stale-24mo`. +- #3587: Warning message when attempting to set `--install_class` or `--uninstall_class` ; current proposed-pass1: `closed:stale-24mo`. +- #3593: `dx` task doesn't work for some commands like `project convert source`; current proposed-pass1: `closed:stale-24mo`. +- #3600: Allow install_managed to use environment variables; current proposed-pass1: `closed:stale-24mo`. +- #3605: Ability to Increment Major Versions when running `upload_production`; current proposed-pass1: `closed:stale-24mo`. +- #3721: create_package_version version_name default should be version number, not "Relea; current proposed-pass1: `closed:stale-24mo`. +- #3734: Exception in cci task upload_production - Malformed Request Error: The version n; current proposed-pass1: `closed:stale-24mo`. +- #3745: cci flow run ci_beta AND cci task install_managed_beta DO not use the latest bet; current proposed-pass1: `closed:stale-24mo`. +- #3746: Deleted Versions used for determining next version; current proposed-pass1: `closed:stale-24mo`. +- #3758: Flow "push_upgrade_org" is incorrectly defined; current proposed-pass1: `closed:stale-24mo`. + +Recommendation: + +- Leave all other issues in this theme on their current proposed-pass1 plan unless flagged elsewhere in this document. + +### Theme: metadata-etl + +Description: Issues in the metadata ETL task family: update_admin_profile, update_package_xml, find_replace, retrieve and deploy variants, and individual ETL transforms. + +Issues (28): + +#808, #2440, #2826, #3100, #3137, #3165, #3167, #3320, #3331, #3518, #3543, #3544, #3561, #3585, #3589, #3593, #3613, #3692, #3762, #3770, #3771, #3773, #3919, #3931, #3938, #3939, #3951, #3953 + +Duplicate clusters within theme: + +- Cluster A: canonical #3544 (last activity: 2025-05-07; comments: 4). Subsumed: #3762 (current proposed-pass1 was `closed:stale-24mo`; recommend converting to `closed:duplicate-of-#3544`; last activity 2024-03-06). + Shared signal: update_admin_profile cannot reconcile the Admin profile when a namespaced scratch org has Person Accounts enabled. + Rationale: Both report the same root cause: running update_admin_profile against a namespaced scratch org with the PersonAccounts feature enabled triggers the same MDAPI failure (no RecordType named Account.Business_Account in the retrieved Admin profile). Reproduction steps converge on the same cumulusci.yml + scratch org config combination. #3544 is more recent (2025-05-07), has 4 comments, and includes a linked external thread; #3762 (2024-03-06, 1 comment) repeats the same diagnosis. + +Singletons in theme (no dup): + +- #3931: Specifying a profile in cumulusci.tasks.salesforce.ProfileGrantAllAccess results; current proposed-pass1: `kept-open`. +- #3938: Rest_Deploy ignores errors; current proposed-pass1: `kept-open`. +- #3939: Deploy task can't parse SOAP Response; current proposed-pass1: `kept-open`. +- #3951: set_duplicate_rule_status broken; current proposed-pass1: `kept-open`. +- #3953: add_picklist_entries never works through CLI; current proposed-pass1: `kept-open`. +- #3137: cci task run update_package_xml and Salesforce Case Custom Object; current proposed-pass1: `closed:missing-fields`. +- #3320: Metadata ETL task to Deactivate a Flow; current proposed-pass1: `closed:missing-fields`. +- #2440: add_permission_set_perms throws 'string indices must be integers' error; current proposed-pass1: `closed:pre-v4.0.0`. +- #3100: uninstall_post is not substituting %%%NAMESPACE%%%; current proposed-pass1: `closed:pre-v4.0.0`. +- #3589: "Workflow" and "MatchingRules" are removed from package.xml after running "updat; current proposed-pass1: `closed:pre-v4.0.0`. +- #3770: Error during cci task run retrieve_changes; current proposed-pass1: `closed:pre-v4.0.0`. +- #3919: uninstall_packaged_incremental was purged even though it was set to "not"; current proposed-pass1: `closed:pre-v4.0.0`. +- #808: deploy_packaging flow runs uninstall_packaged_incremental with wrong package nam; current proposed-pass1: `closed:stale-24mo`. +- #2826: The deploy_unmanaged flow is supposed to silently do nothing if there's not actu; current proposed-pass1: `closed:stale-24mo`. +- #3165: Update Admin Profile task fails when specifying records types without custom pac; current proposed-pass1: `closed:stale-24mo`. +- #3167: Add ability to define page layout assignments with record types using the update; current proposed-pass1: `closed:stale-24mo`. +- #3331: Task update_package_xml does not write correct package.xml for AssignmentRules; current proposed-pass1: `closed:stale-24mo`. +- #3518: Task add_picklist_entries always sets a default value for record types; current proposed-pass1: `closed:stale-24mo`. +- #3543: New Option `load_sfdx_project_paths` for dx_convert_from Task ; current proposed-pass1: `closed:stale-24mo`. +- #3561: Retrieve_unpackaged unusable in MetaDeploy; current proposed-pass1: `closed:stale-24mo`. +- #3585: Error Occurs when Using `update_package_xml` on object with `xsi:nil="true"`; current proposed-pass1: `closed:stale-24mo`. +- #3593: `dx` task doesn't work for some commands like `project convert source`; current proposed-pass1: `closed:stale-24mo`. +- #3613: AddFieldsToPageLayout; current proposed-pass1: `closed:stale-24mo`. +- #3692: No parser configuration found for subdirectory digitalExperiences; current proposed-pass1: `closed:stale-24mo`. +- #3771: find_replace transforms on XPath with predicates does not work; current proposed-pass1: `closed:stale-24mo`. +- #3773: retrieve_profile task seems to be missing some Metadata; current proposed-pass1: `closed:stale-24mo`. + +Recommendation: + +- Promote canonical #3544 to v5-candidate:maybe (and hold from current closure plan). +- Convert these to `closed:duplicate-of-#3544`: #3762. +- Hold the canonical #3544 from current Pass-1 closure (was `closed:pre-v4.0.0`). +- Leave all other issues in this theme on their current proposed-pass1 plan unless flagged elsewhere in this document. + +### Theme: cli + +Description: Issues about CLI mechanics: argument validation, command output, prompts, the VSCode extension, run-time behavior of cci task and cci flow, and flow definition control (when clauses, ci_master rename). + +Issues (37): + +#733, #1348, #1350, #1432, #2140, #2402, #2507, #2697, #3015, #3024, #3089, #3134, #3161, #3307, #3347, #3470, #3479, #3485, #3492, #3506, #3549, #3570, #3585, #3607, #3609, #3612, #3618, #3663, #3733, #3754, #3770, #3784, #3852, #3854, #3899, #3929, #3953 + +Singletons in theme (no dup): + +- #3852: CumulusCI 4 refresh token error; current proposed-pass1: `kept-open`. +- #3854: Issue while Capturing Data; current proposed-pass1: `kept-open`. +- #3899: Getting following Exception in task deploy_packaging.unschedule_apex; current proposed-pass1: `kept-open`. +- #3929: cci task run create_community (and sf community create) Appears to Loop/Timeout ; current proposed-pass1: `kept-open`. +- #3953: add_picklist_entries never works through CLI; current proposed-pass1: `kept-open`. +- #2402: Create a --rebuild-org parameter for cci flow run; current proposed-pass1: `closed:missing-fields`. +- #3015: Request to have the ability to remove an imported dx org from cci org list witho; current proposed-pass1: `closed:missing-fields`. +- #3307: Project Template Support for initialisation; current proposed-pass1: `closed:missing-fields`. +- #3754: Enable configuration for cci version update sources; current proposed-pass1: `closed:missing-fields`. +- #3089: task run_tests not including namespace in query; current proposed-pass1: `closed:pre-v4.0.0`. +- #3134: Running flow always needs a default org or org defined; current proposed-pass1: `closed:pre-v4.0.0`. +- #3733: `cci org remove` doesn't remove org; current proposed-pass1: `closed:pre-v4.0.0`. +- #3770: Error during cci task run retrieve_changes; current proposed-pass1: `closed:pre-v4.0.0`. +- #3784: Can't run test suites if project**test**name_match is defined; current proposed-pass1: `closed:pre-v4.0.0`. +- #733: Prompt to delete scratch org when creating one that already exists; current proposed-pass1: `closed:stale-24mo`. +- #1348: Multiple Git Provider Support; current proposed-pass1: `closed:stale-24mo`. +- #1350: Unable to run tasks in remote projects; current proposed-pass1: `closed:stale-24mo`. +- #1432: CCI Inconsistencies in validating arguments; current proposed-pass1: `closed:stale-24mo`. +- #2140: Prompt Org Configs when Org Does Not Exist and Command Runs Against It; current proposed-pass1: `closed:stale-24mo`. +- #2507: Undo mode for CumulusCI Insert; current proposed-pass1: `closed:stale-24mo`. +- #2697: Initialization issue with 'namespaced' field in 'cci org info' after updating fr; current proposed-pass1: `closed:stale-24mo`. +- #3024: Order of flow groups in cumulusci/cumulusci.yml reflects in the Flows box in CCI; current proposed-pass1: `closed:stale-24mo`. +- #3161: Ability to Hide Option Values When Using Task Options In a Task or Flow Run; current proposed-pass1: `closed:stale-24mo`. +- #3347: Cannot release an unlocked beta package with release_unlocked_beta flow; current proposed-pass1: `closed:stale-24mo`. +- #3470: Rename `ci_master` flow to a `ci_main` or at least create a new duplicate `ci_ma; current proposed-pass1: `closed:stale-24mo`. +- #3479: Error with "cci org import" in github action; current proposed-pass1: `closed:stale-24mo`. +- #3485: "cci task run run_tests" generates incorrect test_results.xml format output; current proposed-pass1: `closed:stale-24mo`. +- #3492: Enhance the "-o" option of "cci flow run" to accept "project\_\_custom" attribute ; current proposed-pass1: `closed:stale-24mo`. +- #3506: when clause support for flow steps which call other flows; current proposed-pass1: `closed:stale-24mo`. +- #3549: Deploy to Salesforce does not create a test output; current proposed-pass1: `closed:stale-24mo`. +- #3570: Feature Request: Flow "finally" or "error" path; current proposed-pass1: `closed:stale-24mo`. +- #3585: Error Occurs when Using `update_package_xml` on object with `xsi:nil="true"`; current proposed-pass1: `closed:stale-24mo`. +- #3607: The `retry_failures` from the task `run_tests` is not working for me. ; current proposed-pass1: `closed:stale-24mo`. +- #3609: Command 'cci task run dx --command "plugins:install sfdx-browserforce-plugin"' f; current proposed-pass1: `closed:stale-24mo`. +- #3612: Maintain the CumulusCI for VSCode Extension; current proposed-pass1: `closed:stale-24mo`. +- #3618: Allow for list when using deleting/removing CumulusCI orgs (`cci org remove` and; current proposed-pass1: `closed:stale-24mo`. +- #3663: When clause | Ability to pass in prior task response values; current proposed-pass1: `closed:stale-24mo`. + +Recommendation: + +- Leave all other issues in this theme on their current proposed-pass1 plan unless flagged elsewhere in this document. + +### Theme: bulkdata + +Description: Issues about extract_data, load_data, generate_and_load_from_yaml, Snowfakery integration, mapping files, dataset record-type handling, and bulk operations. + +Issues (23): + +#1769, #2013, #2096, #2325, #2505, #2506, #2508, #2930, #2951, #3045, #3203, #3283, #3349, #3353, #3360, #3376, #3649, #3699, #3700, #3701, #3768, #3886, #3936 + +Singletons in theme (no dup): + +- #3886: Required Dependencies?; current proposed-pass1: `kept-open`. +- #3936: Error: HTTPSConnectionPool(host='yoursite.scratch.my.salesforce.com', port=443):; current proposed-pass1: `kept-open`. +- #3349: Make generated dataset recordType tables unique based on table instead of sf_obj; current proposed-pass1: `closed:missing-fields`. +- #3353: Enable Snowfakery task to use recipes from other repositories; current proposed-pass1: `closed:missing-fields`. +- #2930: Exception in task load_dataset; current proposed-pass1: `closed:pre-v4.0.0`. +- #3045: create_bulk_data_permission_set errors on multiple runs; current proposed-pass1: `closed:pre-v4.0.0`. +- #3203: generate_and_load_from_yaml task record type extraction fails for namespaced cus; current proposed-pass1: `closed:pre-v4.0.0`. +- #3376: extract_dataset sql error; current proposed-pass1: `closed:pre-v4.0.0`. +- #1769: Unusual case in test_load; current proposed-pass1: `closed:stale-24mo`. +- #2013: Mapping files with steps that are not 1-1 with SObjects are unreliable for extra; current proposed-pass1: `closed:stale-24mo`. +- #2096: REST dataloads throw errors that Bulk loads do not.; current proposed-pass1: `closed:stale-24mo`. +- #2325: Task to turn off validation rules to allow data insert; current proposed-pass1: `closed:stale-24mo`. +- #2505: Filtering records to be extracted; current proposed-pass1: `closed:stale-24mo`. +- #2506: Bulk Operations should have a --debug mode which maintains logs and tempfiles; current proposed-pass1: `closed:stale-24mo`. +- #2508: Manual load retries; current proposed-pass1: `closed:stale-24mo`. +- #2951: Error in task load_dataset - Standard_price_not_defined; current proposed-pass1: `closed:stale-24mo`. +- #3283: json parser error when empty string passed for date field during upsert or updat; current proposed-pass1: `closed:stale-24mo`. +- #3360: Read Only Object Lookup for Load_Dataset; current proposed-pass1: `closed:stale-24mo`. +- #3649: Support serial loads with update_data task; current proposed-pass1: `closed:stale-24mo`. +- #3699: Sort of the data during extraction; current proposed-pass1: `closed:stale-24mo`. +- #3700: Trying to do an upsert on a master-detail child object gets an error around perm; current proposed-pass1: `closed:stale-24mo`. +- #3701: set a mapping to the id instead of it being either a number or the salesforce id; current proposed-pass1: `closed:stale-24mo`. +- #3768: Snowfakery Batch Size and Just Once; current proposed-pass1: `closed:stale-24mo`. + +Recommendation: + +- Leave all other issues in this theme on their current proposed-pass1 plan unless flagged elsewhere in this document. + +### Theme: dependencies + +Description: Issues about cumulusci.yml dependencies, dependency_pins, update_dependencies, resolution strategy, and version pinning. + +Issues (8): + +#3603, #3604, #3615, #3619, #3641, #3781, #3884, #3886 + +Singletons in theme (no dup): + +- #3886: Required Dependencies?; current proposed-pass1: `kept-open`. +- #3604: Task request: Update sfdx-project.json dependencies based off of computed cumulu; current proposed-pass1: `closed:missing-fields`. +- #3884: Running a Dev_Org flow goes through re-install of the the same package version a; current proposed-pass1: `closed:missing-fields`. +- #3641: Prevent Downgrade of dependencies; current proposed-pass1: `closed:pre-v4.0.0`. +- #3781: Package Versions Starting with 0 (0.1,0.2,0.3, etc.) Cause "does not exist" erro; current proposed-pass1: `closed:pre-v4.0.0`. +- #3603: Any issue with git results in the unhelpful "404 not found" error; current proposed-pass1: `closed:stale-24mo`. +- #3615: update_dependencies does not honor resolution strategy; current proposed-pass1: `closed:stale-24mo`. +- #3619: Dependency_pins does not honor passwords; current proposed-pass1: `closed:stale-24mo`. + +Recommendation: + +- Leave all other issues in this theme on their current proposed-pass1 plan unless flagged elsewhere in this document. + +### Theme: robotframework + +Description: Issues about the Robot Framework integration: Open Test Browser, Selenium and Playwright wrappers, browser options, and standalone library asks. Per task constraints, no internal RF code was inspected; classification is from issue text only. + +Issues (6): + +#675, #987, #3047, #3602, #3873, #3955 + +Singletons in theme (no dup): + +- #3955: Open Test Browser - SalesforcePlaywright.robot; current proposed-pass1: `kept-open`. +- #3873: Standalone Robot Framework Library for Selenium-Based Salesforce Automation (Ins; current proposed-pass1: `closed:missing-fields`. +- #3047: Open Test Browser TypeError: 'NoneType' object is not callable when using useral; current proposed-pass1: `closed:pre-v4.0.0`. +- #675: Show full traceback for Python exceptions in robot keywords; current proposed-pass1: `closed:stale-24mo`. +- #987: Last week this test worked, now I get a javascriptexception message.; current proposed-pass1: `closed:stale-24mo`. +- #3602: Need Chrome/Firefox options(browser options/capabilities) in 'Open Test Browser; current proposed-pass1: `closed:stale-24mo`. + +Recommendation: + +- Leave all other issues in this theme on their current proposed-pass1 plan unless flagged elsewhere in this document. + +### Theme: scratch-org-config + +Description: Issues about scratch org definition files, dev_org and qa_org configuration, namespaced toggles, and JSON schema for scratch_def files. + +Issues (6): + +#710, #2140, #2697, #3306, #3884, #3910 + +Singletons in theme (no dup): + +- #3910: JSON Schema incorrectly defines namespaced field as string instead of boolean fo; current proposed-pass1: `kept-open`. +- #3306: Preview Toggle for Scratch org def file; current proposed-pass1: `closed:missing-fields`. +- #3884: Running a Dev_Org flow goes through re-install of the the same package version a; current proposed-pass1: `closed:missing-fields`. +- #710: Allow disabling default scratch org configs; current proposed-pass1: `closed:stale-24mo`. +- #2140: Prompt Org Configs when Org Does Not Exist and Command Runs Against It; current proposed-pass1: `closed:stale-24mo`. +- #2697: Initialization issue with 'namespaced' field in 'cci org info' after updating fr; current proposed-pass1: `closed:stale-24mo`. + +Recommendation: + +- Leave all other issues in this theme on their current proposed-pass1 plan unless flagged elsewhere in this document. + +### Theme: ci-integration + +Description: Issues about MetaCI, GitHub Actions integration, github_automerge_feature, and merge-conflict tooling. + +Issues (5): + +#2153, #3471, #3479, #3717, #3887 + +Singletons in theme (no dup): + +- #3887: Version comparison bug: 0.10.0.1 incorrectly compared as less than 0.9.0.1; current proposed-pass1: `closed:pre-v4.0.0`. +- #2153: Add comment to original PR which tags all branch subscribers when a merge confli; current proposed-pass1: `closed:stale-24mo`. +- #3471: `Merged 0 commits into branch:` message displays when a non-Source Code change i; current proposed-pass1: `closed:stale-24mo`. +- #3479: Error with "cci org import" in github action; current proposed-pass1: `closed:stale-24mo`. +- #3717: Github automerge feature task not working when running through Github Flows; current proposed-pass1: `closed:stale-24mo`. + +Recommendation: + +- Leave all other issues in this theme on their current proposed-pass1 plan unless flagged elsewhere in this document. + +### Theme: auth + +Description: Issues about OAuth refresh, JWT, connected app handling, GitHub Enterprise auth, and the github service connection. + +Issues (5): + +#2667, #2973, #3182, #3810, #3852 + +Singletons in theme (no dup): + +- #3852: CumulusCI 4 refresh token error; current proposed-pass1: `kept-open`. +- #2667: `cci org connect` should output the name of the connected app it is using, espec; current proposed-pass1: `closed:missing-fields`. +- #2973: cumulusci.tasks.salesforce.CreateCommunity has no option to set authentication m; current proposed-pass1: `closed:pre-v4.0.0`. +- #3182: "Error: 'utf-8' codec can't decode byte 0x80 in position 0: invalid start byte" ; current proposed-pass1: `closed:pre-v4.0.0`. +- #3810: Github tasks fail when using github enterprise; current proposed-pass1: `closed:pre-v4.0.0`. + +Recommendation: + +- Leave all other issues in this theme on their current proposed-pass1 plan unless flagged elsewhere in this document. + +### Theme: keychain + +Description: Issues about the encrypted keychain, service config, set_service typing, password_env_name handling, and SFDX alias integration. + +Issues (5): + +#2126, #3407, #3541, #3546, #3619 + +Singletons in theme (no dup): + +- #2126: Support task to encrypt all possible fields with probabilistic encryption; current proposed-pass1: `closed:missing-fields`. +- #3546: password_env_name bleeding over to next package; current proposed-pass1: `closed:pre-v4.0.0`. +- #3407: `set_service(service_config)` type signature is wrong; current proposed-pass1: `closed:stale-24mo`. +- #3541: Getting None\_\_dev as SFDX Alias ; current proposed-pass1: `closed:stale-24mo`. +- #3619: Dependency_pins does not honor passwords; current proposed-pass1: `closed:stale-24mo`. + +Recommendation: + +- Leave all other issues in this theme on their current proposed-pass1 plan unless flagged elsewhere in this document. + +### Theme: docs + +Description: Issues that ask for documentation improvements: undocumented options, project config docs, README updates. + +Issues (4): + +#773, #2500, #3464, #3471 + +Singletons in theme (no dup): + +- #2500: ignore_failure is not documented; current proposed-pass1: `closed:missing-fields`. +- #773: Document task return values and results; current proposed-pass1: `closed:stale-24mo`. +- #3464: Provide concise documentation of cumulusci.yml `project` configuration options; current proposed-pass1: `closed:stale-24mo`. +- #3471: `Merged 0 commits into branch:` message displays when a non-Source Code change i; current proposed-pass1: `closed:stale-24mo`. + +Recommendation: + +- Leave all other issues in this theme on their current proposed-pass1 plan unless flagged elsewhere in this document. + +### Theme: python-modernization + +Description: Issues caused by upstream Python ecosystem changes: urllib3, cryptography, OpenSSL, Python version compatibility. + +Issues (3): + +#3609, #3610, #3849 + +Singletons in theme (no dup): + +- #3849: Installing CumulusCI v 4 installs the latest version of urllib3 which seems to b; current proposed-pass1: `kept-open`. +- #3609: Command 'cci task run dx --command "plugins:install sfdx-browserforce-plugin"' f; current proposed-pass1: `closed:stale-24mo`. +- #3610: Error running `run_tests` task; current proposed-pass1: `closed:stale-24mo`. + +Recommendation: + +- Leave all other issues in this theme on their current proposed-pass1 plan unless flagged elsewhere in this document. + +## Tranche recommendations + +Surviving canonical set (16 issues): the 15 issues already proposed as +`kept-open` plus #3544, promoted by Cluster A. The 126 closure-bound +issues are not assigned to a tranche; they remain on their proposed-pass1 +plan unless the user re-categorizes them. + +### Tranche 1: v5.0 must-fix (effort:small) + +#3852, #3938, #3939, #3849, #3936 + +Rationale: each issue is a recently active bug (within 12 months) in a +core workflow with a clean reproduction. + +- #3852: CumulusCI 4 refresh token error; auth, broken since v4 upgrade, + 5 comments, clear traceback in body. +- #3938: Rest_Deploy ignores errors; deploy correctness, December 2025, + identified offending code path in body. +- #3939: Deploy task can't parse SOAP Response; companion to #3938 from + the same author, separate code path (rest_deploy: False), kept as a + distinct fix because the failing parser code is different. +- #3849: urllib3 incompatibility with Robot tests after CCI v4 install; + 12 comments, well-scoped pin workaround documented. +- #3936: HTTPSConnectionPool read timeout in Snowfakery + bulkdata flow; + recent (2025-12-03), reproducible against any large dataset run. + +### Tranche 2: v5.0 nice-to-have (effort:small/medium) + +#3910, #3953, #3951, #3899, #3902, #3955, #3854, #3886, #3929 + +Rationale: well-scoped fixes or UX improvements with a clean repro and +limited blast radius. None block a major workflow on their own. + +- #3910: JSON Schema namespaced field type wrong; one-line schema fix. +- #3953: add_picklist_entries fails through CLI because entries arrive + as a string instead of a list; small parsing fix. +- #3951: set_duplicate_rule_status broken; small ETL fix. +- #3899: deploy_packaging.unschedule_apex exception in Trailhead module; + small fix, but the trail through Trailhead means user-visible. +- #3902: install_managed security_type not respected with 04t ID. +- #3955: Open Test Browser viewport.width type error in + SalesforcePlaywright; small Playwright integration fix. +- #3854: capture_sample_data total mapping operations error; bulkdata + UX with reproducible failure. +- #3886: extract_dataset "Optional dependencies missing" message; minor + installer hygiene fix. +- #3929: cci task run create_community appears to loop / timeout; + marked needs-repro in proposals.md but recent activity (2025-10-22). + +### Tranche 3: v5.x post-GA (effort:medium/large) + +#3931, #3544 + +Rationale: deeper investigation needed; affects edge configurations. + +- #3931: ProfileGrantAllAccess error when specifying a profile; + needs-investigation, deeper metadata-etl rework. +- #3544: update_admin_profile fails on namespaced + Person Accounts. + Promoted from `closed:pre-v4.0.0` by Cluster A. Root cause may sit + partially in SFDX behavior, so the fix likely requires investigation + of how CCI requests record types from the org. + +### Tranche 4: deferred or won't-fix + +Empty in this analysis. The 126 closure-bound issues remain on their +proposals.md plan; treat them as Tranche 4 if a future controller +decides to re-open any. None of the surviving canonicals belong here. + +## Dedup statistics + +- Total issues analyzed: 142 +- Duplicate clusters found: 1 +- Issues subsumed by clusters: 1 +- Net unique signals after dedup: 142 - 1 = 141 +- Cross-theme dup clusters: 0 + +## Borderline classification calls + +These are pairs that scored high on title and body similarity but were +rejected as dups because the underlying problems are distinct. They may +still benefit from joint resolution and are surfaced here for the +controller's review. + +- #3938 + #3939 (theme: metadata-etl). Same author, same day, same task + family (deploy). #3938 hits the rest_deploy=True code path; #3939 + hits the rest_deploy=False (SOAP) code path. Different parsers, kept + as separate Tranche 1 items. +- #3347 + #3441 (theme: packaging). Both touch + release_unlocked_beta + version_base. #3347 (2022-08-29) is a 1-line + bug report against the default; #3441 (2023-12-15) is a feature ask + to permit overriding the default. Same root area, different framings. +- #3546 + #3619 (theme: dependencies / keychain). Both involve install + keys. #3546 is `password_env_name` bleeding across consecutive + dependencies; #3619 is `dependency_pins` not honoring passwords at + all. Distinct code paths. +- #3015 + #3618 + #3733 (theme: cli). All touch `cci org remove`. #3015 + is a feature ask (decouple from underlying scratch org); #3618 asks + for batch removal; #3733 is a bug where the command silently fails + after the org was deleted via the sf CLI. +- #3047 + #3955 + #3602 (theme: robotframework). All involve Open Test + Browser. Each is a distinct concern (useralias param, viewport type, + browser options request). +- #3137 + #3331 + #3585 + #3589 + #3692 (theme: metadata-etl). All are + distinct bugs in update_package_xml: Case object decomposition, + AssignmentRule pluralization, xsi:nil handling, Workflow and + MatchingRules removal, digitalExperiences subdirectory parser. A + metadata_map.yml refresh might address several at once but each + reproduces independently. +- #3506 + #3663 + #3570 (theme: cli). All are flow-control feature + requests (when clauses for sub-flows; when clauses with task + response references; finally / error path). Distinct enhancements. + +## Anomalies + +- All 142 issues classified into at least one theme (no `unclassified` + residue after refining keyword rules). All issue bodies are in + English. +- No theme exceeded 8 duplicate clusters (the maximum is 1, in + metadata-etl). +- No duplicate cluster has 5+ members; the only confirmed cluster has 2. +- Per task constraints, no file under `cumulusci/robotframework/` was + read. Robot Framework theme classification used title and body text + only. From 2fa6ad84665249a3cb8031ac4feade1785e16162 Mon Sep 17 00:00:00 2001 From: James Estevez Date: Thu, 14 May 2026 09:52:56 -0700 Subject: [PATCH 2/4] test(triage): harvest 73 regression-repro tests from triage pass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds cumulusci/tests/triage/ with 73 xfail tests, one per REPRODUCED-on-dev or REPRODUCED-on-v4.10.0 issue with a code-level assertion target: - 10 from Round 3 (themes covered: keychain, robotframework, docs, python-modernization, auth, plus stragglers) - 63 from Wave A retroactive recovery (all R1+R2 REPRODUCED issues with code-level repros, split across recover-1..4 subagents) Run results: 79 xfailed, 0 xpassed (3 non-xfail "control" tests emitted by some subagents were removed during harvest to keep the directory xfail-only per cumulusci/tests/triage/README.md). Test convention: - @pytest.mark.xfail(strict=False, reason="repro for #NNNN — ...") - Each captures a code-level assertion that the fix-PR will flip green - strict=False means an independent fix surfaces as XPASS, not a CI failure - 10 R3 test files had stale path refs (docs/triage/2026-05-cci-backlog/) normalized to docs/triage/v5/ README at cumulusci/tests/triage/README.md documents the convention, lifecycle, and cross-refs to docs/triage/v5/. Plan reference: docs/superpowers/plans/2026-05-14-cci-triage-upstream-plan.md Task 7 (harvest xfail tests). --- cumulusci/tests/triage/README.md | 50 ++++++++++ cumulusci/tests/triage/__init__.py | 0 cumulusci/tests/triage/test_issue_1348.py | 46 +++++++++ cumulusci/tests/triage/test_issue_1432.py | 50 ++++++++++ cumulusci/tests/triage/test_issue_1769.py | 47 +++++++++ cumulusci/tests/triage/test_issue_2013.py | 51 ++++++++++ cumulusci/tests/triage/test_issue_2140.py | 46 +++++++++ cumulusci/tests/triage/test_issue_2153.py | 48 ++++++++++ cumulusci/tests/triage/test_issue_2325.py | 53 +++++++++++ cumulusci/tests/triage/test_issue_2402.py | 33 +++++++ cumulusci/tests/triage/test_issue_2500.py | 58 +++++++++++ cumulusci/tests/triage/test_issue_2506.py | 40 ++++++++ cumulusci/tests/triage/test_issue_2507.py | 41 ++++++++ cumulusci/tests/triage/test_issue_2508.py | 47 +++++++++ cumulusci/tests/triage/test_issue_2826.py | 46 +++++++++ cumulusci/tests/triage/test_issue_2951.py | 47 +++++++++ cumulusci/tests/triage/test_issue_2979.py | 43 +++++++++ cumulusci/tests/triage/test_issue_3015.py | 36 +++++++ cumulusci/tests/triage/test_issue_3024.py | 56 +++++++++++ cumulusci/tests/triage/test_issue_3137.py | 40 ++++++++ cumulusci/tests/triage/test_issue_3161.py | 35 +++++++ cumulusci/tests/triage/test_issue_3165.py | 55 +++++++++++ cumulusci/tests/triage/test_issue_3307.py | 37 ++++++++ cumulusci/tests/triage/test_issue_3331.py | 46 +++++++++ cumulusci/tests/triage/test_issue_3349.py | 64 +++++++++++++ cumulusci/tests/triage/test_issue_3353.py | 49 ++++++++++ cumulusci/tests/triage/test_issue_3407.py | 111 ++++++++++++++++++++++ cumulusci/tests/triage/test_issue_3429.py | 47 +++++++++ cumulusci/tests/triage/test_issue_3440.py | 44 +++++++++ cumulusci/tests/triage/test_issue_3441.py | 42 ++++++++ cumulusci/tests/triage/test_issue_3446.py | 35 +++++++ cumulusci/tests/triage/test_issue_3464.py | 62 ++++++++++++ cumulusci/tests/triage/test_issue_3470.py | 41 ++++++++ cumulusci/tests/triage/test_issue_3471.py | 44 +++++++++ cumulusci/tests/triage/test_issue_3485.py | 60 ++++++++++++ cumulusci/tests/triage/test_issue_3492.py | 46 +++++++++ cumulusci/tests/triage/test_issue_3506.py | 46 +++++++++ cumulusci/tests/triage/test_issue_3518.py | 43 +++++++++ cumulusci/tests/triage/test_issue_3541.py | 82 ++++++++++++++++ cumulusci/tests/triage/test_issue_3543.py | 35 +++++++ cumulusci/tests/triage/test_issue_3549.py | 37 ++++++++ cumulusci/tests/triage/test_issue_3570.py | 53 +++++++++++ cumulusci/tests/triage/test_issue_3585.py | 73 ++++++++++++++ cumulusci/tests/triage/test_issue_3593.py | 48 ++++++++++ cumulusci/tests/triage/test_issue_3602.py | 73 ++++++++++++++ cumulusci/tests/triage/test_issue_3603.py | 69 ++++++++++++++ cumulusci/tests/triage/test_issue_3604.py | 51 ++++++++++ cumulusci/tests/triage/test_issue_3613.py | 65 +++++++++++++ cumulusci/tests/triage/test_issue_3618.py | 49 ++++++++++ cumulusci/tests/triage/test_issue_3619.py | 60 ++++++++++++ cumulusci/tests/triage/test_issue_3649.py | 38 ++++++++ cumulusci/tests/triage/test_issue_3663.py | 54 +++++++++++ cumulusci/tests/triage/test_issue_3692.py | 41 ++++++++ cumulusci/tests/triage/test_issue_3699.py | 36 +++++++ cumulusci/tests/triage/test_issue_3700.py | 63 ++++++++++++ cumulusci/tests/triage/test_issue_3701.py | 41 ++++++++ cumulusci/tests/triage/test_issue_3721.py | 39 ++++++++ cumulusci/tests/triage/test_issue_3734.py | 57 +++++++++++ cumulusci/tests/triage/test_issue_3746.py | 58 +++++++++++ cumulusci/tests/triage/test_issue_3754.py | 52 ++++++++++ cumulusci/tests/triage/test_issue_3758.py | 44 +++++++++ cumulusci/tests/triage/test_issue_3768.py | 71 ++++++++++++++ cumulusci/tests/triage/test_issue_3771.py | 51 ++++++++++ cumulusci/tests/triage/test_issue_3773.py | 44 +++++++++ cumulusci/tests/triage/test_issue_3849.py | 78 +++++++++++++++ cumulusci/tests/triage/test_issue_3889.py | 54 +++++++++++ cumulusci/tests/triage/test_issue_3910.py | 73 ++++++++++++++ cumulusci/tests/triage/test_issue_3931.py | 82 ++++++++++++++++ cumulusci/tests/triage/test_issue_3951.py | 50 ++++++++++ cumulusci/tests/triage/test_issue_3953.py | 58 +++++++++++ cumulusci/tests/triage/test_issue_3955.py | 92 ++++++++++++++++++ cumulusci/tests/triage/test_issue_710.py | 85 +++++++++++++++++ cumulusci/tests/triage/test_issue_733.py | 34 +++++++ cumulusci/tests/triage/test_issue_773.py | 75 +++++++++++++++ cumulusci/tests/triage/test_issue_808.py | 37 ++++++++ 75 files changed, 3887 insertions(+) create mode 100644 cumulusci/tests/triage/README.md create mode 100644 cumulusci/tests/triage/__init__.py create mode 100644 cumulusci/tests/triage/test_issue_1348.py create mode 100644 cumulusci/tests/triage/test_issue_1432.py create mode 100644 cumulusci/tests/triage/test_issue_1769.py create mode 100644 cumulusci/tests/triage/test_issue_2013.py create mode 100644 cumulusci/tests/triage/test_issue_2140.py create mode 100644 cumulusci/tests/triage/test_issue_2153.py create mode 100644 cumulusci/tests/triage/test_issue_2325.py create mode 100644 cumulusci/tests/triage/test_issue_2402.py create mode 100644 cumulusci/tests/triage/test_issue_2500.py create mode 100644 cumulusci/tests/triage/test_issue_2506.py create mode 100644 cumulusci/tests/triage/test_issue_2507.py create mode 100644 cumulusci/tests/triage/test_issue_2508.py create mode 100644 cumulusci/tests/triage/test_issue_2826.py create mode 100644 cumulusci/tests/triage/test_issue_2951.py create mode 100644 cumulusci/tests/triage/test_issue_2979.py create mode 100644 cumulusci/tests/triage/test_issue_3015.py create mode 100644 cumulusci/tests/triage/test_issue_3024.py create mode 100644 cumulusci/tests/triage/test_issue_3137.py create mode 100644 cumulusci/tests/triage/test_issue_3161.py create mode 100644 cumulusci/tests/triage/test_issue_3165.py create mode 100644 cumulusci/tests/triage/test_issue_3307.py create mode 100644 cumulusci/tests/triage/test_issue_3331.py create mode 100644 cumulusci/tests/triage/test_issue_3349.py create mode 100644 cumulusci/tests/triage/test_issue_3353.py create mode 100644 cumulusci/tests/triage/test_issue_3407.py create mode 100644 cumulusci/tests/triage/test_issue_3429.py create mode 100644 cumulusci/tests/triage/test_issue_3440.py create mode 100644 cumulusci/tests/triage/test_issue_3441.py create mode 100644 cumulusci/tests/triage/test_issue_3446.py create mode 100644 cumulusci/tests/triage/test_issue_3464.py create mode 100644 cumulusci/tests/triage/test_issue_3470.py create mode 100644 cumulusci/tests/triage/test_issue_3471.py create mode 100644 cumulusci/tests/triage/test_issue_3485.py create mode 100644 cumulusci/tests/triage/test_issue_3492.py create mode 100644 cumulusci/tests/triage/test_issue_3506.py create mode 100644 cumulusci/tests/triage/test_issue_3518.py create mode 100644 cumulusci/tests/triage/test_issue_3541.py create mode 100644 cumulusci/tests/triage/test_issue_3543.py create mode 100644 cumulusci/tests/triage/test_issue_3549.py create mode 100644 cumulusci/tests/triage/test_issue_3570.py create mode 100644 cumulusci/tests/triage/test_issue_3585.py create mode 100644 cumulusci/tests/triage/test_issue_3593.py create mode 100644 cumulusci/tests/triage/test_issue_3602.py create mode 100644 cumulusci/tests/triage/test_issue_3603.py create mode 100644 cumulusci/tests/triage/test_issue_3604.py create mode 100644 cumulusci/tests/triage/test_issue_3613.py create mode 100644 cumulusci/tests/triage/test_issue_3618.py create mode 100644 cumulusci/tests/triage/test_issue_3619.py create mode 100644 cumulusci/tests/triage/test_issue_3649.py create mode 100644 cumulusci/tests/triage/test_issue_3663.py create mode 100644 cumulusci/tests/triage/test_issue_3692.py create mode 100644 cumulusci/tests/triage/test_issue_3699.py create mode 100644 cumulusci/tests/triage/test_issue_3700.py create mode 100644 cumulusci/tests/triage/test_issue_3701.py create mode 100644 cumulusci/tests/triage/test_issue_3721.py create mode 100644 cumulusci/tests/triage/test_issue_3734.py create mode 100644 cumulusci/tests/triage/test_issue_3746.py create mode 100644 cumulusci/tests/triage/test_issue_3754.py create mode 100644 cumulusci/tests/triage/test_issue_3758.py create mode 100644 cumulusci/tests/triage/test_issue_3768.py create mode 100644 cumulusci/tests/triage/test_issue_3771.py create mode 100644 cumulusci/tests/triage/test_issue_3773.py create mode 100644 cumulusci/tests/triage/test_issue_3849.py create mode 100644 cumulusci/tests/triage/test_issue_3889.py create mode 100644 cumulusci/tests/triage/test_issue_3910.py create mode 100644 cumulusci/tests/triage/test_issue_3931.py create mode 100644 cumulusci/tests/triage/test_issue_3951.py create mode 100644 cumulusci/tests/triage/test_issue_3953.py create mode 100644 cumulusci/tests/triage/test_issue_3955.py create mode 100644 cumulusci/tests/triage/test_issue_710.py create mode 100644 cumulusci/tests/triage/test_issue_733.py create mode 100644 cumulusci/tests/triage/test_issue_773.py create mode 100644 cumulusci/tests/triage/test_issue_808.py diff --git a/cumulusci/tests/triage/README.md b/cumulusci/tests/triage/README.md new file mode 100644 index 0000000000..aaa1f1d0ff --- /dev/null +++ b/cumulusci/tests/triage/README.md @@ -0,0 +1,50 @@ +# `cumulusci/tests/triage/` + +Regression-repro tests for open issues. Each test file targets one +issue. + +## Conventions + +- File naming: `test_issue_.py` where `` is the GitHub + issue number. +- Every test in this directory uses `@pytest.mark.xfail(strict=False)` + by default. The xfail marker captures the expected failure mode and + is removed by the corresponding fix-PR. +- `strict=False` is intentional: if a bug resolves independently (a + different PR lands, an upstream dependency is fixed, etc.), the + test will `XPASS` rather than fail CI. A harvest pass periodically + converts `XPASS` issues to `NOT-REPRODUCED-on-dev` and either + rewrites the test or drops it. +- Tests MUST be fast (`< 2s`), import-only or mocked. No live + Salesforce org, no real network, no scratch-org creation. Use + `unittest.mock` / fixtures liberally. + +## Lifecycle + +1. Triage subagent verifies a bug reproduces on `origin/dev`. +2. Subagent writes `test_issue_.py` with `@pytest.mark.xfail` + + a code-level assertion that captures the bug. +3. Test is committed to this directory via the triage umbrella PR. +4. When the bug is fixed: + - Fix-PR removes the `@pytest.mark.xfail` marker. + - Fix-PR confirms the test now passes. + - Fix-PR moves the test out of this directory to its natural + home (e.g. `cumulusci/tasks//tests/`) — or leaves it + here with the marker removed, whichever is cleaner. + +## See also + +- `docs/triage/v5/repro-results.md` — narrative evidence per issue. +- `docs/triage/v5/fix-sketches/issue_.md` — proposed fix + approach per issue. +- `docs/triage/v5/proposals.md` — pass-1 classification matrix. + +## Running + +```bash +uv run pytest cumulusci/tests/triage/ -v +``` + +Expected outcome: every test reports `XFAIL`. If any reports `XPASS`, +that is signal that a bug resolved independently — see the harvest +xpass list in `docs/triage/v5/` (if present). diff --git a/cumulusci/tests/triage/__init__.py b/cumulusci/tests/triage/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cumulusci/tests/triage/test_issue_1348.py b/cumulusci/tests/triage/test_issue_1348.py new file mode 100644 index 0000000000..247ed582dd --- /dev/null +++ b/cumulusci/tests/triage/test_issue_1348.py @@ -0,0 +1,46 @@ +"""Regression repro for #1348. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: CumulusCI is GitHub-only. There are no `gitlab` or +`bitbucket` references in the `cumulusci/` package, and the +`ci_feature` flow still hardcodes GitHub-specific tasks +(`github_parent_pr_notes`, `github_automerge_feature`). The +2017 feature ask is to add a VCS abstraction so projects on +other providers can use CumulusCI. + +This test loads the universal cumulusci.yml and asserts that +`ci_feature` does NOT step into any GitHub-specific task — +which it does today, so this fails -> XFAIL. +""" + +import pytest + +from cumulusci.utils.yaml.cumulusci_yml import cci_safe_load +from pathlib import Path + +import cumulusci + + +@pytest.mark.xfail( + reason="repro for #1348 — see docs/triage/v5/repro-results.md", + strict=False, +) +def test_issue_1348(): + universal_yaml = Path(cumulusci.__file__).resolve().parent / "cumulusci.yml" + config = cci_safe_load(universal_yaml.open(), str(universal_yaml)) + flows = config.get("flows", {}) + ci_feature = flows.get("ci_feature") or {} + steps = ci_feature.get("steps", {}) + step_text = " ".join( + str(step.get("task") or step.get("flow") or "") for step in steps.values() + ) + has_github_specific = ( + "github_parent_pr_notes" in step_text or "github_automerge_feature" in step_text + ) + assert not has_github_specific, ( + "ci_feature still references GitHub-specific tasks; no VCS " + "abstraction exposed for GitLab/Bitbucket users (see #1348)." + ) diff --git a/cumulusci/tests/triage/test_issue_1432.py b/cumulusci/tests/triage/test_issue_1432.py new file mode 100644 index 0000000000..ce2df831c6 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_1432.py @@ -0,0 +1,50 @@ +"""Regression repro for #1432. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (no_reverify_needed). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: ``BaseTask._validate_options`` (cumulusci/core/tasks.py +around lines 187-197) only checks for *missing* required options when +the task uses the legacy ``task_options`` dict. Unknown keys are +silently accepted — passing ``-o colour red`` to a task that declares +``color`` results in no error. + +The new-style Pydantic ``Options`` class path *does* reject extras +(``"extra options"`` message in the same file), so the bug is partially +mitigated for tasks that opt in. Legacy ``task_options`` dict tasks +remain affected. + +The fix is to also reject unknown keys when validating the legacy +dict-style options. This test asserts the source of +``BaseTask._validate_options`` checks for unknown keys; on dev it fails +because only ``required`` is checked. +""" + +import inspect + +import pytest + +from cumulusci.core.tasks import BaseTask + + +@pytest.mark.xfail( + reason="repro for #1432 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_1432(): + src = inspect.getsource(BaseTask._validate_options) + has_unknown_check = any( + token in src + for token in ( + "not in self.task_options", + "not in task_options", + "unknown", + "unexpected", + "extra option", + ) + ) + assert has_unknown_check, ( + "BaseTask._validate_options still only checks for missing required " + "options; unknown task_options keys are silently accepted for legacy " + "task_options-dict tasks (see #1432)" + ) diff --git a/cumulusci/tests/triage/test_issue_1769.py b/cumulusci/tests/triage/test_issue_1769.py new file mode 100644 index 0000000000..eee68b0343 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_1769.py @@ -0,0 +1,47 @@ +"""Regression repro for #1769. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: cumulusci/tasks/bulkdata/tests/test_load.py still uses the +2020-vintage pattern `lookups["Id"] = MappingLookup(name="Id", +table="accounts", key_field="sf_id")` (line 739 and several siblings: +~754, 773, 801, 1119, 1187, 1255) to describe an after-step's +UPDATE-on-Id dependency. davidmreed acknowledged in 2020 that this +is a "horrible hack" he intended to clean up; six years later it +remains in the test file. + +A real fix would remove `Id` from the `lookups` dict (or stop using +`MappingLookup` to express the self-update relationship) and have +the after-step logic synthesize that relationship internally. + +This test asserts that the offending pattern is absent from test_load.py. +On dev the pattern is present, so the assertion fails -> XFAIL. +""" + +from pathlib import Path + +import pytest + +import cumulusci + + +@pytest.mark.xfail( + reason="repro for #1769 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_1769(): + test_load_path = ( + Path(cumulusci.__file__).parent + / "tasks" + / "bulkdata" + / "tests" + / "test_load.py" + ) + text = test_load_path.read_text() + bad_pattern = 'lookups["Id"] = MappingLookup(' + assert bad_pattern not in text, ( + f"test_load.py still contains the 2020-vintage smell {bad_pattern!r}; " + "expected the after-step Id-update relationship to be expressed " + "without injecting a MappingLookup keyed on 'Id'." + ) diff --git a/cumulusci/tests/triage/test_issue_2013.py b/cumulusci/tests/triage/test_issue_2013.py new file mode 100644 index 0000000000..a7ce4becf5 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_2013.py @@ -0,0 +1,51 @@ +"""Regression repro for #2013. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: cumulusci.tasks.bulkdata.utils.create_table_if_needed builds +a SQLAlchemy `Table(tablename, metadata, *fields)` before calling +`inspector.has_table()`. When two mapping steps share the same +sf_object name, the SQLAlchemy `Table()` constructor raises +`InvalidRequestError: Table 'X' is already defined ...` BEFORE the +intended `BulkDataException("Table already exists: ...")` is raised. + +The fix is to either (a) wrap the `Table()` call in a try/except and +re-raise as BulkDataException, or (b) validate uniqueness at +mapping-parse time. Either way, when the table already exists in the +metadata, callers should observe a CumulusCI-typed BulkDataException, +not a SQLAlchemy-typed InvalidRequestError. +""" + +from sqlalchemy import Column, MetaData, String, create_engine + +import pytest + +from cumulusci.core.exceptions import BulkDataException +from cumulusci.tasks.bulkdata.utils import create_table_if_needed + + +@pytest.mark.xfail( + reason="repro for #2013 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_2013(): + engine = create_engine("sqlite:///:memory:") + metadata = MetaData(bind=engine) + + create_table_if_needed( + "Account", metadata, [Column("sf_id", String(255), primary_key=True)] + ) + + raised = None + try: + create_table_if_needed( + "Account", metadata, [Column("sf_id", String(255), primary_key=True)] + ) + except BaseException as e: + raised = e + + assert isinstance(raised, BulkDataException), ( + "Expected BulkDataException for duplicate table; " + f"got {type(raised).__name__}: {raised}" + ) diff --git a/cumulusci/tests/triage/test_issue_2140.py b/cumulusci/tests/triage/test_issue_2140.py new file mode 100644 index 0000000000..9fabab9ae0 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_2140.py @@ -0,0 +1,46 @@ +"""Regression repro for #2140. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: `CliRuntime.get_org()` in cumulusci/cli/runtime.py +hard-errors with `click.UsageError("No org specified and no +default org set.")` when the requested org does not exist in +the keychain (or `OrgNotFound` from `keychain.get_org()` +bubbles up to `cli/org.py` as a plain ClickException). The 2020 +ask is to instead surface an interactive prompt that lets the +user pick from configured scratch org configs. + +This test asserts that `get_org` source contains a prompt +mechanism (click.prompt / click.Choice / scratch-config-listing +helper). On dev it doesn't, so the assertion fails -> XFAIL. +""" + +import inspect + +import pytest + +from cumulusci.cli.runtime import CliRuntime + + +@pytest.mark.xfail( + reason="repro for #2140 — see docs/triage/v5/repro-results.md", + strict=False, +) +def test_issue_2140(): + src = inspect.getsource(CliRuntime.get_org) + has_prompt = any( + token in src + for token in ( + "click.prompt", + "click.confirm", + "click.Choice", + "scratch_configs", + "scratch configs", + ) + ) + assert has_prompt, ( + "CliRuntime.get_org still hard-errors when no org is found; " + "no interactive scratch-config picker (see #2140)." + ) diff --git a/cumulusci/tests/triage/test_issue_2153.py b/cumulusci/tests/triage/test_issue_2153.py new file mode 100644 index 0000000000..eb712b0008 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_2153.py @@ -0,0 +1,48 @@ +"""Regression repro for #2153. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: `MergeBranch._create_conflict_pull_request` +(cumulusci/tasks/github/merge.py:264-288) only calls +`self.repo.create_pull(...)` to open the auto-generated +"Merge into " PR. The original 2020 ask is to +also drop a comment on the source/child PR which tags the branch +subscribers so they get notified about the conflict. + +A repo-wide search for `create_comment`/`issue_comment` returns +only test-fixture hits — production GitHub task code never +opens a PR/issue comment as part of this conflict path. + +This test asserts that the merge task surface mentions a +comment-posting call. On dev it doesn't, so the assertion fails +-> XFAIL. +""" + +import inspect + +import pytest + +from cumulusci.tasks.github.merge import MergeBranch + + +@pytest.mark.xfail( + reason="repro for #2153 — see docs/triage/v5/repro-results.md", + strict=False, +) +def test_issue_2153(): + src = inspect.getsource(MergeBranch) + posts_comment = any( + token in src + for token in ( + "create_comment", + "issue_comment", + "post_comment", + ) + ) + assert posts_comment, ( + "MergeBranch still only opens an auto-merge PR on conflict; " + "no comment-on-original-PR path found to notify branch " + "subscribers (see #2153)." + ) diff --git a/cumulusci/tests/triage/test_issue_2325.py b/cumulusci/tests/triage/test_issue_2325.py new file mode 100644 index 0000000000..425d88ff73 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_2325.py @@ -0,0 +1,53 @@ +"""Regression repro for #2325. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (no_reverify_needed). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: CumulusCI ships ``disable_tdtm_trigger_handlers`` / +``restore_tdtm_trigger_handlers`` (cumulusci.yml:738-747) for triggers +and ``set_duplicate_rule_status`` for DuplicateRule, but offers no +analogous task for toggling Salesforce ValidationRules around a data +load. The user requested an OOTB ``set_validation_rule_status`` / +``disable_validation_rules`` task; ``cci task list | grep -i validation`` +returns only the duplicate-rule task on v4.10.0. + +The fix is to add a ``MetadataSingleEntityTransformTask`` subclass for +``entity = "ValidationRule"`` and wire it into ``cumulusci.yml`` with +both disable/restore (or set-status) flavours, mirroring the existing +TDTM/DuplicateRule pattern. + +This test asserts ``cumulusci.yml`` declares at least one validation-rule +toggle task; on dev it fails because no such task exists. +""" + +from pathlib import Path + +import pytest +import yaml + +import cumulusci + + +@pytest.mark.xfail( + reason="repro for #2325 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_2325(): + cci_root = Path(cumulusci.__file__).parent + with open(cci_root / "cumulusci.yml") as f: + data = yaml.safe_load(f) + + task_names = set(data.get("tasks", {}).keys()) + candidates = { + "set_validation_rule_status", + "disable_validation_rules", + "restore_validation_rules", + "activate_validation_rules", + "deactivate_validation_rules", + } + intersection = task_names & candidates + assert intersection, ( + "cumulusci.yml still ships no ValidationRule toggle task. Expected one " + f"of {sorted(candidates)} to mirror the disable_tdtm_trigger_handlers / " + "set_duplicate_rule_status pattern (see #2325)" + ) diff --git a/cumulusci/tests/triage/test_issue_2402.py b/cumulusci/tests/triage/test_issue_2402.py new file mode 100644 index 0000000000..890eefadd0 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_2402.py @@ -0,0 +1,33 @@ +"""Regression repro for #2402. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: `cci flow run` (cumulusci/cli/flow.py:119-145) only exposes +`--delete-org`; there is no `--rebuild-org` switch that would delete +the scratch org before re-running the flow against a freshly-created +one. Users currently have to chain `cci org scratch_delete X && cci +flow run X` manually. + +This test asserts that the `flow run` Click command exposes a +`--rebuild-org` (or equivalent `rebuild_org` parameter). On dev no +such option exists, so the assertion fails -> XFAIL. +""" + +import pytest + +from cumulusci.cli.flow import flow_run + + +@pytest.mark.xfail( + reason="repro for #2402 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_2402(): + param_names = {p.name for p in flow_run.params} + assert "rebuild_org" in param_names or any( + "rebuild-org" in flag for p in flow_run.params for flag in (p.opts or []) + ), ( + "Expected `cci flow run` to expose a --rebuild-org option for " + f"convenience; got params {sorted(param_names)!r}." + ) diff --git a/cumulusci/tests/triage/test_issue_2500.py b/cumulusci/tests/triage/test_issue_2500.py new file mode 100644 index 0000000000..0dbbba8e50 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_2500.py @@ -0,0 +1,58 @@ +"""Repro for SFDO-Tooling/CumulusCI#2500 — ``ignore_failure`` is not documented. + +The ``ignore_failure`` flow-step option has existed since flowrunner was +introduced (see ``cumulusci/core/flowrunner.py`` and +``cumulusci/utils/yaml/cumulusci_yml.py``), but ``docs/config.md`` only +*uses* it inside one example YAML snippet (and ``docs/history.md`` mentions +its introduction in the changelog). No section in the user-facing +"Flow Configurations" chapter explains the option, in contrast to +sibling step options like ``when`` (documented under "Conditionally Run a +Flow Step") or "Skip a Flow Step". + +This test pins down both halves of the gap: + +1. ``ignore_failure`` is a recognised step-level option (sanity check — + the feature really exists and we are not chasing a phantom doc). +2. ``docs/config.md`` contains a narrative section that documents it. + +On ``origin/dev`` (1925a3083) the second assertion fails: the only +matches for ``ignore_failure`` in ``docs/`` are the example YAML at +``docs/config.md:800`` and a one-line changelog blurb in +``docs/history.md``. Mark as xfail until a documentation section is +added. +""" + +from __future__ import annotations + +import re +from pathlib import Path + +import pytest + +import cumulusci + + +REPO_ROOT = Path(cumulusci.__file__).resolve().parent.parent +CONFIG_DOC = REPO_ROOT / "docs" / "config.md" + + +@pytest.mark.xfail( + reason="repro for #2500 — see docs/triage/v5/repro-results.md", + strict=False, +) +def test_ignore_failure_has_narrative_docs_section(): + """``docs/config.md`` should have a narrative section explaining + ``ignore_failure``, not just a single YAML example.""" + assert CONFIG_DOC.is_file(), f"missing {CONFIG_DOC}" + text = CONFIG_DOC.read_text() + + heading_pattern = re.compile( + r"^#{2,3}\s+.*(ignore[ _]failure|ignore a failed|continue.*failure).*$", + re.IGNORECASE | re.MULTILINE, + ) + assert heading_pattern.search(text), ( + "docs/config.md should contain a heading-level section that explains " + "the ignore_failure step option (parallel to 'Conditionally Run a Flow " + "Step' for `when:`). Currently the only mention is inside an example " + "YAML snippet." + ) diff --git a/cumulusci/tests/triage/test_issue_2506.py b/cumulusci/tests/triage/test_issue_2506.py new file mode 100644 index 0000000000..20f1425562 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_2506.py @@ -0,0 +1,40 @@ +"""Regression repro for #2506. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: bulk operations (extract.py, load.py, step.py under +cumulusci/tasks/bulkdata/) do not respect `get_debug_mode()` the way +Snowfakery (snowfakery.py) does. The ask is to keep logs / tempfiles +when debug mode is on. snowfakery.py calls `get_debug_mode()` and logs +the tempdir per loop; the workhorse `load_dataset`/`extract_dataset` +tasks have zero references to `get_debug_mode`. + +This test asserts that at least one of extract.py or load.py +references `get_debug_mode`; on dev neither does, so the assertion +fails -> XFAIL. +""" + +import pathlib + +import pytest + +import cumulusci.tasks.bulkdata as _bulkdata_pkg + + +@pytest.mark.xfail( + reason="repro for #2506 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_2506(): + pkg_path = pathlib.Path(_bulkdata_pkg.__file__).parent + extract_src = (pkg_path / "extract.py").read_text(encoding="utf-8") + load_src = (pkg_path / "load.py").read_text(encoding="utf-8") + + has_debug_in_workhorse = ( + "get_debug_mode" in extract_src or "get_debug_mode" in load_src + ) + assert has_debug_in_workhorse, ( + "Neither extract.py nor load.py references get_debug_mode(); " + "bulk operations still ignore debug-mode toggle for log/tempfile retention." + ) diff --git a/cumulusci/tests/triage/test_issue_2507.py b/cumulusci/tests/triage/test_issue_2507.py new file mode 100644 index 0000000000..277a5f2b3d --- /dev/null +++ b/cumulusci/tests/triage/test_issue_2507.py @@ -0,0 +1,41 @@ +"""Regression repro for #2507. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: there is no `undo_insert` (or similarly-named) +task. The closest mitigation is the `enable_rollback` option on +`load_data` / `snowfakery`, but that only rolls back when an +error occurs during the load — it does not provide the +post-hoc "delete everything I inserted earlier" capability the +2021 ask describes. + +This test loads the universal cumulusci.yml's tasks dict and +asserts that some kind of explicit undo/cleanup task is +registered. On dev no such task exists -> XFAIL. +""" + +from pathlib import Path + +import pytest + +import cumulusci +from cumulusci.utils.yaml.cumulusci_yml import cci_safe_load + + +@pytest.mark.xfail( + reason="repro for #2507 — see docs/triage/v5/repro-results.md", + strict=False, +) +def test_issue_2507(): + universal_yaml = Path(cumulusci.__file__).resolve().parent / "cumulusci.yml" + config = cci_safe_load(universal_yaml.open(), str(universal_yaml)) + tasks = config.get("tasks", {}) + undo_task_names = [ + name for name in tasks if "undo" in name.lower() and "insert" in name.lower() + ] + assert undo_task_names, ( + "No `undo_insert`-style task registered; users still must " + "manually delete records inserted by load_data (see #2507)." + ) diff --git a/cumulusci/tests/triage/test_issue_2508.py b/cumulusci/tests/triage/test_issue_2508.py new file mode 100644 index 0000000000..63cf84b695 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_2508.py @@ -0,0 +1,47 @@ +"""Regression repro for #2508. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (no_reverify_needed). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: There is no OOTB "retry the failed records from the +previous load" feature in CumulusCI. ``load_dataset`` exposes an +``enable_rollback`` option (cumulusci/tasks/bulkdata/load.py:97-98, +``RollbackType`` enum at line 1051), but rollback **undoes** successful +inserts when failures occur — the opposite of "retry the failures". +``RowErrorChecker`` (cumulusci/tasks/bulkdata/utils.py:158) only logs +and (optionally) raises; it never persists a failed-rows artifact that +could be replayed. + +The fix would be to (a) persist failed rows to a CSV/SQLite artifact +on load failure and (b) ship a ``retry_failed_load`` (or +``retry_failed_records``) task that consumes that artifact. + +This test asserts ``cumulusci.yml`` declares at least one retry-named +task; on dev it fails because no such task exists. +""" + +from pathlib import Path + +import pytest +import yaml + +import cumulusci + + +@pytest.mark.xfail( + reason="repro for #2508 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_2508(): + cci_root = Path(cumulusci.__file__).parent + with open(cci_root / "cumulusci.yml") as f: + data = yaml.safe_load(f) + + task_names = list(data.get("tasks", {}).keys()) + retry_named = [ + n for n in task_names if "retry" in n.lower() and "failed" in n.lower() + ] + assert retry_named, ( + "cumulusci.yml still ships no retry-failed-records task; users have no " + "way to re-attempt only the rows that failed in a prior load (see #2508)" + ) diff --git a/cumulusci/tests/triage/test_issue_2826.py b/cumulusci/tests/triage/test_issue_2826.py new file mode 100644 index 0000000000..46866dc56e --- /dev/null +++ b/cumulusci/tests/triage/test_issue_2826.py @@ -0,0 +1,46 @@ +"""Regression repro for #2826. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: PackageXmlGenerator.parse_types +(cumulusci/tasks/metadata/package.py:105-117) calls +``os.listdir(self.directory)`` with no existence check. When +``deploy_unmanaged`` runs against a repo with no ``src/`` directory +(the original 2021 ask was that this flow silently no-op in that case), +``UpdatePackageXml`` raises a raw ``FileNotFoundError`` instead. + +The fix is to either (a) guard ``parse_types`` so a missing directory +yields an empty package.xml, or (b) skip the task at the flow level via +a ``when:`` guard. Either way, the task should no longer surface a +``FileNotFoundError`` to the user. +""" + +import os +import tempfile + +import pytest + +from cumulusci.tasks.metadata.package import PackageXmlGenerator + + +@pytest.mark.xfail( + reason="repro for #2826 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_2826(): + with tempfile.TemporaryDirectory() as tmp: + missing = os.path.join(tmp, "src") + gen = PackageXmlGenerator(directory=missing, api_version="58.0") + + raised = None + try: + gen() + except BaseException as e: + raised = e + + assert not isinstance(raised, FileNotFoundError), ( + "PackageXmlGenerator still raises raw FileNotFoundError on a missing " + "directory; deploy_unmanaged should silently no-op (or surface a typed " + f"CumulusCIException instead). Got: {raised!r}" + ) diff --git a/cumulusci/tests/triage/test_issue_2951.py b/cumulusci/tests/triage/test_issue_2951.py new file mode 100644 index 0000000000..605d2a281f --- /dev/null +++ b/cumulusci/tests/triage/test_issue_2951.py @@ -0,0 +1,47 @@ +"""Regression repro for #2951. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: cumulusci/tasks/bulkdata/load.py + step.py have no +PricebookEntry-aware sequencing. When a single mapping step inserts +both Standard-Price-Book PricebookEntries and custom-pricebook +PricebookEntries, Bulk API processes records in parallel batches and +Salesforce raises STANDARD_PRICE_NOT_DEFINED when a custom price is +created before the matching standard price exists. The default +extract path skips the Standard Price Book entirely (via +hardcoded_default_declarations.py), so the typical extract→load +roundtrip never hits this — but a hand-rolled mapping that includes +both does. + +A real fix is either (a) split PricebookEntry steps into two +implicit batches (standard pricebook first), or (b) validate at +parse time that PricebookEntry steps are not "mixed" and surface a +clear error. + +This test asserts that the loader (load.py or step.py) has some +PricebookEntry-aware sequencing/validation. On dev there is no +mention of PricebookEntry in either module, so the assertion fails +-> XFAIL. +""" + +from pathlib import Path + +import pytest + +import cumulusci + + +@pytest.mark.xfail( + reason="repro for #2951 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_2951(): + bulkdata_dir = Path(cumulusci.__file__).parent / "tasks" / "bulkdata" + load_text = (bulkdata_dir / "load.py").read_text() + step_text = (bulkdata_dir / "step.py").read_text() + combined = load_text + step_text + assert "PricebookEntry" in combined, ( + "Expected loader (load.py or step.py) to contain PricebookEntry-aware " + "sequencing or parse-time validation; neither module references it." + ) diff --git a/cumulusci/tests/triage/test_issue_2979.py b/cumulusci/tests/triage/test_issue_2979.py new file mode 100644 index 0000000000..69ffd8b873 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_2979.py @@ -0,0 +1,43 @@ +"""Regression repro for #2979. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: cumulusci/cumulusci.yml `deploy` task definition still +hard-codes `path: src` for `cumulusci.tasks.salesforce.Deploy`. The +ask (with davisagli's 3-tier fallback design) is to consult the +`default` entry of `packageDirectories` in `sfdx-project.json` (the +existing helper `default_package_path` in +`cumulusci/core/config/project_config.py`) when no explicit `path` +is configured, falling back to `src` only when neither is set. + +`default_package_path` exists but is consumed only by +`create_package_version.py:230`; the Deploy task is not wired into +it. + +This test loads the bundled cumulusci.yml YAML, finds the `deploy` +task definition, and asserts that it does NOT hard-code `path: src`. +On dev the path is still hard-coded, so the assertion fails -> XFAIL. +""" + +import pathlib + +import pytest +import yaml + +import cumulusci as _cci_pkg + + +@pytest.mark.xfail( + reason="repro for #2979 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_2979(): + yml_path = pathlib.Path(_cci_pkg.__file__).parent / "cumulusci.yml" + cfg = yaml.safe_load(yml_path.read_text(encoding="utf-8")) + deploy_options = cfg["tasks"]["deploy"]["options"] + assert deploy_options.get("path") != "src", ( + "deploy task in cumulusci.yml still hard-codes path: src; " + "expected fallback to default_package_path / sfdx packageDirectories. " + f"Current options: {deploy_options!r}" + ) diff --git a/cumulusci/tests/triage/test_issue_3015.py b/cumulusci/tests/triage/test_issue_3015.py new file mode 100644 index 0000000000..be0de726fe --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3015.py @@ -0,0 +1,36 @@ +"""Regression repro for #3015. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: `cci org remove` in cumulusci/cli/org.py:519-543 +always calls `org_config.delete_org()` when `can_delete()` is +truthy. There is no `--keep-org`/`--keep` flag to detach the +keychain entry without deleting the underlying SFDX scratch +org. davisagli's documented workaround in the issue thread +(manually delete `~/.cumulusci//.org`) still +applies. + +This test introspects the Click command's options and asserts +that a "keep" flag exists. On dev there is no such option, so +the assertion fails -> XFAIL. +""" + +import pytest + +from cumulusci.cli.org import org_remove + + +@pytest.mark.xfail( + reason="repro for #3015 — see docs/triage/v5/repro-results.md", + strict=False, +) +def test_issue_3015(): + option_names = {p.name for p in org_remove.params} + has_keep_flag = any("keep" in name.lower() for name in option_names) + assert has_keep_flag, ( + "`cci org remove` still always deletes the underlying scratch " + f"org when can_delete(). No --keep-org flag in params={sorted(option_names)} " + "(see #3015)." + ) diff --git a/cumulusci/tests/triage/test_issue_3024.py b/cumulusci/tests/triage/test_issue_3024.py new file mode 100644 index 0000000000..20062631a3 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3024.py @@ -0,0 +1,56 @@ +"""Regression repro for #3024. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (no_reverify_needed). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: The order of ``group:`` values in +``cumulusci/cumulusci.yml`` still has "Metadata Transformations" first +and buries "Continuous Integration" near the bottom (~position 20+ in +the first-appearance ordering). The user-requested "Org Setup" group +does not exist (the closest is "Setup"). This means the VS Code +extension that drives off ``group:`` shows tasks in the same +not-very-useful order CumulusCI ships them in. + +The fix is either to (a) reorder the canonical YAML so the most +commonly used groups (Continuous Integration, Setup) appear toward +the top, or (b) introduce an explicit ``group_order:`` list in the +project schema and have the extension consume that. + +This test asserts "Continuous Integration" appears in the first half +of the unique groups (by first appearance). On dev it fails because +it currently appears ~last. +""" + +from pathlib import Path + +import pytest +import yaml + +import cumulusci + + +@pytest.mark.xfail( + reason="repro for #3024 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3024(): + cci_root = Path(cumulusci.__file__).parent + with open(cci_root / "cumulusci.yml") as f: + data = yaml.safe_load(f) + + seen = [] + for _, task in data.get("tasks", {}).items(): + group = task.get("group") + if group and group not in seen: + seen.append(group) + + assert "Continuous Integration" in seen, ( + "'Continuous Integration' group missing from cumulusci.yml — test needs updating" + ) + ci_pos = seen.index("Continuous Integration") + halfway = len(seen) // 2 + assert ci_pos < halfway, ( + f"'Continuous Integration' still appears at position {ci_pos + 1} of " + f"{len(seen)} groups (>= halfway {halfway + 1}); cumulusci.yml has not " + f"been reordered to surface common groups first (see #3024). Order: {seen}" + ) diff --git a/cumulusci/tests/triage/test_issue_3137.py b/cumulusci/tests/triage/test_issue_3137.py new file mode 100644 index 0000000000..a20e2ca3a0 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3137.py @@ -0,0 +1,40 @@ +"""Regression repro for #3137. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: cumulusci/tasks/metadata/package.py CustomObjectParser +(L441-459) hard-skips any object file whose name does not end in +`__c.object`, `__mdt.object`, `__e.object`, or `__b.object`. This is +a managed-package-world holdover that excludes Case (and every other +standard SObject with a sidecar `.object` containing custom fields) +from the generated package.xml. UpdatePackageXml does not expose an +opt-in option (e.g. `include_standard_objects=True`) for the user to +override. + +A real fix exposes either a task option (`include_standard_objects`) +or makes the parser configurable so users who genuinely want a +standard Case object listed can do so without monkey-patching. + +This test parses a fake `objects/` folder containing `Case.object` +(a standard object) and asserts the generated members include +`Case`. On dev `Case` is filtered out, so the assertion fails -> +XFAIL. +""" + +import pytest + +from cumulusci.tasks.metadata.package import CustomObjectParser + + +@pytest.mark.xfail( + reason="repro for #3137 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3137(): + parser = CustomObjectParser.__new__(CustomObjectParser) + members = parser._parse_item("Case.object") + assert members == ["Case"], ( + "Expected CustomObjectParser to include standard 'Case' object in " + f"package.xml members (or expose an opt-in option); got {members!r}." + ) diff --git a/cumulusci/tests/triage/test_issue_3161.py b/cumulusci/tests/triage/test_issue_3161.py new file mode 100644 index 0000000000..32242fb1b6 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3161.py @@ -0,0 +1,35 @@ +"""Regression repro for #3161. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: flowrunner.py:300-320 supports masking task options via +`info.get("sensitive")`, but the Robot `vars` option in +cumulusci/tasks/robotframework/robotframework.py:54-56 is NOT marked +`sensitive: True`. The user's specific request — mask multi-line +GitHub Actions secrets passed via `-o robot__vars …` — is therefore +not protected by the existing infrastructure. + +The minimal fix is to mark Robot's `vars` option `sensitive: True` +(or expose a CLI/flow-side hide flag). + +This test imports the Robot task class and asserts the `vars` option +declares `sensitive: True`. On dev it does not, so the assertion +fails -> XFAIL. +""" + +import pytest + +from cumulusci.tasks.robotframework.robotframework import Robot + + +@pytest.mark.xfail( + reason="repro for #3161 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3161(): + vars_option = Robot.task_options.get("vars", {}) + assert vars_option.get("sensitive") is True, ( + "Robot task_options['vars'] is not marked sensitive; -o robot__vars " + f"values are logged in plaintext. Current option metadata: {vars_option!r}" + ) diff --git a/cumulusci/tests/triage/test_issue_3165.py b/cumulusci/tests/triage/test_issue_3165.py new file mode 100644 index 0000000000..c144d36a8e --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3165.py @@ -0,0 +1,55 @@ +"""Regression repro for #3165. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: `ProfileGrantAllAccess._generate_package_xml` in +cumulusci/tasks/salesforce/update_profile.py:137-138 calls +`_expand_package_xml(package_xml)` only when +`include_packaged_objects=True`. `_expand_package_xml_objects` +— the helper that walks `record_types` and adds any referenced +CustomObject to the retrieve package.xml — is invoked only from +inside `_expand_package_xml` (line 182). When a user specifies +`record_types` referencing a standard object (e.g. Case) and +keeps `include_packaged_objects=False`, the retrieve package.xml +omits Case, the deploy then fails because the profile XML +references an unretrievable record type. + +The proposed minimal fix is to always invoke +`_expand_package_xml_objects` regardless of +`include_packaged_objects`, since that helper makes no API call. + +This test asserts that on dev `_generate_package_xml` (or +`_expand_package_xml_objects`) is wired so that `record_types` +expansion runs even when `include_packaged_objects` is False. +We approximate this by reading the source of +`_generate_package_xml` and asserting it calls +`_expand_package_xml_objects` directly (i.e. not only via the +gated `_expand_package_xml`). On dev that direct call is +missing -> XFAIL. +""" + +import inspect + +import pytest + +from cumulusci.tasks.salesforce.update_profile import ProfileGrantAllAccess + + +@pytest.mark.xfail( + reason="repro for #3165 — see docs/triage/v5/repro-results.md", + strict=False, +) +def test_issue_3165(): + src = inspect.getsource(ProfileGrantAllAccess._generate_package_xml) + calls_objects_helper_directly = ( + "_expand_package_xml_objects(" in src + or "self._expand_package_xml_objects" in src + ) + assert calls_objects_helper_directly, ( + "_generate_package_xml does not invoke " + "_expand_package_xml_objects outside the " + "`include_packaged_objects` branch; record_types pointing at " + "objects not in admin_profile.xml still get dropped (see #3165)." + ) diff --git a/cumulusci/tests/triage/test_issue_3307.py b/cumulusci/tests/triage/test_issue_3307.py new file mode 100644 index 0000000000..f6c81e5581 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3307.py @@ -0,0 +1,37 @@ +"""Regression repro for #3307. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (no_reverify_needed). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: ``cci project init`` (cumulusci/cli/project.py:37-41) only +renders Jinja templates from CumulusCI's bundled +``cumulusci/files/templates/project`` directory. There is no +``--template`` (or equivalent) CLI option to point the command at a +user-supplied template directory or git URL, so users cannot +bootstrap a project from an org-specific template. + +The fix is to add a ``--template`` click option to ``project_init`` +that accepts a path or git URL and renders that template instead of +(or in addition to) the bundled one. + +This test asserts ``project_init`` has a ``template``-named click +option; on dev it fails because no such option exists. +""" + +import pytest + +from cumulusci.cli.project import project_init + + +@pytest.mark.xfail( + reason="repro for #3307 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3307(): + param_names = {p.name for p in project_init.params} + template_opts = {n for n in param_names if "template" in n.lower()} + assert template_opts, ( + "cci project init still has no --template CLI option; users cannot " + f"point the command at a custom template directory or git URL. " + f"Existing params: {sorted(param_names)} (see #3307)" + ) diff --git a/cumulusci/tests/triage/test_issue_3331.py b/cumulusci/tests/triage/test_issue_3331.py new file mode 100644 index 0000000000..a347457013 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3331.py @@ -0,0 +1,46 @@ +"""Regression repro for #3331. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: cumulusci/tasks/metadata/metadata_map.yml line 45-48 +maps the `assignmentRules` folder to MDAPI type +`AssignmentRule` (singular). Salesforce Metadata API expects +`AssignmentRules` (plural) — see the analogous `autoResponseRules` +key (lines 60-63) which is already correctly `AutoResponseRules`. + +Running `update_package_xml` against a project with +`assignmentRules/Case.assignmentRules` emits +`AssignmentRule` and the deploy then fails with +"INVALID_TYPE: AssignmentRule is not a valid metadata type". + +A real fix is a single-line YAML change. + +This test asserts the YAML maps `assignmentRules` to the plural +`AssignmentRules`. On dev the mapping is still singular, so the +assertion fails -> XFAIL. +""" + +from pathlib import Path + +import pytest +import yaml + +import cumulusci + + +@pytest.mark.xfail( + reason="repro for #3331 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3331(): + metadata_map_path = ( + Path(cumulusci.__file__).parent / "tasks" / "metadata" / "metadata_map.yml" + ) + metadata_map = yaml.safe_load(metadata_map_path.read_text()) + entries = metadata_map.get("assignmentRules", []) + types = [e.get("type") for e in entries] + assert "AssignmentRules" in types, ( + "Expected metadata_map.yml `assignmentRules` folder to map to MDAPI " + f"type 'AssignmentRules' (plural, matching MDAPI); got types {types!r}." + ) diff --git a/cumulusci/tests/triage/test_issue_3349.py b/cumulusci/tests/triage/test_issue_3349.py new file mode 100644 index 0000000000..7fec2394cf --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3349.py @@ -0,0 +1,64 @@ +"""Regression repro for #3349. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: MappingStep.get_source_record_type_table() and +get_destination_record_type_table() in +cumulusci/tasks/bulkdata/mapping_parser.py:177-179 build the SQLite +recordtype mapping table name solely from `self.sf_object` +(`f"{self.sf_object}_rt_mapping"` and `f"{self.sf_object}_rt_target_mapping"`). +Two MappingStep entries sharing the same `sf_object` (the canonical +case is `Account` Person vs Business with different `record_type` +values) therefore collide on the same table name. load.py:552 and +extract.py:259/393 consume those names without per-step +disambiguation. + +The fix is to include `self.table` (or a hash of record_type+filter) +in the generated name when multiple mapping steps share an +sf_object. + +This test constructs two MappingStep objects with the same +sf_object="Account" but different record_type / table values and +asserts that the recordtype-table names differ. On dev they are +identical (collision), so the assertion fails -> XFAIL. +""" + +import pytest + +from cumulusci.tasks.bulkdata.mapping_parser import MappingStep + + +@pytest.mark.xfail( + reason="repro for #3349 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3349(): + step_business = MappingStep( + sf_object="Account", + table="account_business", + record_type="Business_Account", + fields={"Id": "sf_id", "Name": "Name"}, + ) + step_person = MappingStep( + sf_object="Account", + table="account_person", + record_type="PersonAccount", + fields={"Id": "sf_id", "Name": "Name"}, + ) + + src_business = step_business.get_source_record_type_table() + src_person = step_person.get_source_record_type_table() + dst_business = step_business.get_destination_record_type_table() + dst_person = step_person.get_destination_record_type_table() + + assert src_business != src_person, ( + "Two MappingSteps sharing sf_object='Account' produced the same " + f"source recordtype table name {src_business!r}; expected per-step " + "disambiguation." + ) + assert dst_business != dst_person, ( + "Two MappingSteps sharing sf_object='Account' produced the same " + f"destination recordtype table name {dst_business!r}; expected per-step " + "disambiguation." + ) diff --git a/cumulusci/tests/triage/test_issue_3353.py b/cumulusci/tests/triage/test_issue_3353.py new file mode 100644 index 0000000000..0505519d49 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3353.py @@ -0,0 +1,49 @@ +"""Regression repro for #3353. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: `Snowfakery._validate_options` in +cumulusci/tasks/bulkdata/snowfakery.py validates the `recipe` +option via `Path(recipe).exists()` only. There is no +`SOURCE_NAME:path` parsing, and no call to +`project_config.sources` / `project_config.get_source(...)` +anywhere in `snowfakery.py`. The 2022 ask (resurfaced 2024-08 +by davidjray/jnesong) is to let `recipe:` refer to a recipe in +another configured source repo. + +This test asserts that the snowfakery module source mentions +source-resolution machinery (e.g. `project_config.sources`, +`get_source`, or detection of a `SOURCE_NAME:` prefix). On dev +nothing of the sort exists -> XFAIL. +""" + +import inspect + +import pytest + +from cumulusci.tasks.bulkdata import snowfakery as snowfakery_mod + + +@pytest.mark.xfail( + reason="repro for #3353 — see docs/triage/v5/repro-results.md", + strict=False, +) +def test_issue_3353(): + src = inspect.getsource(snowfakery_mod) + has_source_resolution = any( + token in src + for token in ( + "project_config.sources", + "project_config.get_source", + "get_source(", + "SOURCE_NAME", + 'split(":"', + ) + ) + assert has_source_resolution, ( + "snowfakery.py never resolves SOURCE_NAME:path against " + "project_config.sources; cross-repo recipes still fail " + "Path(recipe).exists() (see #3353)." + ) diff --git a/cumulusci/tests/triage/test_issue_3407.py b/cumulusci/tests/triage/test_issue_3407.py new file mode 100644 index 0000000000..8f56a2c16c --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3407.py @@ -0,0 +1,111 @@ +"""Repro for CumulusCI issue #3407. + +`BaseProjectKeychain.set_service` declares ``service_config: ServiceConfig``, +but :pyfunc:`EncryptedFileProjectKeychain._load_service_files` calls it with a +raw ``str`` (the encrypted file payload) and ``config_encrypted=True``. The +signature is therefore inconsistent with the call sites. + +This test asserts the *correct* behaviour: either the annotation accepts +``str`` (e.g. ``ServiceConfig | str``) or every call site constructs a +``ServiceConfig`` first. It is expected to fail on dev (xfail). + +Pure introspection — no Salesforce / scratch org required. +""" + +from __future__ import annotations + +import inspect +import typing +from typing import Union, get_args, get_origin + +import pytest + +from cumulusci.core.config import ServiceConfig +from cumulusci.core.keychain.base_project_keychain import BaseProjectKeychain +from cumulusci.core.keychain.encrypted_file_project_keychain import ( + EncryptedFileProjectKeychain, +) + + +def _annotation_accepts_str(annotation) -> bool: + """True if ``annotation`` permits ``str`` (directly or via Union).""" + if annotation is str: + return True + origin = get_origin(annotation) + if origin is Union or origin is type(None) or origin is typing.Union: + return any(a is str for a in get_args(annotation)) + return False + + +def _src_has_string_payload_call(func) -> bool: + """Heuristic: does ``func`` source call set_service with config_encrypted=True + while passing a non-ServiceConfig value (i.e. a string variable read from a + file)?""" + src = inspect.getsource(func) + return "config_encrypted=True" in src and "ServiceConfig(" not in src + + +@pytest.mark.xfail( + reason=("repro for #3407 — see docs/triage/v5/repro-results.md"), + strict=False, +) +def test_set_service_annotation_consistent_with_callers(): + """The annotation must agree with all internal call sites.""" + hints = typing.get_type_hints(BaseProjectKeychain.set_service) + annotation = hints["service_config"] + + string_caller = _src_has_string_payload_call( + EncryptedFileProjectKeychain._load_service_files + ) + + assert not string_caller or _annotation_accepts_str(annotation), ( + "BaseProjectKeychain.set_service is annotated " + f"service_config: {annotation!r}, but " + "EncryptedFileProjectKeychain._load_service_files passes a raw str " + "(file contents) with config_encrypted=True. Annotation should be " + "Union[ServiceConfig, str] or callers should construct a " + "ServiceConfig first." + ) + + +@pytest.mark.xfail( + reason=("repro for #3407 — see docs/triage/v5/repro-results.md"), + strict=False, +) +def test_set_service_runtime_accepts_only_serviceconfig_per_annotation(): + """Run-time evidence: a plain string is accepted with config_encrypted=True + even though the annotation says ServiceConfig. If the annotation were the + source of truth, this call would fail. Today it succeeds — proving the + annotation is wrong.""" + + class _Stub(BaseProjectKeychain): + # minimal in-memory subclass exercising the encrypted-payload path + def _set_service( + self, + service_type, + alias, + service_config, + save=True, + config_encrypted=False, + ): + assert isinstance(service_config, ServiceConfig), ( + f"got {type(service_config).__name__}, expected ServiceConfig" + ) + self.services.setdefault(service_type, {})[alias] = service_config + + def _validate_service(self, *a, **kw): + return None + + from cumulusci.core.config import UniversalConfig + + kc = _Stub(UniversalConfig(), None) + # The annotation says only ServiceConfig is allowed. If callers truly + # respected it we'd never reach this line with a str. This is exactly + # what _load_service_files does today. + kc.set_service( + "github", + "from-disk", + "RAW-ENCRYPTED-STRING-PAYLOAD", # type: ignore[arg-type] + save=False, + config_encrypted=True, + ) diff --git a/cumulusci/tests/triage/test_issue_3429.py b/cumulusci/tests/triage/test_issue_3429.py new file mode 100644 index 0000000000..e79db59c8f --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3429.py @@ -0,0 +1,47 @@ +"""Regression repro for #3429. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (no_reverify_needed). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: ``BaseProjectConfig.config_filename`` is hardcoded to +``"cumulusci.yml"`` (cumulusci/core/config/project_config.py:82) and +there is no environment variable (``CUMULUSCI_YML`` / +``CUMULUSCI_EXTRA_YAML``) or CLI flag (``--extra-yaml`` / +``--config-file``) to point at an alternate / additional YAML. + +PR #3969 (branch ``extra-yaml-cli-flag``) is in flight and adds +``--extra-yaml`` plus a ``CUMULUSCI_EXTRA_YAML`` env var, but it has not +been merged into v4.10.0 / dev yet. + +This test asserts the project_config module source references either +``CUMULUSCI_YML`` or ``CUMULUSCI_EXTRA_YAML`` (env-var override) or +exposes some helper such as ``resolve_extra_yaml``; on dev it fails +because none of those are present yet. +""" + +import inspect + +import pytest + +import cumulusci.core.config.project_config as project_config_mod + + +@pytest.mark.xfail( + reason="repro for #3429 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3429(): + src = inspect.getsource(project_config_mod) + tokens = ( + "CUMULUSCI_YML", + "CUMULUSCI_EXTRA_YAML", + "resolve_extra_yaml", + "--extra-yaml", + "--config-file", + ) + found = [t for t in tokens if t in src] + assert found, ( + "cumulusci.core.config.project_config still has no env-var or helper " + f"for an external/extra cumulusci.yml override (looked for {tokens}); " + "config_filename is hardcoded to 'cumulusci.yml' (see #3429)" + ) diff --git a/cumulusci/tests/triage/test_issue_3440.py b/cumulusci/tests/triage/test_issue_3440.py new file mode 100644 index 0000000000..371f750003 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3440.py @@ -0,0 +1,44 @@ +"""Regression repro for #3440. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: cumulusci/core/config/project_config.py:514-523 +`default_package_path` is the simple "first packageDirectory with +`default: true`" pattern; falls back to `force-app`, then `src`. It +takes no arguments, offers no name-based lookup for multi-package +sfdx-project.json layouts, emits no multi-package warnings, and does +not hard-fail when both `default` and `force-app` are missing. + +A real fix likely either (a) refactors `default_package_path` into a +method accepting a package name, or (b) adds a sibling method +(`package_path(name)` / `get_package_directory(name)`) that supports +name-based lookup. + +This test asserts that `BaseProjectConfig` exposes some way to look +up package directories by name for multi-package projects. On dev no +such API exists, so the assertion fails -> XFAIL. +""" + +import pytest + +from cumulusci.core.config.project_config import BaseProjectConfig + + +@pytest.mark.xfail( + reason="repro for #3440 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3440(): + candidate_attrs = ( + "package_path", + "get_package_directory", + "get_package_path", + "package_directory_for_name", + ) + found = [a for a in candidate_attrs if hasattr(BaseProjectConfig, a)] + assert found, ( + "Expected BaseProjectConfig to expose a name-based package-directory " + f"lookup API (one of {candidate_attrs!r}) for multi-package sfdx " + "projects; none present." + ) diff --git a/cumulusci/tests/triage/test_issue_3441.py b/cumulusci/tests/triage/test_issue_3441.py new file mode 100644 index 0000000000..91acc226c6 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3441.py @@ -0,0 +1,42 @@ +"""Regression repro for #3441. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: cumulusci/tasks/create_package_version.py +`_get_base_version_number` (lines 529-563 on v4.10.0) branches only +on `None` (default) and the literal `"latest_github_release"` sentinel; +any other string is parsed as a literal version number. There is no +`"default"` / `"highest"` sentinel and no support for resetting a +flow-overridden `version_base` back to the default behavior. + +The fix (per the issue) is to add a sentinel string such as +`"default"` or `"highest"` that triggers the same SOQL-derived +highest-version lookup the default-None path uses. + +This test inspects `_get_base_version_number` source and asserts that +the function handles a `"default"` (or `"highest"`) sentinel. On dev +it does not, so the assertion fails -> XFAIL. +""" + +import inspect + +import pytest + +from cumulusci.tasks.create_package_version import CreatePackageVersion + + +@pytest.mark.xfail( + reason="repro for #3441 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3441(): + src = inspect.getsource(CreatePackageVersion._get_base_version_number) + has_default_sentinel = ( + '"default"' in src or "'default'" in src or '"highest"' in src + ) + assert has_default_sentinel, ( + "_get_base_version_number does not handle a 'default'/'highest' sentinel " + "for version_base; flow override cannot reset to default lookup. " + f"Current source:\n{src}" + ) diff --git a/cumulusci/tests/triage/test_issue_3446.py b/cumulusci/tests/triage/test_issue_3446.py new file mode 100644 index 0000000000..a270cc1ba8 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3446.py @@ -0,0 +1,35 @@ +"""Regression repro for #3446. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: `BaseSalesforcePushTask._parse_version` in +cumulusci/tasks/push/tasks.py:26-33 unconditionally calls +`version.split(".")`. When the user runs `cci task run push_qa` +with only `--metadata_package_id` (no `--version` / +`--version_id`), `version` is `None` and the call raises +``AttributeError: 'NoneType' object has no attribute 'split'`` +— the exact gist linked in the bug report. + +This test calls `_parse_version(None)` and asserts it raises a +user-friendly TaskOptionsError instead of a bare AttributeError. +On dev it raises AttributeError -> XFAIL. +""" + +import pytest + +from cumulusci.core.exceptions import TaskOptionsError +from cumulusci.tasks.push.tasks import BaseSalesforcePushTask + + +@pytest.mark.xfail( + reason="repro for #3446 — see docs/triage/v5/repro-results.md", + strict=False, +) +def test_issue_3446(): + # Bypass __init__ since BaseSalesforcePushTask needs an org/project + # config; _parse_version only touches the supplied argument. + task = BaseSalesforcePushTask.__new__(BaseSalesforcePushTask) + with pytest.raises(TaskOptionsError): + task._parse_version(None) diff --git a/cumulusci/tests/triage/test_issue_3464.py b/cumulusci/tests/triage/test_issue_3464.py new file mode 100644 index 0000000000..146b1a7450 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3464.py @@ -0,0 +1,62 @@ +"""Repro for SFDO-Tooling/CumulusCI#3464 — Provide concise documentation of +``cumulusci.yml`` ``project`` configuration options. + +The user asked: "I would like ALL configuration tags and options defined, +with a brief description (even just one sentence) in +https://cumulusci.readthedocs.io/en/stable/config.html". + +On ``origin/dev`` (1925a3083) ``cumulusci/utils/yaml/cumulusci_yml.py`` +defines a ``Project`` Pydantic model with these top-level keys: + +* ``name`` +* ``package`` +* ``test`` +* ``git`` +* ``dependencies`` +* ``dependency_resolutions`` +* ``dependency_pins`` +* ``source_format`` +* ``custom`` + +``docs/config.md`` shows ONE example YAML block (line ~281) using a subset +of these keys but has no reference subsection that names every supported +key. Several keys — notably ``dependency_resolutions``, ``dependency_pins``, +and ``source_format`` — never appear in ``docs/config.md`` at all (they +are buried in ``docs/dev.md``, which is exactly the "scattered" complaint +in the issue). + +The xfail test asserts each ``Project`` field name appears at least once +in ``docs/config.md``. Today several keys are missing, so the assertion +fails. Once ``docs/config.md`` gets a "Project Configuration Reference" +section listing every key, the test will XPASS. +""" + +from __future__ import annotations + +from pathlib import Path + +import pytest + +import cumulusci +from cumulusci.utils.yaml.cumulusci_yml import Project + + +REPO_ROOT = Path(cumulusci.__file__).resolve().parent.parent +CONFIG_DOC = REPO_ROOT / "docs" / "config.md" + + +@pytest.mark.xfail( + reason="repro for #3464 — see docs/triage/v5/repro-results.md", + strict=False, +) +def test_every_project_key_is_mentioned_in_config_doc(): + """``docs/config.md`` should mention every top-level ``project:`` key + defined by the ``Project`` Pydantic model. Today several keys are + missing or only documented in other doc pages.""" + text = CONFIG_DOC.read_text() + project_keys = sorted(Project.__fields__.keys()) + missing = [k for k in project_keys if k not in text] + assert not missing, ( + f"docs/config.md does not mention these project-config keys: {missing}. " + f"The full set declared in Project Pydantic model: {project_keys}." + ) diff --git a/cumulusci/tests/triage/test_issue_3470.py b/cumulusci/tests/triage/test_issue_3470.py new file mode 100644 index 0000000000..7d920ff0f2 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3470.py @@ -0,0 +1,41 @@ +"""Regression repro for #3470. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (no_reverify_needed). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: ``cumulusci/cumulusci.yml`` still defines only the +``ci_master`` flow (line 823); no ``ci_main`` alias exists. +``rg ci_main`` returns no matches. davidmreed's 2022 reply indicates +this needs flow-aliasing infrastructure first. + +The fix is either (a) to add a flow-aliasing mechanism and then +register ``ci_main`` as an alias for ``ci_master``, or (b) ship an +inclusive-named ``ci_main`` flow alongside ``ci_master`` (perhaps +deprecating ``ci_master`` over time). + +This test asserts ``ci_main`` is a recognized flow name in +cumulusci.yml; on dev it fails because only ``ci_master`` exists. +""" + +from pathlib import Path + +import pytest +import yaml + +import cumulusci + + +@pytest.mark.xfail( + reason="repro for #3470 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3470(): + cci_root = Path(cumulusci.__file__).parent + with open(cci_root / "cumulusci.yml") as f: + data = yaml.safe_load(f) + + flow_names = set(data.get("flows", {}).keys()) + assert "ci_main" in flow_names, ( + "cumulusci.yml still defines only ci_master; no ci_main alias / flow " + f"exists. Flows present: {sorted(flow_names)} (see #3470)" + ) diff --git a/cumulusci/tests/triage/test_issue_3471.py b/cumulusci/tests/triage/test_issue_3471.py new file mode 100644 index 0000000000..3394bd64f5 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3471.py @@ -0,0 +1,44 @@ +"""Regression repro for #3471. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery; reverified on +origin/dev@1925a3083 — only ruff refactor since v4.10.0). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: cumulusci/tasks/github/merge.py `_merge` (L241-262) logs +"Merged {compare.behind_by} commits into branch: {branch_name}". +`compare.behind_by` comes from github3's CompareCommits which surfaces +GitHub's compare-com API; for effectively no-op content merges +(e.g. README/test.txt where downstream content already matches via +merge-base) the API returns 0, even though `self.repo.merge(...)` at +L249 just shipped a real merge commit. The "Merged 0 commits" +message is therefore confusing to users monitoring the auto-merge +output. + +A real fix is to report either the SHA returned from +`self.repo.merge(...)` or `len(list(compare.commits))` instead of +`compare.behind_by`. + +This test asserts the misleading `compare.behind_by` reference is +absent from merge.py. On dev it is still present at L251, so the +assertion fails -> XFAIL. +""" + +from pathlib import Path + +import pytest + +import cumulusci + + +@pytest.mark.xfail( + reason="repro for #3471 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3471(): + merge_path = Path(cumulusci.__file__).parent / "tasks" / "github" / "merge.py" + text = merge_path.read_text() + assert "compare.behind_by" not in text, ( + "Expected merge.py to no longer report `compare.behind_by` in the " + "'Merged N commits into branch' log line (use compare.commits or the " + "merge SHA instead); the misleading reference is still present." + ) diff --git a/cumulusci/tests/triage/test_issue_3485.py b/cumulusci/tests/triage/test_issue_3485.py new file mode 100644 index 0000000000..2cdcdd24e4 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3485.py @@ -0,0 +1,60 @@ +"""Regression repro for #3485. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: cumulusci/tasks/apex/testrunner.py:802-833 writes a JUnit +`test_results.xml` that: +- has no `` declaration +- writes a bare `` element, not the standard `` + wrapper that JUnit consumers (Jenkins, GitHub Actions, etc.) expect + +Per the user's issue body, downstream JUnit parsers reject this +malformed XML. The minimal fix is to emit the XML declaration and the +top-level `` wrapper. + +This test invokes `_write_output` directly with mocked results and +asserts the generated content starts with an XML declaration and +contains a `` element. On dev neither is true, so the +assertion fails -> XFAIL. +""" + +import pathlib +import tempfile +from unittest import mock + +import pytest + +from cumulusci.tasks.apex.testrunner import RunApexTests + + +@pytest.mark.xfail( + reason="repro for #3485 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3485(): + with tempfile.TemporaryDirectory() as tmpdir: + junit_path = pathlib.Path(tmpdir) / "test_results.xml" + task = RunApexTests.__new__(RunApexTests) + task.options = {"junit_output": str(junit_path), "json_output": ""} + task.logger = mock.MagicMock() + test_results = [ + { + "ClassName": "FooTest", + "Method": "method_a", + "Outcome": "Pass", + "Stats": {"duration": "0.1"}, + "Message": None, + "StackTrace": None, + } + ] + task._write_output(test_results) + content = junit_path.read_text(encoding="utf-8") + + assert content.lstrip().startswith(" declaration. " + f"First 80 chars: {content[:80]!r}" + ) + assert " wrapper. Full content:\n{content}" + ) diff --git a/cumulusci/tests/triage/test_issue_3492.py b/cumulusci/tests/triage/test_issue_3492.py new file mode 100644 index 0000000000..3edf9961c0 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3492.py @@ -0,0 +1,46 @@ +"""Regression repro for #3492. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: `cci flow run -o key value` in +cumulusci/cli/flow.py parses each `-o` pair by doing +`task_name, option_name = key.split("__")` — an exact 2-way +unpack. Passing the user-desired form +`-o project__custom__myattr value` triggers +``ValueError: too many values to unpack (expected 2)`` because +`split("__")` returns three elements. There is no separate +project-level option override path either. + +This test imports the inner parse loop body and asserts that it +tolerates 3+ underscore-separated path segments (i.e. project- +scoped attributes). On dev the unpack still hard-fails -> XFAIL. +""" + +import inspect + +import pytest + +from cumulusci.cli import flow as flow_cli + + +@pytest.mark.xfail( + reason="repro for #3492 — see docs/triage/v5/repro-results.md", + strict=False, +) +def test_issue_3492(): + src = inspect.getsource(flow_cli.flow_run) + has_strict_two_part_unpack = ( + 'task_name, option_name = key.split("__")' in src + or "task_name, option_name = key.split('__')" in src + ) + has_project_scoped_path = ( + "project__custom" in src or "maxsplit" in src or "project_config.config" in src + ) + assert not has_strict_two_part_unpack or has_project_scoped_path, ( + "flow_run still naïvely unpacks key.split('__') into exactly two " + "parts; no project-scoped override path. " + "`-o project__custom__attr value` will crash with " + "'too many values to unpack' (see #3492)." + ) diff --git a/cumulusci/tests/triage/test_issue_3506.py b/cumulusci/tests/triage/test_issue_3506.py new file mode 100644 index 0000000000..e4c7a3e980 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3506.py @@ -0,0 +1,46 @@ +"""Regression repro for #3506. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: ``FlowCoordinator._visit_step`` +(cumulusci/core/flowrunner.py) only wires ``when=step_config.get("when")`` +on the ``task:`` branch (around line 669). The ``flow:`` branch +(around lines 674-697) recurses into nested steps without ever reading +``step_config.get("when")`` — so a ``when:`` clause attached to a +``flow:`` step is silently dropped. + +The fix is to propagate the parent flow-step's ``when:`` down to the +nested StepSpecs (most simply by AND-ing it into each child's ``when``, +or by gating the recursive ``_visit_step`` call on it). This test +asserts the source of ``_visit_step`` references ``step_config.get(\"when\")`` +inside the ``"flow" in step_config`` branch; on dev it fails because +that branch does not read ``when``. +""" + +import inspect + +import pytest + +from cumulusci.core.flowrunner import FlowCoordinator + + +@pytest.mark.xfail( + reason="repro for #3506 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3506(): + src = inspect.getsource(FlowCoordinator._visit_step) + flow_idx = src.find('if "flow" in step_config') + assert flow_idx != -1, ( + "Source of _visit_step no longer has the recognizable " + '`if "flow" in step_config:` branch; test needs updating.' + ) + flow_branch = src[flow_idx:] + has_when = ('step_config.get("when"' in flow_branch) or ( + "step_config.get('when'" in flow_branch + ) + assert has_when, ( + "flow:-step branch in FlowCoordinator._visit_step still ignores " + "step_config.get('when'); when: clauses on flow steps are silently dropped" + ) diff --git a/cumulusci/tests/triage/test_issue_3518.py b/cumulusci/tests/triage/test_issue_3518.py new file mode 100644 index 0000000000..4bfea999df --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3518.py @@ -0,0 +1,43 @@ +"""Regression repro for #3518. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: cumulusci/tasks/metadata_etl/picklists.py line 177 reads: + + default = str(process_bool_arg(entry.get("default", False))).lower + +The `.lower` is referenced as an attribute, not invoked — so +`default` ends up bound to the `str.lower` method itself (a callable +object, always truthy). The subsequent guard at line 214 +(`if default:`) therefore always runs the default-clobbering loop, +marking the new entry as default for every record type regardless of +the user's intent. + +A real fix is a one-character change: `.lower` -> `.lower()`. + +This test asserts that when a user passes `default: False` for a new +picklist entry, the produced `default` value is a falsy string (not +a bound method). On dev `default` is `str.lower` (a method), which +is truthy, so the assertion fails -> XFAIL. +""" + +import pytest + +from cumulusci.core.utils import process_bool_arg + + +@pytest.mark.xfail( + reason="repro for #3518 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3518(): + # Mirrors the exact expression at picklists.py:177 + default = str(process_bool_arg(False)).lower + assert not callable(default), ( + "Expected picklists.py to compute the lowercase string (e.g. via " + "`.lower()`), not the bound `str.lower` method. The current " + "expression yields a callable, so the `if default:` guard at " + "L214 is always truthy and every record-type default is " + f"clobbered. Got {default!r}." + ) diff --git a/cumulusci/tests/triage/test_issue_3541.py b/cumulusci/tests/triage/test_issue_3541.py new file mode 100644 index 0000000000..34b253701f --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3541.py @@ -0,0 +1,82 @@ +"""Repro for CumulusCI issue #3541 — scratch org alias becomes ``None__``. + +When :pyfunc:`BaseProjectKeychain.create_scratch_org` builds the SFDX alias it +does:: + + scratch_config["sfdx_alias"] = ( + f"{self.project_config.project__name}__{org_name}" + ) + +If ``project__name`` evaluates to ``None`` (no ``project.name`` in the loaded +config, or the project hasn't fully resolved yet — e.g. during the eager +``_load_scratch_orgs`` pass on keychain construction) the resulting alias is +the literal string ``"None__"``. That string is then passed to +``sfdx force config set target-org=None__dev`` which is exactly what +the reporter (and at least one other commenter) saw. + +Correct behaviour: either fall back to ``org_name`` alone or raise a clear +CumulusCIException — *never* embed the literal Python repr of ``None`` in a +shell argument. + +No scratch org / network required. +""" + +from __future__ import annotations + +import pytest + +from cumulusci.core.config import BaseProjectConfig, UniversalConfig +from cumulusci.core.keychain import BaseProjectKeychain + + +@pytest.mark.xfail( + reason=("repro for #3541 — see docs/triage/v5/repro-results.md"), + strict=False, +) +def test_create_scratch_org_without_project_name_does_not_yield_None_alias(): + universal_config = UniversalConfig() + project_config = BaseProjectConfig( + universal_config, + {"orgs": {"scratch": {"dev": {}}}}, + ) + assert project_config.project__name is None, ( + "precondition: this repro models a project config where project.name " + "is unset, matching the reporter's symptom" + ) + + keychain = BaseProjectKeychain(project_config, key=None) + keychain.create_scratch_org("dev", "dev") + alias = keychain.get_org("dev").config["sfdx_alias"] + + assert "None" not in alias.split("__"), ( + f"sfdx_alias is {alias!r} — literal 'None' should never appear in a " + "shell-bound SFDX alias. Expected fallback to 'dev' or a raised " + "CumulusCIException." + ) + + +@pytest.mark.xfail( + reason=("repro for #3541 — see docs/triage/v5/repro-results.md"), + strict=False, +) +def test_load_scratch_orgs_on_keychain_init_does_not_yield_None_alias(): + """During keychain construction ``_load_scratch_orgs`` eagerly invokes + ``create_scratch_org`` for every scratch config in cumulusci.yml. If + project.name resolves to None at that moment, every eagerly-created org + inherits a ``None__`` alias — and the user only notices when + ``cci org info dev`` finally runs sfdx with target-org=None__dev.""" + universal_config = UniversalConfig() + project_config = BaseProjectConfig( + universal_config, + {"orgs": {"scratch": {"dev": {}, "qa": {}}}}, + ) + keychain = BaseProjectKeychain(project_config, key=None) + + bad = { + name: keychain.get_org(name).config["sfdx_alias"] + for name in ("dev", "qa") + if "None" in keychain.get_org(name).config["sfdx_alias"].split("__") + } + assert not bad, ( + f"Eagerly-loaded scratch orgs produced None__-prefixed aliases: {bad!r}" + ) diff --git a/cumulusci/tests/triage/test_issue_3543.py b/cumulusci/tests/triage/test_issue_3543.py new file mode 100644 index 0000000000..131b014d32 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3543.py @@ -0,0 +1,35 @@ +"""Regression repro for #3543. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: cumulusci/tasks/dx_convert_from.py only exposes the +`extra` and `src_dir` task options. The issue asks for a +`load_sfdx_project_paths` (a.k.a. `resolve_sfdx_package_dirs`) option +that auto-discovers source directories from `sfdx-project.json` so +multi-package projects can convert all sources in one invocation. + +This test imports `DxConvertFrom` and asserts that +`load_sfdx_project_paths` (or `resolve_sfdx_package_dirs`) is a +declared task option. On dev neither key is present, so the +assertion fails -> XFAIL. +""" + +import pytest + +from cumulusci.tasks.dx_convert_from import DxConvertFrom + + +@pytest.mark.xfail( + reason="repro for #3543 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3543(): + options = DxConvertFrom.task_options + has_option = ( + "load_sfdx_project_paths" in options or "resolve_sfdx_package_dirs" in options + ) + assert has_option, ( + "DxConvertFrom is missing a load_sfdx_project_paths / " + f"resolve_sfdx_package_dirs option. Current options: {list(options.keys())}" + ) diff --git a/cumulusci/tests/triage/test_issue_3549.py b/cumulusci/tests/triage/test_issue_3549.py new file mode 100644 index 0000000000..58a3d0d5d4 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3549.py @@ -0,0 +1,37 @@ +"""Regression repro for #3549. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: `Deploy` in cumulusci/tasks/salesforce/Deploy.py +exposes `test_level` / `specified_tests` and pipes them through +to the Metadata API call but never captures or writes +runTestResult / runTestsResult into a JUnit (or JSON) file. The +2022 ask is to surface CI-consumable test artefacts directly +from `cci task run deploy`. + +This test asserts that `Deploy.task_options` declares a +JUnit/test-output option key. On dev no such option exists -> +XFAIL. +""" + +import pytest + +from cumulusci.tasks.salesforce.Deploy import Deploy + + +@pytest.mark.xfail( + reason="repro for #3549 — see docs/triage/v5/repro-results.md", + strict=False, +) +def test_issue_3549(): + options = Deploy.task_options + has_test_output_option = any( + any(token in key for token in ("junit", "test_output", "test_result")) + for key in options + ) + assert has_test_output_option, ( + "Deploy task still has no junit/test_output/test_result option; " + f"only options: {sorted(options)} (see #3549)." + ) diff --git a/cumulusci/tests/triage/test_issue_3570.py b/cumulusci/tests/triage/test_issue_3570.py new file mode 100644 index 0000000000..b3515c61d8 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3570.py @@ -0,0 +1,53 @@ +"""Regression repro for #3570. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery; reverified on +origin/dev@1925a3083 — only ruff refactor since v4.10.0). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: cumulusci/core/flowrunner.py exposes only per-step +`ignore_failure` (mapped to `StepSpec.allow_failure`); there is no +flow-step type for `finally:` / `on_error:` / `on_failure:` / +`always_run` / `cleanup` to express "this cleanup/rollback step +should always run after the flow regardless of success or failure". +The only `finally:` in flowrunner.py is the Python `try/finally` in +FlowCoordinator.run that invokes the `post_flow` callback — +internal-only, not user-configurable. + +A real fix introduces a step-level metadata flag (e.g. +`always_run: true` or a sibling `on_error:` block) and threads it +through the FlowCoordinator step-execution loop. + +This test asserts that `StepSpec` exposes an "always-run" / +"on-error" attribute. On dev no such attribute exists, so the +assertion fails -> XFAIL. +""" + +import pytest + +from cumulusci.core.flowrunner import StepSpec + + +@pytest.mark.xfail( + reason="repro for #3570 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3570(): + candidate_attrs = ( + "always_run", + "on_error", + "on_failure", + "finally_step", + "cleanup", + ) + field_names = ( + set(StepSpec.__dataclass_fields__.keys()) + if hasattr(StepSpec, "__dataclass_fields__") + else set(dir(StepSpec)) + ) + found = [a for a in candidate_attrs if a in field_names] + assert found, ( + "Expected flowrunner.StepSpec to expose an always-run / on-error " + f"affordance (one of {candidate_attrs!r}) so users can declare " + "cleanup / rollback steps in a flow definition; none present. " + f"Existing fields: {sorted(field_names)!r}" + ) diff --git a/cumulusci/tests/triage/test_issue_3585.py b/cumulusci/tests/triage/test_issue_3585.py new file mode 100644 index 0000000000..db553f9328 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3585.py @@ -0,0 +1,73 @@ +"""Regression repro for #3585. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (no_reverify_needed). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: When ``update_package_xml`` runs against an ``objects/`` +folder where a ``.object`` file contains an element using the +``xsi:nil="true"`` shorthand without declaring ``xmlns:xsi``, +``PackageXmlGenerator`` invokes ``MetadataXmlElementParser`` parsers +(metadata_map.yml maps ``objects:`` to parsers for ListView, +CustomField, etc.) that call ``elementtree_parse_file`` +(cumulusci/utils/xml/__init__.py:10), and Python's ``xml.etree`` +raises ``ParseError: unbound prefix`` because ``xsi:`` is undeclared. + +Salesforce's Metadata API often emits this shorthand, so users who +retrieve metadata and feed it back through ``update_package_xml`` hit +a hard failure they cannot fix by editing the file (it round-trips +this way). + +The fix is to either (a) add an ``xmlns:xsi`` shim before parsing, or +(b) pre-strip ``xsi:nil`` attributes / use a tolerant lxml parser. + +This test writes a tiny ``objects/Foo__c.object`` with an unbound +``xsi:nil`` attribute and asserts ``PackageXmlGenerator`` does not +raise; on dev it fails with an ``unbound prefix`` parse error. +""" + +import os +import tempfile + +import pytest + +from cumulusci.tasks.metadata.package import PackageXmlGenerator + + +XSI_NIL_OBJECT = """ + + + + All + + + +""" + + +@pytest.mark.xfail( + reason="repro for #3585 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3585(): + with tempfile.TemporaryDirectory() as tmp: + objects_dir = os.path.join(tmp, "objects") + os.makedirs(objects_dir) + with open(os.path.join(objects_dir, "Foo__c.object"), "w") as f: + f.write(XSI_NIL_OBJECT) + + gen = PackageXmlGenerator(directory=tmp, api_version="58.0") + + raised = None + try: + gen() + except BaseException as e: + raised = e + + msg = str(raised) if raised else "" + is_unbound = raised is not None and ( + "unbound prefix" in msg or "not well-formed" in msg or "xsi" in msg + ) + assert not is_unbound, ( + f"PackageXmlGenerator still raises XML parse error on .object files " + f"using unbound xsi:nil; got: {raised!r}" + ) diff --git a/cumulusci/tests/triage/test_issue_3593.py b/cumulusci/tests/triage/test_issue_3593.py new file mode 100644 index 0000000000..cc371bb4c6 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3593.py @@ -0,0 +1,48 @@ +"""Regression repro for #3593. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: SFDXOrgTask._get_command in cumulusci/tasks/sfdx.py:47-52 +unconditionally appends ` -o {username}` whenever the org_config is a +ScratchOrgConfig. Some sf subcommands (e.g. `project convert source`) +do not accept a target-org flag, so the resulting command is rejected +by the sf CLI. There is no opt-out option. + +The fix is either (a) a `pass_org: False` / `no_org_command` task +option, or (b) a curated whitelist of no-org sf subcommands. Either +way the bug shape is: there is currently no way to disable the +unconditional `-o` append. + +This test inspects SFDXOrgTask `_get_command` source and asserts the +unconditional append has been replaced with a conditional opt-out +path (e.g., a `pass_org` option or whitelist check). On dev the +append is still unconditional, so the assertion fails -> XFAIL. +""" + +import inspect + +import pytest + +from cumulusci.tasks.sfdx import SFDXOrgTask + + +@pytest.mark.xfail( + reason="repro for #3593 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3593(): + src = inspect.getsource(SFDXOrgTask._get_command) + options = SFDXOrgTask.task_options + has_opt_out_option = ( + "pass_org" in options or "no_org_command" in options or "skip_org" in options + ) + has_opt_out_in_source = ( + "pass_org" in src or "no_org_command" in src or "skip_org" in src + ) + assert has_opt_out_option or has_opt_out_in_source, ( + "SFDXOrgTask still unconditionally appends ' -o {username}' for " + "ScratchOrgConfig with no opt-out option. Need pass_org/no_org_command " + f"toggle. Current _get_command:\n{src}\n" + f"Current task_options keys: {list(options.keys())}" + ) diff --git a/cumulusci/tests/triage/test_issue_3602.py b/cumulusci/tests/triage/test_issue_3602.py new file mode 100644 index 0000000000..d41ddbaa46 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3602.py @@ -0,0 +1,73 @@ +"""Regression marker for SFDO-Tooling/CumulusCI#3602. + +The ``Open Test Browser`` keyword (both the Selenium ``.robot`` keyword and +the Playwright Python implementation) accepts only ``size``, ``alias`` / +``useralias``, ``wait`` and (Playwright only) ``record_video``. There is no +way to pass through Chrome / Firefox / Playwright browser options such as +extensions, ``--incognito``, download directory, ``--accept-ssl-errors`` etc. + +The reporter asks for a hook to forward browser capabilities / options. This +test asserts the Playwright implementation surfaces a ``browser_options`` +(or ``extra_options``) keyword argument; the test fails today because the +signature has no such hook. +""" + +import inspect +import sys +import types +from unittest import mock + +import pytest + + +@pytest.fixture(autouse=True) +def _stub_browser_library(): + browser_mod = types.ModuleType("Browser") + browser_mod.SupportedBrowsers = mock.MagicMock(name="SupportedBrowsers") + utils_mod = types.ModuleType("Browser.utils") + data_types_mod = types.ModuleType("Browser.utils.data_types") + data_types_mod.KeyAction = mock.MagicMock(name="KeyAction") + data_types_mod.PageLoadStates = mock.MagicMock(name="PageLoadStates") + + added = [] + for name, mod in ( + ("Browser", browser_mod), + ("Browser.utils", utils_mod), + ("Browser.utils.data_types", data_types_mod), + ): + if name not in sys.modules: + sys.modules[name] = mod + added.append(name) + try: + yield + finally: + for name in added: + sys.modules.pop(name, None) + + +@pytest.mark.xfail( + reason=("repro for #3602 — see docs/triage/v5/repro-results.md"), + strict=False, +) +def test_open_test_browser_exposes_browser_options_hook(): + """The Playwright ``open_test_browser`` should expose a kwarg that lets + callers forward browser options/capabilities (extensions, incognito, + download dir, accept-ssl, etc.). + """ + from cumulusci.robotframework.SalesforcePlaywright import SalesforcePlaywright + + sig = inspect.signature(SalesforcePlaywright.open_test_browser) + params = sig.parameters + accepts_browser_options = ( + "browser_options" in params + or "extra_options" in params + or "browser_args" in params + or "options" in params + or any(p.kind == inspect.Parameter.VAR_KEYWORD for p in params.values()) + ) + assert accepts_browser_options, ( + "SalesforcePlaywright.open_test_browser should accept a " + "browser_options/extra_options keyword (or **kwargs) so callers can " + "forward Chrome/Firefox/Playwright capabilities (#3602). " + f"Actual signature: {sig}" + ) diff --git a/cumulusci/tests/triage/test_issue_3603.py b/cumulusci/tests/triage/test_issue_3603.py new file mode 100644 index 0000000000..0bb9d096c1 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3603.py @@ -0,0 +1,69 @@ +"""Regression repro for #3603. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (partial; R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: cumulusci/core/source/github.py L126: + self.commit = self.repo.ref(ref).object.sha +lets a raw github3 `NotFoundError("404 [No message]")` bubble out when +the user-specified ref / tag / branch on an _existing_ repo does not +resolve. The peer cases (repo-not-found at L1/2 and the `release:` +spec at L103) ARE wrapped in DependencyResolutionError with the URL +and ref context; only the ref-not-found case-3 path leaks. + +A real fix wraps `self.repo.ref(ref)` in try/except NotFoundError and +re-raises DependencyResolutionError mentioning the repo URL and the +missing ref/tag/branch. + +This test simulates a NotFoundError from `repo.ref()` and asserts the +resulting exception is a DependencyResolutionError (not a raw +NotFoundError) and includes the missing tag in its message. On dev +the raw NotFoundError leaks, so both assertions fail -> XFAIL. +""" + +from unittest import mock + +import pytest +from github3.exceptions import NotFoundError + +from cumulusci.core.exceptions import DependencyResolutionError +from cumulusci.core.source.github import GitHubSource +from cumulusci.utils.yaml.cumulusci_yml import GitHubSourceModel + + +class _DummyResponse: + status_code = 404 + content = "" + + +@pytest.mark.xfail( + reason="repro for #3603 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3603(): + project_config = mock.Mock() + spec = GitHubSourceModel( + github="https://github.com/Test/Repo", + tag="release/9.99.99-no-such-tag", + ) + + fake_repo = mock.Mock() + fake_repo.ref.side_effect = lambda *_a, **_kw: (_ for _ in ()).throw( + NotFoundError(_DummyResponse) + ) + + fake_gh = mock.Mock() + with ( + mock.patch( + "cumulusci.core.source.github.get_github_api_for_repo", + return_value=fake_gh, + ), + mock.patch.object(GitHubSource, "_get_repository", return_value=fake_repo), + ): + with pytest.raises(DependencyResolutionError) as exc: + GitHubSource(project_config, spec) + msg = str(exc.value) + assert "no-such-tag" in msg or "Test/Repo" in msg, ( + "Expected case-3 ref-not-found error to surface a " + f"DependencyResolutionError mentioning the repo or ref; got: {msg!r}" + ) diff --git a/cumulusci/tests/triage/test_issue_3604.py b/cumulusci/tests/triage/test_issue_3604.py new file mode 100644 index 0000000000..462f2d2382 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3604.py @@ -0,0 +1,51 @@ +"""Regression repro for #3604. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: there is no CCI task that writes computed dependencies +into a project's `sfdx-project.json`. Per the narrative: + +> `uv run cci task list` returns 0 tasks that write `sfdx-project.json`. +> A project-wide grep for `unpackagedMetadata` returns no matches. + +The maintainer filed W-13504384 in 2023 but no implementation has +shipped through v4.10.0. + +The fix is to add a new task (e.g. `update_sfdx_project_dependencies`) +that resolves the current cumulusci dependencies and writes them +into `sfdx-project.json` — likely populating the `unpackagedMetadata` +key (or `dependencies`). + +This test scans cumulusci/tasks/ source for references to the +`unpackagedMetadata` key, which is the canonical sfdx-project.json +field for dependency tracking. On dev there are zero references, so +the assertion fails -> XFAIL. +""" + +import pathlib + +import pytest + +import cumulusci as _cci_pkg + + +@pytest.mark.xfail( + reason="repro for #3604 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3604(): + pkg_root = pathlib.Path(_cci_pkg.__file__).parent + tasks_dir = pkg_root / "tasks" + hits = [] + for py in tasks_dir.rglob("*.py"): + text = py.read_text(encoding="utf-8") + if "unpackagedMetadata" in text: + hits.append(str(py.relative_to(pkg_root))) + + assert hits, ( + "No task under cumulusci/tasks/ references the sfdx-project.json " + "'unpackagedMetadata' key; no task writes computed cumulusci " + "dependencies back into sfdx-project.json (W-13504384). " + f"Scanned {tasks_dir}; hits: {hits}" + ) diff --git a/cumulusci/tests/triage/test_issue_3613.py b/cumulusci/tests/triage/test_issue_3613.py new file mode 100644 index 0000000000..fb64e0e193 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3613.py @@ -0,0 +1,65 @@ +"""Regression repro for #3613. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: `MetadataSingleEntityTransformTask._transform` in +cumulusci/tasks/metadata_etl/base.py:330-332 raises +``CumulusCIException(f"Cannot find metadata file {path}")`` +whenever the user-supplied `api_name` does not exactly match +the Metadata API on-disk filename. For Page Layouts the +filename convention is `-.layout`; a user +passing just `Account` (the api_name they see in Setup → Object +Manager) crashes with that bare error and no hint about the +expected format or what was actually retrieved. + +The proposed UX fix is to drive `_transform` against a fake +retrieve directory and assert the raised exception message +includes either the retrieved filename list or a hint at the +expected `-` format. +""" + +import pytest + +from cumulusci.core.exceptions import CumulusCIException +from cumulusci.tasks.metadata_etl.layouts import AddFieldsToPageLayout + + +@pytest.mark.xfail( + reason="repro for #3613 — see docs/triage/v5/repro-results.md", + strict=False, +) +def test_issue_3613(tmp_path): + retrieve_dir = tmp_path / "retrieve" + layouts_dir = retrieve_dir / "layouts" + layouts_dir.mkdir(parents=True) + # Simulate a successful retrieve with the *correct* MDAPI filename. + (layouts_dir / "Account-Account Layout.layout").write_text( + "" + ) + + task = AddFieldsToPageLayout.__new__(AddFieldsToPageLayout) + task.retrieve_dir = retrieve_dir + task.deploy_dir = tmp_path / "deploy" + task.deploy_dir.mkdir() + # User typed just the object api_name, like in the bug report. + task.api_names = {"Account"} + task.api_version = "59.0" + + with pytest.raises(CumulusCIException) as excinfo: + task._transform() + + msg = str(excinfo.value) + helpful = ( + "Account-Account Layout" in msg + or "" in msg + or "available" in msg.lower() + or "expected format" in msg.lower() + ) + assert helpful, ( + "MetadataSingleEntityTransformTask still raises a bare " + f"'Cannot find metadata file ...' message: {msg!r}. " + "It should reference the retrieved files or the expected " + "api_name format (see #3613)." + ) diff --git a/cumulusci/tests/triage/test_issue_3618.py b/cumulusci/tests/triage/test_issue_3618.py new file mode 100644 index 0000000000..f8fc2f0329 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3618.py @@ -0,0 +1,49 @@ +"""Regression repro for #3618. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: `cci org remove` and `cci org scratch_delete` both +take a single `org_name` argument via +`orgname_option_or_argument(required=True)` (Click +`@click.argument` with no `nargs=-1`, no comma-split helper). +The user ask is to accept a list of org names in one invocation +so a CI step can clean up several scratch orgs at once. + +This test introspects the Click commands and asserts that the +`orgname` argument accepts >1 value (either `nargs=-1` or a +list-coerced custom callback). On dev neither command opts in +-> XFAIL. +""" + +import pytest + +from cumulusci.cli.org import org_remove, org_scratch_delete + + +def _orgname_param(cmd): + for param in cmd.params: + if param.name == "orgname": + return param + return None + + +@pytest.mark.xfail( + reason="repro for #3618 — see docs/triage/v5/repro-results.md", + strict=False, +) +def test_issue_3618(): + for cmd in (org_remove, org_scratch_delete): + param = _orgname_param(cmd) + assert param is not None, ( + f"{cmd.name}: expected an 'orgname' click.Argument, none found" + ) + accepts_many = getattr(param, "nargs", 1) in (-1,) or getattr( + param, "multiple", False + ) + assert accepts_many, ( + f"`cci org {cmd.name}` orgname argument still accepts only a " + f"single value (nargs={getattr(param, 'nargs', 1)}). #3618 " + "asks for list/batch support." + ) diff --git a/cumulusci/tests/triage/test_issue_3619.py b/cumulusci/tests/triage/test_issue_3619.py new file mode 100644 index 0000000000..77bc5c7f06 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3619.py @@ -0,0 +1,60 @@ +"""Regression repro for #3619. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (no_reverify_needed). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: ``GitHubDependencyPin`` +(cumulusci/core/dependencies/dependencies.py:79-101) only declares +``github: str`` and ``tag: str``. Adding ``password_env_name:`` to a +``dependency_pins:`` entry triggers +``DependencyParseError: Unable to parse dependency pin: {...}`` from +``parse_dependency_pin()``/``parse_pins()`` because Pydantic rejects +the extra field. + +(Part B of #3619 — the silent password drop in ``pin.pin()`` — is +captured at the same location: even if Part A is fixed by adding the +field, ``pin.pin()`` calls ``GitHubTagResolver().resolve(...)`` +directly and bypasses the password-propagation block in +``resolvers.py`` ~L644-654. Both parts need a fix.) + +The minimal fix for Part A is to add +``password_env_name: Optional[str] = None`` to +``GitHubDependencyPin``; the test here asserts ``parse_pins`` no +longer raises ``DependencyParseError`` on an entry carrying +``password_env_name``. +""" + +import pytest + +from cumulusci.core.dependencies.dependencies import parse_pins +from cumulusci.core.exceptions import DependencyParseError + + +@pytest.mark.xfail( + reason="repro for #3619 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3619(): + pin_dict = { + "github": "https://github.com/example/repo", + "tag": "release/1.0", + "password_env_name": "MY_INSTALL_KEY", + } + + raised = None + parsed = None + try: + parsed = parse_pins([pin_dict]) + except BaseException as e: + raised = e + + assert not isinstance(raised, DependencyParseError), ( + "parse_pins still raises DependencyParseError for an entry that includes " + "password_env_name; GitHubDependencyPin only declares github+tag, so the " + f"password_env_name field is rejected. Got: {raised!r}" + ) + assert parsed is not None and len(parsed) == 1 + assert getattr(parsed[0], "password_env_name", None) == "MY_INSTALL_KEY", ( + "Even if the pin parses, password_env_name is not carried onto the pin " + "object (#3619 Part B). Fix must both accept and propagate it." + ) diff --git a/cumulusci/tests/triage/test_issue_3649.py b/cumulusci/tests/triage/test_issue_3649.py new file mode 100644 index 0000000000..18a1c2b0d3 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3649.py @@ -0,0 +1,38 @@ +"""Regression repro for #3649. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: cumulusci/tasks/bulkdata/update_data.py L184 and L211 +both call `get_query_operation` / `get_dml_operation` with +`api_options={}` hardcoded empty. `BulkApiDmlOperation` in +`step.py` honors `api_options["bulk_mode"]` for Serial/Parallel +selection, but `UpdateData` never exposes a `bulk_mode` (or +`api_options`) task option, so the Snowfakery-driven update path +cannot run in serial mode. `LoadData` and the snowfakery channel +runner DO let users pick `bulk_mode`; `update_data` is the gap. + +A real fix is small (~10 lines): add `bulk_mode` (or `api_options`) +to `UpdateData.task_options` and pipe it into both call sites. + +This test asserts that `UpdateData.task_options` exposes a +`bulk_mode` (or `api_options`) option. On dev neither exists, so the +assertion fails -> XFAIL. +""" + +import pytest + +from cumulusci.tasks.bulkdata.update_data import UpdateData + + +@pytest.mark.xfail( + reason="repro for #3649 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3649(): + options = set(UpdateData.task_options.keys()) + assert "bulk_mode" in options or "api_options" in options, ( + "Expected UpdateData.task_options to expose `bulk_mode` (or " + "`api_options`) so Snowfakery-driven updates can be run in Serial " + f"mode; current options: {sorted(options)!r}." + ) diff --git a/cumulusci/tests/triage/test_issue_3663.py b/cumulusci/tests/triage/test_issue_3663.py new file mode 100644 index 0000000000..74e7ecd66e --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3663.py @@ -0,0 +1,54 @@ +"""Regression repro for #3663. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: ``FlowCoordinator._run_step`` (cumulusci/core/flowrunner.py +around lines 510-516) builds the Jinja2 context for ``when:`` from +only ``project_config`` and ``org_config``. ``self.results`` (prior-task +return values) is never exposed, so a user cannot write +``when: tasks.previous_task.return_values.foo`` in a flow ``when:`` +clause — there is no codepath for that lookup at all. + +The fix is to extend the Jinja2 context (e.g. include a ``tasks`` or +``steps`` mapping built from ``self.results`` keyed by task name) so +``when:`` expressions can reference prior step results, matching the +``^^task.return_value`` resolver that the option-resolution path already +supports. + +This test asserts the source of ``_run_step`` references prior-step +results (``self.results``, ``tasks``, or ``steps``) inside the jinja2 +context build-up. On dev it fails because the context only contains +project_config + org_config. +""" + +import inspect + +import pytest + +from cumulusci.core.flowrunner import FlowCoordinator + + +@pytest.mark.xfail( + reason="repro for #3663 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3663(): + src = inspect.getsource(FlowCoordinator._run_step) + ctx_idx = src.find("jinja2_context") + assert ctx_idx != -1, ( + "Source of _run_step no longer references jinja2_context; test needs updating." + ) + end_idx = src.find("compile_expression", ctx_idx) + if end_idx == -1: + end_idx = len(src) + ctx_block = src[ctx_idx:end_idx] + has_prior_results = any( + token in ctx_block + for token in ("self.results", '"tasks"', "'tasks'", '"steps"', "'steps'") + ) + assert has_prior_results, ( + "FlowCoordinator._run_step still builds the when: Jinja2 context " + "from only project_config + org_config; prior task results " + "(self.results) are not exposed to when: expressions" + ) diff --git a/cumulusci/tests/triage/test_issue_3692.py b/cumulusci/tests/triage/test_issue_3692.py new file mode 100644 index 0000000000..0818a7e25d --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3692.py @@ -0,0 +1,41 @@ +"""Regression repro for #3692. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: cumulusci/tasks/metadata/metadata_map.yml does not include +a `digitalExperiences` (or `digitalExperienceConfigs`) entry. The +`PackageXmlGenerator` therefore raises +`MetadataParserMissingError("No parser configuration found for +subdirectory %s")` on any Enhanced LWR site, which corresponds +directly to the user's reported error. + +The fix is to add `digitalExperiences` (and likely +`digitalExperienceConfigs`) entries to `metadata_map.yml` with a +suitable bundle parser class. + +This test loads metadata_map.yml and asserts that the +`digitalExperiences` key is present. On dev it is absent, so the +assertion fails -> XFAIL. +""" + +import pathlib + +import pytest +import yaml + +import cumulusci.tasks.metadata as _md_pkg + + +@pytest.mark.xfail( + reason="repro for #3692 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3692(): + map_path = pathlib.Path(_md_pkg.__file__).parent / "metadata_map.yml" + cfg = yaml.safe_load(map_path.read_text(encoding="utf-8")) + assert "digitalExperiences" in cfg, ( + "metadata_map.yml is missing a digitalExperiences entry; " + "Enhanced LWR sites fail with MetadataParserMissingError. " + f"Present keys (first 30): {sorted(cfg.keys())[:30]}" + ) diff --git a/cumulusci/tests/triage/test_issue_3699.py b/cumulusci/tests/triage/test_issue_3699.py new file mode 100644 index 0000000000..4644e2f18d --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3699.py @@ -0,0 +1,36 @@ +"""Regression repro for #3699. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: `ExtractData._soql_for_mapping` in +cumulusci/tasks/bulkdata/extract.py:132-146 builds the SOQL with +`WHERE` only — there is no `ORDER BY` clause. The +`MappingStep` model in +cumulusci/tasks/bulkdata/mapping_parser.py has no `order_by` / +`sort` field. The user-facing workaround (`soql_filter: "... +ORDER BY ..."`) does work via `append_filter_clause`, but the +2023 ask is for a first-class `order_by` knob to give +deterministic, diff-friendly extracts. + +This test asserts that `MappingStep` declares an `order_by` +(or `sort`) field. On dev it doesn't -> XFAIL. +""" + +import pytest + +from cumulusci.tasks.bulkdata.mapping_parser import MappingStep + + +@pytest.mark.xfail( + reason="repro for #3699 — see docs/triage/v5/repro-results.md", + strict=False, +) +def test_issue_3699(): + field_names = set(MappingStep.model_fields.keys()) + has_order_by = any(name in field_names for name in ("order_by", "sort", "sort_by")) + assert has_order_by, ( + "MappingStep still has no first-class order_by/sort field; " + f"declared fields: {sorted(field_names)} (see #3699)." + ) diff --git a/cumulusci/tests/triage/test_issue_3700.py b/cumulusci/tests/triage/test_issue_3700.py new file mode 100644 index 0000000000..c54e01d522 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3700.py @@ -0,0 +1,63 @@ +"""Regression repro for #3700. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (no_reverify_needed). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: ``MappingStep._get_required_permission_types`` +(cumulusci/tasks/bulkdata/mapping_parser.py:361-381) unconditionally +returns ``("updateable", "createable")`` for any operation in +``(UPSERT, ETL_UPSERT)``. Master-detail lookup fields in Salesforce are +``createable: True`` but ``updateable: False`` (you cannot reparent a +master-detail child after creation), so +``_check_field_permission`` returns ``False`` for the MD lookup on an +upsert mapping. ``_validate_field_dict`` then errors with +``Field xxx__c does not have the correct permissions ('updateable', +'createable') for this operation`` — exactly the symptom #3700 reports. + +The fix is a field-shape-aware permission check: for upsert lookup +fields that look like master-detail (``cascadeDelete: True``, +``updateable: False``, ``createable: True``), accept ``createable`` +alone — the MD lookup never gets updated post-insert anyway. + +This test simulates ``_check_field_permission`` against an MD-shaped +describe and asserts the call returns ``True`` for an UPSERT operation. +On dev it fails because the permission check still demands +``updateable``. +""" + +import pytest + +from cumulusci.tasks.bulkdata.mapping_parser import MappingStep +from cumulusci.tasks.bulkdata.step import DataOperationType + + +@pytest.mark.xfail( + reason="repro for #3700 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3700(): + step = MappingStep( + sf_object="Order__c", + table="Order__c", + action="upsert", + update_key="ExternalId__c", + fields={"Name": "Name", "Account__c": "Account__c"}, + ) + + md_describe = { + "Account__c": { + "createable": True, + "updateable": False, + "name": "Account__c", + } + } + + allowed = step._check_field_permission( + md_describe, "Account__c", DataOperationType.UPSERT + ) + assert allowed, ( + "MappingStep._check_field_permission still rejects an UPSERT against a " + "master-detail-shaped (createable=True, updateable=False) lookup field; " + "upsert should treat the MD lookup as create-only and accept " + "createable alone (see #3700)" + ) diff --git a/cumulusci/tests/triage/test_issue_3701.py b/cumulusci/tests/triage/test_issue_3701.py new file mode 100644 index 0000000000..8ecfa0c667 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3701.py @@ -0,0 +1,41 @@ +"""Regression repro for #3701. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: cumulusci/tasks/bulkdata/mapping_parser.py special-cases +the literal field name "Id" throughout (L171, L190, L228, L241, +L422); the field "Id" is always interpreted as the Salesforce 18-char +Id and is bound to the SQLite `sf_id` column. The MappingStep model +has no `primary_key` / `id_field` option to designate a different +field (e.g. an external-id like `BCM_Unique_Id__c`) as the row's +primary key. The user's example yaml `Id : BCM_Unique_Id__c` is +currently interpreted as "extract the SF Id into a column named +BCM_Unique_Id__c", not "use BCM_Unique_Id__c as the primary key". + +A real fix introduces a per-step opt-in to override the primary-key +identity, touching extract / load / lookup-resolution. + +This test asserts that `MappingStep` exposes some PK-override +affordance. On dev no such field exists, so the assertion fails -> +XFAIL. +""" + +import pytest + +from cumulusci.tasks.bulkdata.mapping_parser import MappingStep + + +@pytest.mark.xfail( + reason="repro for #3701 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3701(): + candidate_attrs = ("primary_key", "id_field", "external_id", "pk_field") + fields = set(MappingStep.model_fields.keys()) + found = [a for a in candidate_attrs if a in fields] + assert found, ( + "Expected MappingStep to expose a PK-override field (one of " + f"{candidate_attrs!r}) so users can designate an external id as the " + f"row's primary key; existing fields: {sorted(fields)!r}." + ) diff --git a/cumulusci/tests/triage/test_issue_3721.py b/cumulusci/tests/triage/test_issue_3721.py new file mode 100644 index 0000000000..8b72136fef --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3721.py @@ -0,0 +1,39 @@ +"""Regression repro for #3721. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: +- cumulusci/tasks/create_package_version.py:184 defaults + `version_name` to the literal string `"Release"`. +- cumulusci/cumulusci.yml `upload_production` task hard-codes + `name: Release`. + +The issue asks for the default to be the predicted version number +(or a jinja2 template that resolves to it), so consumers do not all +end up with a homogeneous `"Release"` name. The fix has shipped on +the muselab-d2x fork (commit 7aaf348f3) but is not in upstream cci. + +This test inspects the source of `create_package_version.py` and +asserts that the literal `or "Release"` fallback has been removed. +On dev it is still present, so the assertion fails -> XFAIL. +""" + +import pathlib + +import pytest + +import cumulusci.tasks.create_package_version as _cpv_mod + + +@pytest.mark.xfail( + reason="repro for #3721 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3721(): + src = pathlib.Path(_cpv_mod.__file__).read_text(encoding="utf-8") + assert 'or "Release"' not in src, ( + "create_package_version.py still defaults version_name to literal " + '"Release"; expected version-number-based default (jinja2 template ' + "or computed string)." + ) diff --git a/cumulusci/tests/triage/test_issue_3734.py b/cumulusci/tests/triage/test_issue_3734.py new file mode 100644 index 0000000000..692f7ac9e2 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3734.py @@ -0,0 +1,57 @@ +"""Regression repro for #3734. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: `PackageUpload._validate_versions` in +cumulusci/tasks/salesforce/package_upload.py runs a SOQL +``ORDER BY MajorVersion DESC, MinorVersion DESC, +PatchVersion DESC, ReleaseState DESC LIMIT 1`` then, when the +returned `ReleaseState` is `Beta`, sets `minor_version` to that +row's `MinorVersion`. When a customer has the typical pattern +(Released 6.13 followed by Beta patch 6.13.1), the query +returns the Beta patch and the next upload is built with +`minor_version=13` — identical to the already-Released minor. +The PackageUploadRequest is rejected with +``FIELD_INTEGRITY_EXCEPTION: The version number must be greater +than the last Managed - Released version number: 6.13``. + +This test drives `_validate_versions` against a mocked +`_get_one_record` returning the Beta-patch row and asserts that +the resulting `minor_version` is bumped past the latest Released +minor. On dev it stays at 13 -> XFAIL. +""" + +from unittest import mock + +import pytest + +from cumulusci.tasks.salesforce.package_upload import PackageUpload + + +@pytest.mark.xfail( + reason="repro for #3734 — see docs/triage/v5/repro-results.md", + strict=False, +) +def test_issue_3734(): + task = PackageUpload.__new__(PackageUpload) + # _validate_versions only consults self.options, self._get_one_record + task.options = {} + task._get_one_record = mock.Mock( + return_value={ + "MajorVersion": 6, + "MinorVersion": 13, + "PatchVersion": 1, + "ReleaseState": "Beta", + } + ) + + task._validate_versions() + + minor = int(task.options["minor_version"]) + assert minor > 13, ( + "PackageUpload._validate_versions still picks the Beta patch as " + "'latest' and reuses its MinorVersion; resulting minor_version=" + f"{minor!r} collides with the already-Released 6.13 (see #3734)." + ) diff --git a/cumulusci/tests/triage/test_issue_3746.py b/cumulusci/tests/triage/test_issue_3746.py new file mode 100644 index 0000000000..fbe0f3c050 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3746.py @@ -0,0 +1,58 @@ +"""Regression repro for #3746. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery; reverified on +origin/dev@1925a3083 — only ruff refactor since v4.10.0). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: cumulusci/tasks/create_package_version.py +`_get_base_version_number` (L529-545) issues a Tooling API SOQL +against Package2Version with no `IsDeprecated = false` filter: + + SELECT MajorVersion, MinorVersion, PatchVersion, BuildNumber, + IsReleased + FROM Package2Version + WHERE Package2Id='{package_id}' + ORDER BY MajorVersion DESC, MinorVersion DESC, ... + LIMIT 1 + +If the highest version was deleted (sf package version delete), the +deprecated row is still returned, so the next version-bump bases off +of a soft-deleted version. The same file at L297 DOES include +`IsDeprecated = FALSE` for `Package2` lookups, so the project knows +about the column — the omission at L535 is asymmetric and matches +the report exactly. + +A real fix is a single-line SOQL change: add +`AND IsDeprecated = false` to the WHERE clause. + +This test reads create_package_version.py and asserts the +`Package2Version` SOQL filters on `IsDeprecated`. On dev it does +not, so the assertion fails -> XFAIL. +""" + +from pathlib import Path + +import pytest + +import cumulusci + + +@pytest.mark.xfail( + reason="repro for #3746 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3746(): + src_path = Path(cumulusci.__file__).parent / "tasks" / "create_package_version.py" + text = src_path.read_text() + # Locate the _get_base_version_number SOQL block. It is the only + # Package2Version SOQL that ORDERs BY MajorVersion DESC ... LIMIT 1. + needle = "ORDER BY MajorVersion DESC" + assert needle in text, "expected the _get_base_version_number SOQL block" + block_start = text.rindex("FROM Package2Version", 0, text.index(needle)) + block_end = text.index("LIMIT 1", block_start) + len("LIMIT 1") + block = text[block_start:block_end].lower() + assert "isdeprecated" in block, ( + "Expected `_get_base_version_number` Package2Version SOQL to filter " + "on IsDeprecated = false (matching the Package2 lookup at L297); the " + f"current WHERE clause has no IsDeprecated filter: {text[block_start:block_end]!r}" + ) diff --git a/cumulusci/tests/triage/test_issue_3754.py b/cumulusci/tests/triage/test_issue_3754.py new file mode 100644 index 0000000000..8d969c99d7 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3754.py @@ -0,0 +1,52 @@ +"""Regression repro for #3754. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (no_reverify_needed). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: ``cumulusci/cli/utils.py``: + +- ``get_latest_final_version`` (lines 65-79) hardcodes + ``https://pypi.org/pypi/cumulusci/json``. There is no env-var or + kwarg to point it at a private index or to disable the call. +- ``check_latest_version`` (lines 82-101) has no opt-out flag; the + only workaround documented in the thread is to touch + ``~/.cumulusci/cumulus_timestamp`` to a far-future epoch so the + hourly check is skipped indefinitely. + +This is painful for offline/air-gapped environments and for users on +corporate networks that block pypi. + +The fix is to add an env var (e.g. ``CUMULUSCI_DISABLE_VERSION_CHECK`` +and/or ``CUMULUSCI_PYPI_URL``) consumed inside ``check_latest_version`` +/ ``get_latest_final_version``. + +This test asserts ``cli.utils`` references one of those env vars or an +explicit disable/skip path; on dev it fails because none of them exist. +""" + +import inspect + +import pytest + +import cumulusci.cli.utils as cli_utils + + +@pytest.mark.xfail( + reason="repro for #3754 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3754(): + src = inspect.getsource(cli_utils) + tokens = ( + "CUMULUSCI_DISABLE_VERSION_CHECK", + "CUMULUSCI_PYPI_URL", + "DISABLE_VERSION_CHECK", + "PYPI_URL", + "PYPI_INDEX", + ) + found = [t for t in tokens if t in src] + assert found, ( + "cumulusci.cli.utils still hardcodes https://pypi.org/pypi/cumulusci/json " + "and offers no env-var to disable or redirect the version check (looked " + f"for {tokens}); offline/air-gapped users have no clean opt-out (see #3754)" + ) diff --git a/cumulusci/tests/triage/test_issue_3758.py b/cumulusci/tests/triage/test_issue_3758.py new file mode 100644 index 0000000000..88260e18ee --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3758.py @@ -0,0 +1,44 @@ +"""Regression repro for #3758. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: cumulusci/cumulusci.yml `push_upgrade_org` flow +(L1161-1177) terminates with `flow: config_qa` as step 5. +Semantically a push-upgrade targets a managed-package UAT sandbox, +so the final step should be `flow: config_managed`, not +`config_qa`. The two flows currently expand to the same task list +(`deploy_post`, `update_admin_profile`, `load_sample_data`) so +behavior is equivalent today — but semantics drift over time and +the docs link customers to the wrong flow page. + +A real fix is a one-line YAML change: `flow: config_qa` -> +`flow: config_managed`. + +This test loads cumulusci.yml and asserts the final step of +`push_upgrade_org` is `config_managed`. On dev it is `config_qa`, +so the assertion fails -> XFAIL. +""" + +from pathlib import Path + +import pytest +import yaml + +import cumulusci + + +@pytest.mark.xfail( + reason="repro for #3758 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3758(): + cumulusci_yml = Path(cumulusci.__file__).parent / "cumulusci.yml" + data = yaml.safe_load(cumulusci_yml.read_text()) + flow = data["flows"]["push_upgrade_org"] + last_step_key = max(flow["steps"].keys(), key=lambda k: int(k)) + last_step = flow["steps"][last_step_key] + assert last_step.get("flow") == "config_managed", ( + "Expected push_upgrade_org's final step to be `flow: config_managed` " + f"(targets a managed-package UAT sandbox), not {last_step!r}." + ) diff --git a/cumulusci/tests/triage/test_issue_3768.py b/cumulusci/tests/triage/test_issue_3768.py new file mode 100644 index 0000000000..3c2a0116a8 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3768.py @@ -0,0 +1,71 @@ +"""Regression repro for #3768. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: the Snowfakery channel runner creates a separate working +directory per batch via `shutil.copytree(template_path, data_dir)` +(`cumulusci/tasks/bulkdata/snowfakery_utils/queue_manager.py:322`). +Before that copy, `Snowfakery._cleanup_object_tables` (snowfakery.py: +720-729) drops every non-`sf_ids` table from the template. So when +batch 2+ starts, the SQLite database carried in the template only +contains `*_sf_ids` mapping tables, with none of the actual rows +created during the initial `just_once: true` batch. + +Snowfakery's `random_reference: Account` resolves at generation time +against rows in the recipe-local database. With just_once Accounts +unavailable after batch 1, subsequent batches generate Contacts with +no Accounts to reference — exactly the user's symptom. + +The fix needs to preserve rows of just_once-referenced objects in +the template DB carried to subsequent batches (not just `_sf_ids` +rows). + +This test invokes `_cleanup_object_tables` against an engine that +contains a `just_once`-style data table and a corresponding +`account_sf_ids` mapping table, then uses the engine inspector to +check whether the data table physically still exists. On dev the +data table is physically dropped, so the assertion fails -> XFAIL. +""" + +from sqlalchemy import Column, MetaData, String, Table, create_engine, inspect + +import pytest + +from cumulusci.tasks.bulkdata.snowfakery import Snowfakery + + +@pytest.mark.xfail( + reason="repro for #3768 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3768(): + engine = create_engine("sqlite:///:memory:") + metadata = MetaData(bind=engine) + Table( + "account", + metadata, + Column("id", String(255), primary_key=True), + Column("Name", String(255)), + ) + Table( + "account_sf_ids", + metadata, + Column("id", String(255), primary_key=True), + Column("sf_id", String(255)), + ) + metadata.create_all(engine) + + assert "account" in inspect(engine).get_table_names(), ( + "test setup is wrong - account table not created" + ) + + task = Snowfakery.__new__(Snowfakery) + task._cleanup_object_tables(engine, metadata) + + remaining = set(inspect(engine).get_table_names()) + assert "account" in remaining, ( + "Snowfakery._cleanup_object_tables physically drops non-sf_ids tables; " + "just_once-referenced data is lost when subsequent batches start. " + f"Remaining physical tables after cleanup: {sorted(remaining)}" + ) diff --git a/cumulusci/tests/triage/test_issue_3771.py b/cumulusci/tests/triage/test_issue_3771.py new file mode 100644 index 0000000000..48559d5ba7 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3771.py @@ -0,0 +1,51 @@ +"""Regression repro for #3771. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: `transform_xpath()` defined inline in +`FindReplaceTransform.process()` (cumulusci/core/source_transforms/ +transforms.py:417-432) splits the user XPath on `/`, wraps each +plain tag in `*[local-name()=""]`, and re-appends the +predicate verbatim. Tags referenced INSIDE the predicate (e.g. +`price` inside `[price>40]`) keep their default namespace +binding, so on documents with a default xmlns the XPath +predicate matches nothing. PR #3772 (leboff's namespace fix) is +not merged. + +We exercise transform_xpath by importing it via inline grab +(it's a closure inside `process`) — instead we just inspect the +source and assert that predicate-internal tags are also wrapped +with `local-name()` (or some equivalent namespace-stripping +machinery). On dev they are not -> XFAIL. +""" + +import inspect + +import pytest + +from cumulusci.core.source_transforms.transforms import FindReplaceTransform + + +@pytest.mark.xfail( + reason="repro for #3771 — see docs/triage/v5/repro-results.md", + strict=False, +) +def test_issue_3771(): + src = inspect.getsource(FindReplaceTransform.process) + has_predicate_ns_handling = any( + token in src + for token in ( + "transform_predicate", + "predicate_local_name", + "strip_namespace", + "register_namespace", + "xmlns", + ) + ) + assert has_predicate_ns_handling, ( + "transform_xpath() in FindReplaceTransform still wraps only the " + "tag name with local-name(); predicate-internal references stay " + "namespace-bound and never match xmlns'd documents (see #3771)." + ) diff --git a/cumulusci/tests/triage/test_issue_3773.py b/cumulusci/tests/triage/test_issue_3773.py new file mode 100644 index 0000000000..4427943c43 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3773.py @@ -0,0 +1,44 @@ +"""Regression repro for #3773. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (no_reverify_needed). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: ``RetrieveProfileApi._queries_retrieve_permissions`` +(cumulusci/salesforce_api/retrieve_profile_api.py:164-195) only builds +queries for ``SetupEntityAccess``, ``ObjectPermissions``, +``PermissionSetTabSetting``, and a flow-specific ``SetupEntityAccess``. +No ``FieldPermissions`` query is built. As a consequence, +``retrieve_profile`` cannot discover that a profile has only +field-level (not object-level) permissions on something like +``AccountContactRelation``, and the parent SObject is never added to +the package.xml — so its field permissions are silently dropped from +the retrieved profile XML. + +The fix is to add a ``FieldPermissions`` query against +``Parent.Profile.Name`` and include those parent SObjectTypes in the +``CustomObject`` retrieve set. + +This test asserts ``_queries_retrieve_permissions`` source mentions +``FieldPermissions``; on dev it fails because the query is not built. +""" + +import inspect + +import pytest + +from cumulusci.salesforce_api.retrieve_profile_api import RetrieveProfileApi + + +@pytest.mark.xfail( + reason="repro for #3773 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3773(): + src = inspect.getsource(RetrieveProfileApi._queries_retrieve_permissions) + has_field_perms = "FieldPermissions" in src or "fieldpermissions" in src.lower() + assert has_field_perms, ( + "RetrieveProfileApi._queries_retrieve_permissions still does not query " + "FieldPermissions; profiles with only field-level perms on an object " + "(e.g. AccountContactRelation) will be retrieved with those perms missing " + "(see #3773)" + ) diff --git a/cumulusci/tests/triage/test_issue_3849.py b/cumulusci/tests/triage/test_issue_3849.py new file mode 100644 index 0000000000..c196b1a8f5 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3849.py @@ -0,0 +1,78 @@ +"""Repro for SFDO-Tooling/CumulusCI#3849. + +Pip-installing CumulusCI today picks ``urllib3>=2`` because ``requests`` +declares ``urllib3<3,>=1.26`` and CumulusCI itself imposes no upper bound. +Selenium 3.141.0 (locked in by ``selenium<4``) and +``robotframework-seleniumlibrary<6`` rely on the urllib3<2 Timeout API, so +Robot tests fail at runtime with:: + + ValueError: Timeout value connect was , + but it must be an int, float or None. + +The modernization (either dropping the ``selenium<4`` / +``robotframework-seleniumlibrary<6`` pins or adding ``urllib3<2`` to the +project dependencies) has not landed on ``origin/dev``. + +This test asserts the EXPECTED-modern state. Once any of those +constraints is fixed in ``pyproject.toml`` the assertion will pass and +``strict=False`` lets the existing suite keep going. + +See ``docs/triage/v5/repro-results.md``. +""" + +from __future__ import annotations + +import re +import tomllib +from pathlib import Path + +import cumulusci +import pytest + + +def _project_dependencies() -> list[str]: + # Locate the worktree's pyproject.toml via the installed cumulusci + # package source so this test is independent of pytest cwd / rootdir. + pkg_dir = Path(cumulusci.__file__).resolve().parent + pyproject = pkg_dir.parent / "pyproject.toml" + assert pyproject.is_file(), f"pyproject.toml not found at {pyproject}" + data = tomllib.loads(pyproject.read_text(encoding="utf-8")) + return list(data["project"]["dependencies"]) + + +def _has_urllib3_upper_bound(deps: list[str]) -> bool: + for spec in deps: + if re.match(r"^\s*urllib3\b", spec) and "<" in spec: + return True + return False + + +def _has_selenium_pin(deps: list[str], pkg: str) -> bool: + for spec in deps: + if re.match(rf"^\s*{re.escape(pkg)}\b.*<", spec): + return True + return False + + +@pytest.mark.xfail( + reason=("repro for #3849 — see docs/triage/v5/repro-results.md"), + strict=False, +) +def test_urllib3_or_selenium_modernized(): + """Either pin urllib3<2 explicitly or drop the selenium<4 / " + robotframework-seleniumlibrary<6 pins.""" + + deps = _project_dependencies() + + fixed = _has_urllib3_upper_bound(deps) or not ( + _has_selenium_pin(deps, "selenium") + and _has_selenium_pin(deps, "robotframework-seleniumlibrary") + ) + + assert fixed, ( + "Issue #3849 still reproduces: pyproject.toml lacks an explicit " + "urllib3 upper bound while still pinning selenium<4 and " + "robotframework-seleniumlibrary<6, so pip installs urllib3>=2 " + "and Robot tests crash on import.\n" + f"Current dependencies: {deps!r}" + ) diff --git a/cumulusci/tests/triage/test_issue_3889.py b/cumulusci/tests/triage/test_issue_3889.py new file mode 100644 index 0000000000..56ed579253 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3889.py @@ -0,0 +1,54 @@ +"""Regression repro for #3889. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: CumulusCI exposes uninstall tasks only for 1GP managed +packages (via namespace + InstalledPackage destructiveChanges): + + - cumulusci/cumulusci.yml:615-642 — uninstall_managed, + uninstall_packaged, uninstall_packaged_incremental, uninstall_src, + uninstall_pre, uninstall_post. None accept a 04t id. + - cumulusci/tasks/salesforce/UninstallPackage.py — `UninstallPackage` + only accepts `namespace` and `purge_on_delete`. + - cumulusci/salesforce_api/package_zip.py — `UninstallPackageZipBuilder` + writes destructiveChanges referencing InstalledPackage by namespace; + no 04t code path. + +The user wants a task that accepts an `04t...` SubscriberPackageVersion +id (or `Package2Version.Id`) and uninstalls via Tooling API (analogous +to `sf package uninstall -p 04t...`) so it doesn't depend on sf CLI +stability. + +A real fix introduces a new task (e.g. `UninstallPackageVersion`) +that calls the Tooling API directly. + +This test asserts `UninstallPackage` (or a sibling task) accepts a +SubscriberPackageVersion / 04t id. On dev no such option exists, so +the assertion fails -> XFAIL. +""" + +import pytest + +from cumulusci.tasks.salesforce.UninstallPackage import UninstallPackage + + +@pytest.mark.xfail( + reason="repro for #3889 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3889(): + options = set(UninstallPackage.task_options.keys()) + candidate_options = ( + "version_id", + "subscriber_package_version_id", + "package_version_id", + "package_version", + ) + found = [opt for opt in candidate_options if opt in options] + assert found, ( + "Expected UninstallPackage (or a sibling task) to expose a " + f"04t / SubscriberPackageVersion id option (one of " + f"{candidate_options!r}) for 2GP uninstalls; current options: " + f"{sorted(options)!r}." + ) diff --git a/cumulusci/tests/triage/test_issue_3910.py b/cumulusci/tests/triage/test_issue_3910.py new file mode 100644 index 0000000000..83673eea78 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3910.py @@ -0,0 +1,73 @@ +"""Repro for SFDO-Tooling/CumulusCI#3910. + +The JSON schema (and underlying Pydantic model) for a ``ScratchOrg`` +incorrectly declares ``namespaced`` as ``str`` when both the +documentation and the actual runtime code path (e.g. +``BaseProjectKeychain.create_scratch_org`` and +``ScratchOrgConfig._build_org_create_args``) treat it as a boolean. + +This test demonstrates the bug from two angles: + +1. The exported JSON schema must declare ``namespaced`` as ``boolean``. +2. The Pydantic model must preserve a YAML-style boolean rather than + silently coercing it to the strings ``"True"``/``"False"``. + +PR #3911 (OPEN as of 2026-05-14) fixes ``cumulusci_yml.py`` (changing +``namespaced: str = None`` to ``bool = None``) and the regenerated +``cumulusci.jsonschema.json``. Once that lands the assertions below +will all pass. +""" + +import json +from pathlib import Path + +import pytest + +from cumulusci.utils.yaml.cumulusci_yml import ScratchOrg + + +REPO_ROOT = Path(__file__).resolve().parents[3] +SCHEMA_PATH = REPO_ROOT / "cumulusci/schema/cumulusci.jsonschema.json" + + +def _scratch_org_namespaced_schema() -> dict: + with SCHEMA_PATH.open() as fh: + schema = json.load(fh) + return schema["definitions"]["ScratchOrg"]["properties"]["namespaced"] + + +@pytest.mark.xfail( + reason="repro for #3910 - see docs/triage/v5/repro-results.md", + strict=False, +) +def test_jsonschema_namespaced_is_boolean(): + assert _scratch_org_namespaced_schema()["type"] == "boolean" + + +@pytest.mark.xfail( + reason="repro for #3910 - see docs/triage/v5/repro-results.md", + strict=False, +) +def test_pydantic_model_namespaced_is_boolean(): + schema = ScratchOrg.schema() + assert schema["properties"]["namespaced"]["type"] == "boolean" + + +@pytest.mark.xfail( + reason="repro for #3910 - see docs/triage/v5/repro-results.md", + strict=False, +) +def test_pydantic_does_not_stringify_boolean_namespaced(): + parsed = ScratchOrg.parse_obj({"namespaced": True}) + assert parsed.namespaced is True + assert not isinstance(parsed.namespaced, str) + + +@pytest.mark.xfail( + reason="repro for #3910 - see docs/triage/v5/repro-results.md", + strict=False, +) +def test_pydantic_does_not_stringify_boolean_namespaced_false(): + parsed = ScratchOrg.parse_obj({"namespaced": False}) + assert parsed.namespaced is False + assert not isinstance(parsed.namespaced, str) diff --git a/cumulusci/tests/triage/test_issue_3931.py b/cumulusci/tests/triage/test_issue_3931.py new file mode 100644 index 0000000000..fcae697f10 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3931.py @@ -0,0 +1,82 @@ +"""Regression repro for #3931. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: cumulusci/tasks/salesforce/update_profile.py:290-292 +contains: + + for elem in tree.findall("layoutAssignments"): + if elem.find("recordType").text == rt["record_type"]: + elem.layout.text = layout_option + +`elem.find("recordType")` returns `None` whenever a +`` element has no `` child (a valid +metadata shape — layoutAssignments without recordType apply to +records lacking a record-type binding). The subsequent `.text` +access then raises `AttributeError: 'NoneType' object has no +attribute 'text'`, which is exactly the user's reported error. + +The fix is to bind `rt_elem = elem.find("recordType")` and check +`if rt_elem is not None and rt_elem.text == rt["record_type"]:` +before mutating. + +This test parses a profile containing a layoutAssignments element +with no recordType child via the CCI metadata_tree wrapper (the same +type ProfileGrantAllAccess._set_record_types operates on), then +calls `_set_record_types`. On dev the path raises AttributeError so +the assertion fails -> XFAIL. +""" + +from unittest import mock + +import pytest + +from cumulusci.tasks.salesforce.update_profile import ProfileGrantAllAccess +from cumulusci.utils.xml import metadata_tree + + +@pytest.mark.xfail( + reason="repro for #3931 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3931(): + profile_xml = b""" + + + Account-Account Layout + + + Account-Business Layout + Account.Business_Account + + + false + Account.Business_Account + true + +""" + tree = metadata_tree.fromstring(profile_xml) + + task = ProfileGrantAllAccess.__new__(ProfileGrantAllAccess) + task.options = { + "record_types": [ + { + "record_type": "Account.Business_Account", + "page_layout": "Account-Replacement Layout", + } + ] + } + task.namespace_prefixes = {"namespaced_org": "", "managed": ""} + task.logger = mock.MagicMock() + + raised = None + try: + task._set_record_types(tree, "Admin") + except AttributeError as e: + raised = e + + assert raised is None, ( + "update_profile._set_record_types raised AttributeError on a " + f"layoutAssignments without recordType child: {raised}" + ) diff --git a/cumulusci/tests/triage/test_issue_3951.py b/cumulusci/tests/triage/test_issue_3951.py new file mode 100644 index 0000000000..66aab85fef --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3951.py @@ -0,0 +1,50 @@ +"""Regression repro for #3951. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: `SetDuplicateRuleStatus` extends +`MetadataSingleEntityTransformTask` whose `_transform` looks for +metadata files by the literal `api_name`. DuplicateRule API +names always follow `.`; users typing only +the rule name (e.g. +``Standard_Rule_for_Leads_with_Duplicate_Contacts``) crash with +the unhelpful ``Cannot find metadata file ... .duplicateRule``. +The task itself does not document or detect this format +requirement. + +Proposed UX fix: improve the `api_names` option help string to +call out the ``.`` format. This test asserts +that today's task surface includes the format hint. On dev it +doesn't -> XFAIL. + +(Same root-cause family as #3613.) +""" + +import pytest + +from cumulusci.tasks.metadata_etl.duplicate_rules import ( + SetDuplicateRuleStatus, +) + + +@pytest.mark.xfail( + reason="repro for #3951 — see docs/triage/v5/repro-results.md", + strict=False, +) +def test_issue_3951(): + api_names_opt = SetDuplicateRuleStatus.task_options.get("api_names", {}) + description = (api_names_opt.get("description") or "").lower() + hints_at_object_prefix = ( + "" in description + or "object_name" in description + or "object.rulename" in description + or "object." in description + ) + assert hints_at_object_prefix, ( + "SetDuplicateRuleStatus.task_options['api_names'] description " + f"({description!r}) still does not warn the user that " + "DuplicateRule API names require the . form " + "(see #3951)." + ) diff --git a/cumulusci/tests/triage/test_issue_3953.py b/cumulusci/tests/triage/test_issue_3953.py new file mode 100644 index 0000000000..12e1d6d4c6 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3953.py @@ -0,0 +1,58 @@ +"""Regression repro for #3953. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-v4.10.0 (no_reverify_needed). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: ``AddPicklistEntries._init_options`` +(cumulusci/tasks/metadata_etl/picklists.py around line 68) checks +``all("fullName" in entry for entry in self.options["entries"])`` +without first parsing ``entries`` from a JSON string. When the task +is invoked from the CLI, ``-o entries '[{...}]'`` arrives as the +literal string; iterating that string walks characters one at a time, +none contain the substring ``"fullName"``, and the task always errors +with ``Error: The 'fullName' key is required on all picklist values``. + +Net effect: ``cci task run add_picklist_entries`` is unusable from the +CLI on v4.10.0. + +The minimal fix is to JSON-parse ``self.options["entries"]`` when it +is a string before validating it (and apply the same coercion to +``record_types`` for symmetry). A more general fix is schema-driven +list coercion via the new Pydantic ``Options`` model. + +This test asserts the source of ``AddPicklistEntries._init_options`` +parses string-form ``entries`` (e.g. references ``json.loads`` or +``process_list_arg`` on ``entries``); on dev it fails because no such +parsing exists. +""" + +import inspect + +import pytest + +from cumulusci.tasks.metadata_etl.picklists import AddPicklistEntries + + +@pytest.mark.xfail( + reason="repro for #3953 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_3953(): + src = inspect.getsource(AddPicklistEntries._init_options) + parses_entries = any( + token in src + for token in ( + 'json.loads(self.options["entries"]', + "json.loads(self.options['entries']", + 'json.loads(self.options.get("entries"', + "json.loads(self.options.get('entries'", + 'process_list_arg(self.options["entries"]', + "process_list_arg(self.options['entries']", + ) + ) + assert parses_entries, ( + "AddPicklistEntries._init_options still does not parse the 'entries' " + "option from a JSON string; CLI invocation 'cci task run " + 'add_picklist_entries -o entries "[{...}]"\' iterates the string char ' + "by char and always raises \"'fullName' key is required\" (see #3953)" + ) diff --git a/cumulusci/tests/triage/test_issue_3955.py b/cumulusci/tests/triage/test_issue_3955.py new file mode 100644 index 0000000000..d49bc1fc0a --- /dev/null +++ b/cumulusci/tests/triage/test_issue_3955.py @@ -0,0 +1,92 @@ +"""Regression marker for SFDO-Tooling/CumulusCI#3955. + +`SalesforcePlaywright.open_test_browser` splits the ``size`` argument with +``str.split("x", 1)`` and forwards the resulting string fragments straight to +``browser.new_context(viewport={"width": , "height": })``. + +Playwright requires ``viewport.width`` / ``viewport.height`` to be ``int``; +passing strings raises:: + + browser.newContext: viewport.width: expected integer, got string + +Expected behaviour: ``width`` and ``height`` should be cast to ``int`` before +being forwarded. +""" + +import sys +import types +from unittest import mock + +import pytest + + +@pytest.fixture(autouse=True) +def _stub_browser_library(): + """``robotframework-browser`` is not a unit-test dependency, so stub the + minimum surface that ``SalesforcePlaywright`` imports at module load.""" + browser_mod = types.ModuleType("Browser") + browser_mod.SupportedBrowsers = mock.MagicMock(name="SupportedBrowsers") + utils_mod = types.ModuleType("Browser.utils") + data_types_mod = types.ModuleType("Browser.utils.data_types") + data_types_mod.KeyAction = mock.MagicMock(name="KeyAction") + data_types_mod.PageLoadStates = mock.MagicMock(name="PageLoadStates") + + added = [] + for name, mod in ( + ("Browser", browser_mod), + ("Browser.utils", utils_mod), + ("Browser.utils.data_types", data_types_mod), + ): + if name not in sys.modules: + sys.modules[name] = mod + added.append(name) + try: + yield + finally: + for name in added: + sys.modules.pop(name, None) + + +@pytest.mark.xfail( + reason=("repro for #3955 — see docs/triage/v5/repro-results.md"), + strict=False, +) +def test_open_test_browser_passes_int_viewport_to_playwright(): + from cumulusci.robotframework.SalesforcePlaywright import SalesforcePlaywright + + lib = SalesforcePlaywright() + + lib._browser = mock.MagicMock(name="Browser") + lib._browser.new_browser.return_value = "browser-id" + lib._browser.new_context.return_value = "context-id" + lib._browser.new_page.return_value = {"page_id": "page-id"} + + lib._cumulusci = mock.MagicMock(name="CumulusCI") + lib._cumulusci.login_url.return_value = "https://test.example.com" + + def _get_variable_value(name, default=None): + if name == "${DEFAULT BROWSER SIZE}": + return "1280x1024" + if name == "${BROWSER}": + return "chrome" + return default + + builtin = mock.MagicMock(name="BuiltIn") + builtin.get_variable_value.side_effect = _get_variable_value + builtin.convert_to_boolean.side_effect = lambda v: bool(v) + lib._builtin = builtin + + with mock.patch.object(lib, "wait_until_salesforce_is_ready"): + lib.open_test_browser() + + assert lib._browser.new_context.called, "new_context should be invoked" + _args, kwargs = lib._browser.new_context.call_args + viewport = kwargs["viewport"] + assert isinstance(viewport["width"], int), ( + "viewport.width should be int (Playwright contract); got " + f"{type(viewport['width']).__name__}: {viewport['width']!r}" + ) + assert isinstance(viewport["height"], int), ( + "viewport.height should be int (Playwright contract); got " + f"{type(viewport['height']).__name__}: {viewport['height']!r}" + ) diff --git a/cumulusci/tests/triage/test_issue_710.py b/cumulusci/tests/triage/test_issue_710.py new file mode 100644 index 0000000000..25d657a1f8 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_710.py @@ -0,0 +1,85 @@ +"""Repro for SFDO-Tooling/CumulusCI#710. + +Projects today inherit four default scratch-org configurations from +``cumulusci/cumulusci.yml`` (``dev``, ``qa``, ``feature``, ``beta``, +``release``). The issue requests that a project be able to disable any +of these defaults via its own ``cumulusci.yml``, e.g.:: + + orgs: + scratch: + dev: + config_file: None + +On ``origin/dev`` this is not honoured: + +* ``cumulusci.core.utils.merge_config`` silently drops a ``None`` + override (``dictmerge`` skips ``None`` values), so the universal + ``config_file: orgs/dev.json`` survives the merge. +* ``BaseProjectKeychain._load_scratch_orgs`` iterates every key under + ``orgs.scratch`` and unconditionally calls ``create_scratch_org``. + +Both behaviours are exercised below so the test fails (XFAIL) today +and passes once #710 is implemented in whichever direction the team +chooses (sentinel ``config_file: None``, an explicit ``disabled: true`` +flag, omission of inherited keys, etc.) - the assertions only check +the externally-visible end state: ``dev`` is not in the keychain after +the project disables it. +""" + +import pytest + +from cumulusci.core.config import BaseProjectConfig, UniversalConfig +from cumulusci.core.keychain import BaseProjectKeychain +from cumulusci.core.utils import merge_config + + +@pytest.fixture() +def disabling_project_config(): + universal_config = UniversalConfig() + merged = merge_config( + { + "universal_config": universal_config.config, + "project_config": { + "project": {"name": "TestProject"}, + "orgs": {"scratch": {"dev": {"config_file": None}}}, + }, + } + ) + project_config = BaseProjectConfig(universal_config, config={"no_yaml": True}) + project_config.config = merged + project_config.project__name = "TestProject" + return project_config + + +@pytest.mark.xfail( + reason="repro for #710 - see docs/triage/v5/repro-results.md", + strict=False, +) +def test_project_can_disable_default_dev_scratch_org_via_none_config_file( + disabling_project_config, +): + keychain = BaseProjectKeychain(disabling_project_config, key="0123456789123456") + assert "dev" not in keychain.orgs, ( + "Setting `config_file: None` on the inherited `dev` scratch org config " + "should disable it, but the keychain still loaded it." + ) + + +@pytest.mark.xfail( + reason="repro for #710 - see docs/triage/v5/repro-results.md", + strict=False, +) +def test_merge_config_preserves_explicit_none_override(): + universal_config = UniversalConfig() + merged = merge_config( + { + "universal_config": universal_config.config, + "project_config": { + "orgs": {"scratch": {"dev": {"config_file": None}}}, + }, + } + ) + assert merged["orgs"]["scratch"]["dev"]["config_file"] is None, ( + "merge_config should preserve an explicit None override so that " + "downstream code can detect a disabled scratch org config." + ) diff --git a/cumulusci/tests/triage/test_issue_733.py b/cumulusci/tests/triage/test_issue_733.py new file mode 100644 index 0000000000..03108111e4 --- /dev/null +++ b/cumulusci/tests/triage/test_issue_733.py @@ -0,0 +1,34 @@ +"""Regression repro for #733. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: CliRuntime.check_org_overwrite() at cumulusci/cli/runtime.py +hardcodes a `click.ClickException` for an already-created scratch org. +The original 2018 ask is to interactively prompt the user (Y/N) to delete +the existing scratch org rather than hard-erroring. + +The fix would introduce `click.confirm` / `click.prompt` (or equivalent) so +the function offers an interactive choice. This test asserts presence of a +prompt mechanism inside `check_org_overwrite`; on dev it fails because the +function still only raises `ClickException`. +""" + +import inspect + +import pytest + +from cumulusci.cli.runtime import CliRuntime + + +@pytest.mark.xfail( + reason="repro for #733 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_733(): + src = inspect.getsource(CliRuntime.check_org_overwrite) + has_prompt = any(token in src for token in ("click.confirm", "click.prompt")) + assert has_prompt, ( + "check_org_overwrite still hard-errors with ClickException; " + "no interactive prompt path found in source" + ) diff --git a/cumulusci/tests/triage/test_issue_773.py b/cumulusci/tests/triage/test_issue_773.py new file mode 100644 index 0000000000..853e42573b --- /dev/null +++ b/cumulusci/tests/triage/test_issue_773.py @@ -0,0 +1,75 @@ +"""Repro for SFDO-Tooling/CumulusCI#773 — Document task return values and results. + +cdcarter requested that tasks be able to *declare* their ``return_values`` +(and ``result``) and that ``cci task info`` / the web docs surface that +declaration. + +On ``origin/dev`` (1925a3083): + +* ``BaseTask`` exposes a ``task_options`` class attribute that + ``doc_task()`` walks (``cumulusci/utils/__init__.py:doc_task``) to emit + an "Options" section. +* ``BaseTask`` exposes a free-form ``task_docs`` string that ``doc_task`` + splices into the output. +* There is **no** declarative analogue for return values: ``self.return_values`` + is an empty dict mutated at runtime, and ``doc_task`` never emits a + "Return Values" / "Returns" section. + +This test pins down the gap by running ``doc_task`` against a task that +sets ``return_values`` at runtime and asserting the rendered RST advertises +those return values. That assertion fails today because the task-info +plumbing has no awareness of return values. Mark xfail until a declarative +schema (e.g. ``return_values_schema``) and matching ``doc_task`` section +are added. +""" + +from __future__ import annotations + +import pytest + +from cumulusci.core.config import BaseProjectConfig, TaskConfig, UniversalConfig +from cumulusci.core.keychain import BaseProjectKeychain +from cumulusci.tasks.salesforce.package_upload import PackageUpload +from cumulusci.utils import doc_task + + +def _make_task_config(): + """Build a minimal TaskConfig pointing at PackageUpload — a real shipping + task that documents (in its docstring / source) that it populates + ``return_values`` with ``version_number``, ``version_id``, and ``package_id``. + """ + universal_config = UniversalConfig() + project_config = BaseProjectConfig(universal_config, config={"noyaml": True}) + project_config.set_keychain(BaseProjectKeychain(project_config, key=None)) + task_config = TaskConfig( + { + "class_path": f"{PackageUpload.__module__}.{PackageUpload.__name__}", + "description": "Uploads a beta release of the metadata currently in the packaging org", + "options": {}, + } + ) + return task_config + + +@pytest.mark.xfail( + reason="repro for #773 — see docs/triage/v5/repro-results.md", + strict=False, +) +def test_doc_task_renders_return_values_section(): + """``cci task info`` (via ``doc_task``) should document a task's + declared return values. Today no declarative mechanism exists, so the + rendered RST has no "Return Values" section even for tasks whose + implementation clearly populates ``self.return_values``. + """ + rendered = doc_task("upload_beta", _make_task_config()) + + assert "Return Values" in rendered or "Returns" in rendered, ( + "doc_task output should include a 'Return Values' (or 'Returns') " + "section sourced from a declarative attribute on the task class " + "(parallel to task_options / task_docs)." + ) + for key in ("version_number", "version_id", "package_id"): + assert key in rendered, ( + f"doc_task output should mention the {key!r} return value populated " + f"by PackageUpload._set_return_values()." + ) diff --git a/cumulusci/tests/triage/test_issue_808.py b/cumulusci/tests/triage/test_issue_808.py new file mode 100644 index 0000000000..875115119b --- /dev/null +++ b/cumulusci/tests/triage/test_issue_808.py @@ -0,0 +1,37 @@ +"""Regression repro for #808. + +See docs/triage/v5/repro-results.md for full narrative. +Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery). +This xfail marker will be removed by the corresponding fix-PR. + +Root cause: UninstallPackaged._init_options() at +cumulusci/tasks/salesforce/UninstallPackaged.py:21-24 defaults the +'package' option to `project__package__name` only. The asymmetric fix +expected (matching InstallPackageVersion._init_options, which falls +back through `name_managed` -> `name` -> `namespace`) is to consult +`project__package__name_managed` first. Today the function never +consults `project__package__name_managed`, so deploy_packaging of a +managed package whose unmanaged display name differs ends up +uninstalling the wrong package. + +This test asserts the override source mentions `name_managed`; on dev +it does not, so the assertion fails -> XFAIL. +""" + +import inspect + +import pytest + +from cumulusci.tasks.salesforce.UninstallPackaged import UninstallPackaged + + +@pytest.mark.xfail( + reason="repro for #808 — see docs/triage/v5/repro-results.md", strict=False +) +def test_issue_808(): + src = inspect.getsource(UninstallPackaged._init_options) + assert "name_managed" in src, ( + "UninstallPackaged._init_options still falls back to " + "project__package__name only; expected name_managed fallback. " + f"Current source:\n{src}" + ) From befe82f772a644b3e292315ada956062d9aa009c Mon Sep 17 00:00:00 2001 From: James Estevez Date: Thu, 14 May 2026 09:56:57 -0700 Subject: [PATCH 3/4] docs(triage/v5): add 75 fix-sketches for REPRODUCED issues For each REPRODUCED issue not in Tranche 1 (75 of 80), add a per-issue fix-sketch at docs/triage/v5/fix-sketches/issue_NNNN.md. Each sketch links to: - The full narrative in docs/triage/v5/repro-results.md - The xfail regression test in cumulusci/tests/triage/test_issue_NNNN.py - The GitHub issue Sketches extract from the underlying narrative: - Bug summary (from Evidence / Classification / Reproduction path) - Target file:line (from fenced code-block locator or Target field) - Recommended approach (from Recommended action / Proposed fix sketch) The Size/risk table is left as TBD-by-fix-PR-author. Tranche 1 (#3852, #3854, #3886, #3938, #3939) does NOT get a fix-sketch because those receive immediate fix PRs (Task 9). #3610 and #3910 are fix-already-on-dev and get a closed:pr-resolved-NNNN pass-1 verdict rather than a fix-sketch. Plan reference: docs/superpowers/plans/2026-05-14-cci-triage-upstream-plan.md Task 6 (build fix-sketches/). --- docs/triage/v5/fix-sketches/issue_1348.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_1432.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_1769.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_2013.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_2140.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_2153.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_2325.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_2402.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_2500.md | 55 +++++++++++++++++++ docs/triage/v5/fix-sketches/issue_2506.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_2507.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_2508.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_2826.md | 42 +++++++++++++++ docs/triage/v5/fix-sketches/issue_2951.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_2979.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_3015.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_3024.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_3137.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_3161.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_3165.md | 42 +++++++++++++++ docs/triage/v5/fix-sketches/issue_3307.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_3331.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_3349.md | 35 ++++++++++++ docs/triage/v5/fix-sketches/issue_3353.md | 35 ++++++++++++ docs/triage/v5/fix-sketches/issue_3407.md | 51 ++++++++++++++++++ docs/triage/v5/fix-sketches/issue_3429.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_3440.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_3441.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_3446.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_3464.md | 62 +++++++++++++++++++++ docs/triage/v5/fix-sketches/issue_3470.md | 38 +++++++++++++ docs/triage/v5/fix-sketches/issue_3471.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_3485.md | 38 +++++++++++++ docs/triage/v5/fix-sketches/issue_3492.md | 38 +++++++++++++ docs/triage/v5/fix-sketches/issue_3506.md | 38 +++++++++++++ docs/triage/v5/fix-sketches/issue_3518.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_3541.md | 65 +++++++++++++++++++++++ docs/triage/v5/fix-sketches/issue_3543.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_3549.md | 38 +++++++++++++ docs/triage/v5/fix-sketches/issue_3570.md | 38 +++++++++++++ docs/triage/v5/fix-sketches/issue_3585.md | 41 ++++++++++++++ docs/triage/v5/fix-sketches/issue_3593.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_3602.md | 54 +++++++++++++++++++ docs/triage/v5/fix-sketches/issue_3603.md | 35 ++++++++++++ docs/triage/v5/fix-sketches/issue_3604.md | 35 ++++++++++++ docs/triage/v5/fix-sketches/issue_3613.md | 47 ++++++++++++++++ docs/triage/v5/fix-sketches/issue_3618.md | 38 +++++++++++++ docs/triage/v5/fix-sketches/issue_3619.md | 35 ++++++++++++ docs/triage/v5/fix-sketches/issue_3649.md | 35 ++++++++++++ docs/triage/v5/fix-sketches/issue_3663.md | 38 +++++++++++++ docs/triage/v5/fix-sketches/issue_3692.md | 42 +++++++++++++++ docs/triage/v5/fix-sketches/issue_3699.md | 35 ++++++++++++ docs/triage/v5/fix-sketches/issue_3700.md | 35 ++++++++++++ docs/triage/v5/fix-sketches/issue_3701.md | 35 ++++++++++++ docs/triage/v5/fix-sketches/issue_3721.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_3734.md | 38 +++++++++++++ docs/triage/v5/fix-sketches/issue_3746.md | 35 ++++++++++++ docs/triage/v5/fix-sketches/issue_3754.md | 38 +++++++++++++ docs/triage/v5/fix-sketches/issue_3758.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_3768.md | 35 ++++++++++++ docs/triage/v5/fix-sketches/issue_3771.md | 41 ++++++++++++++ docs/triage/v5/fix-sketches/issue_3773.md | 41 ++++++++++++++ docs/triage/v5/fix-sketches/issue_3849.md | 35 ++++++++++++ docs/triage/v5/fix-sketches/issue_3873.md | 47 ++++++++++++++++ docs/triage/v5/fix-sketches/issue_3889.md | 38 +++++++++++++ docs/triage/v5/fix-sketches/issue_3910.md | 39 ++++++++++++++ docs/triage/v5/fix-sketches/issue_3931.md | 42 +++++++++++++++ docs/triage/v5/fix-sketches/issue_3951.md | 47 ++++++++++++++++ docs/triage/v5/fix-sketches/issue_3953.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_3955.md | 47 ++++++++++++++++ docs/triage/v5/fix-sketches/issue_675.md | 47 ++++++++++++++++ docs/triage/v5/fix-sketches/issue_710.md | 41 ++++++++++++++ docs/triage/v5/fix-sketches/issue_733.md | 40 ++++++++++++++ docs/triage/v5/fix-sketches/issue_773.md | 60 +++++++++++++++++++++ docs/triage/v5/fix-sketches/issue_808.md | 42 +++++++++++++++ 75 files changed, 3073 insertions(+) create mode 100644 docs/triage/v5/fix-sketches/issue_1348.md create mode 100644 docs/triage/v5/fix-sketches/issue_1432.md create mode 100644 docs/triage/v5/fix-sketches/issue_1769.md create mode 100644 docs/triage/v5/fix-sketches/issue_2013.md create mode 100644 docs/triage/v5/fix-sketches/issue_2140.md create mode 100644 docs/triage/v5/fix-sketches/issue_2153.md create mode 100644 docs/triage/v5/fix-sketches/issue_2325.md create mode 100644 docs/triage/v5/fix-sketches/issue_2402.md create mode 100644 docs/triage/v5/fix-sketches/issue_2500.md create mode 100644 docs/triage/v5/fix-sketches/issue_2506.md create mode 100644 docs/triage/v5/fix-sketches/issue_2507.md create mode 100644 docs/triage/v5/fix-sketches/issue_2508.md create mode 100644 docs/triage/v5/fix-sketches/issue_2826.md create mode 100644 docs/triage/v5/fix-sketches/issue_2951.md create mode 100644 docs/triage/v5/fix-sketches/issue_2979.md create mode 100644 docs/triage/v5/fix-sketches/issue_3015.md create mode 100644 docs/triage/v5/fix-sketches/issue_3024.md create mode 100644 docs/triage/v5/fix-sketches/issue_3137.md create mode 100644 docs/triage/v5/fix-sketches/issue_3161.md create mode 100644 docs/triage/v5/fix-sketches/issue_3165.md create mode 100644 docs/triage/v5/fix-sketches/issue_3307.md create mode 100644 docs/triage/v5/fix-sketches/issue_3331.md create mode 100644 docs/triage/v5/fix-sketches/issue_3349.md create mode 100644 docs/triage/v5/fix-sketches/issue_3353.md create mode 100644 docs/triage/v5/fix-sketches/issue_3407.md create mode 100644 docs/triage/v5/fix-sketches/issue_3429.md create mode 100644 docs/triage/v5/fix-sketches/issue_3440.md create mode 100644 docs/triage/v5/fix-sketches/issue_3441.md create mode 100644 docs/triage/v5/fix-sketches/issue_3446.md create mode 100644 docs/triage/v5/fix-sketches/issue_3464.md create mode 100644 docs/triage/v5/fix-sketches/issue_3470.md create mode 100644 docs/triage/v5/fix-sketches/issue_3471.md create mode 100644 docs/triage/v5/fix-sketches/issue_3485.md create mode 100644 docs/triage/v5/fix-sketches/issue_3492.md create mode 100644 docs/triage/v5/fix-sketches/issue_3506.md create mode 100644 docs/triage/v5/fix-sketches/issue_3518.md create mode 100644 docs/triage/v5/fix-sketches/issue_3541.md create mode 100644 docs/triage/v5/fix-sketches/issue_3543.md create mode 100644 docs/triage/v5/fix-sketches/issue_3549.md create mode 100644 docs/triage/v5/fix-sketches/issue_3570.md create mode 100644 docs/triage/v5/fix-sketches/issue_3585.md create mode 100644 docs/triage/v5/fix-sketches/issue_3593.md create mode 100644 docs/triage/v5/fix-sketches/issue_3602.md create mode 100644 docs/triage/v5/fix-sketches/issue_3603.md create mode 100644 docs/triage/v5/fix-sketches/issue_3604.md create mode 100644 docs/triage/v5/fix-sketches/issue_3613.md create mode 100644 docs/triage/v5/fix-sketches/issue_3618.md create mode 100644 docs/triage/v5/fix-sketches/issue_3619.md create mode 100644 docs/triage/v5/fix-sketches/issue_3649.md create mode 100644 docs/triage/v5/fix-sketches/issue_3663.md create mode 100644 docs/triage/v5/fix-sketches/issue_3692.md create mode 100644 docs/triage/v5/fix-sketches/issue_3699.md create mode 100644 docs/triage/v5/fix-sketches/issue_3700.md create mode 100644 docs/triage/v5/fix-sketches/issue_3701.md create mode 100644 docs/triage/v5/fix-sketches/issue_3721.md create mode 100644 docs/triage/v5/fix-sketches/issue_3734.md create mode 100644 docs/triage/v5/fix-sketches/issue_3746.md create mode 100644 docs/triage/v5/fix-sketches/issue_3754.md create mode 100644 docs/triage/v5/fix-sketches/issue_3758.md create mode 100644 docs/triage/v5/fix-sketches/issue_3768.md create mode 100644 docs/triage/v5/fix-sketches/issue_3771.md create mode 100644 docs/triage/v5/fix-sketches/issue_3773.md create mode 100644 docs/triage/v5/fix-sketches/issue_3849.md create mode 100644 docs/triage/v5/fix-sketches/issue_3873.md create mode 100644 docs/triage/v5/fix-sketches/issue_3889.md create mode 100644 docs/triage/v5/fix-sketches/issue_3910.md create mode 100644 docs/triage/v5/fix-sketches/issue_3931.md create mode 100644 docs/triage/v5/fix-sketches/issue_3951.md create mode 100644 docs/triage/v5/fix-sketches/issue_3953.md create mode 100644 docs/triage/v5/fix-sketches/issue_3955.md create mode 100644 docs/triage/v5/fix-sketches/issue_675.md create mode 100644 docs/triage/v5/fix-sketches/issue_710.md create mode 100644 docs/triage/v5/fix-sketches/issue_733.md create mode 100644 docs/triage/v5/fix-sketches/issue_773.md create mode 100644 docs/triage/v5/fix-sketches/issue_808.md diff --git a/docs/triage/v5/fix-sketches/issue_1348.md b/docs/triage/v5/fix-sketches/issue_1348.md new file mode 100644 index 0000000000..771901dbab --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_1348.md @@ -0,0 +1,40 @@ +# Fix sketch — #1348: Multiple Git Provider Support + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `cli` +**Issue**: + +## Bug + +`rg -li "gitlab" cumulusci/` and `rg -li "bitbucket" cumulusci/` both return zero matches. The `ci_feature` flow still hardcodes GitHub-specific tasks: + +## Target + +`cumulusci/cumulusci.yml` lines 767-789 + +## Recommended approach (from triage narrative) + +- pass1: `closed:stale-24mo` — large architectural change (multi-VCS abstraction); 6yr no traction; user `zenibako` confirmed using cci on GitLab via custom flows is feasible. +- pass2 labels: `enhancement,stale,wontfix-candidate` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_1348.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #1348:`). diff --git a/docs/triage/v5/fix-sketches/issue_1432.md b/docs/triage/v5/fix-sketches/issue_1432.md new file mode 100644 index 0000000000..9a4558490a --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_1432.md @@ -0,0 +1,40 @@ +# Fix sketch — #1432: CCI Inconsistencies in validating arguments + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `cli` +**Issue**: + +## Bug + +Old-style `task_options` dict still does not validate unknown keys: Repro test passes (= unknown `colour` typo is silently accepted via YAML/Python path): Test path: `/tmp/repro/7/tests/test_1432_options_validation.py`. + +## Target + +`cumulusci/core/tasks.py` lines 186-196 + +## Recommended approach (from triage narrative) + +- pass1: `closed:stale-24mo` — 5yr; partial mitigation in place; full fix would require reworking every legacy `task_options` dict task. +- pass2 labels: `bug,stale,partially-fixed` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_1432.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #1432:`). diff --git a/docs/triage/v5/fix-sketches/issue_1769.md b/docs/triage/v5/fix-sketches/issue_1769.md new file mode 100644 index 0000000000..53ea8c6d63 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_1769.md @@ -0,0 +1,40 @@ +# Fix sketch — #1769: Unusual case in test_load + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `bulkdata` +**Issue**: + +## Bug + +The original line 352 in `158a2d4356f` (May 2020) was: In v4.10.0 the same pattern survives, just wrapped in `MappingLookup`: The pattern repeats at lines 754, 773, 801, 1119, 1187, 1255 — declaring `Id` as a "lookup" key inside the `lookups` dict so `_expand_mapping` can express the after-step's UPDATE-on-Id dependency. davidmreed acknowledged in 2020 it was "a horrible hack" he intended to clean... + +## Target + +`cumulusci/tasks/bulkdata/tests/test_load.py` lines 736-739 + +## Recommended approach (from triage narrative) + +- pass1: `closed:stale-24mo` — pure test-fixture nit; never escalated to a real bug; original commenters have moved on. +- pass2 labels: `test-cleanup, low-priority` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_1769.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #1769:`). diff --git a/docs/triage/v5/fix-sketches/issue_2013.md b/docs/triage/v5/fix-sketches/issue_2013.md new file mode 100644 index 0000000000..9c43bbd42f --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_2013.md @@ -0,0 +1,40 @@ +# Fix sketch — #2013: Mapping files with steps that are not 1-1 with SObjects are unreliable for extraction + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `bulkdata` +**Issue**: + +## Bug + +`create_table_if_needed` (`utils.py:133-139`) tries to detect duplicate tables but the SQLAlchemy `Table()` constructor raises first: Reproduction (`/tmp/repro/9/tests/test_2013_multistep.py`) yields the exact 2020 traceback: + +## Target + +`cumulusci/tasks/bulkdata/utils.py` lines 133-139 + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — bug is real, easy to reproduce, easy to fix (catch the SQLAlchemy error and re-raise as `BulkDataException`, or validate at mapping-parse time). +- pass2 labels: `bug, bulkdata, extract_dataset, error-handling` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_2013.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #2013:`). diff --git a/docs/triage/v5/fix-sketches/issue_2140.md b/docs/triage/v5/fix-sketches/issue_2140.md new file mode 100644 index 0000000000..5902478774 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_2140.md @@ -0,0 +1,40 @@ +# Fix sketch — #2140: Prompt Org Configs when Org Does Not Exist and Command Runs Against It + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `cli` +**Issue**: + +## Bug + +`keychain.get_org` raises `OrgNotFound` -> `cli/org.py:530-531` shows `"Org {name} does not exist in the keychain"`. No interactive prompt offering available scratch configs. + +## Target + +`cumulusci/cli/runtime.py` lines 95-104 + +## Recommended approach (from triage narrative) + +- pass1: `closed:stale-24mo` — 5yr `cli-usability` enhancement with no traction. +- pass2 labels: `enhancement,cli-usability,stale` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_2140.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #2140:`). diff --git a/docs/triage/v5/fix-sketches/issue_2153.md b/docs/triage/v5/fix-sketches/issue_2153.md new file mode 100644 index 0000000000..39e63310b0 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_2153.md @@ -0,0 +1,40 @@ +# Fix sketch — #2153: Add comment to original PR which tags all branch subscribers when a merge + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `ci-integration` +**Issue**: + +## Bug + +`cumulusci/tasks/github/merge.py` `_create_conflict_pull_request` (the only place an auto-merge PR is created): The method only creates the conflict PR; it never opens a comment on any PR (the original child PR or otherwise). Repo-wide grep for `create_comment|issue_comment|pr.create_comment|comment.*pull_request` under `cumulusci/tasks/github` returns no hits in production code (only test fixture... + +## Target + +`cumulusci/tasks/github/merge.py` lines 264-288 + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — small, well-scoped enhancement; reasonable "good-second-issue". +- pass2 labels: `enhancement, github, merge-conflict` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_2153.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #2153:`). diff --git a/docs/triage/v5/fix-sketches/issue_2325.md b/docs/triage/v5/fix-sketches/issue_2325.md new file mode 100644 index 0000000000..ab82028f8b --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_2325.md @@ -0,0 +1,40 @@ +# Fix sketch — #2325: Task to turn off validation rules to allow data insert + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `bulkdata` +**Issue**: + +## Bug + +- Trigger analog: `disable_tdtm_trigger_handlers` / `restore_tdtm_trigger_handlers` (`cumulusci.yml:738-747`). - DuplicateRule analog: `set_duplicate_rule_status` → `cumulusci.tasks.metadata_etl.duplicate_rules.SetDuplicateRuleStatus` (a 25-line `MetadataSingleEntityTransformTask` subclass with `entity = "DuplicateRule"`). - ValidationRule equivalent: **none.** `cci task list | grep -i -E "v... + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — feature still missing, clear implementation pattern, modest scope. +- pass2 labels: `enhancement, bulkdata, metadata_etl, good-first-issue` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_2325.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #2325:`). diff --git a/docs/triage/v5/fix-sketches/issue_2402.md b/docs/triage/v5/fix-sketches/issue_2402.md new file mode 100644 index 0000000000..ec11e54ba9 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_2402.md @@ -0,0 +1,40 @@ +# Fix sketch — #2402: Create a --rebuild-org parameter for cci flow run + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `cli` +**Issue**: + +## Bug + +Only `--delete-org` exists. `rg -i "rebuild.org"` returns zero hits. + +## Target + +`cumulusci/cli/flow.py` lines 119-145 + +## Recommended approach (from triage narrative) + +- pass1: `closed:stale-24mo` — 5yr; tracked W-10502624 (no movement); user can accomplish via `cci org scratch_delete X && cci flow run`. +- pass2 labels: `enhancement,stale` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_2402.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #2402:`). diff --git a/docs/triage/v5/fix-sketches/issue_2500.md b/docs/triage/v5/fix-sketches/issue_2500.md new file mode 100644 index 0000000000..9c2f63a9bf --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_2500.md @@ -0,0 +1,55 @@ +# Fix sketch — #2500: `ignore_failure` is not documented + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `docs` +**Issue**: + +## Bug + +`ignore_failure` is not documented + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +Add `### Ignore a Failed Step` (or `### Continue After a Failed Step`) +to `docs/config.md` immediately after the existing `### Skip a Flow Step` +section. Body should cover: + +- What it does: when `ignore_failure: True` is set on a step, an + exception raised by that step does not abort the flow; subsequent + steps still run. +- A minimal YAML example (the existing `release_unlocked_production` + snippet around line 783 already demonstrates it — link to it instead + of duplicating). +- Interaction with `^^step.return_value` references: downstream steps + that reference a failed step's return values must defend against + missing keys. +- When NOT to use it: in CI, silently ignoring a failure hides + regressions; prefer a `when:` clause for intentional conditional + branching. +- One sentence on the difference between `ignore_failure` (post hoc: + swallow the exception) and `when:` (a priori: skip the step entirely). + +This is a tiny, high-leverage docs PR — a strong candidate for a +`good-first-issue` label. + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_2500.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #2500:`). diff --git a/docs/triage/v5/fix-sketches/issue_2506.md b/docs/triage/v5/fix-sketches/issue_2506.md new file mode 100644 index 0000000000..4aa880e7a7 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_2506.md @@ -0,0 +1,40 @@ +# Fix sketch — #2506: Bulk Operations should have a --debug mode which maintains logs and tempfiles + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `bulkdata` +**Issue**: + +## Bug + +- Snowfakery task (`snowfakery.py:241,355,385,565`) calls `get_debug_mode()` and at `:386` logs `f"Working Directory: {tempdir}"` per loop iteration. - `extract.py`, `step.py` — **zero** references to `debug_mode` or `get_debug_mode`. - `load.py:283` uses `tempfile.TemporaryFile` with no debug-mode override; the file is auto-deleted on context exit regardless of debug. + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — partial implementation; remaining work is straightforward (wire `get_debug_mode()` into load/extract, conditionally use `TemporaryDirectory(delete=False)` and emit path). +- pass2 labels: `enhancement, bulkdata, extract_dataset, load_dataset, debugging` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_2506.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #2506:`). diff --git a/docs/triage/v5/fix-sketches/issue_2507.md b/docs/triage/v5/fix-sketches/issue_2507.md new file mode 100644 index 0000000000..c3bc53c86a --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_2507.md @@ -0,0 +1,40 @@ +# Fix sketch — #2507: Undo mode for CumulusCI Insert + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `cli` +**Issue**: + +## Bug + +No `undo_insert` task exists (`rg -l undo_insert` returns nothing). Closest functionality is `enable_rollback` on `load_dataset` and `snowfakery` tasks: That only triggers rollback on error during the load; it does not provide the post-hoc "delete everything we ever inserted" capability the requester described. + +## Target + +`cumulusci/tasks/bulkdata/load.py` lines 97-99 + +## Recommended approach (from triage narrative) + +- pass1: `closed:stale-24mo` — 4yr feature with partial mitigation already shipped. +- pass2 labels: `enhancement,stale,partially-fixed` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_2507.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #2507:`). diff --git a/docs/triage/v5/fix-sketches/issue_2508.md b/docs/triage/v5/fix-sketches/issue_2508.md new file mode 100644 index 0000000000..ee2243d3f3 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_2508.md @@ -0,0 +1,40 @@ +# Fix sketch — #2508: Manual load retries + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `bulkdata` +**Issue**: + +## Bug + +- `cci task list` returns no retry-named task. - `load.py` has an `enable_rollback` option (`:97-98`, `RollbackType` enum at `:1051`) but rollback **undoes successful inserts when failures occur** — the opposite of "retry the failures." - `RowErrorChecker` (`utils.py:158`) only logs and optionally raises; it does not persist a failed-rows artifact that could be replayed. + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — distinct from rollback; would need (a) failed-row CSV/SQL persistence + (b) a new `retry_failed_load` task that consumes it. +- pass2 labels: `enhancement, bulkdata, load_dataset, reliability` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_2508.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #2508:`). diff --git a/docs/triage/v5/fix-sketches/issue_2826.md b/docs/triage/v5/fix-sketches/issue_2826.md new file mode 100644 index 0000000000..722215948f --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_2826.md @@ -0,0 +1,42 @@ +# Fix sketch — #2826: deploy_unmanaged flow is supposed to silently do nothing if there's not actually a package directory + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `metadata-etl` +**Issue**: + +## Bug + +deploy_unmanaged flow is supposed to silently do nothing if there's not actually a package directory + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — small, contained fix. +- pass2 labels: `bug`, `good-first-issue` + +**Notes**: Could be fixed at the task layer (skip with logger.info when path missing) or at the flow layer (`when:` guard on the deploy_unmanaged steps). Task-layer is more defensible because the same task may be referenced from custom flows. + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_2826.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #2826:`). diff --git a/docs/triage/v5/fix-sketches/issue_2951.md b/docs/triage/v5/fix-sketches/issue_2951.md new file mode 100644 index 0000000000..de655640b7 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_2951.md @@ -0,0 +1,40 @@ +# Fix sketch — #2951: Error in task load_dataset - Standard_price_not_defined + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `bulkdata` +**Issue**: + +## Bug + +No special handling exists in the loader to sequence Standard-Price-Book PricebookEntries before custom-pricebook PricebookEntries within a single mapping step. Within one Bulk job, records are processed in parallel within batches and Salesforce throws `STANDARD_PRICE_NOT_DEFINED` when a custom price is created before the matching standard price. Mitigation already in place for the `extract_datase... + +## Target + +`cumulusci/tasks/bulkdata/extract_dataset_utils/hardcoded_default_declarations.py` lines 14-18 + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — bug is latent. Fix options: (a) loader auto-splits PricebookEntry into two implicit batches (standard pricebook first); (b) document the requirement and validate at parse time that PricebookEntry steps are not "mixed." +- pass2 labels: `bug, bulkdata, load_dataset, pricebook, documentation` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_2951.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #2951:`). diff --git a/docs/triage/v5/fix-sketches/issue_2979.md b/docs/triage/v5/fix-sketches/issue_2979.md new file mode 100644 index 0000000000..7420fdff6e --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_2979.md @@ -0,0 +1,40 @@ +# Fix sketch — #2979: deploy task should deploy from default entry in packageDirectories + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `packaging` +**Issue**: + +## Bug + +- `cumulusci/cumulusci.yml:227-229` — the `deploy` task still hard-codes `path: src` for `cumulusci.tasks.salesforce.Deploy`. - `cumulusci/core/config/project_config.py:517-525` — `default_package_path` correctly reads `packageDirectories[*].default` from `sfdx-project.json` when `project__source_format == "sfdx"`. - The only consumer of `default_package_path` is `cumulusci/tasks/create_pack... + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — feature still missing; davisagli's 2021 design comment (3-tier fallback `path` -> sfdx default -> `src`) remains the natural plan. +- pass2 labels: `severity:low,area:packaging,area:sfdx,state:needs-design` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_2979.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #2979:`). diff --git a/docs/triage/v5/fix-sketches/issue_3015.md b/docs/triage/v5/fix-sketches/issue_3015.md new file mode 100644 index 0000000000..a5006e0c6c --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3015.md @@ -0,0 +1,40 @@ +# Fix sketch — #3015: Remove imported dx org from cci list without deleting actual scratch + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `cli` +**Issue**: + +## Bug + +No `--keep-org` flag. davisagli's manual workaround (delete `~/.cumulusci//.org` directly) still applies. + +## Target + +`cumulusci/cli/org.py` lines 519-543 + +## Recommended approach (from triage narrative) + +- pass1: `closed:stale-24mo` — 4yr; tracked W-10502512. +- pass2 labels: `enhancement,stale` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3015.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3015:`). diff --git a/docs/triage/v5/fix-sketches/issue_3024.md b/docs/triage/v5/fix-sketches/issue_3024.md new file mode 100644 index 0000000000..c542f43137 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3024.md @@ -0,0 +1,40 @@ +# Fix sketch — #3024: Order of flow groups in `cumulusci/cumulusci.yml` + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `cli` +**Issue**: + +## Bug + +Sequence of unique `group:` values in `cumulusci/cumulusci.yml` (first appearance): `Continuous Integration` is buried near the bottom; `Org Setup` (the user's preferred name) does not exist (uses `Setup`); ordering does not match the user's request. + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `closed:stale-24mo` — 4yr cosmetic VS Code extension request; the true fix is sorting at the consumer (the extension) rather than rearranging the canonical YAML. +- pass2 labels: `enhancement,stale` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3024.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3024:`). diff --git a/docs/triage/v5/fix-sketches/issue_3137.md b/docs/triage/v5/fix-sketches/issue_3137.md new file mode 100644 index 0000000000..3be157b519 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3137.md @@ -0,0 +1,40 @@ +# Fix sketch — #3137: cci task run update_package_xml and Salesforce Case Custom Object + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `metadata-etl` +**Issue**: + +## Bug + +- `cumulusci/tasks/metadata/package.py:451-458` skips standard objects. - `cumulusci/tasks/metadata/package.py:562-584` `UpdatePackageXml.task_options` has only `path`, `output`, `package_name`, `managed`, `delete`, + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: keep-open — a real product gap remains; mark for design discussion. +- pass2 labels: `severity:low,area:metadata-etl,type:enhancement,state:needs-design` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3137.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3137:`). diff --git a/docs/triage/v5/fix-sketches/issue_3161.md b/docs/triage/v5/fix-sketches/issue_3161.md new file mode 100644 index 0000000000..cd29031931 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3161.md @@ -0,0 +1,40 @@ +# Fix sketch — #3161: Ability to Hide Option Values When Using Task Options + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `cli` +**Issue**: + +## Bug + +A masking infrastructure was added (task-option metadata can opt in via `sensitive: True`), but: 1. The Robot `vars` option is not marked sensitive (`cumulusci/tasks/robotframework/robotframework.py:54-56`). 2. There's no CLI/Robot-side flag for the user to mark an ad-hoc `-o` value as sensitive. + +## Target + +`cumulusci/core/flowrunner.py` lines 300-320 + +## Recommended approach (from triage narrative) + +- pass1: `closed:stale-24mo` — 4yr; partial fix in place. +- pass2 labels: `enhancement,stale,partially-implemented` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3161.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3161:`). diff --git a/docs/triage/v5/fix-sketches/issue_3165.md b/docs/triage/v5/fix-sketches/issue_3165.md new file mode 100644 index 0000000000..7e19b4728a --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3165.md @@ -0,0 +1,42 @@ +# Fix sketch — #3165: Update Admin Profile task fails when specifying record types without custom package.xml + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `metadata-etl` +**Issue**: + +## Bug + +Update Admin Profile task fails when specifying record types without custom package.xml + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — single-line refactor. +- pass2 labels: `bug` + +**Notes**: Smallest fix at update_profile.py:137 — always call `self._expand_package_xml_objects(package_xml)` regardless of `include_packaged_objects`, and only call the broader `self._expand_package_xml` (which does the Tooling API query) when `include_packaged_objects=True`. `_expand_package_xml_objects` itself only walks the user-supplied options, no API call. + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3165.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3165:`). diff --git a/docs/triage/v5/fix-sketches/issue_3307.md b/docs/triage/v5/fix-sketches/issue_3307.md new file mode 100644 index 0000000000..89e912c141 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3307.md @@ -0,0 +1,40 @@ +# Fix sketch — #3307: Project Template Support for `cci project init` + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `cli` +**Issue**: + +## Bug + +`rg "template" cumulusci/cli/project.py` only finds references to internal Jinja templates rendered from `cumulusci/files/templates/project` (lines 220-329). No `--template` CLI option exists. `project_init` (line 41) takes no template-source argument. + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `closed:stale-24mo` — 4yr; explicitly described by the requester as "low priority / nice to have". +- pass2 labels: `enhancement,stale` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3307.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3307:`). diff --git a/docs/triage/v5/fix-sketches/issue_3331.md b/docs/triage/v5/fix-sketches/issue_3331.md new file mode 100644 index 0000000000..6eda4c2c3c --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3331.md @@ -0,0 +1,40 @@ +# Fix sketch — #3331: Task update_package_xml does not write correct package.xml for AssignmentRules + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `metadata-etl` +**Issue**: + +## Bug + +- `cumulusci/tasks/metadata/metadata_map.yml:45-48` maps the `assignmentRules` folder to `type: AssignmentRule` (singular). MDAPI expects the plural type name (cf. `autoResponseRules:` at lines 60-63 + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: keep-open — one-line YAML fix; reporter offered a PR. +- pass2 labels: `severity:medium,area:metadata-etl,type:bug,good-first-issue` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3331.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3331:`). diff --git a/docs/triage/v5/fix-sketches/issue_3349.md b/docs/triage/v5/fix-sketches/issue_3349.md new file mode 100644 index 0000000000..c3b0bdb226 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3349.md @@ -0,0 +1,35 @@ +# Fix sketch — #3349: Make generated dataset recordType tables unique based on table instead of sf_object + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `bulkdata` +**Issue**: + +## Bug + +Make generated dataset recordType tables unique based on table instead of sf_object + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +_See narrative for recommended action._ + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3349.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3349:`). diff --git a/docs/triage/v5/fix-sketches/issue_3353.md b/docs/triage/v5/fix-sketches/issue_3353.md new file mode 100644 index 0000000000..3dc2777eea --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3353.md @@ -0,0 +1,35 @@ +# Fix sketch — #3353: Enable Snowfakery task to use recipes from other repositories + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `bulkdata` +**Issue**: + +## Bug + +Enable Snowfakery task to use recipes from other repositories + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +_See narrative for recommended action._ + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3353.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3353:`). diff --git a/docs/triage/v5/fix-sketches/issue_3407.md b/docs/triage/v5/fix-sketches/issue_3407.md new file mode 100644 index 0000000000..7f0e2cb86e --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3407.md @@ -0,0 +1,51 @@ +# Fix sketch — #3407: `set_service(service_config)` annotation lies + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `keychain` +**Issue**: + +## Bug + +- `cumulusci/core/keychain/base_project_keychain.py` lines 202-209 declare `service_config: ServiceConfig` on `set_service`. - `cumulusci/core/keychain/encrypted_file_project_keychain.py` line 717 + +## Target + +`cumulusci/core/keychain/base_project_keychain.py:202-219`. Also add the same widened annotation on the abstract `_set_service` (line 360) and propagate to `EncryptedFileProjectKeychain._set_service` (line 583). + +## Recommended approach (from triage narrative) + +- **Approach**: Widen the annotation. `set_service`'s `service_config` + parameter should be `Union[ServiceConfig, str]` (or `ServiceConfig | str | +bytes`) and the docstring updated to say "raw encrypted payload when + `config_encrypted=True`". The deeper refactor — splitting the API into + `set_service` (validated `ServiceConfig`) and `set_encrypted_service` + (raw blob) — is cleaner but breaks the public API and is out of scope + for this triage pass. +- **Target**: `cumulusci/core/keychain/base_project_keychain.py:202-219`. + Also add the same widened annotation on the abstract `_set_service` + (line 360) and propagate to `EncryptedFileProjectKeychain._set_service` + (line 583). +- **Size**: ~10 LOC plus a typing-import bump. Single-file change feasible. +- **Risk**: very low. Pure type-hint widening; no runtime behaviour change. + Downstream callers that already pass `ServiceConfig` keep working; + pyright/mypy users gain an accurate hint. +- **API break**: no. Widening a parameter type is non-breaking for + callers. + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3407.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3407:`). diff --git a/docs/triage/v5/fix-sketches/issue_3429.md b/docs/triage/v5/fix-sketches/issue_3429.md new file mode 100644 index 0000000000..d987f9aec3 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3429.md @@ -0,0 +1,40 @@ +# Fix sketch — #3429: Support overriding `cumulusci.yml` to be used for configuration + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `packaging` +**Issue**: + +## Bug + +- `cumulusci/core/config/project_config.py:82` — `config_filename = "cumulusci.yml"` is hardcoded. - `cumulusci/core/config/project_config.py:118-184` — only an `additional_yaml` kwarg (programmatic, used by MetaCI) is supported; no env var or CLI plumbing. - `git merge-base --is-ancestor 9d650ace2 HEAD` returns non-zero — PR #3969 (commits prefixed `feat(cli): add resolve_extra_yaml helper ... + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — feature is genuinely actionable on v4.10.0; auto-close once #3969 merges via `closed:fixed-by-pr-#3969`. +- pass2 labels: `severity:medium,area:packaging,area:cli,state:in-progress` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3429.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3429:`). diff --git a/docs/triage/v5/fix-sketches/issue_3440.md b/docs/triage/v5/fix-sketches/issue_3440.md new file mode 100644 index 0000000000..07665e61e0 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3440.md @@ -0,0 +1,40 @@ +# Fix sketch — #3440: Enhance `default_package_path` to serve multi-package projects better + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `packaging` +**Issue**: + +## Bug + +- `cumulusci/core/config/project_config.py:517-525` — implementation is the simple "first packageDirectory with `default: true`" pattern; falls back to `force-app`, then `src`. No name-based lookup, no multi-package warning, no hard fail when both are missing. + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — same multi-package umbrella as #2979 / #3429; would best be solved together. +- pass2 labels: `severity:low,area:packaging,area:sfdx,area:multi-package` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3440.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3440:`). diff --git a/docs/triage/v5/fix-sketches/issue_3441.md b/docs/triage/v5/fix-sketches/issue_3441.md new file mode 100644 index 0000000000..25446a09e9 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3441.md @@ -0,0 +1,40 @@ +# Fix sketch — #3441: `cci task run create_package_version` should allow `version_base: default` + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `packaging` +**Issue**: + +## Bug + +- `cumulusci/tasks/create_package_version.py:63-112` — `version_base: Optional[str]`; documented values are `None`, a literal version number, or `latest_github_release`. - `cumulusci/tasks/create_package_version.py:529-563` — `_get_base_version_number` only branches on `None` (default) and `"latest_github_release"`; any other string is parsed as a literal version. There is no `"default"`/`"hig... + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — could be solved minimally with a `default`/`highest` sentinel in `_get_base_version_number`, or generalized as a CCI null-override feature. +- pass2 labels: `severity:low,area:packaging,area:flow-overrides,area:cli` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3441.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3441:`). diff --git a/docs/triage/v5/fix-sketches/issue_3446.md b/docs/triage/v5/fix-sketches/issue_3446.md new file mode 100644 index 0000000000..f10894703d --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3446.md @@ -0,0 +1,40 @@ +# Fix sketch — #3446: CCI task push_qa crashes for Unlocked package with no namespace + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `packaging` +**Issue**: + +## Bug + +- `cumulusci/tasks/push/tasks.py:33` — `version_parts = version.split(".")` (no None-guard above). - `cumulusci/tasks/push/tasks.py:283-297` — `_run_task` does not validate `version` before calling `_get_version`. - Test: `/tmp/repro/3/tests/repro_3446_push_qa_no_version.py` passes on v4.10.0. + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — real bug, simple fix. +- pass2 labels: `bug`, `good-first-issue` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3446.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3446:`). diff --git a/docs/triage/v5/fix-sketches/issue_3464.md b/docs/triage/v5/fix-sketches/issue_3464.md new file mode 100644 index 0000000000..a09c4afc6c --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3464.md @@ -0,0 +1,62 @@ +# Fix sketch — #3464: Concise project-config documentation + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `docs` +**Issue**: + +## Bug + +Concise project-config documentation + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +Two-step path: + +1. **Tactical**: expand the `### Project Configurations` heading at + `docs/config.md:673` into a real reference subsection that lists + every `project:` top-level key with a one-sentence description and + one example value. Cross-link to `docs/dev.md` for in-depth treatment + of `dependencies` / `dependency_resolutions` / `dependency_pins` so + we are not duplicating the longer narratives, just providing a + central index. This alone closes the issue per the user's literal + ask. + +2. **Strategic** (separate, follow-up PR): backfill `Field(description=...)` + on every Pydantic attribute in `cumulusci_yml.py` and add a Sphinx + directive (or a `conf.py` autodoc hook) that emits the reference + table directly from the model at docs-build time. This keeps the + reference and the schema in lockstep — the same mechanism powers the + JSON schema (`cumulusci/schema/cumulusci.jsonschema.json`), so the + plumbing is straightforward. + +Step 1 is a single-day effort; step 2 is multi-day but pays back every +time a new field is added to `cumulusci.yml`. Recommend keep-open until +at least step 1 ships. + + + +# Subagent 18 (pymod) — Round 3 narrative + +Worktree: `.worktrees/repro-pymod` @ `worktree/repro/pymod` based on `origin/dev` (`1925a3083`). + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3464.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3464:`). diff --git a/docs/triage/v5/fix-sketches/issue_3470.md b/docs/triage/v5/fix-sketches/issue_3470.md new file mode 100644 index 0000000000..e8071216e1 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3470.md @@ -0,0 +1,38 @@ +# Fix sketch — #3470: Rename `ci_master` to `ci_main` (or alias) + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `cli` +**Issue**: + +## Bug + +`rg "ci_main"` returns no matches. davidmreed's 2022 reply indicated this requires flow-aliasing infrastructure first. + +## Target + +`cumulusci/cumulusci.yml` lines 823-835 + +## Recommended approach (from triage narrative) + +- pass1: `closed:stale-24mo` — 4yr stale; preserve as `closed:stale-24mo` rather than dismiss; the inclusive-language motivation is real and could be revisited if flow aliasing lands. +- pass2 labels: `enhancement,stale,inclusive-language` + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3470.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3470:`). diff --git a/docs/triage/v5/fix-sketches/issue_3471.md b/docs/triage/v5/fix-sketches/issue_3471.md new file mode 100644 index 0000000000..bea086f3ee --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3471.md @@ -0,0 +1,40 @@ +# Fix sketch — #3471: `Merged 0 commits into branch:` message displays when a non-Source Code change is + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `ci-integration` +**Issue**: + +## Bug + +The reported log message originates from `_merge`: The log line at 251 reports `compare.behind_by` from github3's CompareCommits. `behind_by` is computed from the GitHub compare-commits endpoint and reflects how many commits the destination branch is behind the merged commit _as of the comparison's chosen merge-base_; for "effectively no-op" content merges (e.g. README/test.txt scenarios where dow... + +## Target + +`cumulusci/tasks/github/merge.py` lines 241-262 + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — small, well-localized fix (replace `compare.behind_by` with `len(list(compare.commits))` or report the SHA returned from `self.repo.merge(...)`); add a test covering the `behind_by=0` case. +- pass2 labels: `bug, github, merge, low-priority` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3471.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3471:`). diff --git a/docs/triage/v5/fix-sketches/issue_3485.md b/docs/triage/v5/fix-sketches/issue_3485.md new file mode 100644 index 0000000000..990df3595c --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3485.md @@ -0,0 +1,38 @@ +# Fix sketch — #3485: "cci task run run_tests" generates incorrect test_results.xml format + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `cli` +**Issue**: + +## Bug + +- `cumulusci/tasks/apex/testrunner.py:803-834` — `_write_output` opens `junit_output` and writes `'\n'` with no `` declaration and no enclosing `` element. - The closing tag at line 834 is ``. This exactly matches the malformed XML the reporter showed. - `junit_output` defaults to `test_results.xml` (line 201-203), unchanged. + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — small mechanical fix, still affects users producing JUnit reports for CI. +- pass2 labels: `bug, area:apex, good-first-issue` + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3485.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3485:`). diff --git a/docs/triage/v5/fix-sketches/issue_3492.md b/docs/triage/v5/fix-sketches/issue_3492.md new file mode 100644 index 0000000000..43a5e337bc --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3492.md @@ -0,0 +1,38 @@ +# Fix sketch — #3492: Enhance the "-o" option of "cci flow run" to accept "project\_\_custom" attribute values + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `cli` +**Issue**: + +## Bug + +- `cumulusci/cli/flow.py:152-162` — parses `-o` pairs by splitting key on `"__"` and unpacking into exactly two parts (`task_name, option_name = key.split("__")`). - A user passing `-o project__custom__myattr value` would actually error with "too many values to unpack" because the split yields three elements; even worded as `-o project__custom value` there is no codepath that writes into `proj... + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — legitimate usability gap for matrix-style CI. +- pass2 labels: `enhancement, area:cli` + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3492.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3492:`). diff --git a/docs/triage/v5/fix-sketches/issue_3506.md b/docs/triage/v5/fix-sketches/issue_3506.md new file mode 100644 index 0000000000..c84bb3ea9f --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3506.md @@ -0,0 +1,38 @@ +# Fix sketch — #3506: when clause support for flow steps which call other flows + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `cli` +**Issue**: + +## Bug + +- `cumulusci/core/flowrunner.py:660-672` — when the step has a `task:` key, the StepSpec is built with `when=step_config.get("when")`. - `cumulusci/core/flowrunner.py:674-697` — the `flow:` branch recurses via `_visit_step(...)` passing only `parent_options`, `parent_ui_options`, and `from_flow`; it never reads or propagates `step_config.get("when")`. Any `when:` clause attached to a flow-call... + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — confirmed silent-failure foot-gun the user reported. +- pass2 labels: `enhancement, area:flows` + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3506.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3506:`). diff --git a/docs/triage/v5/fix-sketches/issue_3518.md b/docs/triage/v5/fix-sketches/issue_3518.md new file mode 100644 index 0000000000..0deb3a6439 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3518.md @@ -0,0 +1,40 @@ +# Fix sketch — #3518: Task add_picklist_entries always sets a default value for record types + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `metadata-etl` +**Issue**: + +## Bug + +- `cumulusci/tasks/metadata_etl/picklists.py:177` missing `()` after `.lower`. - `cumulusci/tasks/metadata_etl/picklists.py:214-221` unconditionally sets defaults whenever `default` is truthy. + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: keep-open — small targeted fix. +- pass2 labels: `severity:high,area:metadata-etl,type:bug` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3518.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3518:`). diff --git a/docs/triage/v5/fix-sketches/issue_3541.md b/docs/triage/v5/fix-sketches/issue_3541.md new file mode 100644 index 0000000000..b709dadb17 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3541.md @@ -0,0 +1,65 @@ +# Fix sketch — #3541: `None__dev` SFDX alias + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `keychain` +**Issue**: + +## Bug + +- `cumulusci/core/keychain/base_project_keychain.py` lines 77-79: - When `project_config.project__name` is None (cumulusci.yml without a `project.name`, or partially-loaded project_config), this f-string + +## Target + +`cumulusci/core/keychain/base_project_keychain.py:77-79`. Migration helper recommended to scan the keychain for `None__*` aliases and rewrite them once a real `project.name` is available. + +## Recommended approach (from triage narrative) + +- **Approach**: Guard the alias construction. Two reasonable options: + (1) raise `CumulusCIException("Cannot build sfdx_alias: project.name is not set in cumulusci.yml")` — surfaces the misconfiguration at the earliest possible moment. + (2) Fall back to `f"{org_name}"` (no prefix) when `project__name` is None, with a `logger.warning`. Less disruptive for existing setups. + Option 2 is the safer change; option 1 is the more correct one. Pick based on willingness to break first-run UX. + +- **Target**: `cumulusci/core/keychain/base_project_keychain.py:77-79`. + Migration helper recommended to scan the keychain for `None__*` aliases + and rewrite them once a real `project.name` is available. + +- **Size**: ~10 LOC for the guard, ~30 LOC including a one-shot migration + pass on keychain load. + +- **Risk**: medium. Existing keychains in the wild may already contain + `None__dev` rows; option 2 silently writes a new alias on next run, + option 1 forces the user to fix cumulusci.yml. Document either way in + CHANGELOG. + +- **API break**: no public API change. The `OrgConfig.sfdx_alias` field + shape is preserved; only its derivation logic shifts. + +- **Bonus**: remove the `cannot-reproduce` label — the repro here is + deterministic. + + + +# Subagent 17 (docs) — Round 3 narrative + +Worktree: `.worktrees/repro-docs` @ `1925a3083` (off `origin/dev`). +Issues processed: 3/3 (#773, #2500, #3464). +Verdict tally: 3 REPRODUCED-on-dev (all pure doc-gaps with code-level +testable assertions). + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3541.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3541:`). diff --git a/docs/triage/v5/fix-sketches/issue_3543.md b/docs/triage/v5/fix-sketches/issue_3543.md new file mode 100644 index 0000000000..79d89f7209 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3543.md @@ -0,0 +1,40 @@ +# Fix sketch — #3543: New Option `load_sfdx_project_paths` for dx_convert_from Task + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `metadata-etl` +**Issue**: + +## Bug + +- `cumulusci/tasks/dx_convert_from.py:7-14` exposes only `extra` and `src_dir`; no `load_sfdx_project_paths` / `resolve_sfdx_package_dirs`. - The grep hits in `project_config.py` and `cli/project.py` are unrelated + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: keep-open — feature still unimplemented; reporter offered a draft PR. +- pass2 labels: `severity:low,area:metadata-etl,type:enhancement` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3543.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3543:`). diff --git a/docs/triage/v5/fix-sketches/issue_3549.md b/docs/triage/v5/fix-sketches/issue_3549.md new file mode 100644 index 0000000000..4ecff20e7d --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3549.md @@ -0,0 +1,38 @@ +# Fix sketch — #3549: Deploy to Salesforce does not create a test output + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `cli` +**Issue**: + +## Bug + +- `cumulusci/tasks/salesforce/Deploy.py:49-94` — exposes `test_level` and `specified_tests` options and validates them. - `cumulusci/tasks/salesforce/Deploy.py:150-154` — passes them through to the metadata API call but never captures `runTestResult`/`runTestsResult` from the response. - `rg "junit_output|test_results"` against `cumulusci/tasks/salesforce/Deploy.py` and `cumulusci/salesforce... + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — natural feature; tracks #3564. +- pass2 labels: `enhancement, area:metadata-deploy` + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3549.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3549:`). diff --git a/docs/triage/v5/fix-sketches/issue_3570.md b/docs/triage/v5/fix-sketches/issue_3570.md new file mode 100644 index 0000000000..081c74726c --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3570.md @@ -0,0 +1,38 @@ +# Fix sketch — #3570: Feature Request: Flow "finally" or "error" path + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `cli` +**Issue**: + +## Bug + +- `cumulusci/core/flowrunner.py` — only `ignore_failure` (mapped to `StepSpec.allow_failure`, line 122/144) and the `finally:` Python clause inside `flow.run()` (line 500) handle failures. There is no flow-step type for `finally:` / `on_error:` / `cleanup:` / `always_run`. `rg "finally|on_error|on_failure|always_run"` confirms. - `_run_step` (line 503-536) re-raises on `result.exception` if no... + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — design-level feature, but problem is real (rollback, notify on partial failure). +- pass2 labels: `enhancement, area:flows` + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3570.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3570:`). diff --git a/docs/triage/v5/fix-sketches/issue_3585.md b/docs/triage/v5/fix-sketches/issue_3585.md new file mode 100644 index 0000000000..14bfd6e3f2 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3585.md @@ -0,0 +1,41 @@ +# Fix sketch — #3585: Error Occurs when Using `update_package_xml` on object with `xsi:nil="true"` + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `metadata-etl` +**Issue**: + +## Bug + +- `cumulusci/tasks/metadata/package.py:115-130` — when a folder has objects it instantiates the registered parser; for `objects/` the parser uses the metadata tree which is strict about namespaces. + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: keep-open — needs either a namespace-shim before parsing or + pre-stripping of `xsi:nil` attributes. +- pass2 labels: `severity:medium,area:metadata-etl,type:bug,sfdx-compat` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3585.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3585:`). diff --git a/docs/triage/v5/fix-sketches/issue_3593.md b/docs/triage/v5/fix-sketches/issue_3593.md new file mode 100644 index 0000000000..2d3977629d --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3593.md @@ -0,0 +1,40 @@ +# Fix sketch — #3593: `dx` task doesn't work for some commands like `project convert source` + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `packaging` +**Issue**: + +## Bug + +- `cumulusci/tasks/sfdx.py:46-51` — `SFDXOrgTask._get_command` unconditionally appends `" -o {username}"` for any `ScratchOrgConfig`, regardless of whether the underlying sf subcommand accepts a target-org flag. - Repro test FAILS with the resulting command: `sf project convert source -r src -d force-app -o test@example.com` — the same shape that the issue reporter said sf cli rejects. - Not... + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — needs an opt-out option (e.g. `pass_org: False` or a `no_org_command` whitelist). Verifying actual sf cli rejection of `-o` for `project convert source` would need an org/sf cli; the CCI side of the bug is unchanged. +- pass2 labels: `severity:medium,area:packaging,area:sfdx,area:dx-task,state:needs-design` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3593.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3593:`). diff --git a/docs/triage/v5/fix-sketches/issue_3602.md b/docs/triage/v5/fix-sketches/issue_3602.md new file mode 100644 index 0000000000..ac3bfca9d4 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3602.md @@ -0,0 +1,54 @@ +# Fix sketch — #3602: Need Chrome/Firefox options(browser options/capabilities) in 'Open Test Browser' Keyword + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `robotframework` +**Issue**: + +## Bug + +- `cumulusci/robotframework/SalesforcePlaywright.py:60-62` — `def open_test_browser(self, size=None, useralias=None, wait=True, record_video=None):` has no `browser_options`/`extra_options`/`**kwargs` hook. - `cumulusci/robotframework/Salesforce.robot:103` — Selenium keyword signature `[Arguments] ${size}=... ${alias}=${NONE} ${wait}=True ${useralias}=${NONE}` — same gap. - `cumulusci/ro... + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- Approach (Playwright): add a `browser_options: dict | None = None` kwarg; pass through to `new_browser` (browser-launch options) and a separate `context_options` dict merged into the `new_context` call. +- Approach (Selenium): expose a `${EXTRA_CHROME_OPTIONS}` variable / list argument honoured by `Get Chrome Options`; alternatively add an `extra_options` argument to `Open Test Browser` and pipe through to `Create Webdriver With Retry`. +- Target: `cumulusci/robotframework/SalesforcePlaywright.py:60-117`; `cumulusci/robotframework/Salesforce.robot:77-168`. +- Size: medium (~30-60 lines across both implementations + tests + docs). +- Risk: low — additive parameter with safe default. +- API break: no (default `None` preserves current behaviour). + +**Recommended action**: + +- pass1: `keep-open` — reasonable, scoped feature ask; age <36mo; no PR yet; tractable medium-sized contribution. +- pass2 labels: `enhancement, robotframework, playwright, good-second-issue` +- triage test: `cumulusci/tests/triage/test_issue_3602.py` + + + +# Subagent 14 — scratch-org-config theme, Round 3 + +Working tree: `.worktrees/repro-scratch` on `worktree/repro/scratch` off `origin/dev` at `1925a3083`. + +Triaged 3 issues (#3910, #3306, #710). All three remain actionable on dev: #3910 has an open fix PR; #3306 and #710 are never-implemented enhancements. + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3602.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3602:`). diff --git a/docs/triage/v5/fix-sketches/issue_3603.md b/docs/triage/v5/fix-sketches/issue_3603.md new file mode 100644 index 0000000000..2b763f412f --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3603.md @@ -0,0 +1,35 @@ +# Fix sketch — #3603: Any issue with git results in the unhelpful "404 not found" error + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `dependencies` +**Issue**: + +## Bug + +Any issue with git results in the unhelpful "404 not found" error + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +_See narrative for recommended action._ + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3603.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3603:`). diff --git a/docs/triage/v5/fix-sketches/issue_3604.md b/docs/triage/v5/fix-sketches/issue_3604.md new file mode 100644 index 0000000000..1769048e12 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3604.md @@ -0,0 +1,35 @@ +# Fix sketch — #3604: Task request: Update sfdx-project.json dependencies based off of computed cumulusci dependencies + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `dependencies` +**Issue**: + +## Bug + +Task request: Update sfdx-project.json dependencies based off of computed cumulusci dependencies + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +_See narrative for recommended action._ + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3604.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3604:`). diff --git a/docs/triage/v5/fix-sketches/issue_3613.md b/docs/triage/v5/fix-sketches/issue_3613.md new file mode 100644 index 0000000000..6acd35fd0a --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3613.md @@ -0,0 +1,47 @@ +# Fix sketch — #3613: AddFieldsToPageLayout — "Cannot find metadata file" + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `metadata-etl` +**Issue**: + +## Bug + +AddFieldsToPageLayout — "Cannot find metadata file" + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `improve-error-message` — keep open as a UX bug. +- pass2 labels: `bug`, `good-first-issue` + +**Notes**: Two complementary improvements would help: + +1. In `_transform` (base.py:332), include the actual list of files retrieved into `source_metadata_dir` in the error message so the user can spot the naming mismatch. +2. In `AddFieldsToPageLayout._init_options`, warn when an api_name does not contain `-` (Layout API names always do). + +The user was on Windows in 2023 — note that the user might also have been hitting a backslash path issue, but the underlying class of bug is the same: api_name format mismatch. + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3613.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3613:`). diff --git a/docs/triage/v5/fix-sketches/issue_3618.md b/docs/triage/v5/fix-sketches/issue_3618.md new file mode 100644 index 0000000000..e343894ad3 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3618.md @@ -0,0 +1,38 @@ +# Fix sketch — #3618: Allow for list when deleting/removing CumulusCI orgs + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `cli` +**Issue**: + +## Bug + +- `cumulusci/cli/org.py:519-545` — `org_remove` decorated with `@orgname_option_or_argument(required=True)`, takes a single `org_name`. - `cumulusci/cli/org.py:605-625` — `org_scratch_delete` same pattern, single `org_name`. - No `nargs=-1`, no comma-split helper; passing `org1,org2` would be treated as a single literal alias and fail keychain lookup. + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — legitimately useful for cleanup workflows; small implementation surface. +- pass2 labels: `enhancement, area:cli, good-first-issue` + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3618.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3618:`). diff --git a/docs/triage/v5/fix-sketches/issue_3619.md b/docs/triage/v5/fix-sketches/issue_3619.md new file mode 100644 index 0000000000..4872dc1f16 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3619.md @@ -0,0 +1,35 @@ +# Fix sketch — #3619: Dependency_pins does not honor passwords + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `dependencies` +**Issue**: + +## Bug + +Dependency_pins does not honor passwords + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +_See narrative for recommended action._ + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3619.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3619:`). diff --git a/docs/triage/v5/fix-sketches/issue_3649.md b/docs/triage/v5/fix-sketches/issue_3649.md new file mode 100644 index 0000000000..ec2cfaaf6d --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3649.md @@ -0,0 +1,35 @@ +# Fix sketch — #3649: Support serial loads with update_data task + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `bulkdata` +**Issue**: + +## Bug + +Support serial loads with update_data task + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +_See narrative for recommended action._ + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3649.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3649:`). diff --git a/docs/triage/v5/fix-sketches/issue_3663.md b/docs/triage/v5/fix-sketches/issue_3663.md new file mode 100644 index 0000000000..d65ecf4403 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3663.md @@ -0,0 +1,38 @@ +# Fix sketch — #3663: When clause | Ability to pass in prior task response values + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `cli` +**Issue**: + +## Bug + +- `cumulusci/core/flowrunner.py:510-516` — the `when` Jinja context is hardcoded to `{"project_config": ..., "org_config": ...}`. Prior step results (`self.results`) are not exposed. - The `^^task.return_value` resolver lives elsewhere (option resolution path) and is not threaded into the `when` evaluator. + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — natural extension of `when`; complements #3506. +- pass2 labels: `enhancement, area:flows` + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3663.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3663:`). diff --git a/docs/triage/v5/fix-sketches/issue_3692.md b/docs/triage/v5/fix-sketches/issue_3692.md new file mode 100644 index 0000000000..a6a8eb9f73 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3692.md @@ -0,0 +1,42 @@ +# Fix sketch — #3692: No parser configuration found for subdirectory digitalExperiences + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `metadata-etl` +**Issue**: + +## Bug + +- `cumulusci/tasks/metadata/metadata_map.yml` has no `digitalExperiences` key. - `cumulusci/tasks/metadata/package.py:115-118` raises + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: keep-open — add `digitalExperiences` (and likely + `digitalExperienceConfigs`) entries to `metadata_map.yml` with + appropriate parser classes (probably a bundle parser). +- pass2 labels: `severity:medium,area:metadata-etl,type:bug` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3692.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3692:`). diff --git a/docs/triage/v5/fix-sketches/issue_3699.md b/docs/triage/v5/fix-sketches/issue_3699.md new file mode 100644 index 0000000000..4e3b86f1a8 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3699.md @@ -0,0 +1,35 @@ +# Fix sketch — #3699: Sort of the data during extraction + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `bulkdata` +**Issue**: + +## Bug + +Sort of the data during extraction + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +_See narrative for recommended action._ + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3699.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3699:`). diff --git a/docs/triage/v5/fix-sketches/issue_3700.md b/docs/triage/v5/fix-sketches/issue_3700.md new file mode 100644 index 0000000000..ed34a66b62 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3700.md @@ -0,0 +1,35 @@ +# Fix sketch — #3700: Trying to do an upsert on a master-detail child object gets an error around permission + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `bulkdata` +**Issue**: + +## Bug + +Trying to do an upsert on a master-detail child object gets an error around permission + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +_See narrative for recommended action._ + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3700.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3700:`). diff --git a/docs/triage/v5/fix-sketches/issue_3701.md b/docs/triage/v5/fix-sketches/issue_3701.md new file mode 100644 index 0000000000..b6e8513417 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3701.md @@ -0,0 +1,35 @@ +# Fix sketch — #3701: set a mapping to the id instead of it being either a number or the salesforce id + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `bulkdata` +**Issue**: + +## Bug + +set a mapping to the id instead of it being either a number or the salesforce id + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +_See narrative for recommended action._ + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3701.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3701:`). diff --git a/docs/triage/v5/fix-sketches/issue_3721.md b/docs/triage/v5/fix-sketches/issue_3721.md new file mode 100644 index 0000000000..9ae198c805 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3721.md @@ -0,0 +1,40 @@ +# Fix sketch — #3721: `create_package_version` `version_name` default should be version number, not "Release" + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `packaging` +**Issue**: + +## Bug + +- `cumulusci/tasks/create_package_version.py:184` — `version_name=self.options.get("version_name") or "Release"`. Default is still the literal string `"Release"`. - `cumulusci/cumulusci.yml:684-686` — `upload_production` hard-codes `name: Release`. - `cumulusci/tasks/salesforce/package_upload.py:147-154` — passes `VersionName` straight through; no jinja2/template support. + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — needs upstream port + design (templating? plain version number? both 1GP and 2GP?). +- pass2 labels: `severity:low,area:packaging,area:1gp,area:2gp` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3721.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3721:`). diff --git a/docs/triage/v5/fix-sketches/issue_3734.md b/docs/triage/v5/fix-sketches/issue_3734.md new file mode 100644 index 0000000000..6bc8c75607 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3734.md @@ -0,0 +1,38 @@ +# Fix sketch — #3734: upload_production fails with FIELD_INTEGRITY_EXCEPTION when latest is Beta patch + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `packaging` +**Issue**: + +## Bug + +- `cumulusci/tasks/salesforce/package_upload.py:80-98` — SOQL query, `ORDER BY MajorVersion DESC, MinorVersion DESC, PatchVersion DESC, ReleaseState DESC LIMIT 1`. - `cumulusci/tasks/salesforce/package_upload.py:134-137` — Beta branch sets `minor_version` to the same minor. - Test passes on v4.10.0 with mocked `_get_one_record`. + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — confirmed real bug; remove the stale `cannot-reproduce`/`awaiting-more-details` labels. +- pass2 labels: `bug` + +--- + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3734.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3734:`). diff --git a/docs/triage/v5/fix-sketches/issue_3746.md b/docs/triage/v5/fix-sketches/issue_3746.md new file mode 100644 index 0000000000..39362c9dd3 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3746.md @@ -0,0 +1,35 @@ +# Fix sketch — #3746: Deleted Versions used for determining next version + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `packaging` +**Issue**: + +## Bug + +Deleted Versions used for determining next version + +## Target + +`cumulusci/tasks/create_package_version.py` lines 529-545 + +## Recommended approach (from triage narrative) + +_See narrative for recommended action._ + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3746.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3746:`). diff --git a/docs/triage/v5/fix-sketches/issue_3754.md b/docs/triage/v5/fix-sketches/issue_3754.md new file mode 100644 index 0000000000..dce1ed937a --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3754.md @@ -0,0 +1,38 @@ +# Fix sketch — #3754: Enable configuration for cci version update sources + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `cli` +**Issue**: + +## Bug + +- `cumulusci/cli/utils.py:65-79` — `get_latest_final_version` hits `https://pypi.org/pypi/cumulusci/json` literally, no env-var, no kwarg. - `cumulusci/cli/utils.py:82-101` — `check_latest_version` cannot be disabled via flag/env. Workaround in the comments (touch `~/.cumulusci/cumulus_timestamp` to a far-future epoch) confirmed by inspecting the timestamp logic at lines 38-50, 86-89. + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — easy add (e.g. `CUMULUSCI_DISABLE_VERSION_CHECK` env), helps offline/restricted environments. +- pass2 labels: `enhancement, area:cli` + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3754.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3754:`). diff --git a/docs/triage/v5/fix-sketches/issue_3758.md b/docs/triage/v5/fix-sketches/issue_3758.md new file mode 100644 index 0000000000..5f920c96b1 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3758.md @@ -0,0 +1,40 @@ +# Fix sketch — #3758: Flow `push_upgrade_org` is incorrectly defined + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `packaging` +**Issue**: + +## Bug + +- `cumulusci/cumulusci.yml:1161-1177` — final step is `flow: config_qa`. The bug report (correctly, in my view) argues this should be `config_managed` because push upgrades target managed-package orgs (UAT sandboxes), not QA scratch orgs. - Repro test FAILS with `config_qa` != `config_managed`. - Both flows currently expand to the same steps (`deploy_post`, `update_admin_profile`, `load_samp... + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — single-line YAML fix; great `good-first-issue` candidate. Out of scope for this triage pass per task constraints (do not fix bugs). +- pass2 labels: `severity:medium,area:packaging,area:flows,good-first-issue` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3758.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3758:`). diff --git a/docs/triage/v5/fix-sketches/issue_3768.md b/docs/triage/v5/fix-sketches/issue_3768.md new file mode 100644 index 0000000000..8ea2e6e0de --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3768.md @@ -0,0 +1,35 @@ +# Fix sketch — #3768: Snowfakery Batch Size and Just Once + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `bulkdata` +**Issue**: + +## Bug + +Snowfakery Batch Size and Just Once + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +_See narrative for recommended action._ + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3768.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3768:`). diff --git a/docs/triage/v5/fix-sketches/issue_3771.md b/docs/triage/v5/fix-sketches/issue_3771.md new file mode 100644 index 0000000000..fe6506d353 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3771.md @@ -0,0 +1,41 @@ +# Fix sketch — #3771: find_replace transforms on XPath with predicates does not work + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `metadata-etl` +**Issue**: + +## Bug + +- `cumulusci/core/source_transforms/transforms.py:420-435` — naive predicate handling. - `git log --all --oneline --grep="3772\|3771\|XPath.*predicate"` shows + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: keep-open — the leboff PR is a viable starting point; or implement + the reporter's "strip xmlns then re-add" approach for simplicity. +- pass2 labels: `severity:medium,area:source-transforms,type:bug,has-pr` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3771.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3771:`). diff --git a/docs/triage/v5/fix-sketches/issue_3773.md b/docs/triage/v5/fix-sketches/issue_3773.md new file mode 100644 index 0000000000..5cfa405e82 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3773.md @@ -0,0 +1,41 @@ +# Fix sketch — #3773: retrieve_profile task seems to be missing some Metadata + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `metadata-etl` +**Issue**: + +## Bug + +- `cumulusci/salesforce_api/retrieve_profile_api.py:164-195` — no `FieldPermissions` query. - Greped `FieldPermission|field_permission|fieldPermission` — only the + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: keep-open — needs additional `FieldPermissions` query plus + inclusion of those parent SObjectTypes in the `CustomObject` retrieve set. +- pass2 labels: `severity:medium,area:retrieve-profile,type:bug` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3773.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3773:`). diff --git a/docs/triage/v5/fix-sketches/issue_3849.md b/docs/triage/v5/fix-sketches/issue_3849.md new file mode 100644 index 0000000000..8eab4bb419 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3849.md @@ -0,0 +1,35 @@ +# Fix sketch — #3849: urllib3 v2 breaks Robot tests on a fresh pip install + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `python-modernization` +**Issue**: + +## Bug + +urllib3 v2 breaks Robot tests on a fresh pip install + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +_See narrative for recommended action._ + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3849.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3849:`). diff --git a/docs/triage/v5/fix-sketches/issue_3873.md b/docs/triage/v5/fix-sketches/issue_3873.md new file mode 100644 index 0000000000..5c00a0d963 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3873.md @@ -0,0 +1,47 @@ +# Fix sketch — #3873: Standalone Robot Framework Library for Selenium-Based Salesforce Automation (Inspired by Copado QForce) + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `robotframework` +**Issue**: + +## Bug + +- `cumulusci/robotframework/base_library.py:1-39` — `BaseLibrary` lazily resolves `cumulusci.robotframework.CumulusCI`, `cumulusci.robotframework.Salesforce`, `cumulusci.robotframework.SalesforceAPI` libraries through Robot's `BuiltIn`, which require a CumulusCI project context. - `cumulusci/robotframework/Salesforce.py:20-28` — imports `cumulusci.robotframework.locator_manager`, `faker_mixin`... + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- Approach: factor a UI-only subset out of `cumulusci.robotframework.*` into a sibling distribution (e.g. `salesforce-robot-library`) that depends only on Selenium/Playwright + the locator dictionaries; have CumulusCI's Robot task consume that subset. +- Target: package layout change spanning `cumulusci/robotframework/` and `pyproject.toml`. +- Size: large (>100 lines, design change + new distribution). +- Risk: medium — must not break existing tasks/keywords. +- API break: no (additive new distribution). + +**Recommended action**: + +- pass1: `keep-open` — reasonable architectural request, age <24mo, no community PR yet; worth retaining as roadmap signal. +- pass2 labels: `enhancement, robotframework, scope-large` +- triage test: n/a — no concrete API to xfail against. + +--- + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +_None yet — add a regression test as part of the fix-PR._. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3873:`). diff --git a/docs/triage/v5/fix-sketches/issue_3889.md b/docs/triage/v5/fix-sketches/issue_3889.md new file mode 100644 index 0000000000..a6281cd2c4 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3889.md @@ -0,0 +1,38 @@ +# Fix sketch — #3889: Uninstall 2GP task request + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `packaging` +**Issue**: + +## Bug + +- `cumulusci/cumulusci.yml:615-642` — Uninstall tasks: `uninstall_managed`, `uninstall_packaged`, `uninstall_packaged_incremental`, `uninstall_src`, `uninstall_pre`, `uninstall_post`. None take a 04t id. - `cumulusci/tasks/salesforce/UninstallPackage.py:6-32` — `UninstallPackage` accepts only `namespace` (and `purge_on_delete`). Builds an `UninstallPackageZipBuilder` from the namespace. - `c... + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — needs a new `UninstallPackageVersion` task (or extend `UninstallPackage`) that calls Tooling API directly so it doesn't depend on sf cli stability (per the user's note about sf cli breaking changes). +- pass2 labels: `severity:medium,area:packaging,area:2gp,area:unlocked-package` + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3889.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3889:`). diff --git a/docs/triage/v5/fix-sketches/issue_3910.md b/docs/triage/v5/fix-sketches/issue_3910.md new file mode 100644 index 0000000000..6e3cf20407 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3910.md @@ -0,0 +1,39 @@ +# Fix sketch — #3910: JSON Schema incorrectly defines namespaced field as string instead of boolean for scratch org configuration + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `scratch-org-config` +**Issue**: + +## Bug + +JSON Schema incorrectly defines namespaced field as string instead of boolean for scratch org configuration + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- Approach: land PR #3911 essentially as-is (one-line Pydantic field change in `cumulusci_yml.py` + `make schema` regenerated `cumulusci.jsonschema.json`). Both edits must ship together because `test_schema_is_current` would otherwise fail. +- Target file:line: `cumulusci/utils/yaml/cumulusci_yml.py:150` (`namespaced: str = None` → `namespaced: bool = None`); regenerate `cumulusci/schema/cumulusci.jsonschema.json`. +- Size: small. +- Risk: low. The only Pydantic consumers of `ScratchOrg.namespaced` are YAML-validation pathways; the runtime keychain path already uses booleans. +- API break: no (silent coercion was incidental and arguably already broken for users). + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3910.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3910:`). diff --git a/docs/triage/v5/fix-sketches/issue_3931.md b/docs/triage/v5/fix-sketches/issue_3931.md new file mode 100644 index 0000000000..cecb0bc44a --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3931.md @@ -0,0 +1,42 @@ +# Fix sketch — #3931: Specifying a profile in cumulusci.tasks.salesforce.ProfileGrantAllAccess results in an error + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `metadata-etl` +**Issue**: + +## Bug + +Specifying a profile in cumulusci.tasks.salesforce.ProfileGrantAllAccess results in an error + +## Target + +`cumulusci/tasks/salesforce/update_profile.py` lines 290-292 + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — small, contained fix. +- pass2 labels: `bug` + +**Notes**: Minimal fix at update_profile.py:290-293 — bind `rt_elem = elem.find("recordType")` and check `if rt_elem is not None and rt_elem.text == rt["record_type"]`. Worth a quick scan of sibling code in `_set_record_types` for similar None-deref patterns on optional XML children. + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3931.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3931:`). diff --git a/docs/triage/v5/fix-sketches/issue_3951.md b/docs/triage/v5/fix-sketches/issue_3951.md new file mode 100644 index 0000000000..bc42d0b919 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3951.md @@ -0,0 +1,47 @@ +# Fix sketch — #3951: set_duplicate_rule_status broken + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `metadata-etl` +**Issue**: + +## Bug + +set_duplicate_rule_status broken + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `improve-error-message` — keep open. +- pass2 labels: `bug`, `good-first-issue`, `documentation` + +**Notes**: Two improvements: + +1. Update the `set_duplicate_rule_status` task option help to call out the `.` format requirement. +2. Same as #3613 — improve the base.py:332 error to list the files actually retrieved. + +The `Cannot find metadata file` error is shared across most `MetadataSingleEntityTransformTask` subclasses, so a single base-class fix would benefit several issues at once. + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3951.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3951:`). diff --git a/docs/triage/v5/fix-sketches/issue_3953.md b/docs/triage/v5/fix-sketches/issue_3953.md new file mode 100644 index 0000000000..4b0d6ebeea --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3953.md @@ -0,0 +1,40 @@ +# Fix sketch — #3953: add_picklist_entries never works through CLI + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `metadata-etl` +**Issue**: + +## Bug + +add_picklist_entries never works through CLI + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — single-line fix. +- pass2 labels: `bug`, `good-first-issue` + +**Notes**: Minimal fix in `AddPicklistEntries._init_options`: `if isinstance(self.options.get("entries"), str): self.options["entries"] = json.loads(self.options["entries"])`. Apply same pattern to `record_types` for symmetry. The same class of bug exists in `AddFieldsToPageLayout` (encountered while investigating #3613): `cci task run add_page_layout_fields ... -o fields '[...]'` -> `pydantic.ValidationError: value is not a valid list`. A more general fix would be a helper in the CLI/task-base that auto-parses JSON strings for list-typed options, or schema-driven coercion via the new task_options Pydantic models. + +--- + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3953.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3953:`). diff --git a/docs/triage/v5/fix-sketches/issue_3955.md b/docs/triage/v5/fix-sketches/issue_3955.md new file mode 100644 index 0000000000..8bf8faf6b6 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_3955.md @@ -0,0 +1,47 @@ +# Fix sketch — #3955: Open Test Browser - SalesforcePlaywright.robot + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `robotframework` +**Issue**: + +## Bug + +- `cumulusci/robotframework/SalesforcePlaywright.py:106` — `width, height = size.split("x", 1)` returns two `str` values. - `cumulusci/robotframework/SalesforcePlaywright.py:109-111` — the strings are forwarded directly: - Playwright contract requires `viewport.width` / `viewport.height` to be `int`, hence the runtime error `viewport.width: expected integer, got string` reported by the user ... + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- Approach: cast both fragments to `int` immediately after splitting. +- Target: `cumulusci/robotframework/SalesforcePlaywright.py:106` +- Size: small (~1 line) — e.g. `width, height = (int(v) for v in size.split("x", 1))` +- Risk: low — preserves all existing call sites; users were already passing the documented `WxH` string format. +- API break: no. + +**Recommended action**: + +- pass1: `keep-open` — clear, low-risk, single-line bug fix; great good-first-issue candidate. +- pass2 labels: `bug, robotframework, playwright, good-first-issue` +- triage test: `cumulusci/tests/triage/test_issue_3955.py` + +--- + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_3955.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #3955:`). diff --git a/docs/triage/v5/fix-sketches/issue_675.md b/docs/triage/v5/fix-sketches/issue_675.md new file mode 100644 index 0000000000..5b957115db --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_675.md @@ -0,0 +1,47 @@ +# Fix sketch — #675: Show full traceback for Python exceptions in robot keywords + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `robotframework` +**Issue**: + +## Bug + +- `cumulusci/tasks/robotframework/robotframework.py` configures listeners (`KeywordLogger`, `DebugListener`) but never sets `loglevel`/`logtitle`/`pythonpath` to surface Python tracebacks. `rg 'traceback|format_exc|format_tb' cumulusci/robotframework/` returns 0 matches; same for `cumulusci/tasks/robotframework/`. - Robot Framework's default behaviour: when a Python keyword raises, only `str(e... + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- Approach: in `Robot._init_options`, default `options.loglevel` to include `TRACE`, OR install a small listener that captures `sys.exc_info()` in keyword-end events and emits a formatted traceback through `robot.api.logger.error`. +- Target: `cumulusci/tasks/robotframework/robotframework.py:104` (`_init_options`). +- Size: small (~10 lines). +- Risk: low — additive listener; opt-out via options if needed. +- API break: no. + +**Recommended action**: + +- pass1: `closed:stale-24mo` — issue opened 2018-07, last activity 2018-09, ~8 years inactivity. Two simple workarounds exist (`-o loglevel:TRACE`, `traceback.format_exc()` in keywords). Surface as a tip in docs rather than keep the bug open. +- pass2 labels: `cli-usability, robotframework, stale` +- triage test: n/a — observable only in a robot run. + +--- + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +_None yet — add a regression test as part of the fix-PR._. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #675:`). diff --git a/docs/triage/v5/fix-sketches/issue_710.md b/docs/triage/v5/fix-sketches/issue_710.md new file mode 100644 index 0000000000..fa9db96add --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_710.md @@ -0,0 +1,41 @@ +# Fix sketch — #710: Allow disabling default scratch org configs + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `scratch-org-config` +**Issue**: + +## Bug + +Allow disabling default scratch org configs + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +- Approach: introduce a sentinel for "disabled" (recommend an explicit `disabled: true` flag on each scratch org config rather than relying on `config_file: None`, which has overloaded meaning) and skip disabled entries in `_load_scratch_orgs`. Optional: a stricter `merge_config` mode that preserves `None` overrides under `orgs.scratch.*`. +- Target file:line: `cumulusci/utils/yaml/cumulusci_yml.py:147` (add `disabled: bool = None` to `ScratchOrg`); `cumulusci/core/keychain/base_project_keychain.py:155` (skip when `config.get("disabled")`); regenerate `cumulusci/schema/cumulusci.jsonschema.json`. +- Size: small/medium. +- Risk: low. Existing keys remain compatible; only adds new opt-in behaviour. Needs a docs note (`docs/orgs/scratch.md`) on how to disable inherited defaults. +- API break: no (additive). The issue's literal `config_file: None` syntax would NOT be honoured under this proposal; if the team prefers that exact syntax instead, add a `dictmerge` exception so `None` overrides under `orgs.scratch.*` are preserved, then have `_load_scratch_orgs` skip entries with `config_file is None`. Either implementation satisfies the XFAIL test (`dev not in keychain.orgs`). + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_710.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #710:`). diff --git a/docs/triage/v5/fix-sketches/issue_733.md b/docs/triage/v5/fix-sketches/issue_733.md new file mode 100644 index 0000000000..0d32f60d1d --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_733.md @@ -0,0 +1,40 @@ +# Fix sketch — #733: Prompt to delete scratch org when creating one that already exists + +**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) +**Theme**: `cli` +**Issue**: + +## Bug + +Behaviour identical to the 2018 report — hard error, no interactive Y/N prompt. + +## Target + +`cumulusci/cli/runtime.py` lines 126-140 + +## Recommended approach (from triage narrative) + +- pass1: `closed:stale-24mo` — 7-year-old `cli-usability` enhancement, no traction, original tracking W-028291. +- pass2 labels: `enhancement,cli-usability,stale` + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_733.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #733:`). diff --git a/docs/triage/v5/fix-sketches/issue_773.md b/docs/triage/v5/fix-sketches/issue_773.md new file mode 100644 index 0000000000..2782a9a3d6 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_773.md @@ -0,0 +1,60 @@ +# Fix sketch — #773: Document task return values and results + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `docs` +**Issue**: + +## Bug + +Document task return values and results + +## Target + +_See narrative for target file:line._ + +## Recommended approach (from triage narrative) + +1. Add a class attribute on `BaseTask`: + +```python +return_values_schema: ClassVar[Dict[str, str]] = {} +``` + +where each key is the return-values dict key and each value is a one-line +description (parallel to how `task_options` already works). + +2. Extend `doc_task()` in `cumulusci/utils/__init__.py` to render a + "Return Values" RST section (heading + bullet list) when + `task_class.return_values_schema` is non-empty. Update the matching + `get_task_*` helpers to surface the schema for web-doc generation. + +3. Backfill the schema on tasks that already emit return values — search + for `self.return_values\[` across `cumulusci/tasks/`: at minimum + `PackageUpload`, `PromotePackageVersion`, `GithubRelease`, + `CreatePackageVersion`, dependency-resolution tasks. Each gets a few + lines. + +4. Lift the `attention` admonition in `docs/config.md:740-744` once + coverage is broad enough. + +Estimated effort: 1-2 day PR for the framework + first wave of tasks; an +ongoing "every new task documents its return values" contributor +expectation thereafter (enforce in `requesting-code-review` skill). + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_773.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #773:`). diff --git a/docs/triage/v5/fix-sketches/issue_808.md b/docs/triage/v5/fix-sketches/issue_808.md new file mode 100644 index 0000000000..d0fc1205c0 --- /dev/null +++ b/docs/triage/v5/fix-sketches/issue_808.md @@ -0,0 +1,42 @@ +# Fix sketch — #808: deploy_packaging flow runs uninstall_packaged_incremental with wrong package name + +**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) +**Theme**: `metadata-etl` +**Issue**: + +## Bug + +- `UninstallPackaged._init_options` (UninstallPackaged.py:22-25): - Compare to `InstallPackageVersion._init_options` (install_package_version.py:75-79) which DOES use the fall-back chain `name_managed -> name -> namespace`. The asymmetry is the bug. - Bug pattern is unchanged since 2018; no fix has landed. + +## Target + +`cumulusci/tasks/salesforce/UninstallPackaged.py` lines 22-25 + +## Recommended approach (from triage narrative) + +- pass1: `keep-open` — small, contained fix. +- pass2 labels: `bug`, `good-first-issue` + +**Notes**: jlantz's 2018 follow-up about deprecating `project__package__name_managed` (legacy NPSP-only feature) is a separate, larger conversation; for this triage the minimal symmetric fix is enough. + +--- + + + +## Size & risk + +| Field | Value | +| ------------------------------------ | ---------------------- | +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | + +## Regression test + +`cumulusci/tests/triage/test_issue_808.py`. Remove the `@pytest.mark.xfail` marker and confirm green. + +## Full narrative + +See `docs/triage/v5/repro-results.md` (search for `### #808:`). From 3c33dcaaf1565b92d7ca3cb25d559a46ad1c0b6d Mon Sep 17 00:00:00 2001 From: James Estevez Date: Thu, 14 May 2026 10:59:27 -0700 Subject: [PATCH 4/4] docs(triage/v5): scrub internal references and em-dashes Cleans the evidence pack and harvested xfail tests for external review: - Strip /tmp/repro/ session paths; replace with cumulusci/tests/triage/ test paths when the harvested test exists, else neutral placeholder. - Strip internal tracking IDs (Salesforce GUS work-item numbers) from narratives and notes. - Strip per-pass coordination scaffolding (round/subagent/wave headers and per-subagent summary chunks reduced to neutral prose). - Strip scratch-org alias names and DevHub alias from narratives. - Replace all em-dashes / en-dashes with ASCII colons or hyphens. - Cross-link Tranche 1 references between proposals.md, themes.md, and README.md. - Tighten AI assistance disclosure to omit specific model name and references to local-only intermediate artifacts. No semantic changes to verdicts, recommendations, or xfail markers. Test suite remains 79 xfailed / 0 xpassed. --- cumulusci/tests/triage/README.md | 10 +- cumulusci/tests/triage/test_issue_1348.py | 4 +- cumulusci/tests/triage/test_issue_1432.py | 4 +- cumulusci/tests/triage/test_issue_1769.py | 2 +- cumulusci/tests/triage/test_issue_2013.py | 2 +- cumulusci/tests/triage/test_issue_2140.py | 2 +- cumulusci/tests/triage/test_issue_2153.py | 4 +- cumulusci/tests/triage/test_issue_2325.py | 2 +- cumulusci/tests/triage/test_issue_2402.py | 2 +- cumulusci/tests/triage/test_issue_2500.py | 6 +- cumulusci/tests/triage/test_issue_2506.py | 2 +- cumulusci/tests/triage/test_issue_2507.py | 4 +- cumulusci/tests/triage/test_issue_2508.py | 4 +- cumulusci/tests/triage/test_issue_2826.py | 2 +- cumulusci/tests/triage/test_issue_2951.py | 4 +- cumulusci/tests/triage/test_issue_2979.py | 2 +- cumulusci/tests/triage/test_issue_3015.py | 2 +- cumulusci/tests/triage/test_issue_3024.py | 4 +- cumulusci/tests/triage/test_issue_3137.py | 2 +- cumulusci/tests/triage/test_issue_3161.py | 6 +- cumulusci/tests/triage/test_issue_3165.py | 6 +- cumulusci/tests/triage/test_issue_3307.py | 2 +- cumulusci/tests/triage/test_issue_3331.py | 4 +- cumulusci/tests/triage/test_issue_3349.py | 2 +- cumulusci/tests/triage/test_issue_3353.py | 2 +- cumulusci/tests/triage/test_issue_3407.py | 8 +- cumulusci/tests/triage/test_issue_3429.py | 2 +- cumulusci/tests/triage/test_issue_3440.py | 2 +- cumulusci/tests/triage/test_issue_3441.py | 2 +- cumulusci/tests/triage/test_issue_3446.py | 4 +- cumulusci/tests/triage/test_issue_3464.py | 8 +- cumulusci/tests/triage/test_issue_3470.py | 2 +- cumulusci/tests/triage/test_issue_3471.py | 4 +- cumulusci/tests/triage/test_issue_3485.py | 2 +- cumulusci/tests/triage/test_issue_3492.py | 4 +- cumulusci/tests/triage/test_issue_3506.py | 4 +- cumulusci/tests/triage/test_issue_3518.py | 4 +- cumulusci/tests/triage/test_issue_3541.py | 14 +- cumulusci/tests/triage/test_issue_3543.py | 2 +- cumulusci/tests/triage/test_issue_3549.py | 2 +- cumulusci/tests/triage/test_issue_3570.py | 6 +- cumulusci/tests/triage/test_issue_3585.py | 2 +- cumulusci/tests/triage/test_issue_3593.py | 2 +- cumulusci/tests/triage/test_issue_3602.py | 2 +- cumulusci/tests/triage/test_issue_3603.py | 2 +- cumulusci/tests/triage/test_issue_3604.py | 8 +- cumulusci/tests/triage/test_issue_3613.py | 2 +- cumulusci/tests/triage/test_issue_3618.py | 2 +- cumulusci/tests/triage/test_issue_3619.py | 4 +- cumulusci/tests/triage/test_issue_3649.py | 2 +- cumulusci/tests/triage/test_issue_3663.py | 4 +- cumulusci/tests/triage/test_issue_3692.py | 2 +- cumulusci/tests/triage/test_issue_3699.py | 4 +- cumulusci/tests/triage/test_issue_3700.py | 6 +- cumulusci/tests/triage/test_issue_3701.py | 2 +- cumulusci/tests/triage/test_issue_3721.py | 2 +- cumulusci/tests/triage/test_issue_3734.py | 4 +- cumulusci/tests/triage/test_issue_3746.py | 6 +- cumulusci/tests/triage/test_issue_3754.py | 2 +- cumulusci/tests/triage/test_issue_3758.py | 4 +- cumulusci/tests/triage/test_issue_3768.py | 4 +- cumulusci/tests/triage/test_issue_3771.py | 4 +- cumulusci/tests/triage/test_issue_3773.py | 4 +- cumulusci/tests/triage/test_issue_3849.py | 2 +- cumulusci/tests/triage/test_issue_3889.py | 8 +- cumulusci/tests/triage/test_issue_3931.py | 4 +- cumulusci/tests/triage/test_issue_3951.py | 2 +- cumulusci/tests/triage/test_issue_3953.py | 2 +- cumulusci/tests/triage/test_issue_3955.py | 2 +- cumulusci/tests/triage/test_issue_733.py | 2 +- cumulusci/tests/triage/test_issue_773.py | 6 +- cumulusci/tests/triage/test_issue_808.py | 2 +- docs/triage/v5/README.md | 47 +- docs/triage/v5/fix-sketches/issue_1348.md | 48 +- docs/triage/v5/fix-sketches/issue_1432.md | 48 +- docs/triage/v5/fix-sketches/issue_1769.md | 48 +- docs/triage/v5/fix-sketches/issue_2013.md | 48 +- docs/triage/v5/fix-sketches/issue_2140.md | 48 +- docs/triage/v5/fix-sketches/issue_2153.md | 48 +- docs/triage/v5/fix-sketches/issue_2325.md | 48 +- docs/triage/v5/fix-sketches/issue_2402.md | 48 +- docs/triage/v5/fix-sketches/issue_2500.md | 67 +- docs/triage/v5/fix-sketches/issue_2506.md | 48 +- docs/triage/v5/fix-sketches/issue_2507.md | 48 +- docs/triage/v5/fix-sketches/issue_2508.md | 48 +- docs/triage/v5/fix-sketches/issue_2826.md | 50 +- docs/triage/v5/fix-sketches/issue_2951.md | 48 +- docs/triage/v5/fix-sketches/issue_2979.md | 48 +- docs/triage/v5/fix-sketches/issue_3015.md | 48 +- docs/triage/v5/fix-sketches/issue_3024.md | 48 +- docs/triage/v5/fix-sketches/issue_3137.md | 48 +- docs/triage/v5/fix-sketches/issue_3161.md | 48 +- docs/triage/v5/fix-sketches/issue_3165.md | 50 +- docs/triage/v5/fix-sketches/issue_3307.md | 48 +- docs/triage/v5/fix-sketches/issue_3331.md | 48 +- docs/triage/v5/fix-sketches/issue_3349.md | 39 +- docs/triage/v5/fix-sketches/issue_3353.md | 39 +- docs/triage/v5/fix-sketches/issue_3407.md | 59 +- docs/triage/v5/fix-sketches/issue_3429.md | 48 +- docs/triage/v5/fix-sketches/issue_3440.md | 48 +- docs/triage/v5/fix-sketches/issue_3441.md | 48 +- docs/triage/v5/fix-sketches/issue_3446.md | 48 +- docs/triage/v5/fix-sketches/issue_3464.md | 66 +- docs/triage/v5/fix-sketches/issue_3470.md | 46 +- docs/triage/v5/fix-sketches/issue_3471.md | 48 +- docs/triage/v5/fix-sketches/issue_3485.md | 46 +- docs/triage/v5/fix-sketches/issue_3492.md | 46 +- docs/triage/v5/fix-sketches/issue_3506.md | 46 +- docs/triage/v5/fix-sketches/issue_3518.md | 48 +- docs/triage/v5/fix-sketches/issue_3541.md | 68 +- docs/triage/v5/fix-sketches/issue_3543.md | 48 +- docs/triage/v5/fix-sketches/issue_3549.md | 46 +- docs/triage/v5/fix-sketches/issue_3570.md | 46 +- docs/triage/v5/fix-sketches/issue_3585.md | 49 +- docs/triage/v5/fix-sketches/issue_3593.md | 48 +- docs/triage/v5/fix-sketches/issue_3602.md | 58 +- docs/triage/v5/fix-sketches/issue_3603.md | 39 +- docs/triage/v5/fix-sketches/issue_3604.md | 39 +- docs/triage/v5/fix-sketches/issue_3613.md | 53 +- docs/triage/v5/fix-sketches/issue_3618.md | 46 +- docs/triage/v5/fix-sketches/issue_3619.md | 39 +- docs/triage/v5/fix-sketches/issue_3649.md | 39 +- docs/triage/v5/fix-sketches/issue_3663.md | 46 +- docs/triage/v5/fix-sketches/issue_3692.md | 50 +- docs/triage/v5/fix-sketches/issue_3699.md | 39 +- docs/triage/v5/fix-sketches/issue_3700.md | 39 +- docs/triage/v5/fix-sketches/issue_3701.md | 39 +- docs/triage/v5/fix-sketches/issue_3721.md | 48 +- docs/triage/v5/fix-sketches/issue_3734.md | 46 +- docs/triage/v5/fix-sketches/issue_3746.md | 39 +- docs/triage/v5/fix-sketches/issue_3754.md | 46 +- docs/triage/v5/fix-sketches/issue_3758.md | 48 +- docs/triage/v5/fix-sketches/issue_3768.md | 39 +- docs/triage/v5/fix-sketches/issue_3771.md | 49 +- docs/triage/v5/fix-sketches/issue_3773.md | 49 +- docs/triage/v5/fix-sketches/issue_3849.md | 39 +- docs/triage/v5/fix-sketches/issue_3873.md | 52 +- docs/triage/v5/fix-sketches/issue_3889.md | 46 +- docs/triage/v5/fix-sketches/issue_3910.md | 42 +- docs/triage/v5/fix-sketches/issue_3931.md | 50 +- docs/triage/v5/fix-sketches/issue_3951.md | 53 +- docs/triage/v5/fix-sketches/issue_3953.md | 48 +- docs/triage/v5/fix-sketches/issue_3955.md | 54 +- docs/triage/v5/fix-sketches/issue_675.md | 52 +- docs/triage/v5/fix-sketches/issue_710.md | 44 +- docs/triage/v5/fix-sketches/issue_733.md | 48 +- docs/triage/v5/fix-sketches/issue_773.md | 65 +- docs/triage/v5/fix-sketches/issue_808.md | 50 +- docs/triage/v5/proposals.md | 354 ++-- docs/triage/v5/repro-results.csv | 232 +-- docs/triage/v5/repro-results.md | 2048 +++++++++------------ docs/triage/v5/themes.md | 6 +- 152 files changed, 2086 insertions(+), 4453 deletions(-) diff --git a/cumulusci/tests/triage/README.md b/cumulusci/tests/triage/README.md index aaa1f1d0ff..4fed49729c 100644 --- a/cumulusci/tests/triage/README.md +++ b/cumulusci/tests/triage/README.md @@ -29,15 +29,15 @@ issue. - Fix-PR removes the `@pytest.mark.xfail` marker. - Fix-PR confirms the test now passes. - Fix-PR moves the test out of this directory to its natural - home (e.g. `cumulusci/tasks//tests/`) — or leaves it + home (e.g. `cumulusci/tasks//tests/`) - or leaves it here with the marker removed, whichever is cleaner. ## See also -- `docs/triage/v5/repro-results.md` — narrative evidence per issue. -- `docs/triage/v5/fix-sketches/issue_.md` — proposed fix +- `docs/triage/v5/repro-results.md` - narrative evidence per issue. +- `docs/triage/v5/fix-sketches/issue_.md` - proposed fix approach per issue. -- `docs/triage/v5/proposals.md` — pass-1 classification matrix. +- `docs/triage/v5/proposals.md` - pass-1 classification matrix. ## Running @@ -46,5 +46,5 @@ uv run pytest cumulusci/tests/triage/ -v ``` Expected outcome: every test reports `XFAIL`. If any reports `XPASS`, -that is signal that a bug resolved independently — see the harvest +that is signal that a bug resolved independently - see the harvest xpass list in `docs/triage/v5/` (if present). diff --git a/cumulusci/tests/triage/test_issue_1348.py b/cumulusci/tests/triage/test_issue_1348.py index 247ed582dd..ae56c37ebd 100644 --- a/cumulusci/tests/triage/test_issue_1348.py +++ b/cumulusci/tests/triage/test_issue_1348.py @@ -12,7 +12,7 @@ other providers can use CumulusCI. This test loads the universal cumulusci.yml and asserts that -`ci_feature` does NOT step into any GitHub-specific task — +`ci_feature` does NOT step into any GitHub-specific task - which it does today, so this fails -> XFAIL. """ @@ -25,7 +25,7 @@ @pytest.mark.xfail( - reason="repro for #1348 — see docs/triage/v5/repro-results.md", + reason="repro for #1348 - see docs/triage/v5/repro-results.md", strict=False, ) def test_issue_1348(): diff --git a/cumulusci/tests/triage/test_issue_1432.py b/cumulusci/tests/triage/test_issue_1432.py index ce2df831c6..b4e9c78ee4 100644 --- a/cumulusci/tests/triage/test_issue_1432.py +++ b/cumulusci/tests/triage/test_issue_1432.py @@ -7,7 +7,7 @@ Root cause: ``BaseTask._validate_options`` (cumulusci/core/tasks.py around lines 187-197) only checks for *missing* required options when the task uses the legacy ``task_options`` dict. Unknown keys are -silently accepted — passing ``-o colour red`` to a task that declares +silently accepted - passing ``-o colour red`` to a task that declares ``color`` results in no error. The new-style Pydantic ``Options`` class path *does* reject extras @@ -29,7 +29,7 @@ @pytest.mark.xfail( - reason="repro for #1432 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #1432 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_1432(): src = inspect.getsource(BaseTask._validate_options) diff --git a/cumulusci/tests/triage/test_issue_1769.py b/cumulusci/tests/triage/test_issue_1769.py index eee68b0343..3a80907746 100644 --- a/cumulusci/tests/triage/test_issue_1769.py +++ b/cumulusci/tests/triage/test_issue_1769.py @@ -28,7 +28,7 @@ @pytest.mark.xfail( - reason="repro for #1769 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #1769 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_1769(): test_load_path = ( diff --git a/cumulusci/tests/triage/test_issue_2013.py b/cumulusci/tests/triage/test_issue_2013.py index a7ce4becf5..c9571f51c7 100644 --- a/cumulusci/tests/triage/test_issue_2013.py +++ b/cumulusci/tests/triage/test_issue_2013.py @@ -27,7 +27,7 @@ @pytest.mark.xfail( - reason="repro for #2013 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #2013 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_2013(): engine = create_engine("sqlite:///:memory:") diff --git a/cumulusci/tests/triage/test_issue_2140.py b/cumulusci/tests/triage/test_issue_2140.py index 9fabab9ae0..3b781fde3b 100644 --- a/cumulusci/tests/triage/test_issue_2140.py +++ b/cumulusci/tests/triage/test_issue_2140.py @@ -25,7 +25,7 @@ @pytest.mark.xfail( - reason="repro for #2140 — see docs/triage/v5/repro-results.md", + reason="repro for #2140 - see docs/triage/v5/repro-results.md", strict=False, ) def test_issue_2140(): diff --git a/cumulusci/tests/triage/test_issue_2153.py b/cumulusci/tests/triage/test_issue_2153.py index eb712b0008..164ede92d6 100644 --- a/cumulusci/tests/triage/test_issue_2153.py +++ b/cumulusci/tests/triage/test_issue_2153.py @@ -12,7 +12,7 @@ subscribers so they get notified about the conflict. A repo-wide search for `create_comment`/`issue_comment` returns -only test-fixture hits — production GitHub task code never +only test-fixture hits - production GitHub task code never opens a PR/issue comment as part of this conflict path. This test asserts that the merge task surface mentions a @@ -28,7 +28,7 @@ @pytest.mark.xfail( - reason="repro for #2153 — see docs/triage/v5/repro-results.md", + reason="repro for #2153 - see docs/triage/v5/repro-results.md", strict=False, ) def test_issue_2153(): diff --git a/cumulusci/tests/triage/test_issue_2325.py b/cumulusci/tests/triage/test_issue_2325.py index 425d88ff73..9b89733c85 100644 --- a/cumulusci/tests/triage/test_issue_2325.py +++ b/cumulusci/tests/triage/test_issue_2325.py @@ -30,7 +30,7 @@ @pytest.mark.xfail( - reason="repro for #2325 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #2325 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_2325(): cci_root = Path(cumulusci.__file__).parent diff --git a/cumulusci/tests/triage/test_issue_2402.py b/cumulusci/tests/triage/test_issue_2402.py index 890eefadd0..13b23ab08b 100644 --- a/cumulusci/tests/triage/test_issue_2402.py +++ b/cumulusci/tests/triage/test_issue_2402.py @@ -21,7 +21,7 @@ @pytest.mark.xfail( - reason="repro for #2402 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #2402 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_2402(): param_names = {p.name for p in flow_run.params} diff --git a/cumulusci/tests/triage/test_issue_2500.py b/cumulusci/tests/triage/test_issue_2500.py index 0dbbba8e50..4b894a0454 100644 --- a/cumulusci/tests/triage/test_issue_2500.py +++ b/cumulusci/tests/triage/test_issue_2500.py @@ -1,4 +1,4 @@ -"""Repro for SFDO-Tooling/CumulusCI#2500 — ``ignore_failure`` is not documented. +"""Repro for SFDO-Tooling/CumulusCI#2500 - ``ignore_failure`` is not documented. The ``ignore_failure`` flow-step option has existed since flowrunner was introduced (see ``cumulusci/core/flowrunner.py`` and @@ -11,7 +11,7 @@ This test pins down both halves of the gap: -1. ``ignore_failure`` is a recognised step-level option (sanity check — +1. ``ignore_failure`` is a recognised step-level option (sanity check - the feature really exists and we are not chasing a phantom doc). 2. ``docs/config.md`` contains a narrative section that documents it. @@ -37,7 +37,7 @@ @pytest.mark.xfail( - reason="repro for #2500 — see docs/triage/v5/repro-results.md", + reason="repro for #2500 - see docs/triage/v5/repro-results.md", strict=False, ) def test_ignore_failure_has_narrative_docs_section(): diff --git a/cumulusci/tests/triage/test_issue_2506.py b/cumulusci/tests/triage/test_issue_2506.py index 20f1425562..601588650c 100644 --- a/cumulusci/tests/triage/test_issue_2506.py +++ b/cumulusci/tests/triage/test_issue_2506.py @@ -24,7 +24,7 @@ @pytest.mark.xfail( - reason="repro for #2506 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #2506 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_2506(): pkg_path = pathlib.Path(_bulkdata_pkg.__file__).parent diff --git a/cumulusci/tests/triage/test_issue_2507.py b/cumulusci/tests/triage/test_issue_2507.py index 277a5f2b3d..02a35e66f2 100644 --- a/cumulusci/tests/triage/test_issue_2507.py +++ b/cumulusci/tests/triage/test_issue_2507.py @@ -7,7 +7,7 @@ Root cause: there is no `undo_insert` (or similarly-named) task. The closest mitigation is the `enable_rollback` option on `load_data` / `snowfakery`, but that only rolls back when an -error occurs during the load — it does not provide the +error occurs during the load - it does not provide the post-hoc "delete everything I inserted earlier" capability the 2021 ask describes. @@ -25,7 +25,7 @@ @pytest.mark.xfail( - reason="repro for #2507 — see docs/triage/v5/repro-results.md", + reason="repro for #2507 - see docs/triage/v5/repro-results.md", strict=False, ) def test_issue_2507(): diff --git a/cumulusci/tests/triage/test_issue_2508.py b/cumulusci/tests/triage/test_issue_2508.py index 63cf84b695..aaa1bbb2c9 100644 --- a/cumulusci/tests/triage/test_issue_2508.py +++ b/cumulusci/tests/triage/test_issue_2508.py @@ -8,7 +8,7 @@ previous load" feature in CumulusCI. ``load_dataset`` exposes an ``enable_rollback`` option (cumulusci/tasks/bulkdata/load.py:97-98, ``RollbackType`` enum at line 1051), but rollback **undoes** successful -inserts when failures occur — the opposite of "retry the failures". +inserts when failures occur - the opposite of "retry the failures". ``RowErrorChecker`` (cumulusci/tasks/bulkdata/utils.py:158) only logs and (optionally) raises; it never persists a failed-rows artifact that could be replayed. @@ -30,7 +30,7 @@ @pytest.mark.xfail( - reason="repro for #2508 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #2508 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_2508(): cci_root = Path(cumulusci.__file__).parent diff --git a/cumulusci/tests/triage/test_issue_2826.py b/cumulusci/tests/triage/test_issue_2826.py index 46866dc56e..f79f3ef03d 100644 --- a/cumulusci/tests/triage/test_issue_2826.py +++ b/cumulusci/tests/triage/test_issue_2826.py @@ -26,7 +26,7 @@ @pytest.mark.xfail( - reason="repro for #2826 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #2826 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_2826(): with tempfile.TemporaryDirectory() as tmp: diff --git a/cumulusci/tests/triage/test_issue_2951.py b/cumulusci/tests/triage/test_issue_2951.py index 605d2a281f..824b063b4d 100644 --- a/cumulusci/tests/triage/test_issue_2951.py +++ b/cumulusci/tests/triage/test_issue_2951.py @@ -12,7 +12,7 @@ created before the matching standard price exists. The default extract path skips the Standard Price Book entirely (via hardcoded_default_declarations.py), so the typical extract→load -roundtrip never hits this — but a hand-rolled mapping that includes +roundtrip never hits this - but a hand-rolled mapping that includes both does. A real fix is either (a) split PricebookEntry steps into two @@ -34,7 +34,7 @@ @pytest.mark.xfail( - reason="repro for #2951 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #2951 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_2951(): bulkdata_dir = Path(cumulusci.__file__).parent / "tasks" / "bulkdata" diff --git a/cumulusci/tests/triage/test_issue_2979.py b/cumulusci/tests/triage/test_issue_2979.py index 69ffd8b873..1fd12a81ed 100644 --- a/cumulusci/tests/triage/test_issue_2979.py +++ b/cumulusci/tests/triage/test_issue_2979.py @@ -30,7 +30,7 @@ @pytest.mark.xfail( - reason="repro for #2979 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #2979 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_2979(): yml_path = pathlib.Path(_cci_pkg.__file__).parent / "cumulusci.yml" diff --git a/cumulusci/tests/triage/test_issue_3015.py b/cumulusci/tests/triage/test_issue_3015.py index be0de726fe..a703d464a7 100644 --- a/cumulusci/tests/triage/test_issue_3015.py +++ b/cumulusci/tests/triage/test_issue_3015.py @@ -23,7 +23,7 @@ @pytest.mark.xfail( - reason="repro for #3015 — see docs/triage/v5/repro-results.md", + reason="repro for #3015 - see docs/triage/v5/repro-results.md", strict=False, ) def test_issue_3015(): diff --git a/cumulusci/tests/triage/test_issue_3024.py b/cumulusci/tests/triage/test_issue_3024.py index 20062631a3..322d1f0050 100644 --- a/cumulusci/tests/triage/test_issue_3024.py +++ b/cumulusci/tests/triage/test_issue_3024.py @@ -31,7 +31,7 @@ @pytest.mark.xfail( - reason="repro for #3024 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3024 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3024(): cci_root = Path(cumulusci.__file__).parent @@ -45,7 +45,7 @@ def test_issue_3024(): seen.append(group) assert "Continuous Integration" in seen, ( - "'Continuous Integration' group missing from cumulusci.yml — test needs updating" + "'Continuous Integration' group missing from cumulusci.yml - test needs updating" ) ci_pos = seen.index("Continuous Integration") halfway = len(seen) // 2 diff --git a/cumulusci/tests/triage/test_issue_3137.py b/cumulusci/tests/triage/test_issue_3137.py index a20e2ca3a0..edee420327 100644 --- a/cumulusci/tests/triage/test_issue_3137.py +++ b/cumulusci/tests/triage/test_issue_3137.py @@ -29,7 +29,7 @@ @pytest.mark.xfail( - reason="repro for #3137 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3137 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3137(): parser = CustomObjectParser.__new__(CustomObjectParser) diff --git a/cumulusci/tests/triage/test_issue_3161.py b/cumulusci/tests/triage/test_issue_3161.py index 32242fb1b6..1f7cdba1a7 100644 --- a/cumulusci/tests/triage/test_issue_3161.py +++ b/cumulusci/tests/triage/test_issue_3161.py @@ -7,8 +7,8 @@ Root cause: flowrunner.py:300-320 supports masking task options via `info.get("sensitive")`, but the Robot `vars` option in cumulusci/tasks/robotframework/robotframework.py:54-56 is NOT marked -`sensitive: True`. The user's specific request — mask multi-line -GitHub Actions secrets passed via `-o robot__vars …` — is therefore +`sensitive: True`. The user's specific request - mask multi-line +GitHub Actions secrets passed via `-o robot__vars …` - is therefore not protected by the existing infrastructure. The minimal fix is to mark Robot's `vars` option `sensitive: True` @@ -25,7 +25,7 @@ @pytest.mark.xfail( - reason="repro for #3161 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3161 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3161(): vars_option = Robot.task_options.get("vars", {}) diff --git a/cumulusci/tests/triage/test_issue_3165.py b/cumulusci/tests/triage/test_issue_3165.py index c144d36a8e..fba43055a7 100644 --- a/cumulusci/tests/triage/test_issue_3165.py +++ b/cumulusci/tests/triage/test_issue_3165.py @@ -8,8 +8,8 @@ cumulusci/tasks/salesforce/update_profile.py:137-138 calls `_expand_package_xml(package_xml)` only when `include_packaged_objects=True`. `_expand_package_xml_objects` -— the helper that walks `record_types` and adds any referenced -CustomObject to the retrieve package.xml — is invoked only from +- the helper that walks `record_types` and adds any referenced +CustomObject to the retrieve package.xml - is invoked only from inside `_expand_package_xml` (line 182). When a user specifies `record_types` referencing a standard object (e.g. Case) and keeps `include_packaged_objects=False`, the retrieve package.xml @@ -38,7 +38,7 @@ @pytest.mark.xfail( - reason="repro for #3165 — see docs/triage/v5/repro-results.md", + reason="repro for #3165 - see docs/triage/v5/repro-results.md", strict=False, ) def test_issue_3165(): diff --git a/cumulusci/tests/triage/test_issue_3307.py b/cumulusci/tests/triage/test_issue_3307.py index f6c81e5581..59ef3dcaec 100644 --- a/cumulusci/tests/triage/test_issue_3307.py +++ b/cumulusci/tests/triage/test_issue_3307.py @@ -25,7 +25,7 @@ @pytest.mark.xfail( - reason="repro for #3307 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3307 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3307(): param_names = {p.name for p in project_init.params} diff --git a/cumulusci/tests/triage/test_issue_3331.py b/cumulusci/tests/triage/test_issue_3331.py index a347457013..465d316bcb 100644 --- a/cumulusci/tests/triage/test_issue_3331.py +++ b/cumulusci/tests/triage/test_issue_3331.py @@ -7,7 +7,7 @@ Root cause: cumulusci/tasks/metadata/metadata_map.yml line 45-48 maps the `assignmentRules` folder to MDAPI type `AssignmentRule` (singular). Salesforce Metadata API expects -`AssignmentRules` (plural) — see the analogous `autoResponseRules` +`AssignmentRules` (plural) - see the analogous `autoResponseRules` key (lines 60-63) which is already correctly `AutoResponseRules`. Running `update_package_xml` against a project with @@ -31,7 +31,7 @@ @pytest.mark.xfail( - reason="repro for #3331 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3331 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3331(): metadata_map_path = ( diff --git a/cumulusci/tests/triage/test_issue_3349.py b/cumulusci/tests/triage/test_issue_3349.py index 7fec2394cf..834c1a1b78 100644 --- a/cumulusci/tests/triage/test_issue_3349.py +++ b/cumulusci/tests/triage/test_issue_3349.py @@ -31,7 +31,7 @@ @pytest.mark.xfail( - reason="repro for #3349 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3349 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3349(): step_business = MappingStep( diff --git a/cumulusci/tests/triage/test_issue_3353.py b/cumulusci/tests/triage/test_issue_3353.py index 0505519d49..eb92cf2c53 100644 --- a/cumulusci/tests/triage/test_issue_3353.py +++ b/cumulusci/tests/triage/test_issue_3353.py @@ -27,7 +27,7 @@ @pytest.mark.xfail( - reason="repro for #3353 — see docs/triage/v5/repro-results.md", + reason="repro for #3353 - see docs/triage/v5/repro-results.md", strict=False, ) def test_issue_3353(): diff --git a/cumulusci/tests/triage/test_issue_3407.py b/cumulusci/tests/triage/test_issue_3407.py index 8f56a2c16c..9fdbac380b 100644 --- a/cumulusci/tests/triage/test_issue_3407.py +++ b/cumulusci/tests/triage/test_issue_3407.py @@ -9,7 +9,7 @@ ``str`` (e.g. ``ServiceConfig | str``) or every call site constructs a ``ServiceConfig`` first. It is expected to fail on dev (xfail). -Pure introspection — no Salesforce / scratch org required. +Pure introspection - no Salesforce / scratch org required. """ from __future__ import annotations @@ -46,7 +46,7 @@ def _src_has_string_payload_call(func) -> bool: @pytest.mark.xfail( - reason=("repro for #3407 — see docs/triage/v5/repro-results.md"), + reason=("repro for #3407 - see docs/triage/v5/repro-results.md"), strict=False, ) def test_set_service_annotation_consistent_with_callers(): @@ -69,13 +69,13 @@ def test_set_service_annotation_consistent_with_callers(): @pytest.mark.xfail( - reason=("repro for #3407 — see docs/triage/v5/repro-results.md"), + reason=("repro for #3407 - see docs/triage/v5/repro-results.md"), strict=False, ) def test_set_service_runtime_accepts_only_serviceconfig_per_annotation(): """Run-time evidence: a plain string is accepted with config_encrypted=True even though the annotation says ServiceConfig. If the annotation were the - source of truth, this call would fail. Today it succeeds — proving the + source of truth, this call would fail. Today it succeeds - proving the annotation is wrong.""" class _Stub(BaseProjectKeychain): diff --git a/cumulusci/tests/triage/test_issue_3429.py b/cumulusci/tests/triage/test_issue_3429.py index e79db59c8f..60790ee7c8 100644 --- a/cumulusci/tests/triage/test_issue_3429.py +++ b/cumulusci/tests/triage/test_issue_3429.py @@ -28,7 +28,7 @@ @pytest.mark.xfail( - reason="repro for #3429 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3429 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3429(): src = inspect.getsource(project_config_mod) diff --git a/cumulusci/tests/triage/test_issue_3440.py b/cumulusci/tests/triage/test_issue_3440.py index 371f750003..aa00589be4 100644 --- a/cumulusci/tests/triage/test_issue_3440.py +++ b/cumulusci/tests/triage/test_issue_3440.py @@ -27,7 +27,7 @@ @pytest.mark.xfail( - reason="repro for #3440 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3440 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3440(): candidate_attrs = ( diff --git a/cumulusci/tests/triage/test_issue_3441.py b/cumulusci/tests/triage/test_issue_3441.py index 91acc226c6..94b85164f6 100644 --- a/cumulusci/tests/triage/test_issue_3441.py +++ b/cumulusci/tests/triage/test_issue_3441.py @@ -28,7 +28,7 @@ @pytest.mark.xfail( - reason="repro for #3441 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3441 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3441(): src = inspect.getsource(CreatePackageVersion._get_base_version_number) diff --git a/cumulusci/tests/triage/test_issue_3446.py b/cumulusci/tests/triage/test_issue_3446.py index a270cc1ba8..0fd257cfff 100644 --- a/cumulusci/tests/triage/test_issue_3446.py +++ b/cumulusci/tests/triage/test_issue_3446.py @@ -10,7 +10,7 @@ with only `--metadata_package_id` (no `--version` / `--version_id`), `version` is `None` and the call raises ``AttributeError: 'NoneType' object has no attribute 'split'`` -— the exact gist linked in the bug report. +- the exact gist linked in the bug report. This test calls `_parse_version(None)` and asserts it raises a user-friendly TaskOptionsError instead of a bare AttributeError. @@ -24,7 +24,7 @@ @pytest.mark.xfail( - reason="repro for #3446 — see docs/triage/v5/repro-results.md", + reason="repro for #3446 - see docs/triage/v5/repro-results.md", strict=False, ) def test_issue_3446(): diff --git a/cumulusci/tests/triage/test_issue_3464.py b/cumulusci/tests/triage/test_issue_3464.py index 146b1a7450..3c931945fb 100644 --- a/cumulusci/tests/triage/test_issue_3464.py +++ b/cumulusci/tests/triage/test_issue_3464.py @@ -1,4 +1,4 @@ -"""Repro for SFDO-Tooling/CumulusCI#3464 — Provide concise documentation of +"""Repro for SFDO-Tooling/CumulusCI#3464 - Provide concise documentation of ``cumulusci.yml`` ``project`` configuration options. The user asked: "I would like ALL configuration tags and options defined, @@ -20,8 +20,8 @@ ``docs/config.md`` shows ONE example YAML block (line ~281) using a subset of these keys but has no reference subsection that names every supported -key. Several keys — notably ``dependency_resolutions``, ``dependency_pins``, -and ``source_format`` — never appear in ``docs/config.md`` at all (they +key. Several keys - notably ``dependency_resolutions``, ``dependency_pins``, +and ``source_format`` - never appear in ``docs/config.md`` at all (they are buried in ``docs/dev.md``, which is exactly the "scattered" complaint in the issue). @@ -46,7 +46,7 @@ @pytest.mark.xfail( - reason="repro for #3464 — see docs/triage/v5/repro-results.md", + reason="repro for #3464 - see docs/triage/v5/repro-results.md", strict=False, ) def test_every_project_key_is_mentioned_in_config_doc(): diff --git a/cumulusci/tests/triage/test_issue_3470.py b/cumulusci/tests/triage/test_issue_3470.py index 7d920ff0f2..05eefe3d04 100644 --- a/cumulusci/tests/triage/test_issue_3470.py +++ b/cumulusci/tests/triage/test_issue_3470.py @@ -27,7 +27,7 @@ @pytest.mark.xfail( - reason="repro for #3470 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3470 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3470(): cci_root = Path(cumulusci.__file__).parent diff --git a/cumulusci/tests/triage/test_issue_3471.py b/cumulusci/tests/triage/test_issue_3471.py index 3394bd64f5..1afd4f0240 100644 --- a/cumulusci/tests/triage/test_issue_3471.py +++ b/cumulusci/tests/triage/test_issue_3471.py @@ -2,7 +2,7 @@ See docs/triage/v5/repro-results.md for full narrative. Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery; reverified on -origin/dev@1925a3083 — only ruff refactor since v4.10.0). +origin/dev@1925a3083 - only ruff refactor since v4.10.0). This xfail marker will be removed by the corresponding fix-PR. Root cause: cumulusci/tasks/github/merge.py `_merge` (L241-262) logs @@ -32,7 +32,7 @@ @pytest.mark.xfail( - reason="repro for #3471 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3471 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3471(): merge_path = Path(cumulusci.__file__).parent / "tasks" / "github" / "merge.py" diff --git a/cumulusci/tests/triage/test_issue_3485.py b/cumulusci/tests/triage/test_issue_3485.py index 2cdcdd24e4..e6b6eddcb2 100644 --- a/cumulusci/tests/triage/test_issue_3485.py +++ b/cumulusci/tests/triage/test_issue_3485.py @@ -30,7 +30,7 @@ @pytest.mark.xfail( - reason="repro for #3485 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3485 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3485(): with tempfile.TemporaryDirectory() as tmpdir: diff --git a/cumulusci/tests/triage/test_issue_3492.py b/cumulusci/tests/triage/test_issue_3492.py index 3edf9961c0..85052386c0 100644 --- a/cumulusci/tests/triage/test_issue_3492.py +++ b/cumulusci/tests/triage/test_issue_3492.py @@ -6,7 +6,7 @@ Root cause: `cci flow run -o key value` in cumulusci/cli/flow.py parses each `-o` pair by doing -`task_name, option_name = key.split("__")` — an exact 2-way +`task_name, option_name = key.split("__")` - an exact 2-way unpack. Passing the user-desired form `-o project__custom__myattr value` triggers ``ValueError: too many values to unpack (expected 2)`` because @@ -26,7 +26,7 @@ @pytest.mark.xfail( - reason="repro for #3492 — see docs/triage/v5/repro-results.md", + reason="repro for #3492 - see docs/triage/v5/repro-results.md", strict=False, ) def test_issue_3492(): diff --git a/cumulusci/tests/triage/test_issue_3506.py b/cumulusci/tests/triage/test_issue_3506.py index e4c7a3e980..60adfd017a 100644 --- a/cumulusci/tests/triage/test_issue_3506.py +++ b/cumulusci/tests/triage/test_issue_3506.py @@ -8,7 +8,7 @@ (cumulusci/core/flowrunner.py) only wires ``when=step_config.get("when")`` on the ``task:`` branch (around line 669). The ``flow:`` branch (around lines 674-697) recurses into nested steps without ever reading -``step_config.get("when")`` — so a ``when:`` clause attached to a +``step_config.get("when")`` - so a ``when:`` clause attached to a ``flow:`` step is silently dropped. The fix is to propagate the parent flow-step's ``when:`` down to the @@ -27,7 +27,7 @@ @pytest.mark.xfail( - reason="repro for #3506 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3506 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3506(): src = inspect.getsource(FlowCoordinator._visit_step) diff --git a/cumulusci/tests/triage/test_issue_3518.py b/cumulusci/tests/triage/test_issue_3518.py index 4bfea999df..a9d158980d 100644 --- a/cumulusci/tests/triage/test_issue_3518.py +++ b/cumulusci/tests/triage/test_issue_3518.py @@ -8,7 +8,7 @@ default = str(process_bool_arg(entry.get("default", False))).lower -The `.lower` is referenced as an attribute, not invoked — so +The `.lower` is referenced as an attribute, not invoked - so `default` ends up bound to the `str.lower` method itself (a callable object, always truthy). The subsequent guard at line 214 (`if default:`) therefore always runs the default-clobbering loop, @@ -29,7 +29,7 @@ @pytest.mark.xfail( - reason="repro for #3518 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3518 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3518(): # Mirrors the exact expression at picklists.py:177 diff --git a/cumulusci/tests/triage/test_issue_3541.py b/cumulusci/tests/triage/test_issue_3541.py index 34b253701f..1024504200 100644 --- a/cumulusci/tests/triage/test_issue_3541.py +++ b/cumulusci/tests/triage/test_issue_3541.py @@ -1,4 +1,4 @@ -"""Repro for CumulusCI issue #3541 — scratch org alias becomes ``None__``. +"""Repro for CumulusCI issue #3541 - scratch org alias becomes ``None__``. When :pyfunc:`BaseProjectKeychain.create_scratch_org` builds the SFDX alias it does:: @@ -8,14 +8,14 @@ ) If ``project__name`` evaluates to ``None`` (no ``project.name`` in the loaded -config, or the project hasn't fully resolved yet — e.g. during the eager +config, or the project hasn't fully resolved yet - e.g. during the eager ``_load_scratch_orgs`` pass on keychain construction) the resulting alias is the literal string ``"None__"``. That string is then passed to ``sfdx force config set target-org=None__dev`` which is exactly what the reporter (and at least one other commenter) saw. Correct behaviour: either fall back to ``org_name`` alone or raise a clear -CumulusCIException — *never* embed the literal Python repr of ``None`` in a +CumulusCIException - *never* embed the literal Python repr of ``None`` in a shell argument. No scratch org / network required. @@ -30,7 +30,7 @@ @pytest.mark.xfail( - reason=("repro for #3541 — see docs/triage/v5/repro-results.md"), + reason=("repro for #3541 - see docs/triage/v5/repro-results.md"), strict=False, ) def test_create_scratch_org_without_project_name_does_not_yield_None_alias(): @@ -49,21 +49,21 @@ def test_create_scratch_org_without_project_name_does_not_yield_None_alias(): alias = keychain.get_org("dev").config["sfdx_alias"] assert "None" not in alias.split("__"), ( - f"sfdx_alias is {alias!r} — literal 'None' should never appear in a " + f"sfdx_alias is {alias!r} - literal 'None' should never appear in a " "shell-bound SFDX alias. Expected fallback to 'dev' or a raised " "CumulusCIException." ) @pytest.mark.xfail( - reason=("repro for #3541 — see docs/triage/v5/repro-results.md"), + reason=("repro for #3541 - see docs/triage/v5/repro-results.md"), strict=False, ) def test_load_scratch_orgs_on_keychain_init_does_not_yield_None_alias(): """During keychain construction ``_load_scratch_orgs`` eagerly invokes ``create_scratch_org`` for every scratch config in cumulusci.yml. If project.name resolves to None at that moment, every eagerly-created org - inherits a ``None__`` alias — and the user only notices when + inherits a ``None__`` alias - and the user only notices when ``cci org info dev`` finally runs sfdx with target-org=None__dev.""" universal_config = UniversalConfig() project_config = BaseProjectConfig( diff --git a/cumulusci/tests/triage/test_issue_3543.py b/cumulusci/tests/triage/test_issue_3543.py index 131b014d32..0c46cb6e47 100644 --- a/cumulusci/tests/triage/test_issue_3543.py +++ b/cumulusci/tests/triage/test_issue_3543.py @@ -22,7 +22,7 @@ @pytest.mark.xfail( - reason="repro for #3543 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3543 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3543(): options = DxConvertFrom.task_options diff --git a/cumulusci/tests/triage/test_issue_3549.py b/cumulusci/tests/triage/test_issue_3549.py index 58a3d0d5d4..c966967e23 100644 --- a/cumulusci/tests/triage/test_issue_3549.py +++ b/cumulusci/tests/triage/test_issue_3549.py @@ -22,7 +22,7 @@ @pytest.mark.xfail( - reason="repro for #3549 — see docs/triage/v5/repro-results.md", + reason="repro for #3549 - see docs/triage/v5/repro-results.md", strict=False, ) def test_issue_3549(): diff --git a/cumulusci/tests/triage/test_issue_3570.py b/cumulusci/tests/triage/test_issue_3570.py index b3515c61d8..e85684f0e0 100644 --- a/cumulusci/tests/triage/test_issue_3570.py +++ b/cumulusci/tests/triage/test_issue_3570.py @@ -2,7 +2,7 @@ See docs/triage/v5/repro-results.md for full narrative. Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery; reverified on -origin/dev@1925a3083 — only ruff refactor since v4.10.0). +origin/dev@1925a3083 - only ruff refactor since v4.10.0). This xfail marker will be removed by the corresponding fix-PR. Root cause: cumulusci/core/flowrunner.py exposes only per-step @@ -11,7 +11,7 @@ `always_run` / `cleanup` to express "this cleanup/rollback step should always run after the flow regardless of success or failure". The only `finally:` in flowrunner.py is the Python `try/finally` in -FlowCoordinator.run that invokes the `post_flow` callback — +FlowCoordinator.run that invokes the `post_flow` callback - internal-only, not user-configurable. A real fix introduces a step-level metadata flag (e.g. @@ -29,7 +29,7 @@ @pytest.mark.xfail( - reason="repro for #3570 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3570 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3570(): candidate_attrs = ( diff --git a/cumulusci/tests/triage/test_issue_3585.py b/cumulusci/tests/triage/test_issue_3585.py index db553f9328..bd36cb3e94 100644 --- a/cumulusci/tests/triage/test_issue_3585.py +++ b/cumulusci/tests/triage/test_issue_3585.py @@ -46,7 +46,7 @@ @pytest.mark.xfail( - reason="repro for #3585 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3585 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3585(): with tempfile.TemporaryDirectory() as tmp: diff --git a/cumulusci/tests/triage/test_issue_3593.py b/cumulusci/tests/triage/test_issue_3593.py index cc371bb4c6..ec9cc364a0 100644 --- a/cumulusci/tests/triage/test_issue_3593.py +++ b/cumulusci/tests/triage/test_issue_3593.py @@ -29,7 +29,7 @@ @pytest.mark.xfail( - reason="repro for #3593 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3593 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3593(): src = inspect.getsource(SFDXOrgTask._get_command) diff --git a/cumulusci/tests/triage/test_issue_3602.py b/cumulusci/tests/triage/test_issue_3602.py index d41ddbaa46..2d4eaf7d3a 100644 --- a/cumulusci/tests/triage/test_issue_3602.py +++ b/cumulusci/tests/triage/test_issue_3602.py @@ -46,7 +46,7 @@ def _stub_browser_library(): @pytest.mark.xfail( - reason=("repro for #3602 — see docs/triage/v5/repro-results.md"), + reason=("repro for #3602 - see docs/triage/v5/repro-results.md"), strict=False, ) def test_open_test_browser_exposes_browser_options_hook(): diff --git a/cumulusci/tests/triage/test_issue_3603.py b/cumulusci/tests/triage/test_issue_3603.py index 0bb9d096c1..77b737ac2b 100644 --- a/cumulusci/tests/triage/test_issue_3603.py +++ b/cumulusci/tests/triage/test_issue_3603.py @@ -38,7 +38,7 @@ class _DummyResponse: @pytest.mark.xfail( - reason="repro for #3603 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3603 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3603(): project_config = mock.Mock() diff --git a/cumulusci/tests/triage/test_issue_3604.py b/cumulusci/tests/triage/test_issue_3604.py index 462f2d2382..97f674a947 100644 --- a/cumulusci/tests/triage/test_issue_3604.py +++ b/cumulusci/tests/triage/test_issue_3604.py @@ -10,12 +10,12 @@ > `uv run cci task list` returns 0 tasks that write `sfdx-project.json`. > A project-wide grep for `unpackagedMetadata` returns no matches. -The maintainer filed W-13504384 in 2023 but no implementation has +The maintainer filed an internal tracking ticket in 2023 but no implementation has shipped through v4.10.0. The fix is to add a new task (e.g. `update_sfdx_project_dependencies`) that resolves the current cumulusci dependencies and writes them -into `sfdx-project.json` — likely populating the `unpackagedMetadata` +into `sfdx-project.json` - likely populating the `unpackagedMetadata` key (or `dependencies`). This test scans cumulusci/tasks/ source for references to the @@ -32,7 +32,7 @@ @pytest.mark.xfail( - reason="repro for #3604 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3604 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3604(): pkg_root = pathlib.Path(_cci_pkg.__file__).parent @@ -46,6 +46,6 @@ def test_issue_3604(): assert hits, ( "No task under cumulusci/tasks/ references the sfdx-project.json " "'unpackagedMetadata' key; no task writes computed cumulusci " - "dependencies back into sfdx-project.json (W-13504384). " + "dependencies back into sfdx-project.json. " f"Scanned {tasks_dir}; hits: {hits}" ) diff --git a/cumulusci/tests/triage/test_issue_3613.py b/cumulusci/tests/triage/test_issue_3613.py index fb64e0e193..7df76d566c 100644 --- a/cumulusci/tests/triage/test_issue_3613.py +++ b/cumulusci/tests/triage/test_issue_3613.py @@ -27,7 +27,7 @@ @pytest.mark.xfail( - reason="repro for #3613 — see docs/triage/v5/repro-results.md", + reason="repro for #3613 - see docs/triage/v5/repro-results.md", strict=False, ) def test_issue_3613(tmp_path): diff --git a/cumulusci/tests/triage/test_issue_3618.py b/cumulusci/tests/triage/test_issue_3618.py index f8fc2f0329..9d1cb121d2 100644 --- a/cumulusci/tests/triage/test_issue_3618.py +++ b/cumulusci/tests/triage/test_issue_3618.py @@ -30,7 +30,7 @@ def _orgname_param(cmd): @pytest.mark.xfail( - reason="repro for #3618 — see docs/triage/v5/repro-results.md", + reason="repro for #3618 - see docs/triage/v5/repro-results.md", strict=False, ) def test_issue_3618(): diff --git a/cumulusci/tests/triage/test_issue_3619.py b/cumulusci/tests/triage/test_issue_3619.py index 77bc5c7f06..25e1903542 100644 --- a/cumulusci/tests/triage/test_issue_3619.py +++ b/cumulusci/tests/triage/test_issue_3619.py @@ -12,7 +12,7 @@ ``parse_dependency_pin()``/``parse_pins()`` because Pydantic rejects the extra field. -(Part B of #3619 — the silent password drop in ``pin.pin()`` — is +(Part B of #3619 - the silent password drop in ``pin.pin()`` - is captured at the same location: even if Part A is fixed by adding the field, ``pin.pin()`` calls ``GitHubTagResolver().resolve(...)`` directly and bypasses the password-propagation block in @@ -32,7 +32,7 @@ @pytest.mark.xfail( - reason="repro for #3619 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3619 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3619(): pin_dict = { diff --git a/cumulusci/tests/triage/test_issue_3649.py b/cumulusci/tests/triage/test_issue_3649.py index 18a1c2b0d3..f1c03277e2 100644 --- a/cumulusci/tests/triage/test_issue_3649.py +++ b/cumulusci/tests/triage/test_issue_3649.py @@ -27,7 +27,7 @@ @pytest.mark.xfail( - reason="repro for #3649 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3649 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3649(): options = set(UpdateData.task_options.keys()) diff --git a/cumulusci/tests/triage/test_issue_3663.py b/cumulusci/tests/triage/test_issue_3663.py index 74e7ecd66e..c46c85e255 100644 --- a/cumulusci/tests/triage/test_issue_3663.py +++ b/cumulusci/tests/triage/test_issue_3663.py @@ -9,7 +9,7 @@ only ``project_config`` and ``org_config``. ``self.results`` (prior-task return values) is never exposed, so a user cannot write ``when: tasks.previous_task.return_values.foo`` in a flow ``when:`` -clause — there is no codepath for that lookup at all. +clause - there is no codepath for that lookup at all. The fix is to extend the Jinja2 context (e.g. include a ``tasks`` or ``steps`` mapping built from ``self.results`` keyed by task name) so @@ -31,7 +31,7 @@ @pytest.mark.xfail( - reason="repro for #3663 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3663 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3663(): src = inspect.getsource(FlowCoordinator._run_step) diff --git a/cumulusci/tests/triage/test_issue_3692.py b/cumulusci/tests/triage/test_issue_3692.py index 0818a7e25d..945df87237 100644 --- a/cumulusci/tests/triage/test_issue_3692.py +++ b/cumulusci/tests/triage/test_issue_3692.py @@ -29,7 +29,7 @@ @pytest.mark.xfail( - reason="repro for #3692 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3692 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3692(): map_path = pathlib.Path(_md_pkg.__file__).parent / "metadata_map.yml" diff --git a/cumulusci/tests/triage/test_issue_3699.py b/cumulusci/tests/triage/test_issue_3699.py index 4644e2f18d..6a95b3ba8f 100644 --- a/cumulusci/tests/triage/test_issue_3699.py +++ b/cumulusci/tests/triage/test_issue_3699.py @@ -6,7 +6,7 @@ Root cause: `ExtractData._soql_for_mapping` in cumulusci/tasks/bulkdata/extract.py:132-146 builds the SOQL with -`WHERE` only — there is no `ORDER BY` clause. The +`WHERE` only - there is no `ORDER BY` clause. The `MappingStep` model in cumulusci/tasks/bulkdata/mapping_parser.py has no `order_by` / `sort` field. The user-facing workaround (`soql_filter: "... @@ -24,7 +24,7 @@ @pytest.mark.xfail( - reason="repro for #3699 — see docs/triage/v5/repro-results.md", + reason="repro for #3699 - see docs/triage/v5/repro-results.md", strict=False, ) def test_issue_3699(): diff --git a/cumulusci/tests/triage/test_issue_3700.py b/cumulusci/tests/triage/test_issue_3700.py index c54e01d522..a6109474a5 100644 --- a/cumulusci/tests/triage/test_issue_3700.py +++ b/cumulusci/tests/triage/test_issue_3700.py @@ -13,12 +13,12 @@ ``_check_field_permission`` returns ``False`` for the MD lookup on an upsert mapping. ``_validate_field_dict`` then errors with ``Field xxx__c does not have the correct permissions ('updateable', -'createable') for this operation`` — exactly the symptom #3700 reports. +'createable') for this operation`` - exactly the symptom #3700 reports. The fix is a field-shape-aware permission check: for upsert lookup fields that look like master-detail (``cascadeDelete: True``, ``updateable: False``, ``createable: True``), accept ``createable`` -alone — the MD lookup never gets updated post-insert anyway. +alone - the MD lookup never gets updated post-insert anyway. This test simulates ``_check_field_permission`` against an MD-shaped describe and asserts the call returns ``True`` for an UPSERT operation. @@ -33,7 +33,7 @@ @pytest.mark.xfail( - reason="repro for #3700 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3700 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3700(): step = MappingStep( diff --git a/cumulusci/tests/triage/test_issue_3701.py b/cumulusci/tests/triage/test_issue_3701.py index 8ecfa0c667..0229abf574 100644 --- a/cumulusci/tests/triage/test_issue_3701.py +++ b/cumulusci/tests/triage/test_issue_3701.py @@ -28,7 +28,7 @@ @pytest.mark.xfail( - reason="repro for #3701 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3701 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3701(): candidate_attrs = ("primary_key", "id_field", "external_id", "pk_field") diff --git a/cumulusci/tests/triage/test_issue_3721.py b/cumulusci/tests/triage/test_issue_3721.py index 8b72136fef..fb5e8071eb 100644 --- a/cumulusci/tests/triage/test_issue_3721.py +++ b/cumulusci/tests/triage/test_issue_3721.py @@ -28,7 +28,7 @@ @pytest.mark.xfail( - reason="repro for #3721 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3721 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3721(): src = pathlib.Path(_cpv_mod.__file__).read_text(encoding="utf-8") diff --git a/cumulusci/tests/triage/test_issue_3734.py b/cumulusci/tests/triage/test_issue_3734.py index 692f7ac9e2..dcd304a220 100644 --- a/cumulusci/tests/triage/test_issue_3734.py +++ b/cumulusci/tests/triage/test_issue_3734.py @@ -12,7 +12,7 @@ row's `MinorVersion`. When a customer has the typical pattern (Released 6.13 followed by Beta patch 6.13.1), the query returns the Beta patch and the next upload is built with -`minor_version=13` — identical to the already-Released minor. +`minor_version=13` - identical to the already-Released minor. The PackageUploadRequest is rejected with ``FIELD_INTEGRITY_EXCEPTION: The version number must be greater than the last Managed - Released version number: 6.13``. @@ -31,7 +31,7 @@ @pytest.mark.xfail( - reason="repro for #3734 — see docs/triage/v5/repro-results.md", + reason="repro for #3734 - see docs/triage/v5/repro-results.md", strict=False, ) def test_issue_3734(): diff --git a/cumulusci/tests/triage/test_issue_3746.py b/cumulusci/tests/triage/test_issue_3746.py index fbe0f3c050..1de8c90e2c 100644 --- a/cumulusci/tests/triage/test_issue_3746.py +++ b/cumulusci/tests/triage/test_issue_3746.py @@ -2,7 +2,7 @@ See docs/triage/v5/repro-results.md for full narrative. Verdict: REPRODUCED-on-dev (R1+R2 + Task 4 recovery; reverified on -origin/dev@1925a3083 — only ruff refactor since v4.10.0). +origin/dev@1925a3083 - only ruff refactor since v4.10.0). This xfail marker will be removed by the corresponding fix-PR. Root cause: cumulusci/tasks/create_package_version.py @@ -20,7 +20,7 @@ deprecated row is still returned, so the next version-bump bases off of a soft-deleted version. The same file at L297 DOES include `IsDeprecated = FALSE` for `Package2` lookups, so the project knows -about the column — the omission at L535 is asymmetric and matches +about the column - the omission at L535 is asymmetric and matches the report exactly. A real fix is a single-line SOQL change: add @@ -39,7 +39,7 @@ @pytest.mark.xfail( - reason="repro for #3746 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3746 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3746(): src_path = Path(cumulusci.__file__).parent / "tasks" / "create_package_version.py" diff --git a/cumulusci/tests/triage/test_issue_3754.py b/cumulusci/tests/triage/test_issue_3754.py index 8d969c99d7..2a2c19df96 100644 --- a/cumulusci/tests/triage/test_issue_3754.py +++ b/cumulusci/tests/triage/test_issue_3754.py @@ -33,7 +33,7 @@ @pytest.mark.xfail( - reason="repro for #3754 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3754 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3754(): src = inspect.getsource(cli_utils) diff --git a/cumulusci/tests/triage/test_issue_3758.py b/cumulusci/tests/triage/test_issue_3758.py index 88260e18ee..43a18a5e16 100644 --- a/cumulusci/tests/triage/test_issue_3758.py +++ b/cumulusci/tests/triage/test_issue_3758.py @@ -10,7 +10,7 @@ so the final step should be `flow: config_managed`, not `config_qa`. The two flows currently expand to the same task list (`deploy_post`, `update_admin_profile`, `load_sample_data`) so -behavior is equivalent today — but semantics drift over time and +behavior is equivalent today - but semantics drift over time and the docs link customers to the wrong flow page. A real fix is a one-line YAML change: `flow: config_qa` -> @@ -30,7 +30,7 @@ @pytest.mark.xfail( - reason="repro for #3758 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3758 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3758(): cumulusci_yml = Path(cumulusci.__file__).parent / "cumulusci.yml" diff --git a/cumulusci/tests/triage/test_issue_3768.py b/cumulusci/tests/triage/test_issue_3768.py index 3c2a0116a8..9e3d41f706 100644 --- a/cumulusci/tests/triage/test_issue_3768.py +++ b/cumulusci/tests/triage/test_issue_3768.py @@ -16,7 +16,7 @@ Snowfakery's `random_reference: Account` resolves at generation time against rows in the recipe-local database. With just_once Accounts unavailable after batch 1, subsequent batches generate Contacts with -no Accounts to reference — exactly the user's symptom. +no Accounts to reference - exactly the user's symptom. The fix needs to preserve rows of just_once-referenced objects in the template DB carried to subsequent batches (not just `_sf_ids` @@ -37,7 +37,7 @@ @pytest.mark.xfail( - reason="repro for #3768 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3768 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3768(): engine = create_engine("sqlite:///:memory:") diff --git a/cumulusci/tests/triage/test_issue_3771.py b/cumulusci/tests/triage/test_issue_3771.py index 48559d5ba7..2037979c69 100644 --- a/cumulusci/tests/triage/test_issue_3771.py +++ b/cumulusci/tests/triage/test_issue_3771.py @@ -15,7 +15,7 @@ not merged. We exercise transform_xpath by importing it via inline grab -(it's a closure inside `process`) — instead we just inspect the +(it's a closure inside `process`) - instead we just inspect the source and assert that predicate-internal tags are also wrapped with `local-name()` (or some equivalent namespace-stripping machinery). On dev they are not -> XFAIL. @@ -29,7 +29,7 @@ @pytest.mark.xfail( - reason="repro for #3771 — see docs/triage/v5/repro-results.md", + reason="repro for #3771 - see docs/triage/v5/repro-results.md", strict=False, ) def test_issue_3771(): diff --git a/cumulusci/tests/triage/test_issue_3773.py b/cumulusci/tests/triage/test_issue_3773.py index 4427943c43..f3b34ad872 100644 --- a/cumulusci/tests/triage/test_issue_3773.py +++ b/cumulusci/tests/triage/test_issue_3773.py @@ -12,7 +12,7 @@ ``retrieve_profile`` cannot discover that a profile has only field-level (not object-level) permissions on something like ``AccountContactRelation``, and the parent SObject is never added to -the package.xml — so its field permissions are silently dropped from +the package.xml - so its field permissions are silently dropped from the retrieved profile XML. The fix is to add a ``FieldPermissions`` query against @@ -31,7 +31,7 @@ @pytest.mark.xfail( - reason="repro for #3773 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3773 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3773(): src = inspect.getsource(RetrieveProfileApi._queries_retrieve_permissions) diff --git a/cumulusci/tests/triage/test_issue_3849.py b/cumulusci/tests/triage/test_issue_3849.py index c196b1a8f5..56a9cb0cef 100644 --- a/cumulusci/tests/triage/test_issue_3849.py +++ b/cumulusci/tests/triage/test_issue_3849.py @@ -55,7 +55,7 @@ def _has_selenium_pin(deps: list[str], pkg: str) -> bool: @pytest.mark.xfail( - reason=("repro for #3849 — see docs/triage/v5/repro-results.md"), + reason=("repro for #3849 - see docs/triage/v5/repro-results.md"), strict=False, ) def test_urllib3_or_selenium_modernized(): diff --git a/cumulusci/tests/triage/test_issue_3889.py b/cumulusci/tests/triage/test_issue_3889.py index 56ed579253..5b3f880f68 100644 --- a/cumulusci/tests/triage/test_issue_3889.py +++ b/cumulusci/tests/triage/test_issue_3889.py @@ -7,12 +7,12 @@ Root cause: CumulusCI exposes uninstall tasks only for 1GP managed packages (via namespace + InstalledPackage destructiveChanges): - - cumulusci/cumulusci.yml:615-642 — uninstall_managed, + - cumulusci/cumulusci.yml:615-642 - uninstall_managed, uninstall_packaged, uninstall_packaged_incremental, uninstall_src, uninstall_pre, uninstall_post. None accept a 04t id. - - cumulusci/tasks/salesforce/UninstallPackage.py — `UninstallPackage` + - cumulusci/tasks/salesforce/UninstallPackage.py - `UninstallPackage` only accepts `namespace` and `purge_on_delete`. - - cumulusci/salesforce_api/package_zip.py — `UninstallPackageZipBuilder` + - cumulusci/salesforce_api/package_zip.py - `UninstallPackageZipBuilder` writes destructiveChanges referencing InstalledPackage by namespace; no 04t code path. @@ -35,7 +35,7 @@ @pytest.mark.xfail( - reason="repro for #3889 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3889 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3889(): options = set(UninstallPackage.task_options.keys()) diff --git a/cumulusci/tests/triage/test_issue_3931.py b/cumulusci/tests/triage/test_issue_3931.py index fcae697f10..8b76641f65 100644 --- a/cumulusci/tests/triage/test_issue_3931.py +++ b/cumulusci/tests/triage/test_issue_3931.py @@ -13,7 +13,7 @@ `elem.find("recordType")` returns `None` whenever a `` element has no `` child (a valid -metadata shape — layoutAssignments without recordType apply to +metadata shape - layoutAssignments without recordType apply to records lacking a record-type binding). The subsequent `.text` access then raises `AttributeError: 'NoneType' object has no attribute 'text'`, which is exactly the user's reported error. @@ -38,7 +38,7 @@ @pytest.mark.xfail( - reason="repro for #3931 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3931 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3931(): profile_xml = b""" diff --git a/cumulusci/tests/triage/test_issue_3951.py b/cumulusci/tests/triage/test_issue_3951.py index 66aab85fef..f839ecd4a9 100644 --- a/cumulusci/tests/triage/test_issue_3951.py +++ b/cumulusci/tests/triage/test_issue_3951.py @@ -30,7 +30,7 @@ @pytest.mark.xfail( - reason="repro for #3951 — see docs/triage/v5/repro-results.md", + reason="repro for #3951 - see docs/triage/v5/repro-results.md", strict=False, ) def test_issue_3951(): diff --git a/cumulusci/tests/triage/test_issue_3953.py b/cumulusci/tests/triage/test_issue_3953.py index 12e1d6d4c6..1590d3f11b 100644 --- a/cumulusci/tests/triage/test_issue_3953.py +++ b/cumulusci/tests/triage/test_issue_3953.py @@ -35,7 +35,7 @@ @pytest.mark.xfail( - reason="repro for #3953 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #3953 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_3953(): src = inspect.getsource(AddPicklistEntries._init_options) diff --git a/cumulusci/tests/triage/test_issue_3955.py b/cumulusci/tests/triage/test_issue_3955.py index d49bc1fc0a..bda5971011 100644 --- a/cumulusci/tests/triage/test_issue_3955.py +++ b/cumulusci/tests/triage/test_issue_3955.py @@ -48,7 +48,7 @@ def _stub_browser_library(): @pytest.mark.xfail( - reason=("repro for #3955 — see docs/triage/v5/repro-results.md"), + reason=("repro for #3955 - see docs/triage/v5/repro-results.md"), strict=False, ) def test_open_test_browser_passes_int_viewport_to_playwright(): diff --git a/cumulusci/tests/triage/test_issue_733.py b/cumulusci/tests/triage/test_issue_733.py index 03108111e4..e1d4e5506a 100644 --- a/cumulusci/tests/triage/test_issue_733.py +++ b/cumulusci/tests/triage/test_issue_733.py @@ -23,7 +23,7 @@ @pytest.mark.xfail( - reason="repro for #733 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #733 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_733(): src = inspect.getsource(CliRuntime.check_org_overwrite) diff --git a/cumulusci/tests/triage/test_issue_773.py b/cumulusci/tests/triage/test_issue_773.py index 853e42573b..af9d566c41 100644 --- a/cumulusci/tests/triage/test_issue_773.py +++ b/cumulusci/tests/triage/test_issue_773.py @@ -1,4 +1,4 @@ -"""Repro for SFDO-Tooling/CumulusCI#773 — Document task return values and results. +"""Repro for SFDO-Tooling/CumulusCI#773 - Document task return values and results. cdcarter requested that tasks be able to *declare* their ``return_values`` (and ``result``) and that ``cci task info`` / the web docs surface that @@ -34,7 +34,7 @@ def _make_task_config(): - """Build a minimal TaskConfig pointing at PackageUpload — a real shipping + """Build a minimal TaskConfig pointing at PackageUpload - a real shipping task that documents (in its docstring / source) that it populates ``return_values`` with ``version_number``, ``version_id``, and ``package_id``. """ @@ -52,7 +52,7 @@ def _make_task_config(): @pytest.mark.xfail( - reason="repro for #773 — see docs/triage/v5/repro-results.md", + reason="repro for #773 - see docs/triage/v5/repro-results.md", strict=False, ) def test_doc_task_renders_return_values_section(): diff --git a/cumulusci/tests/triage/test_issue_808.py b/cumulusci/tests/triage/test_issue_808.py index 875115119b..12dbef6ebe 100644 --- a/cumulusci/tests/triage/test_issue_808.py +++ b/cumulusci/tests/triage/test_issue_808.py @@ -26,7 +26,7 @@ @pytest.mark.xfail( - reason="repro for #808 — see docs/triage/v5/repro-results.md", strict=False + reason="repro for #808 - see docs/triage/v5/repro-results.md", strict=False ) def test_issue_808(): src = inspect.getsource(UninstallPackaged._init_options) diff --git a/docs/triage/v5/README.md b/docs/triage/v5/README.md index 03ea1d7c84..28464ea49e 100644 --- a/docs/triage/v5/README.md +++ b/docs/triage/v5/README.md @@ -66,42 +66,41 @@ CumulusCI v5. This triage was conducted with AI assistance. Specifically: - Initial classification, theme clustering, and reproducibility - verification were performed by Claude Opus 4.7 with isolated - subagents. -- Each subagent ran in a dedicated `git` worktree with hard-coded - constraints: no source mutation outside scope, no live-org access, - no scratch-org creation outside DevHub-aliased orgs, no GitHub - state mutation, no `git push`. -- The xfail tests are intentionally `strict=False`; an `XPASS` - surfaces a verdict that no longer holds (e.g. the bug was fixed - independently) rather than crashing CI. + verification were performed by AI coding agents working in + isolated `git` worktrees with hard-coded constraints: no source + mutation outside scope, no live-org access, no scratch-org + creation outside a designated DevHub, no GitHub state mutation, + no `git push`. +- The xfail tests in `cumulusci/tests/triage/` are intentionally + `strict=False`; an `XPASS` surfaces a verdict that no longer + holds (e.g. the bug was fixed independently) rather than crashing + CI. - All proposed pass-1 mutations against GitHub issues (close / - label) are gated on explicit maintainer approval before execution - — they are NOT executed by this PR. + label) are gated on explicit maintainer approval before + execution. They are NOT executed by this PR. -The full session evidence (subagent dispatch logs, anomaly notes, -intermediate CSV consolidation steps) lives in a separate local -branch and is intentionally not included here. +Intermediate run logs (dispatch records, anomaly notes, consolidation +scripts) are kept locally and intentionally not included here. ## Spec basis Pass-1 vocabulary used in `proposals.md`: -- `closed:stale-24mo` — no activity >24 months, no maintainer label. -- `closed:pre-v4.0.0` — body declares CumulusCI 3.x; no reporter +- `closed:stale-24mo` - no activity >24 months, no maintainer label. +- `closed:pre-v4.0.0` - body declares CumulusCI 3.x; no reporter reconfirmation against v4+. -- `closed:missing-fields` — issue lacks repro / cci-version / +- `closed:missing-fields` - issue lacks repro / cci-version / expected behaviour. -- `closed:pr-resolved-#NNNN` — fix already on dev via specified PR. -- `closed:not-reproducible-on-v4.10.0` — bug not reproducible on +- `closed:pr-resolved-#NNNN` - fix already on dev via specified PR. +- `closed:not-reproducible-on-v4.10.0` - bug not reproducible on v4.10.0; close with explicit verdict. -- `closed:not-reproducible-on-dev` — bug not reproducible on `dev`; +- `closed:not-reproducible-on-dev` - bug not reproducible on `dev`; close with explicit verdict. -- `closed:feature-implemented` — feature ask already shipped. -- `closed:duplicate-of-#NNNN` — pointer to canonical issue. -- `closed:pr-pending-#NNNN` — fix exists in an open PR ready to +- `closed:feature-implemented` - feature ask already shipped. +- `closed:duplicate-of-#NNNN` - pointer to canonical issue. +- `closed:pr-pending-#NNNN` - fix exists in an open PR ready to land; close once that PR merges. -- `kept-open` — confirmed REPRO; rescue from close. +- `kept-open` - confirmed REPRO; rescue from close. Pass-2 vocabulary (selected): `target:v4-patch`, `v5-candidate:yes|no`, `severity:{critical,major,minor,trivial}`, `area:{packaging,bulkdata, diff --git a/docs/triage/v5/fix-sketches/issue_1348.md b/docs/triage/v5/fix-sketches/issue_1348.md index 771901dbab..b43d363912 100644 --- a/docs/triage/v5/fix-sketches/issue_1348.md +++ b/docs/triage/v5/fix-sketches/issue_1348.md @@ -1,40 +1,12 @@ -# Fix sketch — #1348: Multiple Git Provider Support +# Fix sketch - #1348: Multiple Git Provider Support **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `cli` -**Issue**: - -## Bug - -`rg -li "gitlab" cumulusci/` and `rg -li "bitbucket" cumulusci/` both return zero matches. The `ci_feature` flow still hardcodes GitHub-specific tasks: - -## Target - -`cumulusci/cumulusci.yml` lines 767-789 - -## Recommended approach (from triage narrative) - -- pass1: `closed:stale-24mo` — large architectural change (multi-VCS abstraction); 6yr no traction; user `zenibako` confirmed using cci on GitLab via custom flows is feasible. -- pass2 labels: `enhancement,stale,wontfix-candidate` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_1348.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #1348:`). +**Issue**: ## Bug `rg -li "gitlab" cumulusci/` and `rg -li "bitbucket" cumulusci/` both return zero matches. The `ci_feature` flow still hardcodes GitHub-specific tasks: ## Target `cumulusci/cumulusci.yml` lines 767-789 ## Recommended approach (from triage narrative) - pass1: `closed:stale-24mo` - large architectural change (multi-VCS abstraction); 6yr no traction; user `zenibako` confirmed using cci on GitLab via custom flows is feasible. + +- | pass2 labels: `enhancement,stale,wontfix-candidate` --- ## Size & risk | Field | Value | + | ---------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_1348.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #1348:`). | diff --git a/docs/triage/v5/fix-sketches/issue_1432.md b/docs/triage/v5/fix-sketches/issue_1432.md index 9a4558490a..20a2d9ab62 100644 --- a/docs/triage/v5/fix-sketches/issue_1432.md +++ b/docs/triage/v5/fix-sketches/issue_1432.md @@ -1,40 +1,12 @@ -# Fix sketch — #1432: CCI Inconsistencies in validating arguments +# Fix sketch - #1432: CCI Inconsistencies in validating arguments **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `cli` -**Issue**: - -## Bug - -Old-style `task_options` dict still does not validate unknown keys: Repro test passes (= unknown `colour` typo is silently accepted via YAML/Python path): Test path: `/tmp/repro/7/tests/test_1432_options_validation.py`. - -## Target - -`cumulusci/core/tasks.py` lines 186-196 - -## Recommended approach (from triage narrative) - -- pass1: `closed:stale-24mo` — 5yr; partial mitigation in place; full fix would require reworking every legacy `task_options` dict task. -- pass2 labels: `bug,stale,partially-fixed` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_1432.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #1432:`). +**Issue**: ## Bug Old-style `task_options` dict still does not validate unknown keys: Repro test passes (= unknown `colour` typo is silently accepted via YAML/Python path): Test path: `_(repro evidence; see narrative)_`. ## Target `cumulusci/core/tasks.py` lines 186-196 ## Recommended approach (from triage narrative) - pass1: `closed:stale-24mo` - 5yr; partial mitigation in place; full fix would require reworking every legacy `task_options` dict task. + +- | pass2 labels: `bug,stale,partially-fixed` --- ## Size & risk | Field | Value | + | ------------------------------------------------------------ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_1432.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #1432:`). | diff --git a/docs/triage/v5/fix-sketches/issue_1769.md b/docs/triage/v5/fix-sketches/issue_1769.md index 53ea8c6d63..541664614b 100644 --- a/docs/triage/v5/fix-sketches/issue_1769.md +++ b/docs/triage/v5/fix-sketches/issue_1769.md @@ -1,40 +1,12 @@ -# Fix sketch — #1769: Unusual case in test_load +# Fix sketch - #1769: Unusual case in test_load **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `bulkdata` -**Issue**: - -## Bug - -The original line 352 in `158a2d4356f` (May 2020) was: In v4.10.0 the same pattern survives, just wrapped in `MappingLookup`: The pattern repeats at lines 754, 773, 801, 1119, 1187, 1255 — declaring `Id` as a "lookup" key inside the `lookups` dict so `_expand_mapping` can express the after-step's UPDATE-on-Id dependency. davidmreed acknowledged in 2020 it was "a horrible hack" he intended to clean... - -## Target - -`cumulusci/tasks/bulkdata/tests/test_load.py` lines 736-739 - -## Recommended approach (from triage narrative) - -- pass1: `closed:stale-24mo` — pure test-fixture nit; never escalated to a real bug; original commenters have moved on. -- pass2 labels: `test-cleanup, low-priority` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_1769.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #1769:`). +**Issue**: ## Bug The original line 352 in `158a2d4356f` (May 2020) was: In v4.10.0 the same pattern survives, just wrapped in `MappingLookup`: The pattern repeats at lines 754, 773, 801, 1119, 1187, 1255 - declaring `Id` as a "lookup" key inside the `lookups` dict so `_expand_mapping` can express the after-step's UPDATE-on-Id dependency. davidmreed acknowledged in 2020 it was "a horrible hack" he intended to clean... ## Target `cumulusci/tasks/bulkdata/tests/test_load.py` lines 736-739 ## Recommended approach (from triage narrative) - pass1: `closed:stale-24mo` - pure test-fixture nit; never escalated to a real bug; original commenters have moved on. + +- | pass2 labels: `test-cleanup, low-priority` --- ## Size & risk | Field | Value | + | ------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_1769.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #1769:`). | diff --git a/docs/triage/v5/fix-sketches/issue_2013.md b/docs/triage/v5/fix-sketches/issue_2013.md index 9c43bbd42f..48882f1822 100644 --- a/docs/triage/v5/fix-sketches/issue_2013.md +++ b/docs/triage/v5/fix-sketches/issue_2013.md @@ -1,40 +1,12 @@ -# Fix sketch — #2013: Mapping files with steps that are not 1-1 with SObjects are unreliable for extraction +# Fix sketch - #2013: Mapping files with steps that are not 1-1 with SObjects are unreliable for extraction **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `bulkdata` -**Issue**: - -## Bug - -`create_table_if_needed` (`utils.py:133-139`) tries to detect duplicate tables but the SQLAlchemy `Table()` constructor raises first: Reproduction (`/tmp/repro/9/tests/test_2013_multistep.py`) yields the exact 2020 traceback: - -## Target - -`cumulusci/tasks/bulkdata/utils.py` lines 133-139 - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — bug is real, easy to reproduce, easy to fix (catch the SQLAlchemy error and re-raise as `BulkDataException`, or validate at mapping-parse time). -- pass2 labels: `bug, bulkdata, extract_dataset, error-handling` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_2013.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #2013:`). +**Issue**: ## Bug `create_table_if_needed` (`utils.py:133-139`) tries to detect duplicate tables but the SQLAlchemy `Table()` constructor raises first: Reproduction (`_(repro evidence; see narrative)_`) yields the exact 2020 traceback: ## Target `cumulusci/tasks/bulkdata/utils.py` lines 133-139 ## Recommended approach (from triage narrative) - pass1: `keep-open` - bug is real, easy to reproduce, easy to fix (catch the SQLAlchemy error and re-raise as `BulkDataException`, or validate at mapping-parse time). + +- | pass2 labels: `bug, bulkdata, extract_dataset, error-handling` --- ## Size & risk | Field | Value | + | --------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_2013.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #2013:`). | diff --git a/docs/triage/v5/fix-sketches/issue_2140.md b/docs/triage/v5/fix-sketches/issue_2140.md index 5902478774..614b302840 100644 --- a/docs/triage/v5/fix-sketches/issue_2140.md +++ b/docs/triage/v5/fix-sketches/issue_2140.md @@ -1,40 +1,12 @@ -# Fix sketch — #2140: Prompt Org Configs when Org Does Not Exist and Command Runs Against It +# Fix sketch - #2140: Prompt Org Configs when Org Does Not Exist and Command Runs Against It **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `cli` -**Issue**: - -## Bug - -`keychain.get_org` raises `OrgNotFound` -> `cli/org.py:530-531` shows `"Org {name} does not exist in the keychain"`. No interactive prompt offering available scratch configs. - -## Target - -`cumulusci/cli/runtime.py` lines 95-104 - -## Recommended approach (from triage narrative) - -- pass1: `closed:stale-24mo` — 5yr `cli-usability` enhancement with no traction. -- pass2 labels: `enhancement,cli-usability,stale` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_2140.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #2140:`). +**Issue**: ## Bug `keychain.get_org` raises `OrgNotFound` -> `cli/org.py:530-531` shows `"Org {name} does not exist in the keychain"`. No interactive prompt offering available scratch configs. ## Target `cumulusci/cli/runtime.py` lines 95-104 ## Recommended approach (from triage narrative) - pass1: `closed:stale-24mo` - 5yr `cli-usability` enhancement with no traction. + +- | pass2 labels: `enhancement,cli-usability,stale` --- ## Size & risk | Field | Value | + | ------------------------------------------------------------------ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_2140.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #2140:`). | diff --git a/docs/triage/v5/fix-sketches/issue_2153.md b/docs/triage/v5/fix-sketches/issue_2153.md index 39e63310b0..1f9318d8f3 100644 --- a/docs/triage/v5/fix-sketches/issue_2153.md +++ b/docs/triage/v5/fix-sketches/issue_2153.md @@ -1,40 +1,12 @@ -# Fix sketch — #2153: Add comment to original PR which tags all branch subscribers when a merge +# Fix sketch - #2153: Add comment to original PR which tags all branch subscribers when a merge **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `ci-integration` -**Issue**: - -## Bug - -`cumulusci/tasks/github/merge.py` `_create_conflict_pull_request` (the only place an auto-merge PR is created): The method only creates the conflict PR; it never opens a comment on any PR (the original child PR or otherwise). Repo-wide grep for `create_comment|issue_comment|pr.create_comment|comment.*pull_request` under `cumulusci/tasks/github` returns no hits in production code (only test fixture... - -## Target - -`cumulusci/tasks/github/merge.py` lines 264-288 - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — small, well-scoped enhancement; reasonable "good-second-issue". -- pass2 labels: `enhancement, github, merge-conflict` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_2153.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #2153:`). +**Issue**: ## Bug `cumulusci/tasks/github/merge.py` `_create_conflict_pull_request` (the only place an auto-merge PR is created): The method only creates the conflict PR; it never opens a comment on any PR (the original child PR or otherwise). Repo-wide grep for `create_comment|issue_comment|pr.create_comment|comment.*pull_request` under `cumulusci/tasks/github` returns no hits in production code (only test fixture... ## Target `cumulusci/tasks/github/merge.py` lines 264-288 ## Recommended approach (from triage narrative) - pass1: `keep-open` - small, well-scoped enhancement; reasonable "good-second-issue". + +- | pass2 labels: `enhancement, github, merge-conflict` --- ## Size & risk | Field | Value | + | ---------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_2153.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #2153:`). | diff --git a/docs/triage/v5/fix-sketches/issue_2325.md b/docs/triage/v5/fix-sketches/issue_2325.md index ab82028f8b..41730f06fe 100644 --- a/docs/triage/v5/fix-sketches/issue_2325.md +++ b/docs/triage/v5/fix-sketches/issue_2325.md @@ -1,40 +1,12 @@ -# Fix sketch — #2325: Task to turn off validation rules to allow data insert +# Fix sketch - #2325: Task to turn off validation rules to allow data insert **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `bulkdata` -**Issue**: - -## Bug - -- Trigger analog: `disable_tdtm_trigger_handlers` / `restore_tdtm_trigger_handlers` (`cumulusci.yml:738-747`). - DuplicateRule analog: `set_duplicate_rule_status` → `cumulusci.tasks.metadata_etl.duplicate_rules.SetDuplicateRuleStatus` (a 25-line `MetadataSingleEntityTransformTask` subclass with `entity = "DuplicateRule"`). - ValidationRule equivalent: **none.** `cci task list | grep -i -E "v... - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — feature still missing, clear implementation pattern, modest scope. -- pass2 labels: `enhancement, bulkdata, metadata_etl, good-first-issue` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_2325.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #2325:`). +**Issue**: ## Bug - Trigger analog: `disable_tdtm_trigger_handlers` / `restore_tdtm_trigger_handlers` (`cumulusci.yml:738-747`). - DuplicateRule analog: `set_duplicate_rule_status` → `cumulusci.tasks.metadata_etl.duplicate_rules.SetDuplicateRuleStatus` (a 25-line `MetadataSingleEntityTransformTask` subclass with `entity = "DuplicateRule"`). - ValidationRule equivalent: **none.** `cci task list | grep -i -E "v... ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `keep-open` - feature still missing, clear implementation pattern, modest scope. + +- | pass2 labels: `enhancement, bulkdata, metadata_etl, good-first-issue` --- ## Size & risk | Field | Value | + | ---------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_2325.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #2325:`). | diff --git a/docs/triage/v5/fix-sketches/issue_2402.md b/docs/triage/v5/fix-sketches/issue_2402.md index ec11e54ba9..04d7b9bd30 100644 --- a/docs/triage/v5/fix-sketches/issue_2402.md +++ b/docs/triage/v5/fix-sketches/issue_2402.md @@ -1,40 +1,12 @@ -# Fix sketch — #2402: Create a --rebuild-org parameter for cci flow run +# Fix sketch - #2402: Create a --rebuild-org parameter for cci flow run **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `cli` -**Issue**: - -## Bug - -Only `--delete-org` exists. `rg -i "rebuild.org"` returns zero hits. - -## Target - -`cumulusci/cli/flow.py` lines 119-145 - -## Recommended approach (from triage narrative) - -- pass1: `closed:stale-24mo` — 5yr; tracked W-10502624 (no movement); user can accomplish via `cci org scratch_delete X && cci flow run`. -- pass2 labels: `enhancement,stale` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_2402.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #2402:`). +**Issue**: ## Bug Only `--delete-org` exists. `rg -i "rebuild.org"` returns zero hits. ## Target `cumulusci/cli/flow.py` lines 119-145 ## Recommended approach (from triage narrative) - pass1: `closed:stale-24mo` - 5yr; (no movement); user can accomplish via `cci org scratch_delete X && cci flow run`. + +- | pass2 labels: `enhancement,stale` --- ## Size & risk | Field | Value | + | ---------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_2402.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #2402:`). | diff --git a/docs/triage/v5/fix-sketches/issue_2500.md b/docs/triage/v5/fix-sketches/issue_2500.md index 9c2f63a9bf..d041f04cba 100644 --- a/docs/triage/v5/fix-sketches/issue_2500.md +++ b/docs/triage/v5/fix-sketches/issue_2500.md @@ -1,55 +1,18 @@ -# Fix sketch — #2500: `ignore_failure` is not documented +# Fix sketch - #2500: `ignore_failure` is not documented **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `docs` -**Issue**: - -## Bug - -`ignore_failure` is not documented - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -Add `### Ignore a Failed Step` (or `### Continue After a Failed Step`) +**Issue**: ## Bug `ignore_failure` is not documented ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) Add `### Ignore a Failed Step` (or `### Continue After a Failed Step`) to `docs/config.md` immediately after the existing `### Skip a Flow Step` -section. Body should cover: - -- What it does: when `ignore_failure: True` is set on a step, an - exception raised by that step does not abort the flow; subsequent - steps still run. -- A minimal YAML example (the existing `release_unlocked_production` - snippet around line 783 already demonstrates it — link to it instead - of duplicating). -- Interaction with `^^step.return_value` references: downstream steps - that reference a failed step's return values must defend against - missing keys. -- When NOT to use it: in CI, silently ignoring a failure hides - regressions; prefer a `when:` clause for intentional conditional - branching. -- One sentence on the difference between `ignore_failure` (post hoc: - swallow the exception) and `when:` (a priori: skip the step entirely). - -This is a tiny, high-leverage docs PR — a strong candidate for a -`good-first-issue` label. - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_2500.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #2500:`). +section. Body should cover: - What it does: when `ignore_failure: True` is set on a step, an exception raised by that step does not abort the flow; subsequent steps still run. + +- A minimal YAML example (the existing `release_unlocked_production` snippet around line 783 already demonstrates it - link to it instead of duplicating). +- Interaction with `^^step.return_value` references: downstream steps that reference a failed step's return values must defend against missing keys. +- When NOT to use it: in CI, silently ignoring a failure hides regressions; prefer a `when:` clause for intentional conditional branching. +- One sentence on the difference between `ignore_failure` (post hoc: swallow the exception) and `when:` (a priori: skip the step entirely). This is a tiny, high-leverage docs PR - a strong candidate for a + `good-first-issue` label. ## Size & risk | Field | Value | + | ------------------------------------ | ---------------------- | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_2500.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #2500:`). diff --git a/docs/triage/v5/fix-sketches/issue_2506.md b/docs/triage/v5/fix-sketches/issue_2506.md index 4aa880e7a7..a2ec208409 100644 --- a/docs/triage/v5/fix-sketches/issue_2506.md +++ b/docs/triage/v5/fix-sketches/issue_2506.md @@ -1,40 +1,12 @@ -# Fix sketch — #2506: Bulk Operations should have a --debug mode which maintains logs and tempfiles +# Fix sketch - #2506: Bulk Operations should have a --debug mode which maintains logs and tempfiles **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `bulkdata` -**Issue**: - -## Bug - -- Snowfakery task (`snowfakery.py:241,355,385,565`) calls `get_debug_mode()` and at `:386` logs `f"Working Directory: {tempdir}"` per loop iteration. - `extract.py`, `step.py` — **zero** references to `debug_mode` or `get_debug_mode`. - `load.py:283` uses `tempfile.TemporaryFile` with no debug-mode override; the file is auto-deleted on context exit regardless of debug. - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — partial implementation; remaining work is straightforward (wire `get_debug_mode()` into load/extract, conditionally use `TemporaryDirectory(delete=False)` and emit path). -- pass2 labels: `enhancement, bulkdata, extract_dataset, load_dataset, debugging` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_2506.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #2506:`). +**Issue**: ## Bug - Snowfakery task (`snowfakery.py:241,355,385,565`) calls `get_debug_mode()` and at `:386` logs `f"Working Directory: {tempdir}"` per loop iteration. - `extract.py`, `step.py` - **zero** references to `debug_mode` or `get_debug_mode`. - `load.py:283` uses `tempfile.TemporaryFile` with no debug-mode override; the file is auto-deleted on context exit regardless of debug. ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `keep-open` - partial implementation; remaining work is straightforward (wire `get_debug_mode()` into load/extract, conditionally use `TemporaryDirectory(delete=False)` and emit path). + +- | pass2 labels: `enhancement, bulkdata, extract_dataset, load_dataset, debugging` --- ## Size & risk | Field | Value | + | -------------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_2506.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #2506:`). | diff --git a/docs/triage/v5/fix-sketches/issue_2507.md b/docs/triage/v5/fix-sketches/issue_2507.md index c3bc53c86a..a9ef9e1975 100644 --- a/docs/triage/v5/fix-sketches/issue_2507.md +++ b/docs/triage/v5/fix-sketches/issue_2507.md @@ -1,40 +1,12 @@ -# Fix sketch — #2507: Undo mode for CumulusCI Insert +# Fix sketch - #2507: Undo mode for CumulusCI Insert **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `cli` -**Issue**: - -## Bug - -No `undo_insert` task exists (`rg -l undo_insert` returns nothing). Closest functionality is `enable_rollback` on `load_dataset` and `snowfakery` tasks: That only triggers rollback on error during the load; it does not provide the post-hoc "delete everything we ever inserted" capability the requester described. - -## Target - -`cumulusci/tasks/bulkdata/load.py` lines 97-99 - -## Recommended approach (from triage narrative) - -- pass1: `closed:stale-24mo` — 4yr feature with partial mitigation already shipped. -- pass2 labels: `enhancement,stale,partially-fixed` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_2507.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #2507:`). +**Issue**: ## Bug No `undo_insert` task exists (`rg -l undo_insert` returns nothing). Closest functionality is `enable_rollback` on `load_dataset` and `snowfakery` tasks: That only triggers rollback on error during the load; it does not provide the post-hoc "delete everything we ever inserted" capability the requester described. ## Target `cumulusci/tasks/bulkdata/load.py` lines 97-99 ## Recommended approach (from triage narrative) - pass1: `closed:stale-24mo` - 4yr feature with partial mitigation already shipped. + +- | pass2 labels: `enhancement,stale,partially-fixed` --- ## Size & risk | Field | Value | + | -------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_2507.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #2507:`). | diff --git a/docs/triage/v5/fix-sketches/issue_2508.md b/docs/triage/v5/fix-sketches/issue_2508.md index ee2243d3f3..846bab89d6 100644 --- a/docs/triage/v5/fix-sketches/issue_2508.md +++ b/docs/triage/v5/fix-sketches/issue_2508.md @@ -1,40 +1,12 @@ -# Fix sketch — #2508: Manual load retries +# Fix sketch - #2508: Manual load retries **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `bulkdata` -**Issue**: - -## Bug - -- `cci task list` returns no retry-named task. - `load.py` has an `enable_rollback` option (`:97-98`, `RollbackType` enum at `:1051`) but rollback **undoes successful inserts when failures occur** — the opposite of "retry the failures." - `RowErrorChecker` (`utils.py:158`) only logs and optionally raises; it does not persist a failed-rows artifact that could be replayed. - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — distinct from rollback; would need (a) failed-row CSV/SQL persistence + (b) a new `retry_failed_load` task that consumes it. -- pass2 labels: `enhancement, bulkdata, load_dataset, reliability` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_2508.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #2508:`). +**Issue**: ## Bug - `cci task list` returns no retry-named task. - `load.py` has an `enable_rollback` option (`:97-98`, `RollbackType` enum at `:1051`) but rollback **undoes successful inserts when failures occur** - the opposite of "retry the failures." - `RowErrorChecker` (`utils.py:158`) only logs and optionally raises; it does not persist a failed-rows artifact that could be replayed. ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `keep-open` - distinct from rollback; would need (a) failed-row CSV/SQL persistence + (b) a new `retry_failed_load` task that consumes it. + +- | pass2 labels: `enhancement, bulkdata, load_dataset, reliability` --- ## Size & risk | Field | Value | + | ----------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_2508.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #2508:`). | diff --git a/docs/triage/v5/fix-sketches/issue_2826.md b/docs/triage/v5/fix-sketches/issue_2826.md index 722215948f..9788f0b7ba 100644 --- a/docs/triage/v5/fix-sketches/issue_2826.md +++ b/docs/triage/v5/fix-sketches/issue_2826.md @@ -1,42 +1,12 @@ -# Fix sketch — #2826: deploy_unmanaged flow is supposed to silently do nothing if there's not actually a package directory +# Fix sketch - #2826: deploy_unmanaged flow is supposed to silently do nothing if there's not actually a package directory **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `metadata-etl` -**Issue**: - -## Bug - -deploy_unmanaged flow is supposed to silently do nothing if there's not actually a package directory - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — small, contained fix. -- pass2 labels: `bug`, `good-first-issue` - -**Notes**: Could be fixed at the task layer (skip with logger.info when path missing) or at the flow layer (`when:` guard on the deploy_unmanaged steps). Task-layer is more defensible because the same task may be referenced from custom flows. - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_2826.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #2826:`). +**Issue**: ## Bug deploy*unmanaged flow is supposed to silently do nothing if there's not actually a package directory ## Target \_See narrative for target file:line.* ## Recommended approach (from triage narrative) - pass1: `keep-open` - small, contained fix. + +- | pass2 labels: `bug`, `good-first-issue` **Notes**: Could be fixed at the task layer (skip with logger.info when path missing) or at the flow layer (`when:` guard on the deploy_unmanaged steps). Task-layer is more defensible because the same task may be referenced from custom flows. --- ## Size & risk | Field | Value | + | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_2826.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #2826:`). | diff --git a/docs/triage/v5/fix-sketches/issue_2951.md b/docs/triage/v5/fix-sketches/issue_2951.md index de655640b7..e3409369ac 100644 --- a/docs/triage/v5/fix-sketches/issue_2951.md +++ b/docs/triage/v5/fix-sketches/issue_2951.md @@ -1,40 +1,12 @@ -# Fix sketch — #2951: Error in task load_dataset - Standard_price_not_defined +# Fix sketch - #2951: Error in task load_dataset - Standard_price_not_defined **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `bulkdata` -**Issue**: - -## Bug - -No special handling exists in the loader to sequence Standard-Price-Book PricebookEntries before custom-pricebook PricebookEntries within a single mapping step. Within one Bulk job, records are processed in parallel within batches and Salesforce throws `STANDARD_PRICE_NOT_DEFINED` when a custom price is created before the matching standard price. Mitigation already in place for the `extract_datase... - -## Target - -`cumulusci/tasks/bulkdata/extract_dataset_utils/hardcoded_default_declarations.py` lines 14-18 - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — bug is latent. Fix options: (a) loader auto-splits PricebookEntry into two implicit batches (standard pricebook first); (b) document the requirement and validate at parse time that PricebookEntry steps are not "mixed." -- pass2 labels: `bug, bulkdata, load_dataset, pricebook, documentation` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_2951.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #2951:`). +**Issue**: ## Bug No special handling exists in the loader to sequence Standard-Price-Book PricebookEntries before custom-pricebook PricebookEntries within a single mapping step. Within one Bulk job, records are processed in parallel within batches and Salesforce throws `STANDARD_PRICE_NOT_DEFINED` when a custom price is created before the matching standard price. Mitigation already in place for the `extract_datase... ## Target `cumulusci/tasks/bulkdata/extract_dataset_utils/hardcoded_default_declarations.py`lines 14-18 ## Recommended approach (from triage narrative) - pass1:`keep-open` - bug is latent. Fix options: (a) loader auto-splits PricebookEntry into two implicit batches (standard pricebook first); (b) document the requirement and validate at parse time that PricebookEntry steps are not "mixed." + +- | pass2 labels: `bug, bulkdata, load_dataset, pricebook, documentation` --- ## Size & risk | Field | Value | + | ---------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_2951.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #2951:`). | diff --git a/docs/triage/v5/fix-sketches/issue_2979.md b/docs/triage/v5/fix-sketches/issue_2979.md index 7420fdff6e..ccf8f56107 100644 --- a/docs/triage/v5/fix-sketches/issue_2979.md +++ b/docs/triage/v5/fix-sketches/issue_2979.md @@ -1,40 +1,12 @@ -# Fix sketch — #2979: deploy task should deploy from default entry in packageDirectories +# Fix sketch - #2979: deploy task should deploy from default entry in packageDirectories **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `packaging` -**Issue**: - -## Bug - -- `cumulusci/cumulusci.yml:227-229` — the `deploy` task still hard-codes `path: src` for `cumulusci.tasks.salesforce.Deploy`. - `cumulusci/core/config/project_config.py:517-525` — `default_package_path` correctly reads `packageDirectories[*].default` from `sfdx-project.json` when `project__source_format == "sfdx"`. - The only consumer of `default_package_path` is `cumulusci/tasks/create_pack... - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — feature still missing; davisagli's 2021 design comment (3-tier fallback `path` -> sfdx default -> `src`) remains the natural plan. -- pass2 labels: `severity:low,area:packaging,area:sfdx,state:needs-design` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_2979.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #2979:`). +**Issue**: ## Bug - `cumulusci/cumulusci.yml:227-229` - the `deploy` task still hard-codes `path: src` for `cumulusci.tasks.salesforce.Deploy`. - `cumulusci/core/config/project_config.py:517-525` - `default_package_path` correctly reads `packageDirectories[*].default` from `sfdx-project.json` when `project__source_format == "sfdx"`. - The only consumer of `default_package_path` is `cumulusci/tasks/create_pack... ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `keep-open`- feature still missing; davisagli's 2021 design comment (3-tier fallback`path`-> sfdx default ->`src`) remains the natural plan. + +- | pass2 labels: `severity:low,area:packaging,area:sfdx,state:needs-design` --- ## Size & risk | Field | Value | + | ------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_2979.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #2979:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3015.md b/docs/triage/v5/fix-sketches/issue_3015.md index a5006e0c6c..0327a2449f 100644 --- a/docs/triage/v5/fix-sketches/issue_3015.md +++ b/docs/triage/v5/fix-sketches/issue_3015.md @@ -1,40 +1,12 @@ -# Fix sketch — #3015: Remove imported dx org from cci list without deleting actual scratch +# Fix sketch - #3015: Remove imported dx org from cci list without deleting actual scratch **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `cli` -**Issue**: - -## Bug - -No `--keep-org` flag. davisagli's manual workaround (delete `~/.cumulusci//.org` directly) still applies. - -## Target - -`cumulusci/cli/org.py` lines 519-543 - -## Recommended approach (from triage narrative) - -- pass1: `closed:stale-24mo` — 4yr; tracked W-10502512. -- pass2 labels: `enhancement,stale` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3015.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3015:`). +**Issue**: ## Bug No `--keep-org` flag. davisagli's manual workaround (delete `~/.cumulusci//.org` directly) still applies. ## Target `cumulusci/cli/org.py` lines 519-543 ## Recommended approach (from triage narrative) - pass1: `closed:stale-24mo` - 4yr; . + +- | pass2 labels: `enhancement,stale` --- ## Size & risk | Field | Value | + | ---------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3015.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3015:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3024.md b/docs/triage/v5/fix-sketches/issue_3024.md index c542f43137..4faaf041d5 100644 --- a/docs/triage/v5/fix-sketches/issue_3024.md +++ b/docs/triage/v5/fix-sketches/issue_3024.md @@ -1,40 +1,12 @@ -# Fix sketch — #3024: Order of flow groups in `cumulusci/cumulusci.yml` +# Fix sketch - #3024: Order of flow groups in `cumulusci/cumulusci.yml` **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `cli` -**Issue**: - -## Bug - -Sequence of unique `group:` values in `cumulusci/cumulusci.yml` (first appearance): `Continuous Integration` is buried near the bottom; `Org Setup` (the user's preferred name) does not exist (uses `Setup`); ordering does not match the user's request. - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `closed:stale-24mo` — 4yr cosmetic VS Code extension request; the true fix is sorting at the consumer (the extension) rather than rearranging the canonical YAML. -- pass2 labels: `enhancement,stale` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3024.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3024:`). +**Issue**: ## Bug Sequence of unique `group:` values in `cumulusci/cumulusci.yml` (first appearance): `Continuous Integration` is buried near the bottom; `Org Setup` (the user's preferred name) does not exist (uses `Setup`); ordering does not match the user's request. ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `closed:stale-24mo` - 4yr cosmetic VS Code extension request; the true fix is sorting at the consumer (the extension) rather than rearranging the canonical YAML. + +- | pass2 labels: `enhancement,stale` --- ## Size & risk | Field | Value | + | ---------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3024.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3024:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3137.md b/docs/triage/v5/fix-sketches/issue_3137.md index 3be157b519..88aeb95421 100644 --- a/docs/triage/v5/fix-sketches/issue_3137.md +++ b/docs/triage/v5/fix-sketches/issue_3137.md @@ -1,40 +1,12 @@ -# Fix sketch — #3137: cci task run update_package_xml and Salesforce Case Custom Object +# Fix sketch - #3137: cci task run update_package_xml and Salesforce Case Custom Object **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `metadata-etl` -**Issue**: - -## Bug - -- `cumulusci/tasks/metadata/package.py:451-458` skips standard objects. - `cumulusci/tasks/metadata/package.py:562-584` `UpdatePackageXml.task_options` has only `path`, `output`, `package_name`, `managed`, `delete`, - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: keep-open — a real product gap remains; mark for design discussion. -- pass2 labels: `severity:low,area:metadata-etl,type:enhancement,state:needs-design` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3137.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3137:`). +**Issue**: ## Bug - `cumulusci/tasks/metadata/package.py:451-458` skips standard objects. - `cumulusci/tasks/metadata/package.py:562-584` `UpdatePackageXml.task_options` has only `path`, `output`, `package_name`, `managed`, `delete`, ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: keep-open - a real product gap remains; mark for design discussion. + +- | pass2 labels: `severity:low,area:metadata-etl,type:enhancement,state:needs-design` --- ## Size & risk | Field | Value | + | ----------------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3137.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3137:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3161.md b/docs/triage/v5/fix-sketches/issue_3161.md index cd29031931..daa356f777 100644 --- a/docs/triage/v5/fix-sketches/issue_3161.md +++ b/docs/triage/v5/fix-sketches/issue_3161.md @@ -1,40 +1,12 @@ -# Fix sketch — #3161: Ability to Hide Option Values When Using Task Options +# Fix sketch - #3161: Ability to Hide Option Values When Using Task Options **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `cli` -**Issue**: - -## Bug - -A masking infrastructure was added (task-option metadata can opt in via `sensitive: True`), but: 1. The Robot `vars` option is not marked sensitive (`cumulusci/tasks/robotframework/robotframework.py:54-56`). 2. There's no CLI/Robot-side flag for the user to mark an ad-hoc `-o` value as sensitive. - -## Target - -`cumulusci/core/flowrunner.py` lines 300-320 - -## Recommended approach (from triage narrative) - -- pass1: `closed:stale-24mo` — 4yr; partial fix in place. -- pass2 labels: `enhancement,stale,partially-implemented` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3161.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3161:`). +**Issue**: ## Bug A masking infrastructure was added (task-option metadata can opt in via `sensitive: True`), but: 1. The Robot `vars` option is not marked sensitive (`cumulusci/tasks/robotframework/robotframework.py:54-56`). 2. There's no CLI/Robot-side flag for the user to mark an ad-hoc `-o` value as sensitive. ## Target `cumulusci/core/flowrunner.py` lines 300-320 ## Recommended approach (from triage narrative) - pass1: `closed:stale-24mo` - 4yr; partial fix in place. + +- | pass2 labels: `enhancement,stale,partially-implemented` --- ## Size & risk | Field | Value | + | -------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3161.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3161:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3165.md b/docs/triage/v5/fix-sketches/issue_3165.md index 7e19b4728a..881d08fbc0 100644 --- a/docs/triage/v5/fix-sketches/issue_3165.md +++ b/docs/triage/v5/fix-sketches/issue_3165.md @@ -1,42 +1,12 @@ -# Fix sketch — #3165: Update Admin Profile task fails when specifying record types without custom package.xml +# Fix sketch - #3165: Update Admin Profile task fails when specifying record types without custom package.xml **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `metadata-etl` -**Issue**: - -## Bug - -Update Admin Profile task fails when specifying record types without custom package.xml - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — single-line refactor. -- pass2 labels: `bug` - -**Notes**: Smallest fix at update_profile.py:137 — always call `self._expand_package_xml_objects(package_xml)` regardless of `include_packaged_objects`, and only call the broader `self._expand_package_xml` (which does the Tooling API query) when `include_packaged_objects=True`. `_expand_package_xml_objects` itself only walks the user-supplied options, no API call. - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3165.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3165:`). +**Issue**: ## Bug Update Admin Profile task fails when specifying record types without custom package.xml ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `keep-open` - single-line refactor. + +- | pass2 labels: `bug` **Notes**: Smallest fix at update_profile.py:137 - always call `self._expand_package_xml_objects(package_xml)` regardless of `include_packaged_objects`, and only call the broader `self._expand_package_xml` (which does the Tooling API query) when `include_packaged_objects=True`. `_expand_package_xml_objects` itself only walks the user-supplied options, no API call. --- ## Size & risk | Field | Value | + | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3165.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3165:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3307.md b/docs/triage/v5/fix-sketches/issue_3307.md index 89e912c141..98269f5ec9 100644 --- a/docs/triage/v5/fix-sketches/issue_3307.md +++ b/docs/triage/v5/fix-sketches/issue_3307.md @@ -1,40 +1,12 @@ -# Fix sketch — #3307: Project Template Support for `cci project init` +# Fix sketch - #3307: Project Template Support for `cci project init` **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `cli` -**Issue**: - -## Bug - -`rg "template" cumulusci/cli/project.py` only finds references to internal Jinja templates rendered from `cumulusci/files/templates/project` (lines 220-329). No `--template` CLI option exists. `project_init` (line 41) takes no template-source argument. - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `closed:stale-24mo` — 4yr; explicitly described by the requester as "low priority / nice to have". -- pass2 labels: `enhancement,stale` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3307.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3307:`). +**Issue**: ## Bug `rg "template" cumulusci/cli/project.py` only finds references to internal Jinja templates rendered from `cumulusci/files/templates/project` (lines 220-329). No `--template` CLI option exists. `project_init` (line 41) takes no template-source argument. ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `closed:stale-24mo` - 4yr; explicitly described by the requester as "low priority / nice to have". + +- | pass2 labels: `enhancement,stale` --- ## Size & risk | Field | Value | + | ---------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3307.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3307:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3331.md b/docs/triage/v5/fix-sketches/issue_3331.md index 6eda4c2c3c..2517b0d57e 100644 --- a/docs/triage/v5/fix-sketches/issue_3331.md +++ b/docs/triage/v5/fix-sketches/issue_3331.md @@ -1,40 +1,12 @@ -# Fix sketch — #3331: Task update_package_xml does not write correct package.xml for AssignmentRules +# Fix sketch - #3331: Task update_package_xml does not write correct package.xml for AssignmentRules **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `metadata-etl` -**Issue**: - -## Bug - -- `cumulusci/tasks/metadata/metadata_map.yml:45-48` maps the `assignmentRules` folder to `type: AssignmentRule` (singular). MDAPI expects the plural type name (cf. `autoResponseRules:` at lines 60-63 - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: keep-open — one-line YAML fix; reporter offered a PR. -- pass2 labels: `severity:medium,area:metadata-etl,type:bug,good-first-issue` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3331.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3331:`). +**Issue**: ## Bug - `cumulusci/tasks/metadata/metadata_map.yml:45-48` maps the `assignmentRules` folder to `type: AssignmentRule` (singular). MDAPI expects the plural type name (cf. `autoResponseRules:` at lines 60-63 ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: keep-open - one-line YAML fix; reporter offered a PR. + +- | pass2 labels: `severity:medium,area:metadata-etl,type:bug,good-first-issue` --- ## Size & risk | Field | Value | + | ---------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3331.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3331:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3349.md b/docs/triage/v5/fix-sketches/issue_3349.md index c3b0bdb226..324069e48e 100644 --- a/docs/triage/v5/fix-sketches/issue_3349.md +++ b/docs/triage/v5/fix-sketches/issue_3349.md @@ -1,35 +1,10 @@ -# Fix sketch — #3349: Make generated dataset recordType tables unique based on table instead of sf_object +# Fix sketch - #3349: Make generated dataset recordType tables unique based on table instead of sf_object **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `bulkdata` -**Issue**: - -## Bug - -Make generated dataset recordType tables unique based on table instead of sf_object - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -_See narrative for recommended action._ - -## Size & risk - -| Field | Value | +**Issue**: ## Bug Make generated dataset recordType tables unique based on table instead of sf*object ## Target \_See narrative for target file:line.* ## Recommended approach (from triage narrative) _See narrative for recommended action._ ## Size & risk | Field | Value | | ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3349.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3349:`). +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3349.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3349:`). diff --git a/docs/triage/v5/fix-sketches/issue_3353.md b/docs/triage/v5/fix-sketches/issue_3353.md index 3dc2777eea..efdedee9d2 100644 --- a/docs/triage/v5/fix-sketches/issue_3353.md +++ b/docs/triage/v5/fix-sketches/issue_3353.md @@ -1,35 +1,10 @@ -# Fix sketch — #3353: Enable Snowfakery task to use recipes from other repositories +# Fix sketch - #3353: Enable Snowfakery task to use recipes from other repositories **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `bulkdata` -**Issue**: - -## Bug - -Enable Snowfakery task to use recipes from other repositories - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -_See narrative for recommended action._ - -## Size & risk - -| Field | Value | +**Issue**: ## Bug Enable Snowfakery task to use recipes from other repositories ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) _See narrative for recommended action._ ## Size & risk | Field | Value | | ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3353.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3353:`). +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3353.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3353:`). diff --git a/docs/triage/v5/fix-sketches/issue_3407.md b/docs/triage/v5/fix-sketches/issue_3407.md index 7f0e2cb86e..327839ee22 100644 --- a/docs/triage/v5/fix-sketches/issue_3407.md +++ b/docs/triage/v5/fix-sketches/issue_3407.md @@ -1,51 +1,16 @@ -# Fix sketch — #3407: `set_service(service_config)` annotation lies +# Fix sketch - #3407: `set_service(service_config)` annotation lies **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `keychain` -**Issue**: +**Issue**: ## Bug - `cumulusci/core/keychain/base_project_keychain.py` lines 202-209 declare `service_config: ServiceConfig` on `set_service`. - `cumulusci/core/keychain/encrypted_file_project_keychain.py` line 717 ## Target `cumulusci/core/keychain/base_project_keychain.py:202-219`. Also add the same widened annotation on the abstract `_set_service` (line 360) and propagate to `EncryptedFileProjectKeychain._set_service` (line 583). ## Recommended approach (from triage narrative) - **Approach**: Widen the annotation. `set_service`'s `service_config` parameter should be `Union[ServiceConfig, str]` (or `ServiceConfig | str | +bytes`) and the docstring updated to say "raw encrypted payload when `config_encrypted=True`". The deeper refactor - splitting the API into `set_service` (validated `ServiceConfig`) and `set_encrypted_service` (raw blob) - is cleaner but breaks the public API and is out of scope for this triage pass. -## Bug - -- `cumulusci/core/keychain/base_project_keychain.py` lines 202-209 declare `service_config: ServiceConfig` on `set_service`. - `cumulusci/core/keychain/encrypted_file_project_keychain.py` line 717 - -## Target - -`cumulusci/core/keychain/base_project_keychain.py:202-219`. Also add the same widened annotation on the abstract `_set_service` (line 360) and propagate to `EncryptedFileProjectKeychain._set_service` (line 583). - -## Recommended approach (from triage narrative) - -- **Approach**: Widen the annotation. `set_service`'s `service_config` - parameter should be `Union[ServiceConfig, str]` (or `ServiceConfig | str | -bytes`) and the docstring updated to say "raw encrypted payload when - `config_encrypted=True`". The deeper refactor — splitting the API into - `set_service` (validated `ServiceConfig`) and `set_encrypted_service` - (raw blob) — is cleaner but breaks the public API and is out of scope - for this triage pass. -- **Target**: `cumulusci/core/keychain/base_project_keychain.py:202-219`. - Also add the same widened annotation on the abstract `_set_service` - (line 360) and propagate to `EncryptedFileProjectKeychain._set_service` - (line 583). +- **Target**: `cumulusci/core/keychain/base_project_keychain.py:202-219`. Also add the same widened annotation on the abstract `_set_service` (line 360) and propagate to `EncryptedFileProjectKeychain._set_service` (line 583). - **Size**: ~10 LOC plus a typing-import bump. Single-file change feasible. -- **Risk**: very low. Pure type-hint widening; no runtime behaviour change. - Downstream callers that already pass `ServiceConfig` keep working; - pyright/mypy users gain an accurate hint. -- **API break**: no. Widening a parameter type is non-breaking for - callers. - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3407.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3407:`). +- **Risk**: very low. Pure type-hint widening; no runtime behaviour change. Downstream callers that already pass `ServiceConfig` keep working; pyright/mypy users gain an accurate hint. +- | **API break**: no. Widening a parameter type is non-breaking for callers. ## Size & risk | Field | Value | + | ---------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3407.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3407:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3429.md b/docs/triage/v5/fix-sketches/issue_3429.md index d987f9aec3..9f4723dad3 100644 --- a/docs/triage/v5/fix-sketches/issue_3429.md +++ b/docs/triage/v5/fix-sketches/issue_3429.md @@ -1,40 +1,12 @@ -# Fix sketch — #3429: Support overriding `cumulusci.yml` to be used for configuration +# Fix sketch - #3429: Support overriding `cumulusci.yml` to be used for configuration **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `packaging` -**Issue**: - -## Bug - -- `cumulusci/core/config/project_config.py:82` — `config_filename = "cumulusci.yml"` is hardcoded. - `cumulusci/core/config/project_config.py:118-184` — only an `additional_yaml` kwarg (programmatic, used by MetaCI) is supported; no env var or CLI plumbing. - `git merge-base --is-ancestor 9d650ace2 HEAD` returns non-zero — PR #3969 (commits prefixed `feat(cli): add resolve_extra_yaml helper ... - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — feature is genuinely actionable on v4.10.0; auto-close once #3969 merges via `closed:fixed-by-pr-#3969`. -- pass2 labels: `severity:medium,area:packaging,area:cli,state:in-progress` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3429.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3429:`). +**Issue**: ## Bug - `cumulusci/core/config/project_config.py:82` - `config_filename = "cumulusci.yml"` is hardcoded. - `cumulusci/core/config/project_config.py:118-184` - only an `additional_yaml` kwarg (programmatic, used by MetaCI) is supported; no env var or CLI plumbing. - `git merge-base --is-ancestor 9d650ace2 HEAD` returns non-zero - PR #3969 (commits prefixed `feat(cli): add resolve_extra_yaml helper ... ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `keep-open`- feature is genuinely actionable on v4.10.0; auto-close once #3969 merges via`closed:fixed-by-pr-#3969`. + +- | pass2 labels: `severity:medium,area:packaging,area:cli,state:in-progress` --- ## Size & risk | Field | Value | + | -------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3429.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3429:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3440.md b/docs/triage/v5/fix-sketches/issue_3440.md index 07665e61e0..60e7faacab 100644 --- a/docs/triage/v5/fix-sketches/issue_3440.md +++ b/docs/triage/v5/fix-sketches/issue_3440.md @@ -1,40 +1,12 @@ -# Fix sketch — #3440: Enhance `default_package_path` to serve multi-package projects better +# Fix sketch - #3440: Enhance `default_package_path` to serve multi-package projects better **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `packaging` -**Issue**: - -## Bug - -- `cumulusci/core/config/project_config.py:517-525` — implementation is the simple "first packageDirectory with `default: true`" pattern; falls back to `force-app`, then `src`. No name-based lookup, no multi-package warning, no hard fail when both are missing. - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — same multi-package umbrella as #2979 / #3429; would best be solved together. -- pass2 labels: `severity:low,area:packaging,area:sfdx,area:multi-package` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3440.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3440:`). +**Issue**: ## Bug - `cumulusci/core/config/project_config.py:517-525` - implementation is the simple "first packageDirectory with `default: true`" pattern; falls back to `force-app`, then `src`. No name-based lookup, no multi-package warning, no hard fail when both are missing. ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `keep-open` - same multi-package umbrella as #2979 / #3429; would best be solved together. + +- | pass2 labels: `severity:low,area:packaging,area:sfdx,area:multi-package` --- ## Size & risk | Field | Value | + | ------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3440.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3440:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3441.md b/docs/triage/v5/fix-sketches/issue_3441.md index 25446a09e9..719b5f5cdc 100644 --- a/docs/triage/v5/fix-sketches/issue_3441.md +++ b/docs/triage/v5/fix-sketches/issue_3441.md @@ -1,40 +1,12 @@ -# Fix sketch — #3441: `cci task run create_package_version` should allow `version_base: default` +# Fix sketch - #3441: `cci task run create_package_version` should allow `version_base: default` **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `packaging` -**Issue**: - -## Bug - -- `cumulusci/tasks/create_package_version.py:63-112` — `version_base: Optional[str]`; documented values are `None`, a literal version number, or `latest_github_release`. - `cumulusci/tasks/create_package_version.py:529-563` — `_get_base_version_number` only branches on `None` (default) and `"latest_github_release"`; any other string is parsed as a literal version. There is no `"default"`/`"hig... - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — could be solved minimally with a `default`/`highest` sentinel in `_get_base_version_number`, or generalized as a CCI null-override feature. -- pass2 labels: `severity:low,area:packaging,area:flow-overrides,area:cli` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3441.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3441:`). +**Issue**: ## Bug - `cumulusci/tasks/create_package_version.py:63-112` - `version_base: Optional[str]`; documented values are `None`, a literal version number, or `latest_github_release`. - `cumulusci/tasks/create_package_version.py:529-563` - `_get_base_version_number` only branches on `None` (default) and `"latest_github_release"`; any other string is parsed as a literal version. There is no `"default"`/`"hig... ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `keep-open`- could be solved minimally with a`default`/`highest`sentinel in`\_get_base_version_number`, or generalized as a CCI null-override feature. + +- | pass2 labels: `severity:low,area:packaging,area:flow-overrides,area:cli` --- ## Size & risk | Field | Value | + | ------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3441.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3441:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3446.md b/docs/triage/v5/fix-sketches/issue_3446.md index f10894703d..103a367557 100644 --- a/docs/triage/v5/fix-sketches/issue_3446.md +++ b/docs/triage/v5/fix-sketches/issue_3446.md @@ -1,40 +1,12 @@ -# Fix sketch — #3446: CCI task push_qa crashes for Unlocked package with no namespace +# Fix sketch - #3446: CCI task push_qa crashes for Unlocked package with no namespace **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `packaging` -**Issue**: - -## Bug - -- `cumulusci/tasks/push/tasks.py:33` — `version_parts = version.split(".")` (no None-guard above). - `cumulusci/tasks/push/tasks.py:283-297` — `_run_task` does not validate `version` before calling `_get_version`. - Test: `/tmp/repro/3/tests/repro_3446_push_qa_no_version.py` passes on v4.10.0. - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — real bug, simple fix. -- pass2 labels: `bug`, `good-first-issue` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3446.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3446:`). +**Issue**: ## Bug - `cumulusci/tasks/push/tasks.py:33` - `version_parts = version.split(".")` (no None-guard above). - `cumulusci/tasks/push/tasks.py:283-297` - `_run_task` does not validate `version` before calling `_get_version`. - Test: `_(repro evidence; see narrative)_` passes on v4.10.0. ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `keep-open` - real bug, simple fix. + +- | pass2 labels: `bug`, `good-first-issue` --- ## Size & risk | Field | Value | + | ---------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3446.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3446:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3464.md b/docs/triage/v5/fix-sketches/issue_3464.md index a09c4afc6c..c7f16794d7 100644 --- a/docs/triage/v5/fix-sketches/issue_3464.md +++ b/docs/triage/v5/fix-sketches/issue_3464.md @@ -1,62 +1,12 @@ -# Fix sketch — #3464: Concise project-config documentation +# Fix sketch - #3464: Concise project-config documentation **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `docs` -**Issue**: - -## Bug - -Concise project-config documentation - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -Two-step path: - -1. **Tactical**: expand the `### Project Configurations` heading at - `docs/config.md:673` into a real reference subsection that lists - every `project:` top-level key with a one-sentence description and - one example value. Cross-link to `docs/dev.md` for in-depth treatment - of `dependencies` / `dependency_resolutions` / `dependency_pins` so - we are not duplicating the longer narratives, just providing a - central index. This alone closes the issue per the user's literal - ask. - -2. **Strategic** (separate, follow-up PR): backfill `Field(description=...)` - on every Pydantic attribute in `cumulusci_yml.py` and add a Sphinx - directive (or a `conf.py` autodoc hook) that emits the reference - table directly from the model at docs-build time. This keeps the - reference and the schema in lockstep — the same mechanism powers the - JSON schema (`cumulusci/schema/cumulusci.jsonschema.json`), so the - plumbing is straightforward. - -Step 1 is a single-day effort; step 2 is multi-day but pays back every +**Issue**: ## Bug Concise project-config documentation ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) Two-step path: 1. **Tactical**: expand the `### Project Configurations` heading at `docs/config.md:673` into a real reference subsection that lists every `project:` top-level key with a one-sentence description and one example value. Cross-link to `docs/dev.md` for in-depth treatment of `dependencies` / `dependency_resolutions` / `dependency_pins` so we are not duplicating the longer narratives, just providing a central index. This alone closes the issue per the user's literal ask. 2. **Strategic** (separate, follow-up PR): backfill `Field(description=...)` on every Pydantic attribute in `cumulusci_yml.py` and add a Sphinx directive (or a `conf.py` autodoc hook) that emits the reference table directly from the model at docs-build time. This keeps the reference and the schema in lockstep - the same mechanism powers the JSON schema (`cumulusci/schema/cumulusci.jsonschema.json`), so the plumbing is straightforward. Step 1 is a single-day effort; step 2 is multi-day but pays back every time a new field is added to `cumulusci.yml`. Recommend keep-open until -at least step 1 ships. - - - -# Subagent 18 (pymod) — Round 3 narrative - -Worktree: `.worktrees/repro-pymod` @ `worktree/repro/pymod` based on `origin/dev` (`1925a3083`). - -## Size & risk - -| Field | Value | +at least step 1 ships. Worktree: the triage worktree @ the triage worktree based on `origin/dev` (`1925a3083`). ## Size & risk | Field | Value | | ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3464.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3464:`). +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3464.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3464:`). diff --git a/docs/triage/v5/fix-sketches/issue_3470.md b/docs/triage/v5/fix-sketches/issue_3470.md index e8071216e1..20009be579 100644 --- a/docs/triage/v5/fix-sketches/issue_3470.md +++ b/docs/triage/v5/fix-sketches/issue_3470.md @@ -1,38 +1,12 @@ -# Fix sketch — #3470: Rename `ci_master` to `ci_main` (or alias) +# Fix sketch - #3470: Rename `ci_master` to `ci_main` (or alias) **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `cli` -**Issue**: - -## Bug - -`rg "ci_main"` returns no matches. davidmreed's 2022 reply indicated this requires flow-aliasing infrastructure first. - -## Target - -`cumulusci/cumulusci.yml` lines 823-835 - -## Recommended approach (from triage narrative) - -- pass1: `closed:stale-24mo` — 4yr stale; preserve as `closed:stale-24mo` rather than dismiss; the inclusive-language motivation is real and could be revisited if flow aliasing lands. -- pass2 labels: `enhancement,stale,inclusive-language` - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3470.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3470:`). +**Issue**: ## Bug `rg "ci_main"` returns no matches. davidmreed's 2022 reply indicated this requires flow-aliasing infrastructure first. ## Target `cumulusci/cumulusci.yml` lines 823-835 ## Recommended approach (from triage narrative) - pass1: `closed:stale-24mo` - 4yr stale; preserve as `closed:stale-24mo` rather than dismiss; the inclusive-language motivation is real and could be revisited if flow aliasing lands. + +- | pass2 labels: `enhancement,stale,inclusive-language` ## Size & risk | Field | Value | + | ------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3470.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3470:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3471.md b/docs/triage/v5/fix-sketches/issue_3471.md index bea086f3ee..900e39436e 100644 --- a/docs/triage/v5/fix-sketches/issue_3471.md +++ b/docs/triage/v5/fix-sketches/issue_3471.md @@ -1,40 +1,12 @@ -# Fix sketch — #3471: `Merged 0 commits into branch:` message displays when a non-Source Code change is +# Fix sketch - #3471: `Merged 0 commits into branch:` message displays when a non-Source Code change is **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `ci-integration` -**Issue**: - -## Bug - -The reported log message originates from `_merge`: The log line at 251 reports `compare.behind_by` from github3's CompareCommits. `behind_by` is computed from the GitHub compare-commits endpoint and reflects how many commits the destination branch is behind the merged commit _as of the comparison's chosen merge-base_; for "effectively no-op" content merges (e.g. README/test.txt scenarios where dow... - -## Target - -`cumulusci/tasks/github/merge.py` lines 241-262 - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — small, well-localized fix (replace `compare.behind_by` with `len(list(compare.commits))` or report the SHA returned from `self.repo.merge(...)`); add a test covering the `behind_by=0` case. -- pass2 labels: `bug, github, merge, low-priority` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3471.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3471:`). +**Issue**: ## Bug The reported log message originates from `_merge`: The log line at 251 reports `compare.behind_by` from github3's CompareCommits. `behind_by` is computed from the GitHub compare-commits endpoint and reflects how many commits the destination branch is behind the merged commit _as of the comparison's chosen merge-base_; for "effectively no-op" content merges (e.g. README/test.txt scenarios where dow... ## Target `cumulusci/tasks/github/merge.py` lines 241-262 ## Recommended approach (from triage narrative) - pass1: `keep-open` - small, well-localized fix (replace `compare.behind_by` with `len(list(compare.commits))` or report the SHA returned from `self.repo.merge(...)`); add a test covering the `behind_by=0` case. + +- | pass2 labels: `bug, github, merge, low-priority` --- ## Size & risk | Field | Value | + | ------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3471.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3471:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3485.md b/docs/triage/v5/fix-sketches/issue_3485.md index 990df3595c..74f426e63f 100644 --- a/docs/triage/v5/fix-sketches/issue_3485.md +++ b/docs/triage/v5/fix-sketches/issue_3485.md @@ -1,38 +1,12 @@ -# Fix sketch — #3485: "cci task run run_tests" generates incorrect test_results.xml format +# Fix sketch - #3485: "cci task run run_tests" generates incorrect test_results.xml format **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `cli` -**Issue**: - -## Bug - -- `cumulusci/tasks/apex/testrunner.py:803-834` — `_write_output` opens `junit_output` and writes `'\n'` with no `` declaration and no enclosing `` element. - The closing tag at line 834 is ``. This exactly matches the malformed XML the reporter showed. - `junit_output` defaults to `test_results.xml` (line 201-203), unchanged. - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — small mechanical fix, still affects users producing JUnit reports for CI. -- pass2 labels: `bug, area:apex, good-first-issue` - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3485.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3485:`). +**Issue**: ## Bug - `cumulusci/tasks/apex/testrunner.py:803-834` - `_write_output` opens `junit_output` and writes `'\n'` with no `` declaration and no enclosing `` element. - The closing tag at line 834 is ``. This exactly matches the malformed XML the reporter showed. - `junit_output` defaults to `test_results.xml` (line 201-203), unchanged. ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `keep-open` - small mechanical fix, still affects users producing JUnit reports for CI. + +- | pass2 labels: `bug, area:apex, good-first-issue` ## Size & risk | Field | Value | + | --------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3485.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3485:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3492.md b/docs/triage/v5/fix-sketches/issue_3492.md index 43a5e337bc..19afc36583 100644 --- a/docs/triage/v5/fix-sketches/issue_3492.md +++ b/docs/triage/v5/fix-sketches/issue_3492.md @@ -1,38 +1,12 @@ -# Fix sketch — #3492: Enhance the "-o" option of "cci flow run" to accept "project\_\_custom" attribute values +# Fix sketch - #3492: Enhance the "-o" option of "cci flow run" to accept "project\_\_custom" attribute values **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `cli` -**Issue**: - -## Bug - -- `cumulusci/cli/flow.py:152-162` — parses `-o` pairs by splitting key on `"__"` and unpacking into exactly two parts (`task_name, option_name = key.split("__")`). - A user passing `-o project__custom__myattr value` would actually error with "too many values to unpack" because the split yields three elements; even worded as `-o project__custom value` there is no codepath that writes into `proj... - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — legitimate usability gap for matrix-style CI. -- pass2 labels: `enhancement, area:cli` - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3492.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3492:`). +**Issue**: ## Bug - `cumulusci/cli/flow.py:152-162` - parses `-o` pairs by splitting key on `"__"` and unpacking into exactly two parts (`task_name, option_name = key.split("__")`). - A user passing `-o project__custom__myattr value` would actually error with "too many values to unpack" because the split yields three elements; even worded as `-o project__custom value` there is no codepath that writes into `proj... ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `keep-open` - legitimate usability gap for matrix-style CI. + +- | pass2 labels: `enhancement, area:cli` ## Size & risk | Field | Value | + | ---------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3492.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3492:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3506.md b/docs/triage/v5/fix-sketches/issue_3506.md index c84bb3ea9f..71706507bb 100644 --- a/docs/triage/v5/fix-sketches/issue_3506.md +++ b/docs/triage/v5/fix-sketches/issue_3506.md @@ -1,38 +1,12 @@ -# Fix sketch — #3506: when clause support for flow steps which call other flows +# Fix sketch - #3506: when clause support for flow steps which call other flows **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `cli` -**Issue**: - -## Bug - -- `cumulusci/core/flowrunner.py:660-672` — when the step has a `task:` key, the StepSpec is built with `when=step_config.get("when")`. - `cumulusci/core/flowrunner.py:674-697` — the `flow:` branch recurses via `_visit_step(...)` passing only `parent_options`, `parent_ui_options`, and `from_flow`; it never reads or propagates `step_config.get("when")`. Any `when:` clause attached to a flow-call... - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — confirmed silent-failure foot-gun the user reported. -- pass2 labels: `enhancement, area:flows` - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3506.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3506:`). +**Issue**: ## Bug - `cumulusci/core/flowrunner.py:660-672` - when the step has a `task:` key, the StepSpec is built with `when=step_config.get("when")`. - `cumulusci/core/flowrunner.py:674-697` - the `flow:` branch recurses via `_visit_step(...)` passing only `parent_options`, `parent_ui_options`, and `from_flow`; it never reads or propagates `step_config.get("when")`. Any `when:` clause attached to a flow-call... ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `keep-open` - confirmed silent-failure foot-gun the user reported. + +- | pass2 labels: `enhancement, area:flows` ## Size & risk | Field | Value | + | ------------------------------------------------------ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3506.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3506:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3518.md b/docs/triage/v5/fix-sketches/issue_3518.md index 0deb3a6439..9c9171fac2 100644 --- a/docs/triage/v5/fix-sketches/issue_3518.md +++ b/docs/triage/v5/fix-sketches/issue_3518.md @@ -1,40 +1,12 @@ -# Fix sketch — #3518: Task add_picklist_entries always sets a default value for record types +# Fix sketch - #3518: Task add_picklist_entries always sets a default value for record types **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `metadata-etl` -**Issue**: - -## Bug - -- `cumulusci/tasks/metadata_etl/picklists.py:177` missing `()` after `.lower`. - `cumulusci/tasks/metadata_etl/picklists.py:214-221` unconditionally sets defaults whenever `default` is truthy. - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: keep-open — small targeted fix. -- pass2 labels: `severity:high,area:metadata-etl,type:bug` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3518.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3518:`). +**Issue**: ## Bug - `cumulusci/tasks/metadata_etl/picklists.py:177` missing `()` after `.lower`. - `cumulusci/tasks/metadata_etl/picklists.py:214-221` unconditionally sets defaults whenever `default` is truthy. ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: keep-open - small targeted fix. + +- | pass2 labels: `severity:high,area:metadata-etl,type:bug` --- ## Size & risk | Field | Value | + | --------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3518.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3518:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3541.md b/docs/triage/v5/fix-sketches/issue_3541.md index b709dadb17..6a5463f00b 100644 --- a/docs/triage/v5/fix-sketches/issue_3541.md +++ b/docs/triage/v5/fix-sketches/issue_3541.md @@ -1,65 +1,13 @@ -# Fix sketch — #3541: `None__dev` SFDX alias +# Fix sketch - #3541: `None__dev` SFDX alias **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `keychain` -**Issue**: - -## Bug - -- `cumulusci/core/keychain/base_project_keychain.py` lines 77-79: - When `project_config.project__name` is None (cumulusci.yml without a `project.name`, or partially-loaded project_config), this f-string - -## Target - -`cumulusci/core/keychain/base_project_keychain.py:77-79`. Migration helper recommended to scan the keychain for `None__*` aliases and rewrite them once a real `project.name` is available. - -## Recommended approach (from triage narrative) - -- **Approach**: Guard the alias construction. Two reasonable options: - (1) raise `CumulusCIException("Cannot build sfdx_alias: project.name is not set in cumulusci.yml")` — surfaces the misconfiguration at the earliest possible moment. - (2) Fall back to `f"{org_name}"` (no prefix) when `project__name` is None, with a `logger.warning`. Less disruptive for existing setups. - Option 2 is the safer change; option 1 is the more correct one. Pick based on willingness to break first-run UX. - -- **Target**: `cumulusci/core/keychain/base_project_keychain.py:77-79`. - Migration helper recommended to scan the keychain for `None__*` aliases - and rewrite them once a real `project.name` is available. - -- **Size**: ~10 LOC for the guard, ~30 LOC including a one-shot migration - pass on keychain load. - -- **Risk**: medium. Existing keychains in the wild may already contain - `None__dev` rows; option 2 silently writes a new alias on next run, - option 1 forces the user to fix cumulusci.yml. Document either way in - CHANGELOG. - -- **API break**: no public API change. The `OrgConfig.sfdx_alias` field - shape is preserved; only its derivation logic shifts. - -- **Bonus**: remove the `cannot-reproduce` label — the repro here is - deterministic. - - - -# Subagent 17 (docs) — Round 3 narrative - -Worktree: `.worktrees/repro-docs` @ `1925a3083` (off `origin/dev`). +**Issue**: ## Bug - `cumulusci/core/keychain/base_project_keychain.py` lines 77-79: - When `project_config.project__name` is None (cumulusci.yml without a `project.name`, or partially-loaded project*config), this f-string ## Target `cumulusci/core/keychain/base_project_keychain.py:77-79`. Migration helper recommended to scan the keychain for `None\_\_*`aliases and rewrite them once a real`project.name`is available. ## Recommended approach (from triage narrative) - **Approach**: Guard the alias construction. Two reasonable options: (1) raise`CumulusCIException("Cannot build sfdx\*alias: project.name is not set in cumulusci.yml")`- surfaces the misconfiguration at the earliest possible moment. (2) Fall back to`f"{org*name}"`(no prefix) when`project**name`is None, with a`logger.warning`. Less disruptive for existing setups. Option 2 is the safer change; option 1 is the more correct one. Pick based on willingness to break first-run UX. - **Target**: `cumulusci/core/keychain/base_project_keychain.py:77-79`. Migration helper recommended to scan the keychain for `None\***`aliases and rewrite them once a real`project.name`is available. - **Size**: ~10 LOC for the guard, ~30 LOC including a one-shot migration pass on keychain load. - **Risk**: medium. Existing keychains in the wild may already contain`None\_\_dev`rows; option 2 silently writes a new alias on next run, option 1 forces the user to fix cumulusci.yml. Document either way in CHANGELOG. - **API break**: no public API change. The`OrgConfig.sfdx_alias`field shape is preserved; only its derivation logic shifts. - **Bonus**: remove the`cannot-reproduce`label - the repro here is deterministic. Worktree: the triage worktree @`1925a3083`(off`origin/dev`). Issues processed: 3/3 (#773, #2500, #3464). Verdict tally: 3 REPRODUCED-on-dev (all pure doc-gaps with code-level -testable assertions). - -## Size & risk - -| Field | Value | +testable assertions). ## Size & risk | Field | Value | | ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3541.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3541:`). +| Size estimate | \_TBD by fix-PR author* | +| Risk | \_TBD by fix-PR author* | +| Touches `cumulusci/robotframework/\*` | \_TBD* | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3541.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3541:`). diff --git a/docs/triage/v5/fix-sketches/issue_3543.md b/docs/triage/v5/fix-sketches/issue_3543.md index 79d89f7209..f3283dd3e8 100644 --- a/docs/triage/v5/fix-sketches/issue_3543.md +++ b/docs/triage/v5/fix-sketches/issue_3543.md @@ -1,40 +1,12 @@ -# Fix sketch — #3543: New Option `load_sfdx_project_paths` for dx_convert_from Task +# Fix sketch - #3543: New Option `load_sfdx_project_paths` for dx_convert_from Task **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `metadata-etl` -**Issue**: - -## Bug - -- `cumulusci/tasks/dx_convert_from.py:7-14` exposes only `extra` and `src_dir`; no `load_sfdx_project_paths` / `resolve_sfdx_package_dirs`. - The grep hits in `project_config.py` and `cli/project.py` are unrelated - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: keep-open — feature still unimplemented; reporter offered a draft PR. -- pass2 labels: `severity:low,area:metadata-etl,type:enhancement` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3543.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3543:`). +**Issue**: ## Bug - `cumulusci/tasks/dx_convert_from.py:7-14` exposes only `extra` and `src_dir`; no `load_sfdx_project_paths` / `resolve_sfdx_package_dirs`. - The grep hits in `project_config.py` and `cli/project.py` are unrelated ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: keep-open - feature still unimplemented; reporter offered a draft PR. + +- | pass2 labels: `severity:low,area:metadata-etl,type:enhancement` --- ## Size & risk | Field | Value | + | ---------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3543.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3543:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3549.md b/docs/triage/v5/fix-sketches/issue_3549.md index 4ecff20e7d..d85161c780 100644 --- a/docs/triage/v5/fix-sketches/issue_3549.md +++ b/docs/triage/v5/fix-sketches/issue_3549.md @@ -1,38 +1,12 @@ -# Fix sketch — #3549: Deploy to Salesforce does not create a test output +# Fix sketch - #3549: Deploy to Salesforce does not create a test output **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `cli` -**Issue**: - -## Bug - -- `cumulusci/tasks/salesforce/Deploy.py:49-94` — exposes `test_level` and `specified_tests` options and validates them. - `cumulusci/tasks/salesforce/Deploy.py:150-154` — passes them through to the metadata API call but never captures `runTestResult`/`runTestsResult` from the response. - `rg "junit_output|test_results"` against `cumulusci/tasks/salesforce/Deploy.py` and `cumulusci/salesforce... - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — natural feature; tracks #3564. -- pass2 labels: `enhancement, area:metadata-deploy` - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3549.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3549:`). +**Issue**: ## Bug - `cumulusci/tasks/salesforce/Deploy.py:49-94` - exposes `test_level` and `specified_tests` options and validates them. - `cumulusci/tasks/salesforce/Deploy.py:150-154` - passes them through to the metadata API call but never captures `runTestResult`/`runTestsResult` from the response. - `rg "junit_output|test_results"` against `cumulusci/tasks/salesforce/Deploy.py` and `cumulusci/salesforce... ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `keep-open` - natural feature; tracks #3564. + +- | pass2 labels: `enhancement, area:metadata-deploy` ## Size & risk | Field | Value | + | ---------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3549.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3549:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3570.md b/docs/triage/v5/fix-sketches/issue_3570.md index 081c74726c..c7f631acfa 100644 --- a/docs/triage/v5/fix-sketches/issue_3570.md +++ b/docs/triage/v5/fix-sketches/issue_3570.md @@ -1,38 +1,12 @@ -# Fix sketch — #3570: Feature Request: Flow "finally" or "error" path +# Fix sketch - #3570: Feature Request: Flow "finally" or "error" path **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `cli` -**Issue**: - -## Bug - -- `cumulusci/core/flowrunner.py` — only `ignore_failure` (mapped to `StepSpec.allow_failure`, line 122/144) and the `finally:` Python clause inside `flow.run()` (line 500) handle failures. There is no flow-step type for `finally:` / `on_error:` / `cleanup:` / `always_run`. `rg "finally|on_error|on_failure|always_run"` confirms. - `_run_step` (line 503-536) re-raises on `result.exception` if no... - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — design-level feature, but problem is real (rollback, notify on partial failure). -- pass2 labels: `enhancement, area:flows` - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3570.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3570:`). +**Issue**: ## Bug - `cumulusci/core/flowrunner.py` - only `ignore_failure` (mapped to `StepSpec.allow_failure`, line 122/144) and the `finally:` Python clause inside `flow.run()` (line 500) handle failures. There is no flow-step type for `finally:` / `on_error:` / `cleanup:` / `always_run`. `rg "finally|on_error|on_failure|always_run"` confirms. - `_run_step` (line 503-536) re-raises on `result.exception` if no... ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `keep-open` - design-level feature, but problem is real (rollback, notify on partial failure). + +- | pass2 labels: `enhancement, area:flows` ## Size & risk | Field | Value | + | ------------------------------------------------------ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3570.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3570:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3585.md b/docs/triage/v5/fix-sketches/issue_3585.md index 14bfd6e3f2..e15251d684 100644 --- a/docs/triage/v5/fix-sketches/issue_3585.md +++ b/docs/triage/v5/fix-sketches/issue_3585.md @@ -1,41 +1,12 @@ -# Fix sketch — #3585: Error Occurs when Using `update_package_xml` on object with `xsi:nil="true"` +# Fix sketch - #3585: Error Occurs when Using `update_package_xml` on object with `xsi:nil="true"` **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `metadata-etl` -**Issue**: - -## Bug - -- `cumulusci/tasks/metadata/package.py:115-130` — when a folder has objects it instantiates the registered parser; for `objects/` the parser uses the metadata tree which is strict about namespaces. - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: keep-open — needs either a namespace-shim before parsing or - pre-stripping of `xsi:nil` attributes. -- pass2 labels: `severity:medium,area:metadata-etl,type:bug,sfdx-compat` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3585.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3585:`). +**Issue**: ## Bug - `cumulusci/tasks/metadata/package.py:115-130` - when a folder has objects it instantiates the registered parser; for `objects/` the parser uses the metadata tree which is strict about namespaces. ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: keep-open - needs either a namespace-shim before parsing or pre-stripping of `xsi:nil` attributes. + +- | pass2 labels: `severity:medium,area:metadata-etl,type:bug,sfdx-compat` --- ## Size & risk | Field | Value | + | ----------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3585.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3585:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3593.md b/docs/triage/v5/fix-sketches/issue_3593.md index 2d3977629d..d292daa43a 100644 --- a/docs/triage/v5/fix-sketches/issue_3593.md +++ b/docs/triage/v5/fix-sketches/issue_3593.md @@ -1,40 +1,12 @@ -# Fix sketch — #3593: `dx` task doesn't work for some commands like `project convert source` +# Fix sketch - #3593: `dx` task doesn't work for some commands like `project convert source` **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `packaging` -**Issue**: - -## Bug - -- `cumulusci/tasks/sfdx.py:46-51` — `SFDXOrgTask._get_command` unconditionally appends `" -o {username}"` for any `ScratchOrgConfig`, regardless of whether the underlying sf subcommand accepts a target-org flag. - Repro test FAILS with the resulting command: `sf project convert source -r src -d force-app -o test@example.com` — the same shape that the issue reporter said sf cli rejects. - Not... - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — needs an opt-out option (e.g. `pass_org: False` or a `no_org_command` whitelist). Verifying actual sf cli rejection of `-o` for `project convert source` would need an org/sf cli; the CCI side of the bug is unchanged. -- pass2 labels: `severity:medium,area:packaging,area:sfdx,area:dx-task,state:needs-design` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3593.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3593:`). +**Issue**: ## Bug - `cumulusci/tasks/sfdx.py:46-51` - `SFDXOrgTask._get_command` unconditionally appends `" -o {username}"` for any `ScratchOrgConfig`, regardless of whether the underlying sf subcommand accepts a target-org flag. - Repro test FAILS with the resulting command: `sf project convert source -r src -d force-app -o test@example.com` - the same shape that the issue reporter said sf cli rejects. - Not... ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `keep-open` - needs an opt-out option (e.g. `pass_org: False` or a `no_org_command` whitelist). Verifying actual sf cli rejection of `-o` for `project convert source` would need an org/sf cli; the CCI side of the bug is unchanged. + +- | pass2 labels: `severity:medium,area:packaging,area:sfdx,area:dx-task,state:needs-design` --- ## Size & risk | Field | Value | + | ----------------------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3593.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3593:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3602.md b/docs/triage/v5/fix-sketches/issue_3602.md index ac3bfca9d4..14afbf8826 100644 --- a/docs/triage/v5/fix-sketches/issue_3602.md +++ b/docs/triage/v5/fix-sketches/issue_3602.md @@ -1,54 +1,18 @@ -# Fix sketch — #3602: Need Chrome/Firefox options(browser options/capabilities) in 'Open Test Browser' Keyword +# Fix sketch - #3602: Need Chrome/Firefox options(browser options/capabilities) in 'Open Test Browser' Keyword **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `robotframework` -**Issue**: +**Issue**: ## Bug - `cumulusci/robotframework/SalesforcePlaywright.py:60-62` - `def open_test_browser(self, size=None, useralias=None, wait=True, record_video=None):` has no `browser_options`/`extra_options`/`**kwargs` hook. - `cumulusci/robotframework/Salesforce.robot:103` - Selenium keyword signature `[Arguments] ${size}=... ${alias}=${NONE} ${wait}=True ${useralias}=${NONE}` - same gap. - `cumulusci/ro... ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - Approach (Playwright): add a `browser_options: dict | None = None`kwarg; pass through to`new_browser`(browser-launch options) and a separate`context_options`dict merged into the`new_context` call. -## Bug - -- `cumulusci/robotframework/SalesforcePlaywright.py:60-62` — `def open_test_browser(self, size=None, useralias=None, wait=True, record_video=None):` has no `browser_options`/`extra_options`/`**kwargs` hook. - `cumulusci/robotframework/Salesforce.robot:103` — Selenium keyword signature `[Arguments] ${size}=... ${alias}=${NONE} ${wait}=True ${useralias}=${NONE}` — same gap. - `cumulusci/ro... - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- Approach (Playwright): add a `browser_options: dict | None = None` kwarg; pass through to `new_browser` (browser-launch options) and a separate `context_options` dict merged into the `new_context` call. - Approach (Selenium): expose a `${EXTRA_CHROME_OPTIONS}` variable / list argument honoured by `Get Chrome Options`; alternatively add an `extra_options` argument to `Open Test Browser` and pipe through to `Create Webdriver With Retry`. - Target: `cumulusci/robotframework/SalesforcePlaywright.py:60-117`; `cumulusci/robotframework/Salesforce.robot:77-168`. - Size: medium (~30-60 lines across both implementations + tests + docs). -- Risk: low — additive parameter with safe default. -- API break: no (default `None` preserves current behaviour). - -**Recommended action**: - -- pass1: `keep-open` — reasonable, scoped feature ask; age <36mo; no PR yet; tractable medium-sized contribution. +- Risk: low - additive parameter with safe default. +- API break: no (default `None` preserves current behaviour). **Recommended action**: - pass1: `keep-open` - reasonable, scoped feature ask; age <36mo; no PR yet; tractable medium-sized contribution. - pass2 labels: `enhancement, robotframework, playwright, good-second-issue` -- triage test: `cumulusci/tests/triage/test_issue_3602.py` - - - -# Subagent 14 — scratch-org-config theme, Round 3 - -Working tree: `.worktrees/repro-scratch` on `worktree/repro/scratch` off `origin/dev` at `1925a3083`. - -Triaged 3 issues (#3910, #3306, #710). All three remain actionable on dev: #3910 has an open fix PR; #3306 and #710 are never-implemented enhancements. - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3602.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3602:`). +- | triage test: `cumulusci/tests/triage/test_issue_3602.py` Working tree: the triage worktree on the triage worktree off `origin/dev` at `1925a3083`. Triaged 3 issues (#3910, #3306, #710). All three remain actionable on dev: #3910 has an open fix PR; #3306 and #710 are never-implemented enhancements. ## Size & risk | Field | Value | + | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3602.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3602:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3603.md b/docs/triage/v5/fix-sketches/issue_3603.md index 2b763f412f..6b80bd854b 100644 --- a/docs/triage/v5/fix-sketches/issue_3603.md +++ b/docs/triage/v5/fix-sketches/issue_3603.md @@ -1,35 +1,10 @@ -# Fix sketch — #3603: Any issue with git results in the unhelpful "404 not found" error +# Fix sketch - #3603: Any issue with git results in the unhelpful "404 not found" error **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `dependencies` -**Issue**: - -## Bug - -Any issue with git results in the unhelpful "404 not found" error - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -_See narrative for recommended action._ - -## Size & risk - -| Field | Value | +**Issue**: ## Bug Any issue with git results in the unhelpful "404 not found" error ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) _See narrative for recommended action._ ## Size & risk | Field | Value | | ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3603.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3603:`). +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3603.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3603:`). diff --git a/docs/triage/v5/fix-sketches/issue_3604.md b/docs/triage/v5/fix-sketches/issue_3604.md index 1769048e12..19a3ae1a92 100644 --- a/docs/triage/v5/fix-sketches/issue_3604.md +++ b/docs/triage/v5/fix-sketches/issue_3604.md @@ -1,35 +1,10 @@ -# Fix sketch — #3604: Task request: Update sfdx-project.json dependencies based off of computed cumulusci dependencies +# Fix sketch - #3604: Task request: Update sfdx-project.json dependencies based off of computed cumulusci dependencies **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `dependencies` -**Issue**: - -## Bug - -Task request: Update sfdx-project.json dependencies based off of computed cumulusci dependencies - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -_See narrative for recommended action._ - -## Size & risk - -| Field | Value | +**Issue**: ## Bug Task request: Update sfdx-project.json dependencies based off of computed cumulusci dependencies ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) _See narrative for recommended action._ ## Size & risk | Field | Value | | ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3604.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3604:`). +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3604.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3604:`). diff --git a/docs/triage/v5/fix-sketches/issue_3613.md b/docs/triage/v5/fix-sketches/issue_3613.md index 6acd35fd0a..e243cad986 100644 --- a/docs/triage/v5/fix-sketches/issue_3613.md +++ b/docs/triage/v5/fix-sketches/issue_3613.md @@ -1,47 +1,14 @@ -# Fix sketch — #3613: AddFieldsToPageLayout — "Cannot find metadata file" +# Fix sketch - #3613: AddFieldsToPageLayout - "Cannot find metadata file" **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `metadata-etl` -**Issue**: +**Issue**: ## Bug AddFieldsToPageLayout - "Cannot find metadata file" ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `improve-error-message` - keep open as a UX bug. -## Bug +- pass2 labels: `bug`, `good-first-issue` **Notes**: Two complementary improvements would help: 1. In `_transform` (base.py:332), include the actual list of files retrieved into `source_metadata_dir` in the error message so the user can spot the naming mismatch. -AddFieldsToPageLayout — "Cannot find metadata file" - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `improve-error-message` — keep open as a UX bug. -- pass2 labels: `bug`, `good-first-issue` - -**Notes**: Two complementary improvements would help: - -1. In `_transform` (base.py:332), include the actual list of files retrieved into `source_metadata_dir` in the error message so the user can spot the naming mismatch. -2. In `AddFieldsToPageLayout._init_options`, warn when an api_name does not contain `-` (Layout API names always do). - -The user was on Windows in 2023 — note that the user might also have been hitting a backslash path issue, but the underlying class of bug is the same: api_name format mismatch. - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3613.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3613:`). +2. | In `AddFieldsToPageLayout._init_options`, warn when an api_name does not contain `-` (Layout API names always do). The user was on Windows in 2023 - note that the user might also have been hitting a backslash path issue, but the underlying class of bug is the same: api_name format mismatch. --- ## Size & risk | Field | Value | + | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3613.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3613:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3618.md b/docs/triage/v5/fix-sketches/issue_3618.md index e343894ad3..1d0288f33b 100644 --- a/docs/triage/v5/fix-sketches/issue_3618.md +++ b/docs/triage/v5/fix-sketches/issue_3618.md @@ -1,38 +1,12 @@ -# Fix sketch — #3618: Allow for list when deleting/removing CumulusCI orgs +# Fix sketch - #3618: Allow for list when deleting/removing CumulusCI orgs **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `cli` -**Issue**: - -## Bug - -- `cumulusci/cli/org.py:519-545` — `org_remove` decorated with `@orgname_option_or_argument(required=True)`, takes a single `org_name`. - `cumulusci/cli/org.py:605-625` — `org_scratch_delete` same pattern, single `org_name`. - No `nargs=-1`, no comma-split helper; passing `org1,org2` would be treated as a single literal alias and fail keychain lookup. - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — legitimately useful for cleanup workflows; small implementation surface. -- pass2 labels: `enhancement, area:cli, good-first-issue` - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3618.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3618:`). +**Issue**: ## Bug - `cumulusci/cli/org.py:519-545` - `org_remove` decorated with `@orgname_option_or_argument(required=True)`, takes a single `org_name`. - `cumulusci/cli/org.py:605-625` - `org_scratch_delete` same pattern, single `org_name`. - No `nargs=-1`, no comma-split helper; passing `org1,org2` would be treated as a single literal alias and fail keychain lookup. ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `keep-open` - legitimately useful for cleanup workflows; small implementation surface. + +- | pass2 labels: `enhancement, area:cli, good-first-issue` ## Size & risk | Field | Value | + | ---------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3618.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3618:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3619.md b/docs/triage/v5/fix-sketches/issue_3619.md index 4872dc1f16..807f9e59f0 100644 --- a/docs/triage/v5/fix-sketches/issue_3619.md +++ b/docs/triage/v5/fix-sketches/issue_3619.md @@ -1,35 +1,10 @@ -# Fix sketch — #3619: Dependency_pins does not honor passwords +# Fix sketch - #3619: Dependency_pins does not honor passwords **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `dependencies` -**Issue**: - -## Bug - -Dependency_pins does not honor passwords - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -_See narrative for recommended action._ - -## Size & risk - -| Field | Value | +**Issue**: ## Bug Dependency*pins does not honor passwords ## Target \_See narrative for target file:line.* ## Recommended approach (from triage narrative) _See narrative for recommended action._ ## Size & risk | Field | Value | | ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3619.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3619:`). +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3619.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3619:`). diff --git a/docs/triage/v5/fix-sketches/issue_3649.md b/docs/triage/v5/fix-sketches/issue_3649.md index ec2cfaaf6d..4fd7340806 100644 --- a/docs/triage/v5/fix-sketches/issue_3649.md +++ b/docs/triage/v5/fix-sketches/issue_3649.md @@ -1,35 +1,10 @@ -# Fix sketch — #3649: Support serial loads with update_data task +# Fix sketch - #3649: Support serial loads with update_data task **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `bulkdata` -**Issue**: - -## Bug - -Support serial loads with update_data task - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -_See narrative for recommended action._ - -## Size & risk - -| Field | Value | +**Issue**: ## Bug Support serial loads with update*data task ## Target \_See narrative for target file:line.* ## Recommended approach (from triage narrative) _See narrative for recommended action._ ## Size & risk | Field | Value | | ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3649.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3649:`). +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3649.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3649:`). diff --git a/docs/triage/v5/fix-sketches/issue_3663.md b/docs/triage/v5/fix-sketches/issue_3663.md index d65ecf4403..cfc3f56abe 100644 --- a/docs/triage/v5/fix-sketches/issue_3663.md +++ b/docs/triage/v5/fix-sketches/issue_3663.md @@ -1,38 +1,12 @@ -# Fix sketch — #3663: When clause | Ability to pass in prior task response values +# Fix sketch - #3663: When clause | Ability to pass in prior task response values **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `cli` -**Issue**: - -## Bug - -- `cumulusci/core/flowrunner.py:510-516` — the `when` Jinja context is hardcoded to `{"project_config": ..., "org_config": ...}`. Prior step results (`self.results`) are not exposed. - The `^^task.return_value` resolver lives elsewhere (option resolution path) and is not threaded into the `when` evaluator. - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — natural extension of `when`; complements #3506. -- pass2 labels: `enhancement, area:flows` - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3663.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3663:`). +**Issue**: ## Bug - `cumulusci/core/flowrunner.py:510-516` - the `when` Jinja context is hardcoded to `{"project_config": ..., "org_config": ...}`. Prior step results (`self.results`) are not exposed. - The `^^task.return_value` resolver lives elsewhere (option resolution path) and is not threaded into the `when` evaluator. ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `keep-open` - natural extension of `when`; complements #3506. + +- | pass2 labels: `enhancement, area:flows` ## Size & risk | Field | Value | + | ------------------------------------------------------ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3663.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3663:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3692.md b/docs/triage/v5/fix-sketches/issue_3692.md index a6a8eb9f73..f757cad90e 100644 --- a/docs/triage/v5/fix-sketches/issue_3692.md +++ b/docs/triage/v5/fix-sketches/issue_3692.md @@ -1,42 +1,12 @@ -# Fix sketch — #3692: No parser configuration found for subdirectory digitalExperiences +# Fix sketch - #3692: No parser configuration found for subdirectory digitalExperiences **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `metadata-etl` -**Issue**: - -## Bug - -- `cumulusci/tasks/metadata/metadata_map.yml` has no `digitalExperiences` key. - `cumulusci/tasks/metadata/package.py:115-118` raises - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: keep-open — add `digitalExperiences` (and likely - `digitalExperienceConfigs`) entries to `metadata_map.yml` with - appropriate parser classes (probably a bundle parser). -- pass2 labels: `severity:medium,area:metadata-etl,type:bug` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3692.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3692:`). +**Issue**: ## Bug - `cumulusci/tasks/metadata/metadata_map.yml` has no `digitalExperiences` key. - `cumulusci/tasks/metadata/package.py:115-118` raises ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: keep-open - add `digitalExperiences` (and likely `digitalExperienceConfigs`) entries to `metadata_map.yml` with appropriate parser classes (probably a bundle parser). + +- | pass2 labels: `severity:medium,area:metadata-etl,type:bug` --- ## Size & risk | Field | Value | + | ----------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3692.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3692:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3699.md b/docs/triage/v5/fix-sketches/issue_3699.md index 4e3b86f1a8..a3a482103e 100644 --- a/docs/triage/v5/fix-sketches/issue_3699.md +++ b/docs/triage/v5/fix-sketches/issue_3699.md @@ -1,35 +1,10 @@ -# Fix sketch — #3699: Sort of the data during extraction +# Fix sketch - #3699: Sort of the data during extraction **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `bulkdata` -**Issue**: - -## Bug - -Sort of the data during extraction - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -_See narrative for recommended action._ - -## Size & risk - -| Field | Value | +**Issue**: ## Bug Sort of the data during extraction ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) _See narrative for recommended action._ ## Size & risk | Field | Value | | ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3699.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3699:`). +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3699.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3699:`). diff --git a/docs/triage/v5/fix-sketches/issue_3700.md b/docs/triage/v5/fix-sketches/issue_3700.md index ed34a66b62..5d9f3639fc 100644 --- a/docs/triage/v5/fix-sketches/issue_3700.md +++ b/docs/triage/v5/fix-sketches/issue_3700.md @@ -1,35 +1,10 @@ -# Fix sketch — #3700: Trying to do an upsert on a master-detail child object gets an error around permission +# Fix sketch - #3700: Trying to do an upsert on a master-detail child object gets an error around permission **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `bulkdata` -**Issue**: - -## Bug - -Trying to do an upsert on a master-detail child object gets an error around permission - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -_See narrative for recommended action._ - -## Size & risk - -| Field | Value | +**Issue**: ## Bug Trying to do an upsert on a master-detail child object gets an error around permission ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) _See narrative for recommended action._ ## Size & risk | Field | Value | | ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3700.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3700:`). +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3700.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3700:`). diff --git a/docs/triage/v5/fix-sketches/issue_3701.md b/docs/triage/v5/fix-sketches/issue_3701.md index b6e8513417..acece4c3ff 100644 --- a/docs/triage/v5/fix-sketches/issue_3701.md +++ b/docs/triage/v5/fix-sketches/issue_3701.md @@ -1,35 +1,10 @@ -# Fix sketch — #3701: set a mapping to the id instead of it being either a number or the salesforce id +# Fix sketch - #3701: set a mapping to the id instead of it being either a number or the salesforce id **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `bulkdata` -**Issue**: - -## Bug - -set a mapping to the id instead of it being either a number or the salesforce id - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -_See narrative for recommended action._ - -## Size & risk - -| Field | Value | +**Issue**: ## Bug set a mapping to the id instead of it being either a number or the salesforce id ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) _See narrative for recommended action._ ## Size & risk | Field | Value | | ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3701.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3701:`). +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3701.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3701:`). diff --git a/docs/triage/v5/fix-sketches/issue_3721.md b/docs/triage/v5/fix-sketches/issue_3721.md index 9ae198c805..4beda9eab4 100644 --- a/docs/triage/v5/fix-sketches/issue_3721.md +++ b/docs/triage/v5/fix-sketches/issue_3721.md @@ -1,40 +1,12 @@ -# Fix sketch — #3721: `create_package_version` `version_name` default should be version number, not "Release" +# Fix sketch - #3721: `create_package_version` `version_name` default should be version number, not "Release" **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `packaging` -**Issue**: - -## Bug - -- `cumulusci/tasks/create_package_version.py:184` — `version_name=self.options.get("version_name") or "Release"`. Default is still the literal string `"Release"`. - `cumulusci/cumulusci.yml:684-686` — `upload_production` hard-codes `name: Release`. - `cumulusci/tasks/salesforce/package_upload.py:147-154` — passes `VersionName` straight through; no jinja2/template support. - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — needs upstream port + design (templating? plain version number? both 1GP and 2GP?). -- pass2 labels: `severity:low,area:packaging,area:1gp,area:2gp` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3721.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3721:`). +**Issue**: ## Bug - `cumulusci/tasks/create_package_version.py:184` - `version_name=self.options.get("version_name") or "Release"`. Default is still the literal string `"Release"`. - `cumulusci/cumulusci.yml:684-686` - `upload_production` hard-codes `name: Release`. - `cumulusci/tasks/salesforce/package_upload.py:147-154` - passes `VersionName` straight through; no jinja2/template support. ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `keep-open` - needs upstream port + design (templating? plain version number? both 1GP and 2GP?). + +- | pass2 labels: `severity:low,area:packaging,area:1gp,area:2gp` --- ## Size & risk | Field | Value | + | -------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3721.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3721:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3734.md b/docs/triage/v5/fix-sketches/issue_3734.md index 6bc8c75607..d1b70e3c92 100644 --- a/docs/triage/v5/fix-sketches/issue_3734.md +++ b/docs/triage/v5/fix-sketches/issue_3734.md @@ -1,38 +1,12 @@ -# Fix sketch — #3734: upload_production fails with FIELD_INTEGRITY_EXCEPTION when latest is Beta patch +# Fix sketch - #3734: upload_production fails with FIELD_INTEGRITY_EXCEPTION when latest is Beta patch **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `packaging` -**Issue**: - -## Bug - -- `cumulusci/tasks/salesforce/package_upload.py:80-98` — SOQL query, `ORDER BY MajorVersion DESC, MinorVersion DESC, PatchVersion DESC, ReleaseState DESC LIMIT 1`. - `cumulusci/tasks/salesforce/package_upload.py:134-137` — Beta branch sets `minor_version` to the same minor. - Test passes on v4.10.0 with mocked `_get_one_record`. - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — confirmed real bug; remove the stale `cannot-reproduce`/`awaiting-more-details` labels. -- pass2 labels: `bug` - ---- - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3734.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3734:`). +**Issue**: ## Bug - `cumulusci/tasks/salesforce/package_upload.py:80-98` - SOQL query, `ORDER BY MajorVersion DESC, MinorVersion DESC, PatchVersion DESC, ReleaseState DESC LIMIT 1`. - `cumulusci/tasks/salesforce/package_upload.py:134-137` - Beta branch sets `minor_version` to the same minor. - Test passes on v4.10.0 with mocked `_get_one_record`. ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `keep-open` - confirmed real bug; remove the stale `cannot-reproduce`/`awaiting-more-details` labels. + +- | pass2 labels: `bug` --- ## Size & risk | Field | Value | + | -------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3734.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3734:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3746.md b/docs/triage/v5/fix-sketches/issue_3746.md index 39362c9dd3..489b006436 100644 --- a/docs/triage/v5/fix-sketches/issue_3746.md +++ b/docs/triage/v5/fix-sketches/issue_3746.md @@ -1,35 +1,10 @@ -# Fix sketch — #3746: Deleted Versions used for determining next version +# Fix sketch - #3746: Deleted Versions used for determining next version **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `packaging` -**Issue**: - -## Bug - -Deleted Versions used for determining next version - -## Target - -`cumulusci/tasks/create_package_version.py` lines 529-545 - -## Recommended approach (from triage narrative) - -_See narrative for recommended action._ - -## Size & risk - -| Field | Value | +**Issue**: ## Bug Deleted Versions used for determining next version ## Target `cumulusci/tasks/create_package_version.py` lines 529-545 ## Recommended approach (from triage narrative) _See narrative for recommended action._ ## Size & risk | Field | Value | | ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3746.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3746:`). +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3746.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3746:`). diff --git a/docs/triage/v5/fix-sketches/issue_3754.md b/docs/triage/v5/fix-sketches/issue_3754.md index dce1ed937a..b8760e3f66 100644 --- a/docs/triage/v5/fix-sketches/issue_3754.md +++ b/docs/triage/v5/fix-sketches/issue_3754.md @@ -1,38 +1,12 @@ -# Fix sketch — #3754: Enable configuration for cci version update sources +# Fix sketch - #3754: Enable configuration for cci version update sources **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `cli` -**Issue**: - -## Bug - -- `cumulusci/cli/utils.py:65-79` — `get_latest_final_version` hits `https://pypi.org/pypi/cumulusci/json` literally, no env-var, no kwarg. - `cumulusci/cli/utils.py:82-101` — `check_latest_version` cannot be disabled via flag/env. Workaround in the comments (touch `~/.cumulusci/cumulus_timestamp` to a far-future epoch) confirmed by inspecting the timestamp logic at lines 38-50, 86-89. - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — easy add (e.g. `CUMULUSCI_DISABLE_VERSION_CHECK` env), helps offline/restricted environments. -- pass2 labels: `enhancement, area:cli` - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3754.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3754:`). +**Issue**: ## Bug - `cumulusci/cli/utils.py:65-79` - `get_latest_final_version` hits `https://pypi.org/pypi/cumulusci/json` literally, no env-var, no kwarg. - `cumulusci/cli/utils.py:82-101` - `check_latest_version` cannot be disabled via flag/env. Workaround in the comments (touch `~/.cumulusci/cumulus_timestamp` to a far-future epoch) confirmed by inspecting the timestamp logic at lines 38-50, 86-89. ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `keep-open` - easy add (e.g. `CUMULUSCI_DISABLE_VERSION_CHECK` env), helps offline/restricted environments. + +- | pass2 labels: `enhancement, area:cli` ## Size & risk | Field | Value | + | ---------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3754.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3754:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3758.md b/docs/triage/v5/fix-sketches/issue_3758.md index 5f920c96b1..660a3cc35b 100644 --- a/docs/triage/v5/fix-sketches/issue_3758.md +++ b/docs/triage/v5/fix-sketches/issue_3758.md @@ -1,40 +1,12 @@ -# Fix sketch — #3758: Flow `push_upgrade_org` is incorrectly defined +# Fix sketch - #3758: Flow `push_upgrade_org` is incorrectly defined **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `packaging` -**Issue**: - -## Bug - -- `cumulusci/cumulusci.yml:1161-1177` — final step is `flow: config_qa`. The bug report (correctly, in my view) argues this should be `config_managed` because push upgrades target managed-package orgs (UAT sandboxes), not QA scratch orgs. - Repro test FAILS with `config_qa` != `config_managed`. - Both flows currently expand to the same steps (`deploy_post`, `update_admin_profile`, `load_samp... - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — single-line YAML fix; great `good-first-issue` candidate. Out of scope for this triage pass per task constraints (do not fix bugs). -- pass2 labels: `severity:medium,area:packaging,area:flows,good-first-issue` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3758.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3758:`). +**Issue**: ## Bug - `cumulusci/cumulusci.yml:1161-1177` - final step is `flow: config_qa`. The bug report (correctly, in my view) argues this should be `config_managed` because push upgrades target managed-package orgs (UAT sandboxes), not QA scratch orgs. - Repro test FAILS with `config_qa` != `config_managed`. - Both flows currently expand to the same steps (`deploy_post`, `update_admin_profile`, `load_samp... ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `keep-open`- single-line YAML fix; great`good-first-issue` candidate. Out of scope for this triage pass per task constraints (do not fix bugs). + +- | pass2 labels: `severity:medium,area:packaging,area:flows,good-first-issue` --- ## Size & risk | Field | Value | + | --------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3758.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3758:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3768.md b/docs/triage/v5/fix-sketches/issue_3768.md index 8ea2e6e0de..8db82fd23a 100644 --- a/docs/triage/v5/fix-sketches/issue_3768.md +++ b/docs/triage/v5/fix-sketches/issue_3768.md @@ -1,35 +1,10 @@ -# Fix sketch — #3768: Snowfakery Batch Size and Just Once +# Fix sketch - #3768: Snowfakery Batch Size and Just Once **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `bulkdata` -**Issue**: - -## Bug - -Snowfakery Batch Size and Just Once - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -_See narrative for recommended action._ - -## Size & risk - -| Field | Value | +**Issue**: ## Bug Snowfakery Batch Size and Just Once ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) _See narrative for recommended action._ ## Size & risk | Field | Value | | ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3768.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3768:`). +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3768.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3768:`). diff --git a/docs/triage/v5/fix-sketches/issue_3771.md b/docs/triage/v5/fix-sketches/issue_3771.md index fe6506d353..59c679a4d9 100644 --- a/docs/triage/v5/fix-sketches/issue_3771.md +++ b/docs/triage/v5/fix-sketches/issue_3771.md @@ -1,41 +1,12 @@ -# Fix sketch — #3771: find_replace transforms on XPath with predicates does not work +# Fix sketch - #3771: find_replace transforms on XPath with predicates does not work **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `metadata-etl` -**Issue**: - -## Bug - -- `cumulusci/core/source_transforms/transforms.py:420-435` — naive predicate handling. - `git log --all --oneline --grep="3772\|3771\|XPath.*predicate"` shows - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: keep-open — the leboff PR is a viable starting point; or implement - the reporter's "strip xmlns then re-add" approach for simplicity. -- pass2 labels: `severity:medium,area:source-transforms,type:bug,has-pr` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3771.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3771:`). +**Issue**: ## Bug - `cumulusci/core/source_transforms/transforms.py:420-435` - naive predicate handling. - `git log --all --oneline --grep="3772\|3771\|XPath.*predicate"` shows ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: keep-open - the leboff PR is a viable starting point; or implement the reporter's "strip xmlns then re-add" approach for simplicity. + +- | pass2 labels: `severity:medium,area:source-transforms,type:bug,has-pr` --- ## Size & risk | Field | Value | + | ----------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3771.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3771:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3773.md b/docs/triage/v5/fix-sketches/issue_3773.md index 5cfa405e82..09cdac28ad 100644 --- a/docs/triage/v5/fix-sketches/issue_3773.md +++ b/docs/triage/v5/fix-sketches/issue_3773.md @@ -1,41 +1,12 @@ -# Fix sketch — #3773: retrieve_profile task seems to be missing some Metadata +# Fix sketch - #3773: retrieve_profile task seems to be missing some Metadata **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `metadata-etl` -**Issue**: - -## Bug - -- `cumulusci/salesforce_api/retrieve_profile_api.py:164-195` — no `FieldPermissions` query. - Greped `FieldPermission|field_permission|fieldPermission` — only the - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: keep-open — needs additional `FieldPermissions` query plus - inclusion of those parent SObjectTypes in the `CustomObject` retrieve set. -- pass2 labels: `severity:medium,area:retrieve-profile,type:bug` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3773.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3773:`). +**Issue**: ## Bug - `cumulusci/salesforce_api/retrieve_profile_api.py:164-195` - no `FieldPermissions` query. - Greped `FieldPermission|field_permission|fieldPermission` - only the ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: keep-open - needs additional `FieldPermissions` query plus inclusion of those parent SObjectTypes in the `CustomObject` retrieve set. + +- | pass2 labels: `severity:medium,area:retrieve-profile,type:bug` --- ## Size & risk | Field | Value | + | --------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3773.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3773:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3849.md b/docs/triage/v5/fix-sketches/issue_3849.md index 8eab4bb419..e30424ce47 100644 --- a/docs/triage/v5/fix-sketches/issue_3849.md +++ b/docs/triage/v5/fix-sketches/issue_3849.md @@ -1,35 +1,10 @@ -# Fix sketch — #3849: urllib3 v2 breaks Robot tests on a fresh pip install +# Fix sketch - #3849: urllib3 v2 breaks Robot tests on a fresh pip install **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `python-modernization` -**Issue**: - -## Bug - -urllib3 v2 breaks Robot tests on a fresh pip install - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -_See narrative for recommended action._ - -## Size & risk - -| Field | Value | +**Issue**: ## Bug urllib3 v2 breaks Robot tests on a fresh pip install ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) _See narrative for recommended action._ ## Size & risk | Field | Value | | ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3849.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3849:`). +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3849.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3849:`). diff --git a/docs/triage/v5/fix-sketches/issue_3873.md b/docs/triage/v5/fix-sketches/issue_3873.md index 5c00a0d963..030f235b22 100644 --- a/docs/triage/v5/fix-sketches/issue_3873.md +++ b/docs/triage/v5/fix-sketches/issue_3873.md @@ -1,47 +1,17 @@ -# Fix sketch — #3873: Standalone Robot Framework Library for Selenium-Based Salesforce Automation (Inspired by Copado QForce) +# Fix sketch - #3873: Standalone Robot Framework Library for Selenium-Based Salesforce Automation (Inspired by Copado QForce) **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `robotframework` -**Issue**: +**Issue**: ## Bug - `cumulusci/robotframework/base_library.py:1-39` - `BaseLibrary` lazily resolves `cumulusci.robotframework.CumulusCI`, `cumulusci.robotframework.Salesforce`, `cumulusci.robotframework.SalesforceAPI` libraries through Robot's `BuiltIn`, which require a CumulusCI project context. - `cumulusci/robotframework/Salesforce.py:20-28` - imports `cumulusci.robotframework.locator_manager`, `faker_mixin`... ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - Approach: factor a UI-only subset out of `cumulusci.robotframework.*` into a sibling distribution (e.g. `salesforce-robot-library`) that depends only on Selenium/Playwright + the locator dictionaries; have CumulusCI's Robot task consume that subset. -## Bug - -- `cumulusci/robotframework/base_library.py:1-39` — `BaseLibrary` lazily resolves `cumulusci.robotframework.CumulusCI`, `cumulusci.robotframework.Salesforce`, `cumulusci.robotframework.SalesforceAPI` libraries through Robot's `BuiltIn`, which require a CumulusCI project context. - `cumulusci/robotframework/Salesforce.py:20-28` — imports `cumulusci.robotframework.locator_manager`, `faker_mixin`... - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- Approach: factor a UI-only subset out of `cumulusci.robotframework.*` into a sibling distribution (e.g. `salesforce-robot-library`) that depends only on Selenium/Playwright + the locator dictionaries; have CumulusCI's Robot task consume that subset. - Target: package layout change spanning `cumulusci/robotframework/` and `pyproject.toml`. - Size: large (>100 lines, design change + new distribution). -- Risk: medium — must not break existing tasks/keywords. -- API break: no (additive new distribution). - -**Recommended action**: - -- pass1: `keep-open` — reasonable architectural request, age <24mo, no community PR yet; worth retaining as roadmap signal. +- Risk: medium - must not break existing tasks/keywords. +- API break: no (additive new distribution). **Recommended action**: - pass1: `keep-open` - reasonable architectural request, age <24mo, no community PR yet; worth retaining as roadmap signal. - pass2 labels: `enhancement, robotframework, scope-large` -- triage test: n/a — no concrete API to xfail against. - ---- - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -_None yet — add a regression test as part of the fix-PR._. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3873:`). +- | triage test: n/a - no concrete API to xfail against. --- ## Size & risk | Field | Value | + | ----------------------------------------------------------------------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test _None yet - add a regression test as part of the fix-PR._. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3873:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3889.md b/docs/triage/v5/fix-sketches/issue_3889.md index a6281cd2c4..39291c7a0f 100644 --- a/docs/triage/v5/fix-sketches/issue_3889.md +++ b/docs/triage/v5/fix-sketches/issue_3889.md @@ -1,38 +1,12 @@ -# Fix sketch — #3889: Uninstall 2GP task request +# Fix sketch - #3889: Uninstall 2GP task request **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `packaging` -**Issue**: - -## Bug - -- `cumulusci/cumulusci.yml:615-642` — Uninstall tasks: `uninstall_managed`, `uninstall_packaged`, `uninstall_packaged_incremental`, `uninstall_src`, `uninstall_pre`, `uninstall_post`. None take a 04t id. - `cumulusci/tasks/salesforce/UninstallPackage.py:6-32` — `UninstallPackage` accepts only `namespace` (and `purge_on_delete`). Builds an `UninstallPackageZipBuilder` from the namespace. - `c... - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — needs a new `UninstallPackageVersion` task (or extend `UninstallPackage`) that calls Tooling API directly so it doesn't depend on sf cli stability (per the user's note about sf cli breaking changes). -- pass2 labels: `severity:medium,area:packaging,area:2gp,area:unlocked-package` - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3889.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3889:`). +**Issue**: ## Bug - `cumulusci/cumulusci.yml:615-642` - Uninstall tasks: `uninstall_managed`, `uninstall_packaged`, `uninstall_packaged_incremental`, `uninstall_src`, `uninstall_pre`, `uninstall_post`. None take a 04t id. - `cumulusci/tasks/salesforce/UninstallPackage.py:6-32` - `UninstallPackage` accepts only `namespace` (and `purge_on_delete`). Builds an `UninstallPackageZipBuilder` from the namespace. - `c... ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - pass1: `keep-open`- needs a new`UninstallPackageVersion`task (or extend`UninstallPackage`) that calls Tooling API directly so it doesn't depend on sf cli stability (per the user's note about sf cli breaking changes). + +- | pass2 labels: `severity:medium,area:packaging,area:2gp,area:unlocked-package` ## Size & risk | Field | Value | + | -------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3889.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3889:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3910.md b/docs/triage/v5/fix-sketches/issue_3910.md index 6e3cf20407..258fd089b2 100644 --- a/docs/triage/v5/fix-sketches/issue_3910.md +++ b/docs/triage/v5/fix-sketches/issue_3910.md @@ -1,39 +1,15 @@ -# Fix sketch — #3910: JSON Schema incorrectly defines namespaced field as string instead of boolean for scratch org configuration +# Fix sketch - #3910: JSON Schema incorrectly defines namespaced field as string instead of boolean for scratch org configuration **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `scratch-org-config` -**Issue**: +**Issue**: ## Bug JSON Schema incorrectly defines namespaced field as string instead of boolean for scratch org configuration ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - Approach: land PR #3911 essentially as-is (one-line Pydantic field change in `cumulusci_yml.py` + `make schema` regenerated `cumulusci.jsonschema.json`). Both edits must ship together because `test_schema_is_current` would otherwise fail. -## Bug - -JSON Schema incorrectly defines namespaced field as string instead of boolean for scratch org configuration - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- Approach: land PR #3911 essentially as-is (one-line Pydantic field change in `cumulusci_yml.py` + `make schema` regenerated `cumulusci.jsonschema.json`). Both edits must ship together because `test_schema_is_current` would otherwise fail. - Target file:line: `cumulusci/utils/yaml/cumulusci_yml.py:150` (`namespaced: str = None` → `namespaced: bool = None`); regenerate `cumulusci/schema/cumulusci.jsonschema.json`. - Size: small. - Risk: low. The only Pydantic consumers of `ScratchOrg.namespaced` are YAML-validation pathways; the runtime keychain path already uses booleans. -- API break: no (silent coercion was incidental and arguably already broken for users). - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3910.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3910:`). +- | API break: no (silent coercion was incidental and arguably already broken for users). ## Size & risk | Field | Value | + | ---------------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3910.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3910:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3931.md b/docs/triage/v5/fix-sketches/issue_3931.md index cecb0bc44a..68caab4326 100644 --- a/docs/triage/v5/fix-sketches/issue_3931.md +++ b/docs/triage/v5/fix-sketches/issue_3931.md @@ -1,42 +1,12 @@ -# Fix sketch — #3931: Specifying a profile in cumulusci.tasks.salesforce.ProfileGrantAllAccess results in an error +# Fix sketch - #3931: Specifying a profile in cumulusci.tasks.salesforce.ProfileGrantAllAccess results in an error **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `metadata-etl` -**Issue**: - -## Bug - -Specifying a profile in cumulusci.tasks.salesforce.ProfileGrantAllAccess results in an error - -## Target - -`cumulusci/tasks/salesforce/update_profile.py` lines 290-292 - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — small, contained fix. -- pass2 labels: `bug` - -**Notes**: Minimal fix at update_profile.py:290-293 — bind `rt_elem = elem.find("recordType")` and check `if rt_elem is not None and rt_elem.text == rt["record_type"]`. Worth a quick scan of sibling code in `_set_record_types` for similar None-deref patterns on optional XML children. - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3931.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3931:`). +**Issue**: ## Bug Specifying a profile in cumulusci.tasks.salesforce.ProfileGrantAllAccess results in an error ## Target `cumulusci/tasks/salesforce/update_profile.py` lines 290-292 ## Recommended approach (from triage narrative) - pass1: `keep-open` - small, contained fix. + +- | pass2 labels: `bug` **Notes**: Minimal fix at update_profile.py:290-293 - bind `rt_elem = elem.find("recordType")` and check `if rt_elem is not None and rt_elem.text == rt["record_type"]`. Worth a quick scan of sibling code in `_set_record_types` for similar None-deref patterns on optional XML children. --- ## Size & risk | Field | Value | + | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3931.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3931:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3951.md b/docs/triage/v5/fix-sketches/issue_3951.md index bc42d0b919..4a1ae24a6f 100644 --- a/docs/triage/v5/fix-sketches/issue_3951.md +++ b/docs/triage/v5/fix-sketches/issue_3951.md @@ -1,47 +1,14 @@ -# Fix sketch — #3951: set_duplicate_rule_status broken +# Fix sketch - #3951: set_duplicate_rule_status broken **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `metadata-etl` -**Issue**: +**Issue**: ## Bug set*duplicate_rule_status broken ## Target \_See narrative for target file:line.* ## Recommended approach (from triage narrative) - pass1: `improve-error-message` - keep open. -## Bug +- pass2 labels: `bug`, `good-first-issue`, `documentation` **Notes**: Two improvements: 1. Update the `set_duplicate_rule_status` task option help to call out the `.` format requirement. -set_duplicate_rule_status broken - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `improve-error-message` — keep open. -- pass2 labels: `bug`, `good-first-issue`, `documentation` - -**Notes**: Two improvements: - -1. Update the `set_duplicate_rule_status` task option help to call out the `.` format requirement. -2. Same as #3613 — improve the base.py:332 error to list the files actually retrieved. - -The `Cannot find metadata file` error is shared across most `MetadataSingleEntityTransformTask` subclasses, so a single base-class fix would benefit several issues at once. - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3951.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3951:`). +2. | Same as #3613 - improve the base.py:332 error to list the files actually retrieved. The `Cannot find metadata file` error is shared across most `MetadataSingleEntityTransformTask` subclasses, so a single base-class fix would benefit several issues at once. --- ## Size & risk | Field | Value | + | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3951.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3951:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3953.md b/docs/triage/v5/fix-sketches/issue_3953.md index 4b0d6ebeea..49c11d1c7b 100644 --- a/docs/triage/v5/fix-sketches/issue_3953.md +++ b/docs/triage/v5/fix-sketches/issue_3953.md @@ -1,40 +1,12 @@ -# Fix sketch — #3953: add_picklist_entries never works through CLI +# Fix sketch - #3953: add_picklist_entries never works through CLI **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `metadata-etl` -**Issue**: - -## Bug - -add_picklist_entries never works through CLI - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — single-line fix. -- pass2 labels: `bug`, `good-first-issue` - -**Notes**: Minimal fix in `AddPicklistEntries._init_options`: `if isinstance(self.options.get("entries"), str): self.options["entries"] = json.loads(self.options["entries"])`. Apply same pattern to `record_types` for symmetry. The same class of bug exists in `AddFieldsToPageLayout` (encountered while investigating #3613): `cci task run add_page_layout_fields ... -o fields '[...]'` -> `pydantic.ValidationError: value is not a valid list`. A more general fix would be a helper in the CLI/task-base that auto-parses JSON strings for list-typed options, or schema-driven coercion via the new task_options Pydantic models. - ---- - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3953.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3953:`). +**Issue**: ## Bug add*picklist_entries never works through CLI ## Target \_See narrative for target file:line.* ## Recommended approach (from triage narrative) - pass1: `keep-open` - single-line fix. + +- | pass2 labels: `bug`, `good-first-issue` **Notes**: Minimal fix in `AddPicklistEntries._init_options`: `if isinstance(self.options.get("entries"), str): self.options["entries"] = json.loads(self.options["entries"])`. Apply same pattern to `record_types` for symmetry. The same class of bug exists in `AddFieldsToPageLayout` (encountered while investigating #3613): `cci task run add_page_layout_fields ... -o fields '[...]'` -> `pydantic.ValidationError: value is not a valid list`. A more general fix would be a helper in the CLI/task-base that auto-parses JSON strings for list-typed options, or schema-driven coercion via the new task_options Pydantic models. --- ## Size & risk | Field | Value | + | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3953.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3953:`). | diff --git a/docs/triage/v5/fix-sketches/issue_3955.md b/docs/triage/v5/fix-sketches/issue_3955.md index 8bf8faf6b6..420448c67f 100644 --- a/docs/triage/v5/fix-sketches/issue_3955.md +++ b/docs/triage/v5/fix-sketches/issue_3955.md @@ -1,47 +1,17 @@ -# Fix sketch — #3955: Open Test Browser - SalesforcePlaywright.robot +# Fix sketch - #3955: Open Test Browser - SalesforcePlaywright.robot **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `robotframework` -**Issue**: +**Issue**: ## Bug - `cumulusci/robotframework/SalesforcePlaywright.py:106` - `width, height = size.split("x", 1)` returns two `str` values. - `cumulusci/robotframework/SalesforcePlaywright.py:109-111` - the strings are forwarded directly: - Playwright contract requires `viewport.width` / `viewport.height` to be `int`, hence the runtime error `viewport.width: expected integer, got string` reported by the user ... ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - Approach: cast both fragments to `int` immediately after splitting. -## Bug - -- `cumulusci/robotframework/SalesforcePlaywright.py:106` — `width, height = size.split("x", 1)` returns two `str` values. - `cumulusci/robotframework/SalesforcePlaywright.py:109-111` — the strings are forwarded directly: - Playwright contract requires `viewport.width` / `viewport.height` to be `int`, hence the runtime error `viewport.width: expected integer, got string` reported by the user ... - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- Approach: cast both fragments to `int` immediately after splitting. - Target: `cumulusci/robotframework/SalesforcePlaywright.py:106` -- Size: small (~1 line) — e.g. `width, height = (int(v) for v in size.split("x", 1))` -- Risk: low — preserves all existing call sites; users were already passing the documented `WxH` string format. -- API break: no. - -**Recommended action**: - -- pass1: `keep-open` — clear, low-risk, single-line bug fix; great good-first-issue candidate. +- Size: small (~1 line) - e.g. `width, height = (int(v) for v in size.split("x", 1))` +- Risk: low - preserves all existing call sites; users were already passing the documented `WxH` string format. +- API break: no. **Recommended action**: - pass1: `keep-open` - clear, low-risk, single-line bug fix; great good-first-issue candidate. - pass2 labels: `bug, robotframework, playwright, good-first-issue` -- triage test: `cumulusci/tests/triage/test_issue_3955.py` - ---- - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_3955.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #3955:`). +- | triage test: `cumulusci/tests/triage/test_issue_3955.py` --- ## Size & risk | Field | Value | + | --------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_3955.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #3955:`). | diff --git a/docs/triage/v5/fix-sketches/issue_675.md b/docs/triage/v5/fix-sketches/issue_675.md index 5b957115db..ff062d3544 100644 --- a/docs/triage/v5/fix-sketches/issue_675.md +++ b/docs/triage/v5/fix-sketches/issue_675.md @@ -1,47 +1,17 @@ -# Fix sketch — #675: Show full traceback for Python exceptions in robot keywords +# Fix sketch - #675: Show full traceback for Python exceptions in robot keywords **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `robotframework` -**Issue**: +**Issue**: ## Bug - `cumulusci/tasks/robotframework/robotframework.py` configures listeners (`KeywordLogger`, `DebugListener`) but never sets `loglevel`/`logtitle`/`pythonpath` to surface Python tracebacks. `rg 'traceback|format_exc|format_tb' cumulusci/robotframework/` returns 0 matches; same for `cumulusci/tasks/robotframework/`. - Robot Framework's default behaviour: when a Python keyword raises, only `str(e... ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - Approach: in `Robot.\_init_options`, default `options.loglevel`to include`TRACE`, OR install a small listener that captures `sys.exc_info()`in keyword-end events and emits a formatted traceback through`robot.api.logger.error`. -## Bug - -- `cumulusci/tasks/robotframework/robotframework.py` configures listeners (`KeywordLogger`, `DebugListener`) but never sets `loglevel`/`logtitle`/`pythonpath` to surface Python tracebacks. `rg 'traceback|format_exc|format_tb' cumulusci/robotframework/` returns 0 matches; same for `cumulusci/tasks/robotframework/`. - Robot Framework's default behaviour: when a Python keyword raises, only `str(e... - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- Approach: in `Robot._init_options`, default `options.loglevel` to include `TRACE`, OR install a small listener that captures `sys.exc_info()` in keyword-end events and emits a formatted traceback through `robot.api.logger.error`. - Target: `cumulusci/tasks/robotframework/robotframework.py:104` (`_init_options`). - Size: small (~10 lines). -- Risk: low — additive listener; opt-out via options if needed. -- API break: no. - -**Recommended action**: - -- pass1: `closed:stale-24mo` — issue opened 2018-07, last activity 2018-09, ~8 years inactivity. Two simple workarounds exist (`-o loglevel:TRACE`, `traceback.format_exc()` in keywords). Surface as a tip in docs rather than keep the bug open. +- Risk: low - additive listener; opt-out via options if needed. +- API break: no. **Recommended action**: - pass1: `closed:stale-24mo` - issue opened 2018-07, last activity 2018-09, ~8 years inactivity. Two simple workarounds exist (`-o loglevel:TRACE`, `traceback.format_exc()` in keywords). Surface as a tip in docs rather than keep the bug open. - pass2 labels: `cli-usability, robotframework, stale` -- triage test: n/a — observable only in a robot run. - ---- - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -_None yet — add a regression test as part of the fix-PR._. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #675:`). +- | triage test: n/a - observable only in a robot run. --- ## Size & risk | Field | Value | + | --------------------------------------------------------------------- | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test _None yet - add a regression test as part of the fix-PR._. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #675:`). | diff --git a/docs/triage/v5/fix-sketches/issue_710.md b/docs/triage/v5/fix-sketches/issue_710.md index fa9db96add..047f32b61f 100644 --- a/docs/triage/v5/fix-sketches/issue_710.md +++ b/docs/triage/v5/fix-sketches/issue_710.md @@ -1,41 +1,15 @@ -# Fix sketch — #710: Allow disabling default scratch org configs +# Fix sketch - #710: Allow disabling default scratch org configs **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `scratch-org-config` -**Issue**: +**Issue**: ## Bug Allow disabling default scratch org configs ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) - Approach: introduce a sentinel for "disabled" (recommend an explicit `disabled: true` flag on each scratch org config rather than relying on `config_file: None`, which has overloaded meaning) and skip disabled entries in `_load_scratch_orgs`. Optional: a stricter `merge_config` mode that preserves `None` overrides under `orgs.scratch.*`. -## Bug - -Allow disabling default scratch org configs - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -- Approach: introduce a sentinel for "disabled" (recommend an explicit `disabled: true` flag on each scratch org config rather than relying on `config_file: None`, which has overloaded meaning) and skip disabled entries in `_load_scratch_orgs`. Optional: a stricter `merge_config` mode that preserves `None` overrides under `orgs.scratch.*`. - Target file:line: `cumulusci/utils/yaml/cumulusci_yml.py:147` (add `disabled: bool = None` to `ScratchOrg`); `cumulusci/core/keychain/base_project_keychain.py:155` (skip when `config.get("disabled")`); regenerate `cumulusci/schema/cumulusci.jsonschema.json`. - Size: small/medium. - Risk: low. Existing keys remain compatible; only adds new opt-in behaviour. Needs a docs note (`docs/orgs/scratch.md`) on how to disable inherited defaults. -- API break: no (additive). The issue's literal `config_file: None` syntax would NOT be honoured under this proposal; if the team prefers that exact syntax instead, add a `dictmerge` exception so `None` overrides under `orgs.scratch.*` are preserved, then have `_load_scratch_orgs` skip entries with `config_file is None`. Either implementation satisfies the XFAIL test (`dev not in keychain.orgs`). - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_710.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #710:`). +- | API break: no (additive). The issue's literal `config_file: None` syntax would NOT be honoured under this proposal; if the team prefers that exact syntax instead, add a `dictmerge` exception so `None` overrides under `orgs.scratch.*` are preserved, then have `_load_scratch_orgs` skip entries with `config_file is None`. Either implementation satisfies the XFAIL test (`dev not in keychain.orgs`). ## Size & risk | Field | Value | + | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_710.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #710:`). | diff --git a/docs/triage/v5/fix-sketches/issue_733.md b/docs/triage/v5/fix-sketches/issue_733.md index 0d32f60d1d..8e989d4638 100644 --- a/docs/triage/v5/fix-sketches/issue_733.md +++ b/docs/triage/v5/fix-sketches/issue_733.md @@ -1,40 +1,12 @@ -# Fix sketch — #733: Prompt to delete scratch org when creating one that already exists +# Fix sketch - #733: Prompt to delete scratch org when creating one that already exists **Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) -**Verdict**: `REPRODUCED-on-v4.10.0` (verdict_source: `v4.10.0`) **Theme**: `cli` -**Issue**: - -## Bug - -Behaviour identical to the 2018 report — hard error, no interactive Y/N prompt. - -## Target - -`cumulusci/cli/runtime.py` lines 126-140 - -## Recommended approach (from triage narrative) - -- pass1: `closed:stale-24mo` — 7-year-old `cli-usability` enhancement, no traction, original tracking W-028291. -- pass2 labels: `enhancement,cli-usability,stale` - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_733.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #733:`). +**Issue**: ## Bug Behaviour identical to the 2018 report - hard error, no interactive Y/N prompt. ## Target `cumulusci/cli/runtime.py` lines 126-140 ## Recommended approach (from triage narrative) - pass1: `closed:stale-24mo` - 7-year-old `cli-usability` enhancement, no traction. + +- | pass2 labels: `enhancement,cli-usability,stale` --- ## Size & risk | Field | Value | + | ------------------------------------------------------------------ | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_733.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #733:`). | diff --git a/docs/triage/v5/fix-sketches/issue_773.md b/docs/triage/v5/fix-sketches/issue_773.md index 2782a9a3d6..ad19427f79 100644 --- a/docs/triage/v5/fix-sketches/issue_773.md +++ b/docs/triage/v5/fix-sketches/issue_773.md @@ -1,60 +1,17 @@ -# Fix sketch — #773: Document task return values and results +# Fix sketch - #773: Document task return values and results **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `docs` -**Issue**: - -## Bug - -Document task return values and results - -## Target - -_See narrative for target file:line._ - -## Recommended approach (from triage narrative) - -1. Add a class attribute on `BaseTask`: - -```python +**Issue**: ## Bug Document task return values and results ## Target _See narrative for target file:line._ ## Recommended approach (from triage narrative) 1. Add a class attribute on `BaseTask`: ```python return_values_schema: ClassVar[Dict[str, str]] = {} -``` - -where each key is the return-values dict key and each value is a one-line -description (parallel to how `task_options` already works). - -2. Extend `doc_task()` in `cumulusci/utils/__init__.py` to render a - "Return Values" RST section (heading + bullet list) when - `task_class.return_values_schema` is non-empty. Update the matching - `get_task_*` helpers to surface the schema for web-doc generation. -3. Backfill the schema on tasks that already emit return values — search - for `self.return_values\[` across `cumulusci/tasks/`: at minimum - `PackageUpload`, `PromotePackageVersion`, `GithubRelease`, - `CreatePackageVersion`, dependency-resolution tasks. Each gets a few - lines. - -4. Lift the `attention` admonition in `docs/config.md:740-744` once - coverage is broad enough. - -Estimated effort: 1-2 day PR for the framework + first wave of tasks; an +```where each key is the return-values dict key and each value is a one-line +description (parallel to how `task_options` already works). 2. Extend `doc_task()` in `cumulusci/utils/__init__.py` to render a "Return Values" RST section (heading + bullet list) when `task_class.return_values_schema` is non-empty. Update the matching `get_task_*` helpers to surface the schema for web-doc generation. 3. Backfill the schema on tasks that already emit return values - search for `self.return_values\[` across `cumulusci/tasks/`: at minimum `PackageUpload`, `PromotePackageVersion`, `GithubRelease`, `CreatePackageVersion`, dependency-resolution tasks. Each gets a few lines. 4. Lift the `attention` admonition in `docs/config.md:740-744` once coverage is broad enough. Estimated effort: 1-2 day PR for the framework + first wave of tasks; an ongoing "every new task documents its return values" contributor -expectation thereafter (enforce in `requesting-code-review` skill). - -## Size & risk - -| Field | Value | +expectation thereafter (enforce in `requesting-code-review` skill). ## Size & risk | Field | Value | | ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_773.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #773:`). +| Size estimate | _TBD by fix-PR author_ | +| Risk | _TBD by fix-PR author_ | +| Touches `cumulusci/robotframework/*` | _TBD_ | +| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | +| Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_773.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #773:`). +``` diff --git a/docs/triage/v5/fix-sketches/issue_808.md b/docs/triage/v5/fix-sketches/issue_808.md index d0fc1205c0..63e598bf8f 100644 --- a/docs/triage/v5/fix-sketches/issue_808.md +++ b/docs/triage/v5/fix-sketches/issue_808.md @@ -1,42 +1,12 @@ -# Fix sketch — #808: deploy_packaging flow runs uninstall_packaged_incremental with wrong package name +# Fix sketch - #808: deploy_packaging flow runs uninstall_packaged_incremental with wrong package name **Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) -**Verdict**: `REPRODUCED-on-dev` (verdict_source: `dev`) **Theme**: `metadata-etl` -**Issue**: - -## Bug - -- `UninstallPackaged._init_options` (UninstallPackaged.py:22-25): - Compare to `InstallPackageVersion._init_options` (install_package_version.py:75-79) which DOES use the fall-back chain `name_managed -> name -> namespace`. The asymmetry is the bug. - Bug pattern is unchanged since 2018; no fix has landed. - -## Target - -`cumulusci/tasks/salesforce/UninstallPackaged.py` lines 22-25 - -## Recommended approach (from triage narrative) - -- pass1: `keep-open` — small, contained fix. -- pass2 labels: `bug`, `good-first-issue` - -**Notes**: jlantz's 2018 follow-up about deprecating `project__package__name_managed` (legacy NPSP-only feature) is a separate, larger conversation; for this triage the minimal symmetric fix is enough. - ---- - - - -## Size & risk - -| Field | Value | -| ------------------------------------ | ---------------------- | -| Size estimate | _TBD by fix-PR author_ | -| Risk | _TBD by fix-PR author_ | -| Touches `cumulusci/robotframework/*` | _TBD_ | -| Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | -| Breaks public CLI surface | _TBD_ | - -## Regression test - -`cumulusci/tests/triage/test_issue_808.py`. Remove the `@pytest.mark.xfail` marker and confirm green. - -## Full narrative - -See `docs/triage/v5/repro-results.md` (search for `### #808:`). +**Issue**: ## Bug - `UninstallPackaged._init_options` (UninstallPackaged.py:22-25): - Compare to `InstallPackageVersion._init_options` (install_package_version.py:75-79) which DOES use the fall-back chain `name_managed -> name -> namespace`. The asymmetry is the bug. - Bug pattern is unchanged since 2018; no fix has landed. ## Target `cumulusci/tasks/salesforce/UninstallPackaged.py` lines 22-25 ## Recommended approach (from triage narrative) - pass1: `keep-open` - small, contained fix. + +- | pass2 labels: `bug`, `good-first-issue` **Notes**: jlantz's 2018 follow-up about deprecating `project__package__name_managed` (legacy NPSP-only feature) is a separate, larger conversation; for this triage the minimal symmetric fix is enough. --- ## Size & risk | Field | Value | + | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | + | Size estimate | _TBD by fix-PR author_ | + | Risk | _TBD by fix-PR author_ | + | Touches `cumulusci/robotframework/*` | _TBD_ | + | Touches `cumulusci/tasks/bulkdata/*` | _TBD_ | + | Breaks public CLI surface | _TBD_ | ## Regression test `cumulusci/tests/triage/test_issue_808.py`. Remove the `@pytest.mark.xfail` marker and confirm green. ## Full narrative See `docs/triage/v5/repro-results.md` (search for `### #808:`). | diff --git a/docs/triage/v5/proposals.md b/docs/triage/v5/proposals.md index 1ad054bab0..959124ce3f 100644 --- a/docs/triage/v5/proposals.md +++ b/docs/triage/v5/proposals.md @@ -25,15 +25,15 @@ By risk: - medium-high: 45 - high: 0 -## Repro pass updates (Task 2.5c) +## Repro pass updates (the reproducibility pass) Two rounds of subagents verified 98 of 142 open issues against v4.10.0 source on `origin/main` (see `repro-results.md` and `repro-results.csv`): -- **Round 1**: packaging + metadata-etl (45 issues, subagents 1-6). -- **Round 2**: cli + bulkdata + dependencies + ci-integration (53 issues, subagents 7-12). +- **the initial reproducibility pass**: packaging + metadata-etl (45 issues, the triage). +- **the follow-up reproducibility pass**: cli + bulkdata + dependencies + ci-integration (53 issues, the triage). -This file integrates Round 1 + Round 2 verdicts. Proposed-pass1 was changed for **62 rows**; **24 rows** were confirmed by repro and marked in `rule-rationale`. Untouched themes (44 issues): `robotframework`, `scratch-org-config`, `auth`, `keychain`, `docs`, `python-modernization`, plus all `closed:pre-v4.0.0` rows. +This file integrates the initial reproducibility pass + the follow-up reproducibility pass verdicts. Proposed-pass1 was changed for **62 rows**; **24 rows** were confirmed by repro and marked in `rule-rationale`. Untouched themes (44 issues): `robotframework`, `scratch-org-config`, `auth`, `keychain`, `docs`, `python-modernization`, plus all `closed:pre-v4.0.0` rows. ### New proposed-pass1 vocabulary introduced by repro pass @@ -46,33 +46,31 @@ The repro pass introduces three pass1 values that are not yet in the spec sectio ### Repro pass cross-cutting findings (relevant to Phase 2 execution and v5 planning) - **Same-file pairs / triplets** (worth bundling as one fix epic each): - - #2153 + #3471: both touch `cumulusci/tasks/github/merge.py` (`MergeBranch`). - - #3506 + #3570 + #3663: flow `when:` evaluator in `cumulusci/core/flowrunner.py:510-516` and missing propagation in the flow branch (lines 660-697). - - #3349 + #2013: shared root cause in `MappingStep` table-naming (uses `sf_object` not `table`). - - #3603 + #3604 + #3619: dependency-resolution UX gaps (404 leak, missing pin password env, missing sfdx-project.json writeback). -- **Recent regressions still active** (Tranche 1 candidates for v4.10.x patch): - - #3852 (sarge cosmetic, Py 3.13). - - #3854 (PR #3741 / commit `2c5d0056e` introduced a still-active validation error in `cumulusci/tasks/bulkdata/extract.py:371-374`). - - #3938, #3939 (already in Round 1; reaffirmed REPRO). +- #2153 + #3471: both touch `cumulusci/tasks/github/merge.py` (`MergeBranch`). +- #3506 + #3570 + #3663: flow `when:` evaluator in `cumulusci/core/flowrunner.py:510-516` and missing propagation in the flow branch (lines 660-697). +- #3349 + #2013: shared root cause in `MappingStep` table-naming (uses `sf_object` not `table`). +- #3603 + #3604 + #3619: dependency-resolution UX gaps (404 leak, missing pin password env, missing sfdx-project.json writeback). +- **Recent regressions still active** ([Tranche 1](../../docs/triage/v5/README.md#tranche-1-candidate-list) candidates for v4.10.x patch): +- #3852 (sarge cosmetic, Py 3.13). +- #3854 (PR #3741 / commit `2c5d0056e` introduced a still-active validation error in `cumulusci/tasks/bulkdata/extract.py:371-374`). +- #3938, #3939 (already in the initial reproducibility pass; reaffirmed REPRO). - **Wrong-repo report**: - - #3612: `cci robot ...` issue belongs in `cci-vscode`, not cci core. Recommend new spec vocab `closed:wrong-repo` and a one-line "filed-in-wrong-repo" close comment. -- **Cross-room duplicate confirmation** (Round 1): - - #3762 -> closed:duplicate-of-#3544 (Cluster A canonical). +- #3612: `cci robot ...` issue belongs in `cci-vscode`, not cci core. Recommend new spec vocab `closed:wrong-repo` and a one-line "filed-in-wrong-repo" close comment. +- **Cross-room duplicate confirmation** (the initial reproducibility pass): +- #3762 -> closed:duplicate-of-#3544 (Cluster A canonical). - **Unchanged INCONCLUSIVE-needs-X** (kept-open with informational note in narrative; no proposals.md row change required): - - #3418 + #3717: both `INCONCLUSIVE-needs-cumulus-actions-workflow` (cci has zero GitHub Actions env auto-detect; structural gap). - - #3542: needs 2GP CI pipeline. - - #3936: flaky-network read-timeout; intermittent. +- #3418 + #3717: both `INCONCLUSIVE-needs-cumulus-actions-workflow` (cci has zero GitHub Actions env auto-detect; structural gap). +- #3542: needs 2GP CI pipeline. +- #3936: flaky-network read-timeout; intermittent. - **Adjacent-finding** surfaced but not blocking: - - `TypeError` in `cumulusci/utils/__init__.py:229` when `namespaced_org=True` is supplied against a project with `namespace=None` (Round 1). - - `cumulusci[select]` warning at module-import time in `cumulusci/tasks/bulkdata/select_utils.py` (#3886, fires on every `extract_dataset`). +- `TypeError` in `cumulusci/utils/__init__.py:229` when `namespaced_org=True` is supplied against a project with `namespace=None` (the initial reproducibility pass). +- `cumulusci[select]` warning at module-import time in `cumulusci/tasks/bulkdata/select_utils.py` (#3886, fires on every `extract_dataset`). ### Approval-gate hint Most `closed:stale-24mo -> kept-open` rescues warrant a `target:v4-patch` or `v5-candidate` pass2 label, but those columns were left unchanged here so the next user gate can attach labels deliberately. -## Round 3 updates (2026-05-13 → 2026-05-14) - -Round 3 added 17 issues across 6 themes (`robotframework`, `scratch-org-config`, `auth`, `keychain`, `docs`, `python-modernization`) against `origin/dev` (NOT v4.10.0). Each updated row in the proposal table is annotated with `+repro Task 2.5c R3: {verdict}`. +the dev-branch verification pass added 17 issues across 6 themes (`robotframework`, `scratch-org-config`, `auth`, `keychain`, `docs`, `python-modernization`) against `origin/dev` (NOT v4.10.0). Each updated row in the proposal table is annotated with `+repro: {verdict}`. - **12 REPRODUCED-on-dev**: #675, #710, #773, #2500, #3407, #3464, #3541, #3602, #3849, #3873, #3910, #3955. - **5 NOT-REPRODUCED-on-dev**: #987, #2126, #2667, #3306, #3610. @@ -80,168 +78,168 @@ Round 3 added 17 issues across 6 themes (`robotframework`, `scratch-org-config`, R3 rescues from prior closure verdicts: - **From `closed:missing-fields` (5 issues)**: - - `#2126`, `#2667` → `closed:stale-24mo` (NOT-REPRO on dev; ancient). - - `#2500` → `kept-open` (REPRO; documentation gap, not stale). - - `#3306` confirmed kept-open (NOT-REPRO, but real reporter). - - `#3873` confirmed kept-open (REPRO; feature ask, not stale). +- `#2126`, `#2667` → `closed:stale-24mo` (NOT-REPRO on dev; ancient). +- `#2500` → `kept-open` (REPRO; documentation gap, not stale). +- `#3306` confirmed kept-open (NOT-REPRO, but real reporter). +- `#3873` confirmed kept-open (REPRO; feature ask, not stale). - **From `closed:stale-24mo` (5 issues)**: - - `#710`, `#773` → `kept-open` (REPRO on dev; surface as v5 candidates). - - `#987` confirmed `closed:stale-24mo` (NOT-REPRO; ancient). - - `#675` confirmed `closed:stale-24mo` (REPRO but robot-runner-only with no python test path). - - `#3407` confirmed kept-open. +- `#710`, `#773` → `kept-open` (REPRO on dev; surface as v5 candidates). +- `#987` confirmed `closed:stale-24mo` (NOT-REPRO; ancient). +- `#675` confirmed `closed:stale-24mo` (REPRO but robot-runner-only with no python test path). +- `#3407` confirmed kept-open. - **New PR-resolved (1 issue)**: - - `#3610` → `closed:pr-resolved-#3681` (fixed on dev by commit 84389d998; regression tests already on dev). +- `#3610` → `closed:pr-resolved-#3681` (fixed on dev by commit 84389d998; regression tests already on dev). Notable R3 findings (also captured in repro-results.md narrative): - `#3910` (REPRO on dev) has an open PR `#3911` that fixes it; suggest `closed:pr-pending-#3911` close vocab once PR merges. Until then, keep open. - `#3849` (REPRO on dev) is a urllib3 v2 / Selenium 3 ABI conflict on a fresh `pip install`; `.venv` only survives via the `uv.lock` pin. Surface as a dependency-modernization candidate for v5. -- `#3955` and `#3602` (REPRO on dev) are RF-theme bugs with pytest-stubbable repros — first proof that the parent plan's no-RF-inspection rule is too broad for evidence/test work (addressed in plan's "RF scope clarification" subsection). -- `#3541` (REPRO on dev) is a keychain corruption when the password is missing — reproducible via test stubbing the encryption layer. +- `#3955` and `#3602` (REPRO on dev) are RF-theme bugs with pytest-stubbable repros - first proof that the parent plan's no-RF-inspection rule is too broad for evidence/test work (addressed in plan's "RF scope clarification" subsection). +- `#3541` (REPRO on dev) is a keychain corruption when the password is missing - reproducible via test stubbing the encryption layer. ## Proposal table -| issue# | title | last-activity | proposed-pass1 | proposed-pass2 | proposed-v5 | rule-rationale | risk | approval | -| -----: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------- | ---------------------------------- | -------------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------- | ----------- | -------- | -| #675 | Show full traceback for Python exceptions in robot keywords | 2018-09-11 | closed:stale-24mo | n/a | n/a | rule 1: updated 2018-09-11, no maintainer label; +repro Task 2.5c R3: REPRO-on-dev | low | | -| #710 | Allow disabling default scratch org configs | 2018-11-02 | kept-open | n/a | n/a | rule 1: updated 2018-11-02, no maintainer label; +repro Task 2.5c R3: REPRO-on-dev | low | | -| #733 | Prompt to delete scratch org when creating one that already exists | 2018-09-11 | closed:stale-24mo | n/a | n/a | rule 1: updated 2018-09-11, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | -| #773 | Document task return values and results | 2018-11-19 | kept-open | n/a | n/a | rule 1: updated 2018-11-19, no maintainer label; +repro Task 2.5c R3: REPRO-on-dev | low | | -| #808 | deploy_packaging flow runs uninstall_packaged_incremental with wrong package name | 2018-10-09 | kept-open | n/a | n/a | rule 1: updated 2018-10-09, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #987 | Last week this test worked, now I get a javascriptexception message. | 2022-06-16 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-06-16, no maintainer label; +repro Task 2.5c R3: NOT-REPRO-on-dev | low | | -| #1348 | Multiple Git Provider Support | 2022-11-07 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-11-07, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | -| #1350 | Unable to run tasks in remote projects | 2022-07-07 | closed:not-reproducible-on-v4.10.0 | n/a | n/a | rule 1: updated 2022-07-07, no maintainer label; +repro Task 2.5c: NOT-REPRO | low | | -| #1432 | CCI Inconsistencies in validating arguments | 2020-01-03 | closed:stale-24mo | n/a | n/a | rule 1: updated 2020-01-03, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | -| #1769 | Unusual case in test_load | 2020-08-07 | closed:stale-24mo | n/a | n/a | rule 1: updated 2020-08-07, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | -| #2013 | Mapping files with steps that are not 1-1 with SObjects are unreliable for extraction | 2020-09-13 | kept-open | n/a | n/a | rule 1: updated 2020-09-13, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #2096 | REST dataloads throw errors that Bulk loads do not. | 2020-10-15 | closed:not-reproducible-on-v4.10.0 | n/a | n/a | rule 1: updated 2020-10-15, no maintainer label; +repro Task 2.5c: NOT-REPRO | low | | -| #2126 | Support task to encrypt all possible fields with probabilistic encryption | 2022-01-28 | closed:stale-24mo | n/a | n/a | rule 3: missing cci-version; updated 2022-01-28; +repro Task 2.5c R3: NOT-REPRO-on-dev | medium-high | | -| #2140 | Prompt Org Configs when Org Does Not Exist and Command Runs Against It | 2022-05-20 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-05-20, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | -| #2153 | Add comment to original PR which tags all branch subscribers when a merge conflict auto-generated PR is created ("Merge master into ") | 2020-11-11 | kept-open | n/a | n/a | rule 1: updated 2020-11-11, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #2325 | Task to turn off validation rules to allow data insert | 2021-01-19 | kept-open | n/a | n/a | rule 1: updated 2021-01-19, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #2402 | Create a --rebuild-org parameter for cci flow run | 2022-01-28 | closed:stale-24mo | n/a | n/a | rule 3: missing repro, cci-version; updated 2022-01-28; +repro Task 2.5c: REPRO | medium-high | | -| #2440 | add_permission_set_perms throws 'string indices must be integers' error | 2022-01-28 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #2500 | ignore_failure is not documented | 2022-03-28 | kept-open | n/a | n/a | rule 3: missing repro, cci-version; updated 2022-03-28; +repro Task 2.5c R3: REPRO-on-dev | medium-high | | -| #2505 | Filtering records to be extracted | 2021-06-02 | closed:feature-implemented | n/a | n/a | rule 1: updated 2021-06-02, no maintainer label; +repro Task 2.5c: NOT-REPRO | low | | -| #2506 | Bulk Operations should have a --debug mode which maintains logs and tempfiles | 2021-03-27 | kept-open | n/a | n/a | rule 1: updated 2021-03-27, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #2507 | Undo mode for CumulusCI Insert | 2021-03-27 | closed:stale-24mo | n/a | n/a | rule 1: updated 2021-03-27, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | -| #2508 | Manual load retries | 2021-03-27 | kept-open | n/a | n/a | rule 1: updated 2021-03-27, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #2667 | `cci org connect` should output the name of the connected app it is using, especially if it is non-default | 2022-01-28 | closed:stale-24mo | n/a | n/a | rule 3: missing repro, cci-version; updated 2022-01-28; +repro Task 2.5c R3: NOT-REPRO-on-dev | medium-high | | -| #2697 | Initialization issue with 'namespaced' field in 'cci org info' after updating from a non-namespaced scratch org to namespaced | 2021-06-25 | closed:stale-24mo | n/a | n/a | rule 1: updated 2021-06-25, no maintainer label; +repro Task 2.5c: INCONCL:scratch-slot (confirms) | low | | -| #2826 | The deploy_unmanaged flow is supposed to silently do nothing if there's not actually a package directory | 2021-08-25 | kept-open | n/a | n/a | rule 1: updated 2021-08-25, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #2930 | Exception in task load_dataset | 2022-01-28 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #2951 | Error in task load_dataset - Standard_price_not_defined | 2021-11-11 | kept-open | n/a | n/a | rule 1: updated 2021-11-11, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #2973 | cumulusci.tasks.salesforce.CreateCommunity has no option to set authentication mode for LWR Community | 2022-01-28 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #2979 | deploy task should deploy from the default entry in packageDirectories in sfdx-project.json if the project is using sfdx format. | 2021-11-17 | kept-open | n/a | n/a | rule 1: updated 2021-11-17, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3015 | Request to have the ability to remove an imported dx org from cci org list without deleting the actual scratch org. | 2022-01-28 | closed:stale-24mo | n/a | n/a | rule 3: missing repro, cci-version; updated 2022-01-28; +repro Task 2.5c: REPRO | medium-high | | -| #3024 | Order of flow groups in cumulusci/cumulusci.yml reflects in the Flows box in CCI VSCode extension, but order is not natural | 2022-01-05 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-01-05, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | -| #3045 | create_bulk_data_permission_set errors on multiple runs | 2022-01-28 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #3047 | Open Test Browser TypeError: 'NoneType' object is not callable when using useralias param | 2022-01-28 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #3089 | task run_tests not including namespace in query | 2022-02-21 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #3100 | uninstall_post is not substituting %%%NAMESPACE%%% | 2023-10-02 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #3134 | Running flow always needs a default org or org defined | 2022-04-18 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #3137 | cci task run update_package_xml and Salesforce Case Custom Object | 2022-05-18 | kept-open | n/a | n/a | rule 3: missing repro; updated 2022-05-18; +repro Task 2.5c: REPRO | medium-high | | -| #3161 | Ability to Hide Option Values When Using Task Options In a Task or Flow Run | 2022-04-21 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-04-21, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | -| #3165 | Update Admin Profile task fails when specifying records types without custom package.xml | 2022-04-19 | kept-open | n/a | n/a | rule 1: updated 2022-04-19, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3167 | Add ability to define page layout assignments with record types using the update_admin_profile task | 2022-04-20 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-04-20, no maintainer label; +repro Task 2.5c: NOT-REPRO (confirms) | low | | -| #3182 | "Error: 'utf-8' codec can't decode byte 0x80 in position 0: invalid start byte" when running any CCI command after connecting Github service | 2025-02-19 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #3203 | generate_and_load_from_yaml task record type extraction fails for namespaced custom objects | 2023-01-09 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #3283 | json parser error when empty string passed for date field during upsert or update | 2022-09-16 | closed:pr-resolved-#3361 | n/a | n/a | rule 1: updated 2022-09-16, no maintainer label; +repro Task 2.5c: NOT-REPRO | low | | -| #3306 | Preview Toggle for Scratch org def file | 2023-09-13 | kept-open | n/a | n/a | rule 3: missing repro, cci-version; updated 2023-09-13; +repro Task 2.5c R3: NOT-REPRO-on-dev | medium-high | | -| #3307 | Project Template Support for initialisation | 2022-07-25 | closed:stale-24mo | n/a | n/a | rule 3: missing repro, cci-version; updated 2022-07-25; +repro Task 2.5c: REPRO | medium-high | | -| #3320 | Metadata ETL task to Deactivate a Flow | 2023-02-15 | closed:feature-implemented | n/a | n/a | rule 3: missing repro, cci-version; updated 2023-02-15; +repro Task 2.5c: NOT-REPRO | medium-high | | -| #3331 | Task update_package_xml does not write correct package.xml for AssignmentRules | 2022-10-11 | kept-open | n/a | n/a | rule 1: updated 2022-10-11, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3347 | Cannot release an unlocked beta package with release_unlocked_beta flow | 2022-08-29 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-08-29, no maintainer label; +repro Task 2.5c: NOT-REPRO (confirms) | low | | -| #3349 | Make generated dataset recordType tables unique based on table instead of sf_object | 2022-09-26 | kept-open | n/a | n/a | rule 3: missing repro, cci-version; updated 2022-09-26; +repro Task 2.5c: REPRO | medium-high | | -| #3353 | Enable Snowfakery task to use recipes from other repositories | 2024-08-20 | kept-open | n/a | n/a | rule 3: missing repro, cci-version; updated 2024-08-20; +repro Task 2.5c: REPRO | medium-high | | -| #3360 | Read Only Object Lookup for Load_Dataset | 2022-09-15 | closed:feature-implemented | n/a | n/a | rule 1: updated 2022-09-15, no maintainer label; +repro Task 2.5c: NOT-REPRO | low | | -| #3376 | extract_dataset sql error | 2022-10-03 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #3407 | `set_service(service_config)` type signature is wrong | 2022-10-19 | kept-open | n/a | n/a | rule 1: updated 2022-10-19, no maintainer label; +repro Task 2.5c R3: REPRO-on-dev | low | | -| #3418 | Error creating 1gp release | 2022-11-01 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-11-01, no maintainer label; +repro Task 2.5c: INCONCL:cumulus-actions-workflow (confirms) | low | | -| #3429 | Support overriding `cumulusci.yml` to be used for configuration | 2022-11-08 | kept-open | n/a | n/a | rule 1: updated 2022-11-08, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3440 | Enhance default_package_path to serve multi package projects better | 2022-11-17 | kept-open | n/a | n/a | rule 1: updated 2022-11-17, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3441 | "cci task run create_package_version" should allow option "version_base: default" in cumulusci.yml | 2023-12-15 | kept-open | n/a | n/a | rule 1: updated 2023-12-15, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3446 | CCI task "push_qa" crashes for Unlocked package with no namespace | 2022-12-13 | kept-open | n/a | n/a | rule 1: updated 2022-12-13, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3464 | Provide concise documentation of cumulusci.yml `project` configuration options | 2022-12-12 | kept-open | n/a | n/a | rule 1: updated 2022-12-12, no maintainer label; +repro Task 2.5c R3: REPRO-on-dev | low | | -| #3466 | Ability to specify a test suite to run instead of just test_name_match in the run_tests task | 2022-12-13 | closed:feature-implemented | n/a | n/a | rule 3: missing repro, cci-version; updated 2022-12-13; +repro Task 2.5c: NOT-REPRO | medium-high | | -| #3470 | Rename `ci_master` flow to a `ci_main` or at least create a new duplicate `ci_main` flow | 2022-12-16 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-12-16, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | -| #3471 | `Merged 0 commits into branch:` message displays when a non-Source Code change is made in `github_automerge_feature` task | 2022-12-16 | kept-open | n/a | n/a | rule 1: updated 2022-12-16, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3479 | Error with "cci org import" in github action | 2023-02-22 | closed:not-reproducible-on-v4.10.0 | n/a | n/a | rule 1: updated 2023-02-22, no maintainer label; +repro Task 2.5c: NOT-REPRO | low | | -| #3485 | "cci task run run_tests" generates incorrect test_results.xml format output | 2024-01-28 | kept-open | n/a | n/a | rule 1: updated 2024-01-28, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3492 | Enhance the "-o" option of "cci flow run" to accept "project\_\_custom" attribute values | 2023-01-17 | kept-open | n/a | n/a | rule 1: updated 2023-01-17, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3506 | when clause support for flow steps which call other flows | 2023-01-25 | kept-open | n/a | n/a | rule 1: updated 2023-01-25, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3512 | `namespace` does not display when running `cci org info` on a packaging org (does work when you add `--json` flag) | 2023-02-03 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #3518 | Task add_picklist_entries always sets a default value for record types | 2023-02-03 | kept-open | n/a | n/a | rule 1: updated 2023-02-03, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3541 | Getting None\_\_dev as SFDX Alias | 2023-07-07 | kept-open | n/a | n/a | rule 1: updated 2023-07-07, no maintainer label; +repro Task 2.5c R3: REPRO-on-dev | low | | -| #3542 | 2GP flows fail in the local environment to test: `ci_feature_2gp` or `qa_org_2gp` with error: Could not find package version id | 2023-02-22 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-02-22, no maintainer label; +repro Task 2.5c: INCONCL:2GP-CI-pipeline (confirms) | low | | -| #3543 | New Option `load_sfdx_project_paths` for dx_convert_from Task | 2023-03-30 | kept-open | n/a | n/a | rule 1: updated 2023-03-30, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3544 | Task `update_admin_profile` errors when the org has person accounts and a namespace | 2025-05-07 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation; +repro Task 2.5c: INCONCL:namespaced-project (confirms) | medium-high | | -| #3546 | password_env_name bleeding over to next package | 2024-09-13 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #3549 | Deploy to Salesforce does not create a test output | 2023-04-05 | kept-open | n/a | n/a | rule 1: updated 2023-04-05, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3561 | Retrieve_unpackaged unusable in MetaDeploy | 2023-03-15 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-03-15, no maintainer label; +repro Task 2.5c: NOT-REPRO (confirms) | low | | -| #3563 | Unmanaged Metadata not deploying during 2GP Package Create | 2024-06-21 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #3570 | Feature Request: Flow "finally" or "error" path | 2023-04-04 | kept-open | n/a | n/a | rule 1: updated 2023-04-04, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3585 | Error Occurs when Using `update_package_xml` on object with `xsi:nil="true"` | 2023-04-19 | kept-open | n/a | n/a | rule 1: updated 2023-04-19, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3587 | Warning message when attempting to set `--install_class` or `--uninstall_class` flag on `update_package_xml` and `--managed` is `false` or null (defaults to true) | 2023-04-23 | kept-open | n/a | n/a | rule 1: updated 2023-04-23, no maintainer label; +repro Task 2.5c: NOT-REPRO | low | | -| #3589 | "Workflow" and "MatchingRules" are removed from package.xml after running "update_package_xml" task | 2023-04-25 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #3592 | release_unlocked_beta doesn't work when an install key is specified | 2023-08-02 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #3593 | `dx` task doesn't work for some commands like `project convert source` | 2023-05-03 | kept-open | n/a | n/a | rule 1: updated 2023-05-03, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3600 | Allow install_managed to use environment variables | 2023-05-25 | kept-open | n/a | n/a | rule 1: updated 2023-05-25, no maintainer label; +repro Task 2.5c: NOT-REPRO | low | | -| #3602 | Need Chrome/Firefox options(browser options/capabilities) in 'Open Test Browser' Keyword | 2023-05-26 | kept-open | n/a | n/a | rule 1: updated 2023-05-26, no maintainer label; +repro Task 2.5c R3: REPRO-on-dev | low | | -| #3603 | Any issue with git results in the unhelpful "404 not found" error | 2023-05-30 | kept-open | n/a | n/a | rule 1: updated 2023-05-30, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3604 | Task request: Update sfdx-project.json dependencies based off of computed cumulusci dependencies | 2023-05-30 | kept-open | n/a | n/a | rule 3: missing repro, cci-version; updated 2023-05-30; +repro Task 2.5c: REPRO | medium-high | | -| #3605 | Ability to Increment Major Versions when running `upload_production` | 2023-05-31 | closed:pr-resolved-#3651 | n/a | n/a | rule 1: updated 2023-05-31, no maintainer label; +repro Task 2.5c: NOT-REPRO | low | | -| #3607 | The `retry_failures` from the task `run_tests` is not working for me. | 2023-06-01 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-06-01, no maintainer label; +repro Task 2.5c: INCONCL:org-with-managed-package (confirms) | low | | -| #3609 | Command 'cci task run dx --command "plugins:install sfdx-browserforce-plugin"' fails | 2023-06-05 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-06-05, no maintainer label; +repro Task 2.5c: INCONCL:live-cli-test (confirms) | low | | -| #3610 | Error running `run_tests` task | 2023-06-05 | closed:pr-resolved-#3681 | n/a | n/a | rule 1: updated 2023-06-05, no maintainer label; +repro Task 2.5c R3: NOT-REPRO-on-dev (fixed on dev by PR #3681) | low | | -| #3612 | Maintain the CumulusCI for VSCode Extension | 2023-06-23 | closed:not-reproducible-on-v4.10.0 | n/a | n/a | rule 1: updated 2023-06-23, no maintainer label; +repro Task 2.5c: NOT-REPRO | low | | -| #3613 | AddFieldsToPageLayout | 2023-06-23 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-06-23, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | -| #3615 | update_dependencies does not honor resolution strategy | 2023-07-06 | closed:not-reproducible-on-v4.10.0 | n/a | n/a | rule 1: updated 2023-07-06, no maintainer label; +repro Task 2.5c: NOT-REPRO | low | | -| #3618 | Allow for list when using deleting/removing CumulusCI orgs (`cci org remove` and `cci org scratch_delete`) | 2023-07-13 | kept-open | n/a | n/a | rule 1: updated 2023-07-13, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3619 | Dependency_pins does not honor passwords | 2023-08-02 | kept-open | n/a | n/a | rule 1: updated 2023-08-02, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3641 | Prevent Downgrade of dependencies | 2024-05-17 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #3649 | Support serial loads with update_data task | 2023-09-08 | kept-open | n/a | n/a | rule 1: updated 2023-09-08, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3663 | When clause | Ability to pass in prior task response values | 2023-09-21 | kept-open | n/a | n/a | rule 1: updated 2023-09-21, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3692 | No parser configuration found for subdirectory digitalExperiences | 2023-10-30 | kept-open | n/a | n/a | rule 1: updated 2023-10-30, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3699 | Sort of the data during extraction | 2023-11-10 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-11-10, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | -| #3700 | Trying to do an upsert on a master-detail child object gets an error around permission | 2023-11-10 | kept-open | n/a | n/a | rule 1: updated 2023-11-10, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3701 | set a mapping to the id instead of it being either a number or the salesforce id | 2023-11-10 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-11-10, no maintainer label; +repro Task 2.5c: REPRO (confirms) | low | | -| #3717 | Github automerge feature task not working when running through Github Flows | 2023-12-08 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-12-08, no maintainer label; +repro Task 2.5c: INCONCL:cumulus-actions-workflow (confirms) | low | | -| #3721 | create_package_version version_name default should be version number, not "Release" | 2024-02-12 | kept-open | n/a | n/a | rule 1: updated 2024-02-12, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3733 | `cci org remove` doesn't remove org | 2025-02-01 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #3734 | Exception in cci task upload_production - Malformed Request Error: The version number must be greater than the last Managed - Released version number | 2024-02-15 | kept-open | n/a | n/a | rule 1: updated 2024-02-15, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3745 | cci flow run ci_beta AND cci task install_managed_beta DO not use the latest beta | 2024-02-13 | closed:stale-24mo | n/a | n/a | rule 1: updated 2024-02-13, no maintainer label; +repro Task 2.5c: NOT-REPRO (confirms) | low | | -| #3746 | Deleted Versions used for determining next version | 2024-02-09 | kept-open | n/a | n/a | rule 1: updated 2024-02-09, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3754 | Enable configuration for cci version update sources | 2024-05-16 | kept-open | n/a | n/a | rule 3: missing repro, cci-version; updated 2024-05-16; +repro Task 2.5c: REPRO | medium-high | | -| #3758 | Flow "push_upgrade_org" is incorrectly defined | 2024-02-28 | kept-open | n/a | n/a | rule 1: updated 2024-02-28, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3762 | `update_admin_profile` task fails on namespaced org with Person Accounts enabled | 2024-03-06 | closed:stale-24mo | n/a | n/a | rule 1: updated 2024-03-06, no maintainer label; +repro Task 2.5c: closed:duplicate-of-#3544 (confirms) | low | | -| #3763 | Namespace not being added into Flow references in minority of cases | 2024-06-18 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #3768 | Snowfakery Batch Size and Just Once | 2024-03-27 | kept-open | n/a | n/a | rule 1: updated 2024-03-27, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3770 | Error during cci task run retrieve_changes | 2024-08-05 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #3771 | find_replace transforms on XPath with predicates does not work | 2024-04-12 | kept-open | n/a | n/a | rule 1: updated 2024-04-12, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3773 | retrieve_profile task seems to be missing some Metadata | 2024-04-30 | kept-open | n/a | n/a | rule 1: updated 2024-04-30, no maintainer label; +repro Task 2.5c: REPRO | low | | -| #3781 | Package Versions Starting with 0 (0.1,0.2,0.3, etc.) Cause "does not exist" error When Referenced in cumulusci.yml Dependencies | 2024-06-13 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #3784 | Can't run test suites if project**test**name_match is defined | 2024-05-13 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #3796 | cci task run get_installed_packages/uninstall_managed do not see 2GP beta | 2024-06-03 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #3810 | Github tasks fail when using github enterprise | 2024-07-12 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #3849 | Installing CumulusCI v 4 installs the latest version of urllib3 which seems to be incompatable with running ROBOT tests | 2025-09-04 | kept-open | severity:minor,area:robotframework,v5-candidate:no,needs-repro | no | kept-open: bug, area:robotframework; +repro Task 2.5c R3: REPRO-on-dev | low | | -| #3852 | CumulusCI 4 refresh token error | 2025-06-09 | kept-open | severity:minor,area:auth,v5-candidate:no | no | kept-open: bug, area:auth; +repro Task 2.5c: REPRO (confirms) | low | | -| #3854 | Issue while Capturing Data | 2025-02-03 | kept-open | severity:minor,area:cli,v5-candidate:no | no | kept-open: bug, area:cli; +repro Task 2.5c: REPRO (confirms) | low | | -| #3873 | Standalone Robot Framework Library for Selenium-Based Salesforce Automation (Inspired by Copado QForce) | 2025-01-24 | kept-open | n/a | n/a | rule 3: missing cci-version; updated 2025-01-24; +repro Task 2.5c R3: REPRO-on-dev | medium-high | | -| #3884 | Running a Dev_Org flow goes through re-install of the the same package version again. | 2025-02-26 | closed:missing-fields | n/a | n/a | rule 3: missing cci-version; updated 2025-02-26; +repro Task 2.5c: INCONCL:project-with-managed-deps (confirms) | medium-high | | -| #3885 | Versioning in CumulusCI Releases Does Not Support Full Versioning with Build Numbers | 2025-03-21 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 1.x; no reporter v4+ reconfirmation | medium-high | | -| #3886 | Required Dependencies? | 2025-03-06 | kept-open | severity:minor,area:bulkdata,v5-candidate:no | no | kept-open: bug, area:bulkdata; +repro Task 2.5c: REPRO (confirms) | low | | -| #3887 | Version comparison bug: 0.10.0.1 incorrectly compared as less than 0.9.0.1 | 2025-03-06 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #3889 | Uninstall 2GP task request | 2025-03-21 | kept-open | n/a | n/a | rule 3: missing repro, cci-version; updated 2025-03-21; +repro Task 2.5c: REPRO | medium-high | | -| #3899 | Getting following Exception in task deploy_packaging.unschedule_apex | 2025-05-15 | kept-open | severity:minor,area:packaging,v5-candidate:no | no | kept-open: bug, area:packaging; +repro Task 2.5c: INCONCL:1gp-packaging-org (confirms) | low | | -| #3902 | Task install_managed security_type not being respected with 04t ID | 2025-06-03 | kept-open | severity:minor,area:packaging,v5-candidate:no | no | kept-open: bug, area:packaging; +repro Task 2.5c: INCONCL:managed-package-04t (confirms) | low | | -| #3910 | JSON Schema incorrectly defines namespaced field as string instead of boolean for scratch org configuration | 2025-07-14 | kept-open | severity:minor,area:keychain,v5-candidate:no | no | kept-open: bug, area:keychain; +repro Task 2.5c R3: REPRO-on-dev (open PR #3911 ready to land) | low | | -| #3919 | uninstall_packaged_incremental was purged even though it was set to "not" | 2025-08-15 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | -| #3929 | cci task run create_community (and sf community create) Appears to Loop/Timeout During Community Creation | 2025-10-22 | closed:not-reproducible-on-v4.10.0 | severity:minor,area:cli,v5-candidate:no,needs-repro | no | kept-open: bug, area:cli; +repro Task 2.5c: NOT-REPRO | low | | -| #3931 | Specifying a profile in cumulusci.tasks.salesforce.ProfileGrantAllAccess results in an error | 2025-10-17 | kept-open | severity:minor,area:metadata-etl,v5-candidate:no | no | kept-open: bug, area:metadata-etl; +repro Task 2.5c: REPRO (confirms) | low | | -| #3936 | Error: HTTPSConnectionPool(host='yoursite.scratch.my.salesforce.com', port=443): Read timed out. (read timeout=None) | 2025-12-03 | kept-open | severity:minor,area:bulkdata,v5-candidate:no | no | kept-open: bug, area:bulkdata; +repro Task 2.5c: INCONCL:flaky-network (confirms) | low | | -| #3938 | Rest_Deploy ignores errors | 2025-12-16 | kept-open | severity:minor,area:other,v5-candidate:no | no | kept-open: bug, area:other; +repro Task 2.5c: REPRO (confirms) | low | | -| #3939 | Deploy task can't parse SOAP Response | 2025-12-16 | kept-open | severity:minor,area:other,v5-candidate:no | no | kept-open: bug, area:other; +repro Task 2.5c: REPRO (confirms) | low | | -| #3951 | set_duplicate_rule_status broken | 2026-02-03 | kept-open | severity:minor,area:metadata-etl,v5-candidate:no | no | kept-open: bug, area:metadata-etl; +repro Task 2.5c: REPRO (confirms) | low | | -| #3953 | add_picklist_entries never works through CLI | 2026-02-13 | kept-open | severity:minor,area:metadata-etl,v5-candidate:no | no | kept-open: bug, area:metadata-etl; +repro Task 2.5c: REPRO (confirms) | low | | -| #3955 | Open Test Browser - SalesforcePlaywright.robot | 2026-03-05 | kept-open | severity:minor,area:robotframework,v5-candidate:no,needs-repro | no | kept-open: bug, area:robotframework; +repro Task 2.5c R3: REPRO-on-dev | low | | +| issue# | title | last-activity | proposed-pass1 | proposed-pass2 | proposed-v5 | rule-rationale | risk | approval | +| -----: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------- | ---------------------------------- | -------------------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | -------- | +| #675 | Show full traceback for Python exceptions in robot keywords | 2018-09-11 | closed:stale-24mo | n/a | n/a | rule 1: updated 2018-09-11, no maintainer label; +repro: REPRO-on-dev | low | | +| #710 | Allow disabling default scratch org configs | 2018-11-02 | kept-open | n/a | n/a | rule 1: updated 2018-11-02, no maintainer label; +repro: REPRO-on-dev | low | | +| #733 | Prompt to delete scratch org when creating one that already exists | 2018-09-11 | closed:stale-24mo | n/a | n/a | rule 1: updated 2018-09-11, no maintainer label; +repro the reproducibility pass: REPRO (confirms) | low | | +| #773 | Document task return values and results | 2018-11-19 | kept-open | n/a | n/a | rule 1: updated 2018-11-19, no maintainer label; +repro: REPRO-on-dev | low | | +| #808 | deploy_packaging flow runs uninstall_packaged_incremental with wrong package name | 2018-10-09 | kept-open | n/a | n/a | rule 1: updated 2018-10-09, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #987 | Last week this test worked, now I get a javascriptexception message. | 2022-06-16 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-06-16, no maintainer label; +repro: NOT-REPRO-on-dev | low | | +| #1348 | Multiple Git Provider Support | 2022-11-07 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-11-07, no maintainer label; +repro the reproducibility pass: REPRO (confirms) | low | | +| #1350 | Unable to run tasks in remote projects | 2022-07-07 | closed:not-reproducible-on-v4.10.0 | n/a | n/a | rule 1: updated 2022-07-07, no maintainer label; +repro the reproducibility pass: NOT-REPRO | low | | +| #1432 | CCI Inconsistencies in validating arguments | 2020-01-03 | closed:stale-24mo | n/a | n/a | rule 1: updated 2020-01-03, no maintainer label; +repro the reproducibility pass: REPRO (confirms) | low | | +| #1769 | Unusual case in test_load | 2020-08-07 | closed:stale-24mo | n/a | n/a | rule 1: updated 2020-08-07, no maintainer label; +repro the reproducibility pass: REPRO (confirms) | low | | +| #2013 | Mapping files with steps that are not 1-1 with SObjects are unreliable for extraction | 2020-09-13 | kept-open | n/a | n/a | rule 1: updated 2020-09-13, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #2096 | REST dataloads throw errors that Bulk loads do not. | 2020-10-15 | closed:not-reproducible-on-v4.10.0 | n/a | n/a | rule 1: updated 2020-10-15, no maintainer label; +repro the reproducibility pass: NOT-REPRO | low | | +| #2126 | Support task to encrypt all possible fields with probabilistic encryption | 2022-01-28 | closed:stale-24mo | n/a | n/a | rule 3: missing cci-version; updated 2022-01-28; +repro: NOT-REPRO-on-dev | medium-high | | +| #2140 | Prompt Org Configs when Org Does Not Exist and Command Runs Against It | 2022-05-20 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-05-20, no maintainer label; +repro the reproducibility pass: REPRO (confirms) | low | | +| #2153 | Add comment to original PR which tags all branch subscribers when a merge conflict auto-generated PR is created ("Merge master into ") | 2020-11-11 | kept-open | n/a | n/a | rule 1: updated 2020-11-11, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #2325 | Task to turn off validation rules to allow data insert | 2021-01-19 | kept-open | n/a | n/a | rule 1: updated 2021-01-19, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #2402 | Create a --rebuild-org parameter for cci flow run | 2022-01-28 | closed:stale-24mo | n/a | n/a | rule 3: missing repro, cci-version; updated 2022-01-28; +repro the reproducibility pass: REPRO | medium-high | | +| #2440 | add_permission_set_perms throws 'string indices must be integers' error | 2022-01-28 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #2500 | ignore_failure is not documented | 2022-03-28 | kept-open | n/a | n/a | rule 3: missing repro, cci-version; updated 2022-03-28; +repro: REPRO-on-dev | medium-high | | +| #2505 | Filtering records to be extracted | 2021-06-02 | closed:feature-implemented | n/a | n/a | rule 1: updated 2021-06-02, no maintainer label; +repro the reproducibility pass: NOT-REPRO | low | | +| #2506 | Bulk Operations should have a --debug mode which maintains logs and tempfiles | 2021-03-27 | kept-open | n/a | n/a | rule 1: updated 2021-03-27, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #2507 | Undo mode for CumulusCI Insert | 2021-03-27 | closed:stale-24mo | n/a | n/a | rule 1: updated 2021-03-27, no maintainer label; +repro the reproducibility pass: REPRO (confirms) | low | | +| #2508 | Manual load retries | 2021-03-27 | kept-open | n/a | n/a | rule 1: updated 2021-03-27, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #2667 | `cci org connect` should output the name of the connected app it is using, especially if it is non-default | 2022-01-28 | closed:stale-24mo | n/a | n/a | rule 3: missing repro, cci-version; updated 2022-01-28; +repro: NOT-REPRO-on-dev | medium-high | | +| #2697 | Initialization issue with 'namespaced' field in 'cci org info' after updating from a non-namespaced scratch org to namespaced | 2021-06-25 | closed:stale-24mo | n/a | n/a | rule 1: updated 2021-06-25, no maintainer label; +repro the reproducibility pass: INCONCL:scratch-slot (confirms) | low | | +| #2826 | The deploy_unmanaged flow is supposed to silently do nothing if there's not actually a package directory | 2021-08-25 | kept-open | n/a | n/a | rule 1: updated 2021-08-25, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #2930 | Exception in task load_dataset | 2022-01-28 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #2951 | Error in task load_dataset - Standard_price_not_defined | 2021-11-11 | kept-open | n/a | n/a | rule 1: updated 2021-11-11, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #2973 | cumulusci.tasks.salesforce.CreateCommunity has no option to set authentication mode for LWR Community | 2022-01-28 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #2979 | deploy task should deploy from the default entry in packageDirectories in sfdx-project.json if the project is using sfdx format. | 2021-11-17 | kept-open | n/a | n/a | rule 1: updated 2021-11-17, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3015 | Request to have the ability to remove an imported dx org from cci org list without deleting the actual scratch org. | 2022-01-28 | closed:stale-24mo | n/a | n/a | rule 3: missing repro, cci-version; updated 2022-01-28; +repro the reproducibility pass: REPRO | medium-high | | +| #3024 | Order of flow groups in cumulusci/cumulusci.yml reflects in the Flows box in CCI VSCode extension, but order is not natural | 2022-01-05 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-01-05, no maintainer label; +repro the reproducibility pass: REPRO (confirms) | low | | +| #3045 | create_bulk_data_permission_set errors on multiple runs | 2022-01-28 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3047 | Open Test Browser TypeError: 'NoneType' object is not callable when using useralias param | 2022-01-28 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3089 | task run_tests not including namespace in query | 2022-02-21 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3100 | uninstall_post is not substituting %%%NAMESPACE%%% | 2023-10-02 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3134 | Running flow always needs a default org or org defined | 2022-04-18 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3137 | cci task run update_package_xml and Salesforce Case Custom Object | 2022-05-18 | kept-open | n/a | n/a | rule 3: missing repro; updated 2022-05-18; +repro the reproducibility pass: REPRO | medium-high | | +| #3161 | Ability to Hide Option Values When Using Task Options In a Task or Flow Run | 2022-04-21 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-04-21, no maintainer label; +repro the reproducibility pass: REPRO (confirms) | low | | +| #3165 | Update Admin Profile task fails when specifying records types without custom package.xml | 2022-04-19 | kept-open | n/a | n/a | rule 1: updated 2022-04-19, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3167 | Add ability to define page layout assignments with record types using the update_admin_profile task | 2022-04-20 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-04-20, no maintainer label; +repro the reproducibility pass: NOT-REPRO (confirms) | low | | +| #3182 | "Error: 'utf-8' codec can't decode byte 0x80 in position 0: invalid start byte" when running any CCI command after connecting Github service | 2025-02-19 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3203 | generate_and_load_from_yaml task record type extraction fails for namespaced custom objects | 2023-01-09 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3283 | json parser error when empty string passed for date field during upsert or update | 2022-09-16 | closed:pr-resolved-#3361 | n/a | n/a | rule 1: updated 2022-09-16, no maintainer label; +repro the reproducibility pass: NOT-REPRO | low | | +| #3306 | Preview Toggle for Scratch org def file | 2023-09-13 | kept-open | n/a | n/a | rule 3: missing repro, cci-version; updated 2023-09-13; +repro: NOT-REPRO-on-dev | medium-high | | +| #3307 | Project Template Support for initialisation | 2022-07-25 | closed:stale-24mo | n/a | n/a | rule 3: missing repro, cci-version; updated 2022-07-25; +repro the reproducibility pass: REPRO | medium-high | | +| #3320 | Metadata ETL task to Deactivate a Flow | 2023-02-15 | closed:feature-implemented | n/a | n/a | rule 3: missing repro, cci-version; updated 2023-02-15; +repro the reproducibility pass: NOT-REPRO | medium-high | | +| #3331 | Task update_package_xml does not write correct package.xml for AssignmentRules | 2022-10-11 | kept-open | n/a | n/a | rule 1: updated 2022-10-11, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3347 | Cannot release an unlocked beta package with release_unlocked_beta flow | 2022-08-29 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-08-29, no maintainer label; +repro the reproducibility pass: NOT-REPRO (confirms) | low | | +| #3349 | Make generated dataset recordType tables unique based on table instead of sf_object | 2022-09-26 | kept-open | n/a | n/a | rule 3: missing repro, cci-version; updated 2022-09-26; +repro the reproducibility pass: REPRO | medium-high | | +| #3353 | Enable Snowfakery task to use recipes from other repositories | 2024-08-20 | kept-open | n/a | n/a | rule 3: missing repro, cci-version; updated 2024-08-20; +repro the reproducibility pass: REPRO | medium-high | | +| #3360 | Read Only Object Lookup for Load_Dataset | 2022-09-15 | closed:feature-implemented | n/a | n/a | rule 1: updated 2022-09-15, no maintainer label; +repro the reproducibility pass: NOT-REPRO | low | | +| #3376 | extract_dataset sql error | 2022-10-03 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3407 | `set_service(service_config)` type signature is wrong | 2022-10-19 | kept-open | n/a | n/a | rule 1: updated 2022-10-19, no maintainer label; +repro: REPRO-on-dev | low | | +| #3418 | Error creating 1gp release | 2022-11-01 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-11-01, no maintainer label; +repro the reproducibility pass: INCONCL:cumulus-actions-workflow (confirms) | low | | +| #3429 | Support overriding `cumulusci.yml` to be used for configuration | 2022-11-08 | kept-open | n/a | n/a | rule 1: updated 2022-11-08, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3440 | Enhance default_package_path to serve multi package projects better | 2022-11-17 | kept-open | n/a | n/a | rule 1: updated 2022-11-17, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3441 | "cci task run create_package_version" should allow option "version_base: default" in cumulusci.yml | 2023-12-15 | kept-open | n/a | n/a | rule 1: updated 2023-12-15, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3446 | CCI task "push_qa" crashes for Unlocked package with no namespace | 2022-12-13 | kept-open | n/a | n/a | rule 1: updated 2022-12-13, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3464 | Provide concise documentation of cumulusci.yml `project` configuration options | 2022-12-12 | kept-open | n/a | n/a | rule 1: updated 2022-12-12, no maintainer label; +repro: REPRO-on-dev | low | | +| #3466 | Ability to specify a test suite to run instead of just test_name_match in the run_tests task | 2022-12-13 | closed:feature-implemented | n/a | n/a | rule 3: missing repro, cci-version; updated 2022-12-13; +repro the reproducibility pass: NOT-REPRO | medium-high | | +| #3470 | Rename `ci_master` flow to a `ci_main` or at least create a new duplicate `ci_main` flow | 2022-12-16 | closed:stale-24mo | n/a | n/a | rule 1: updated 2022-12-16, no maintainer label; +repro the reproducibility pass: REPRO (confirms) | low | | +| #3471 | `Merged 0 commits into branch:` message displays when a non-Source Code change is made in `github_automerge_feature` task | 2022-12-16 | kept-open | n/a | n/a | rule 1: updated 2022-12-16, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3479 | Error with "cci org import" in github action | 2023-02-22 | closed:not-reproducible-on-v4.10.0 | n/a | n/a | rule 1: updated 2023-02-22, no maintainer label; +repro the reproducibility pass: NOT-REPRO | low | | +| #3485 | "cci task run run_tests" generates incorrect test_results.xml format output | 2024-01-28 | kept-open | n/a | n/a | rule 1: updated 2024-01-28, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3492 | Enhance the "-o" option of "cci flow run" to accept "project\_\_custom" attribute values | 2023-01-17 | kept-open | n/a | n/a | rule 1: updated 2023-01-17, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3506 | when clause support for flow steps which call other flows | 2023-01-25 | kept-open | n/a | n/a | rule 1: updated 2023-01-25, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3512 | `namespace` does not display when running `cci org info` on a packaging org (does work when you add `--json` flag) | 2023-02-03 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3518 | Task add_picklist_entries always sets a default value for record types | 2023-02-03 | kept-open | n/a | n/a | rule 1: updated 2023-02-03, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3541 | Getting None\_\_dev as SFDX Alias | 2023-07-07 | kept-open | n/a | n/a | rule 1: updated 2023-07-07, no maintainer label; +repro: REPRO-on-dev | low | | +| #3542 | 2GP flows fail in the local environment to test: `ci_feature_2gp` or `qa_org_2gp` with error: Could not find package version id | 2023-02-22 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-02-22, no maintainer label; +repro the reproducibility pass: INCONCL:2GP-CI-pipeline (confirms) | low | | +| #3543 | New Option `load_sfdx_project_paths` for dx_convert_from Task | 2023-03-30 | kept-open | n/a | n/a | rule 1: updated 2023-03-30, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3544 | Task `update_admin_profile` errors when the org has person accounts and a namespace | 2025-05-07 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation; +repro the reproducibility pass: INCONCL:namespaced-project (confirms) | medium-high | | +| #3546 | password_env_name bleeding over to next package | 2024-09-13 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3549 | Deploy to Salesforce does not create a test output | 2023-04-05 | kept-open | n/a | n/a | rule 1: updated 2023-04-05, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3561 | Retrieve_unpackaged unusable in MetaDeploy | 2023-03-15 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-03-15, no maintainer label; +repro the reproducibility pass: NOT-REPRO (confirms) | low | | +| #3563 | Unmanaged Metadata not deploying during 2GP Package Create | 2024-06-21 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3570 | Feature Request: Flow "finally" or "error" path | 2023-04-04 | kept-open | n/a | n/a | rule 1: updated 2023-04-04, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3585 | Error Occurs when Using `update_package_xml` on object with `xsi:nil="true"` | 2023-04-19 | kept-open | n/a | n/a | rule 1: updated 2023-04-19, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3587 | Warning message when attempting to set `--install_class` or `--uninstall_class` flag on `update_package_xml` and `--managed` is `false` or null (defaults to true) | 2023-04-23 | kept-open | n/a | n/a | rule 1: updated 2023-04-23, no maintainer label; +repro the reproducibility pass: NOT-REPRO | low | | +| #3589 | "Workflow" and "MatchingRules" are removed from package.xml after running "update_package_xml" task | 2023-04-25 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3592 | release_unlocked_beta doesn't work when an install key is specified | 2023-08-02 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3593 | `dx` task doesn't work for some commands like `project convert source` | 2023-05-03 | kept-open | n/a | n/a | rule 1: updated 2023-05-03, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3600 | Allow install_managed to use environment variables | 2023-05-25 | kept-open | n/a | n/a | rule 1: updated 2023-05-25, no maintainer label; +repro the reproducibility pass: NOT-REPRO | low | | +| #3602 | Need Chrome/Firefox options(browser options/capabilities) in 'Open Test Browser' Keyword | 2023-05-26 | kept-open | n/a | n/a | rule 1: updated 2023-05-26, no maintainer label; +repro: REPRO-on-dev | low | | +| #3603 | Any issue with git results in the unhelpful "404 not found" error | 2023-05-30 | kept-open | n/a | n/a | rule 1: updated 2023-05-30, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3604 | Task request: Update sfdx-project.json dependencies based off of computed cumulusci dependencies | 2023-05-30 | kept-open | n/a | n/a | rule 3: missing repro, cci-version; updated 2023-05-30; +repro the reproducibility pass: REPRO | medium-high | | +| #3605 | Ability to Increment Major Versions when running `upload_production` | 2023-05-31 | closed:pr-resolved-#3651 | n/a | n/a | rule 1: updated 2023-05-31, no maintainer label; +repro the reproducibility pass: NOT-REPRO | low | | +| #3607 | The `retry_failures` from the task `run_tests` is not working for me. | 2023-06-01 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-06-01, no maintainer label; +repro the reproducibility pass: INCONCL:org-with-managed-package (confirms) | low | | +| #3609 | Command 'cci task run dx --command "plugins:install sfdx-browserforce-plugin"' fails | 2023-06-05 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-06-05, no maintainer label; +repro the reproducibility pass: INCONCL:live-cli-test (confirms) | low | | +| #3610 | Error running `run_tests` task | 2023-06-05 | closed:pr-resolved-#3681 | n/a | n/a | rule 1: updated 2023-06-05, no maintainer label; +repro: NOT-REPRO-on-dev (fixed on dev by PR #3681) | low | | +| #3612 | Maintain the CumulusCI for VSCode Extension | 2023-06-23 | closed:not-reproducible-on-v4.10.0 | n/a | n/a | rule 1: updated 2023-06-23, no maintainer label; +repro the reproducibility pass: NOT-REPRO | low | | +| #3613 | AddFieldsToPageLayout | 2023-06-23 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-06-23, no maintainer label; +repro the reproducibility pass: REPRO (confirms) | low | | +| #3615 | update_dependencies does not honor resolution strategy | 2023-07-06 | closed:not-reproducible-on-v4.10.0 | n/a | n/a | rule 1: updated 2023-07-06, no maintainer label; +repro the reproducibility pass: NOT-REPRO | low | | +| #3618 | Allow for list when using deleting/removing CumulusCI orgs (`cci org remove` and `cci org scratch_delete`) | 2023-07-13 | kept-open | n/a | n/a | rule 1: updated 2023-07-13, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3619 | Dependency_pins does not honor passwords | 2023-08-02 | kept-open | n/a | n/a | rule 1: updated 2023-08-02, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3641 | Prevent Downgrade of dependencies | 2024-05-17 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3649 | Support serial loads with update_data task | 2023-09-08 | kept-open | n/a | n/a | rule 1: updated 2023-09-08, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3663 | When clause | Ability to pass in prior task response values | 2023-09-21 | kept-open | n/a | n/a | rule 1: updated 2023-09-21, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3692 | No parser configuration found for subdirectory digitalExperiences | 2023-10-30 | kept-open | n/a | n/a | rule 1: updated 2023-10-30, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3699 | Sort of the data during extraction | 2023-11-10 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-11-10, no maintainer label; +repro the reproducibility pass: REPRO (confirms) | low | | +| #3700 | Trying to do an upsert on a master-detail child object gets an error around permission | 2023-11-10 | kept-open | n/a | n/a | rule 1: updated 2023-11-10, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3701 | set a mapping to the id instead of it being either a number or the salesforce id | 2023-11-10 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-11-10, no maintainer label; +repro the reproducibility pass: REPRO (confirms) | low | | +| #3717 | Github automerge feature task not working when running through Github Flows | 2023-12-08 | closed:stale-24mo | n/a | n/a | rule 1: updated 2023-12-08, no maintainer label; +repro the reproducibility pass: INCONCL:cumulus-actions-workflow (confirms) | low | | +| #3721 | create_package_version version_name default should be version number, not "Release" | 2024-02-12 | kept-open | n/a | n/a | rule 1: updated 2024-02-12, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3733 | `cci org remove` doesn't remove org | 2025-02-01 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3734 | Exception in cci task upload_production - Malformed Request Error: The version number must be greater than the last Managed - Released version number | 2024-02-15 | kept-open | n/a | n/a | rule 1: updated 2024-02-15, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3745 | cci flow run ci_beta AND cci task install_managed_beta DO not use the latest beta | 2024-02-13 | closed:stale-24mo | n/a | n/a | rule 1: updated 2024-02-13, no maintainer label; +repro the reproducibility pass: NOT-REPRO (confirms) | low | | +| #3746 | Deleted Versions used for determining next version | 2024-02-09 | kept-open | n/a | n/a | rule 1: updated 2024-02-09, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3754 | Enable configuration for cci version update sources | 2024-05-16 | kept-open | n/a | n/a | rule 3: missing repro, cci-version; updated 2024-05-16; +repro the reproducibility pass: REPRO | medium-high | | +| #3758 | Flow "push_upgrade_org" is incorrectly defined | 2024-02-28 | kept-open | n/a | n/a | rule 1: updated 2024-02-28, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3762 | `update_admin_profile` task fails on namespaced org with Person Accounts enabled | 2024-03-06 | closed:stale-24mo | n/a | n/a | rule 1: updated 2024-03-06, no maintainer label; +repro the reproducibility pass: closed:duplicate-of-#3544 (confirms) | low | | +| #3763 | Namespace not being added into Flow references in minority of cases | 2024-06-18 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3768 | Snowfakery Batch Size and Just Once | 2024-03-27 | kept-open | n/a | n/a | rule 1: updated 2024-03-27, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3770 | Error during cci task run retrieve_changes | 2024-08-05 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3771 | find_replace transforms on XPath with predicates does not work | 2024-04-12 | kept-open | n/a | n/a | rule 1: updated 2024-04-12, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3773 | retrieve_profile task seems to be missing some Metadata | 2024-04-30 | kept-open | n/a | n/a | rule 1: updated 2024-04-30, no maintainer label; +repro the reproducibility pass: REPRO | low | | +| #3781 | Package Versions Starting with 0 (0.1,0.2,0.3, etc.) Cause "does not exist" error When Referenced in cumulusci.yml Dependencies | 2024-06-13 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3784 | Can't run test suites if project**test**name_match is defined | 2024-05-13 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3796 | cci task run get_installed_packages/uninstall_managed do not see 2GP beta | 2024-06-03 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3810 | Github tasks fail when using github enterprise | 2024-07-12 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3849 | Installing CumulusCI v 4 installs the latest version of urllib3 which seems to be incompatable with running ROBOT tests | 2025-09-04 | kept-open | severity:minor,area:robotframework,v5-candidate:no,needs-repro | no | kept-open: bug, area:robotframework; +repro: REPRO-on-dev | low | | +| #3852 | CumulusCI 4 refresh token error | 2025-06-09 | kept-open | severity:minor,area:auth,v5-candidate:no | no | kept-open: bug, area:auth; +repro the reproducibility pass: REPRO (confirms) | low | | +| #3854 | Issue while Capturing Data | 2025-02-03 | kept-open | severity:minor,area:cli,v5-candidate:no | no | kept-open: bug, area:cli; +repro the reproducibility pass: REPRO (confirms) | low | | +| #3873 | Standalone Robot Framework Library for Selenium-Based Salesforce Automation (Inspired by Copado QForce) | 2025-01-24 | kept-open | n/a | n/a | rule 3: missing cci-version; updated 2025-01-24; +repro: REPRO-on-dev | medium-high | | +| #3884 | Running a Dev_Org flow goes through re-install of the the same package version again. | 2025-02-26 | closed:missing-fields | n/a | n/a | rule 3: missing cci-version; updated 2025-02-26; +repro the reproducibility pass: INCONCL:project-with-managed-deps (confirms) | medium-high | | +| #3885 | Versioning in CumulusCI Releases Does Not Support Full Versioning with Build Numbers | 2025-03-21 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 1.x; no reporter v4+ reconfirmation | medium-high | | +| #3886 | Required Dependencies? | 2025-03-06 | kept-open | severity:minor,area:bulkdata,v5-candidate:no | no | kept-open: bug, area:bulkdata; +repro the reproducibility pass: REPRO (confirms) | low | | +| #3887 | Version comparison bug: 0.10.0.1 incorrectly compared as less than 0.9.0.1 | 2025-03-06 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3889 | Uninstall 2GP task request | 2025-03-21 | kept-open | n/a | n/a | rule 3: missing repro, cci-version; updated 2025-03-21; +repro the reproducibility pass: REPRO | medium-high | | +| #3899 | Getting following Exception in task deploy_packaging.unschedule_apex | 2025-05-15 | kept-open | severity:minor,area:packaging,v5-candidate:no | no | kept-open: bug, area:packaging; +repro the reproducibility pass: INCONCL:1gp-packaging-org (confirms) | low | | +| #3902 | Task install_managed security_type not being respected with 04t ID | 2025-06-03 | kept-open | severity:minor,area:packaging,v5-candidate:no | no | kept-open: bug, area:packaging; +repro the reproducibility pass: INCONCL:managed-package-04t (confirms) | low | | +| #3910 | JSON Schema incorrectly defines namespaced field as string instead of boolean for scratch org configuration | 2025-07-14 | kept-open | severity:minor,area:keychain,v5-candidate:no | no | kept-open: bug, area:keychain; +repro: REPRO-on-dev (open PR #3911 ready to land) | low | | +| #3919 | uninstall_packaged_incremental was purged even though it was set to "not" | 2025-08-15 | closed:pre-v4.0.0 | n/a | n/a | rule 2: body declares CumulusCI 3.x; no reporter v4+ reconfirmation | medium-high | | +| #3929 | cci task run create_community (and sf community create) Appears to Loop/Timeout During Community Creation | 2025-10-22 | closed:not-reproducible-on-v4.10.0 | severity:minor,area:cli,v5-candidate:no,needs-repro | no | kept-open: bug, area:cli; +repro the reproducibility pass: NOT-REPRO | low | | +| #3931 | Specifying a profile in cumulusci.tasks.salesforce.ProfileGrantAllAccess results in an error | 2025-10-17 | kept-open | severity:minor,area:metadata-etl,v5-candidate:no | no | kept-open: bug, area:metadata-etl; +repro the reproducibility pass: REPRO (confirms) | low | | +| #3936 | Error: HTTPSConnectionPool(host='yoursite.scratch.my.salesforce.com', port=443): Read timed out. (read timeout=None) | 2025-12-03 | kept-open | severity:minor,area:bulkdata,v5-candidate:no | no | kept-open: bug, area:bulkdata; +repro the reproducibility pass: INCONCL:flaky-network (confirms) | low | | +| #3938 | Rest_Deploy ignores errors | 2025-12-16 | kept-open | severity:minor,area:other,v5-candidate:no | no | kept-open: bug, area:other; +repro the reproducibility pass: REPRO (confirms) | low | | +| #3939 | Deploy task can't parse SOAP Response | 2025-12-16 | kept-open | severity:minor,area:other,v5-candidate:no | no | kept-open: bug, area:other; +repro the reproducibility pass: REPRO (confirms) | low | | +| #3951 | set_duplicate_rule_status broken | 2026-02-03 | kept-open | severity:minor,area:metadata-etl,v5-candidate:no | no | kept-open: bug, area:metadata-etl; +repro the reproducibility pass: REPRO (confirms) | low | | +| #3953 | add_picklist_entries never works through CLI | 2026-02-13 | kept-open | severity:minor,area:metadata-etl,v5-candidate:no | no | kept-open: bug, area:metadata-etl; +repro the reproducibility pass: REPRO (confirms) | low | | +| #3955 | Open Test Browser - SalesforcePlaywright.robot | 2026-03-05 | kept-open | severity:minor,area:robotframework,v5-candidate:no,needs-repro | no | kept-open: bug, area:robotframework; +repro: REPRO-on-dev | low | | diff --git a/docs/triage/v5/repro-results.csv b/docs/triage/v5/repro-results.csv index 918d85954c..e5644bbe21 100644 --- a/docs/triage/v5/repro-results.csv +++ b/docs/triage/v5/repro-results.csv @@ -1,116 +1,116 @@ -number,theme,bucket,repro_type,verdict,evidence_summary,repro_test_path,recommended_pass1,recommended_pass2_labels,verdict_source,notes -675,robotframework,feature-request,feature,REPRODUCED-on-dev,cumulusci/tasks/robotframework/robotframework.py does not configure traceback logging; rg 'traceback|format_exc|format_tb' in cumulusci/robotframework returns 0 matches. Default robot output shows only the exception's str(); full Python tracebacks require --loglevel TRACE or a custom listener which cumulusci does not provide.,,closed:stale-24mo,"cli-usability,robotframework,stale",dev,"Issue from 2018-07, last activity 2018-09, no activity for ~8 years. Two pragmatic workarounds exist today: (1) users can pass options=loglevel:TRACE to the robot task; (2) python keywords can wrap with traceback.format_exc() and log themselves. Workarounds make this low-priority. Close as stale." -710,scratch-org-config,feature,unit-pytest,REPRODUCED-on-dev,"The four+ default scratch org configs in cumulusci/cumulusci.yml:1559 cannot be disabled by a project. `merge_config` (cumulusci/core/utils.py:158, via dictmerge) drops ``None`` overrides, and BaseProjectKeychain._load_scratch_orgs (cumulusci/core/keychain/base_project_keychain.py:149) iterates every key unconditionally. Two XFAIL assertions added showing the issue's proposed `config_file: None` syntax has no effect today.",cumulusci/tests/triage/test_issue_710.py,keep-open,"enhancement,needs-spec",dev,"API question: should disabling use `config_file: None`, an explicit `disabled: true` flag, or sentinel removal? Tests assert end-state (`dev not in keychain.orgs`) so any of those implementations would pass." -733,cli,A,feature,REPRODUCED-on-v4.10.0,runtime.py:131-133 still raises ClickException with same hard error message; no interactive prompt path,,closed:stale-24mo,"enhancement,cli-usability,stale",v4.10.0,Stale 7yr feature request; confirm dry-run proposal stands -773,docs,feature-with-doc-component,doc-gap,REPRODUCED-on-dev,"cdcarter (2018) asked for tasks to declare ``return_values``/``result`` and for ``cci task info`` plus the web docs to surface them. On dev (1925a3083), ``BaseTask`` (``cumulusci/core/tasks.py:51``) only declares ``return_values`` as a runtime dict (line 64, populated as ``self.return_values = {}`` at line 92) — no declarative schema attribute. ``doc_task()`` in ``cumulusci/utils/__init__.py:354`` walks ``task_options`` and a free-form ``task_docs`` string but emits no ""Return Values"" / ""Returns"" section. The docs themselves admit the gap: ``docs/config.md:740-744`` literally says ""Current task return values are _not_ documented, so finding return values set by a specific task (if any) requires you to read the source code"". 8 years stale but still 100% accurate.",/tmp/repro/17/tests/test_issue_773.py,keep-open,"area/docs,area/tasks,type/enhancement",dev,"Pass-2: still actionable. Fix sketch: add a class attr like ``return_values_schema: Dict[str, str]`` (key -> one-line description) on BaseTask, extend ``doc_task`` to render a ""Return Values"" RST section when the attr is non-empty, and backfill the common return-value-emitting tasks (PackageUpload, GithubRelease, PromotePackageVersion, etc.). Same convention can power web docs since web docs use the same ``doc_task``." -808,metadata-etl,B,bug,REPRODUCED-on-dev,UninstallPackaged._init_options (cumulusci/tasks/salesforce/UninstallPackaged.py:25) defaults the 'package' option to project__package__name only; project__package__name_managed is never consulted (compare InstallPackageVersion which does fall back through name_managed -> name -> namespace at install_package_version.py:75-79). uninstall_packaged_incremental therefore retrieves the wrong package when name_managed is set,,keep-open,"bug,good-first-issue",dev,"Static-analysis confirmation; live repro needs a packaging org with a managed package whose name differs from project__package__name. Minimal fix: in UninstallPackaged._init_options, do `self.project_config.project__package__name_managed or self.project_config.project__package__name`. Also revisit jlantz's 2018 follow-up about deprecating name_managed entirely.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d)." -987,robotframework,user-error-or-stale,bug,NOT-REPRODUCED-on-dev,"Issue is Spring 19 Salesforce + Chromedriver 2.46 + Selenium ~3.x shadow-DOM-specific. Reporter explicitly stated workaround works (""I figured out a work-around. Use firefox with geckodriver. Everything works as intended now."") and the underlying Chrome/Selenium/Salesforce stack has changed substantially. cumulusci/robotframework/Salesforce.py:154 click_object_button still uses _jsclick but the upstream shadow-DOM bug it depends on no longer manifests the same way.",,closed:stale-24mo,"stale,user-error",dev,"Reporter found workaround within days; last meaningful activity 2022-06. Spring 19 UI no longer exists. 7 years stale, ineligible for repro without specific reproducible scenario." -1348,cli,A,feature,REPRODUCED-on-v4.10.0,No 'gitlab' or 'bitbucket' references anywhere in cumulusci/; ci_feature flow still uses github_parent_pr_notes/github_automerge_feature tasks,,closed:stale-24mo,"enhancement,stale,wontfix-candidate",v4.10.0,Architectural change scoped to GitHub only; stale 6yr -1350,cli,A,bug,NOT-REPRODUCED-on-v4.10.0,project_config.py:52-57 sets up synthetic 'tasks' namespace package; include_source() at line 662 calls _add_tasks_directory_to_python_path() which extends tasks.__path__ for each loaded source,,closed:not-reproducible-on-v4.10.0,fixed,v4.10.0,Original ModuleNotFoundError fixed via tasks namespace package; collision concern raised in 2022 comments is separate -1432,cli,A,bug,REPRODUCED-on-v4.10.0,core/tasks.py:186-196 _validate_options() only checks required; old-style task_options dict path silently accepts unknown keys (test passed). Pydantic Options class path now rejects extras.,/tmp/repro/7/tests/test_1432_options_validation.py,closed:stale-24mo,"bug,stale,partially-fixed",v4.10.0,Partially mitigated for tasks using new Pydantic Options class; old task_options dict still vulnerable -1769,bulkdata,A,bug,REPRODUCED-on-v4.10.0,"Test code-smell: `lookups[""Id""] = MappingLookup(name=""Id"", table=""accounts"", key_field=""sf_id"")` pattern still present in test_load.py:736 (was line 352 in 2020). davidmreed acknowledged ""horrible hack"" but never refactored. Pattern repeats at lines 754, 773, 801. Used to express UPDATE-on-Id dependency in `_expand_mapping` after_steps fixtures.",,closed:stale-24mo,"test-cleanup,low-priority",v4.10.0,"Issue is a test-fixture style question, never escalated to bug. 6 yrs old." -2013,bulkdata,A,bug,REPRODUCED-on-v4.10.0,"`create_table_if_needed` (utils.py:133-139) calls `Table(tablename, metadata, *fields)` then checks `inspector.has_table()` for the BulkDataException. SQLAlchemy raises `InvalidRequestError: Table 'X' is already defined for this MetaData instance` BEFORE the inspector check fires. Reproduced exact 2020 traceback verbatim with two MappingStep(sf_object=Account, table=Account) entries.",/tmp/repro/9/tests/test_2013_multistep.py,keep-open,"bug,bulkdata,extract_dataset,error-handling",v4.10.0,"Trivial fix: try/except around Table() to convert to BulkDataException, or use `extend_existing=True`. Or detect the duplicate-table case in mapping_parser at validation time." -2096,bulkdata,A,bug,NOT-REPRODUCED-on-v4.10.0,REST DML (`step.py:778-784 RestApiDmlOperation._record_to_json`) calls `process_bool_arg` for boolean fields. `process_bool_arg` (core/utils.py:53-83) accepts the full Salesforce Data Loader spectrum: yes/y/true/on/1 -> True; no/n/false/off/0 -> False (case-insensitive). Tested all 20 spectrum values; all pass.,/tmp/repro/9/tests/test_2096_rest_booleans.py,closed:not-reproducible-on-v4.10.0,"resolved,bulkdata",v4.10.0,Fix predates v4.10.0; the spec referenced in the issue is now followed. -2126,keychain,feature,feature,NOT-REPRODUCED-on-dev,"Feature request for `encrypt_all_encryptable_fields` Metadata-ETL task using probabilistic Shield encryption. Author (davidmreed, 2022-01-28) wrote ""feature has been developed but is blocked by bugs in the underlying platform functionality"". No matching task exists in cumulusci/ today (grep for `encryptionScheme`/`encrypt_all_encryptable`/`probabilistic` returns 0 hits in cumulusci/). 5+ years stale, still labelled `blocked`. Not a keychain bug \u2014 theme misclassification (encryption-via-Shield, not encryption-at-rest).",,closed:stale-24mo,"area/metadata-etl,blocked",dev,"Theme mislabel: this is metadata-etl/Shield, not keychain. Pass-2: relabel before closing; if owner still wants it, keep-open with `blocked`." -2140,cli,A,feature,REPRODUCED-on-v4.10.0,runtime.py get_org() calls keychain.get_org which raises OrgNotFound; cli/org.py:530-531 just shows 'Org X does not exist'; no interactive prompt offering scratch configs,,closed:stale-24mo,"enhancement,cli-usability,stale",v4.10.0,Stale 5yr feature request -2153,ci-integration,A,feature,REPRODUCED-on-dev,"Code scan of cumulusci/tasks/github/merge.py shows _create_conflict_pull_request (lines 264-288) only calls self.repo.create_pull(...) for the new auto-generated ""Merge into "" PR. There is no call to comment on the original (source) PR or its branch's open PR. Repo-wide grep for ""create_comment"" / ""issue_comment"" in cumulusci/tasks/github returns no matches in production code (only in test fixture util_github_api.py). Feature is still unimplemented on v4.10.0.",,keep-open,"enhancement,github,merge-conflict",dev,"Small enhancement; could be implemented inside _create_conflict_pull_request after pull = self.repo.create_pull(...). Need design decision on how to find the ""original PR"" (search open PRs whose head==branch_name?).; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d)." -2325,bulkdata,A,feature,REPRODUCED-on-v4.10.0,"No `set_validation_rule_status` or `disable_validation_rules` task in cumulusci.yml. Analogs exist for triggers (`disable_tdtm_trigger_handlers`/`restore_tdtm_trigger_handlers` lines 738-747) and DuplicateRules (`set_duplicate_rule_status` -> tasks/metadata_etl/duplicate_rules.py). Implementation pattern is established: a `MetadataSingleEntityTransformTask` subclass with `entity = ""ValidationRule""` would satisfy this.",,keep-open,"enhancement,bulkdata,metadata_etl,good-first-issue",v4.10.0,Clear pattern to follow from SetDuplicateRuleStatus. Small implementation effort. -2402,cli,A,feature,REPRODUCED-on-v4.10.0,cli/flow.py:119-145 flow_run only has --delete-org flag; no --rebuild-org option; no rg matches anywhere,,closed:stale-24mo,"enhancement,stale",v4.10.0,Stale 5yr; tracked as W-10502624 -2500,docs,feature-with-doc-component,doc-gap,REPRODUCED-on-dev,"prescod (2021) flagged that ``ignore_failure`` is not documented. On dev, the option is real and supported: ``Step.ignore_failure: bool = False`` (``cumulusci/utils/yaml/cumulusci_yml.py:45``), used in ``flowrunner.py:667`` as ``allow_failure=step_config.get(""ignore_failure"", False)``, and present in the JSON schema (``cumulusci/schema/cumulusci.jsonschema.json:149``). In the docs directory, the only mentions are (a) a single example YAML at ``docs/config.md:800`` (in a release-flow snippet) and (b) a one-line changelog blurb at ``docs/history.md:5993``. The ""Flow Configurations"" chapter has subsections for ""Add a Flow Step"", ""Skip a Flow Step"", ""Replace a Flow Step"", ""Conditionally Run a Flow Step"" (``when:``), but no parallel subsection for ``ignore_failure``. The follow-up GUS ticket W-10908655 (davidmreed, 2022-03-28) was created but nothing landed.",/tmp/repro/17/tests/test_issue_2500.py,keep-open,"area/docs,area/flows,good-first-issue",dev,"Pass-2: trivial documentation PR. Fix sketch: add a ``### Ignore a Failed Step`` (or ``Continue on Step Failure``) subsection under ``## Flow Configurations`` in ``docs/config.md``, parallel to ""Conditionally Run a Flow Step"". Cover: (1) what the option does (don't raise the task's exception; the flow continues with the next step); (2) interaction with ``result`` / ``return_values`` for downstream steps that conditioned on success; (3) when NOT to use it (silently swallowing failures hides regressions in CI); (4) link to the ``when:`` mechanism for branching instead of swallowing." -2505,bulkdata,A,feature,NOT-REPRODUCED-on-v4.10.0,"`MappingStep.soql_filter` field added (mapping_parser.py:120). `extract.py:142-147` applies it via `append_filter_clause` (extract.py:420). Also surfaced in extract-mapping generator (extract_mapping_file_generator.py:26 reads `where:` from declarations into `soql_filter`). Tests cover plain filter, filter prefixed with WHERE, and no-record-type variants (test_extract.py:1216,1248,1280).",,closed:feature-implemented,"resolved,bulkdata,extract_dataset",v4.10.0,WHERE-clause filtering for extraction is implemented via `soql_filter` per mapping step. -2506,bulkdata,A,feature,REPRODUCED-on-v4.10.0,"Snowfakery task DOES respect `get_debug_mode()` (snowfakery.py:241,355,385,565) and prints the working tempdir on each loop iteration. But the core bulk operations (extract.py, load.py, step.py) have no `--debug` mode that retains tempfiles or logs their paths. extract.py and step.py have ZERO matches for debug_mode/get_debug_mode/delete=False.",,keep-open,"enhancement,bulkdata,extract_dataset,load_dataset,debugging",v4.10.0,Partial: Snowfakery only. Could be extended to load_dataset/extract_dataset by wiring `get_debug_mode` and using TemporaryDirectory(delete=False) when set. -2507,cli,A,feature,REPRODUCED-on-v4.10.0,"No undo_insert task in repo; bulkdata/load.py and snowfakery have enable_rollback option but only triggers on error, not the requested ad-hoc undo",,closed:stale-24mo,"enhancement,stale,partially-fixed",v4.10.0,Partial mitigation via enable_rollback (rollback on error); standalone undo task still missing -2508,bulkdata,A,feature,REPRODUCED-on-v4.10.0,"No retry-only-failed-records feature in v4.10.0. `cci task list` shows zero retry-named tasks. There is an `enable_rollback` option on load_dataset (load.py:97-98, RollbackType enum at load.py:1051) but that performs the OPPOSITE: undoes successful inserts when failures occur. RowErrorChecker (utils.py:158) only logs/raises; it does not persist failed rows for retry.",,keep-open,"enhancement,bulkdata,load_dataset,reliability",v4.10.0,Distinct from rollback. Would require persisting failed-record CSV/SQL output and a new task that consumes it. -2667,auth,enhancement,cli-output,NOT-REPRODUCED-on-dev,"cumulusci/cli/org.py:204 already emits ""Connecting org using the {connected_app_name} connected app..."" before connecting. Implemented by commit 40520bee4 (2022-01-31, post-issue-filing). Existing tests at cumulusci/cli/tests/test_org.py:135 and :191 assert the connected-app name is present in CLI output for both default (""built-in"") and non-default (""other"") connected apps. All 10 org_connect tests pass on dev (1925a3083). Issue description requested ""Using connected_app 'xyzzy'""; current implementation produces functionally equivalent message.",,close-stale,"resolved,implemented",dev,"Originally requested by prescod 2021-06-08; davidmreed noted W-9863651 covering on 2022-01-28. Implementation landed shortly after. davisagli's follow-up suggestions (storing connected_app on OrgConfig, configurable login URLs per connected app) are partially addressed: org_config.config[""connected_app""] is now stored (line 155). Login-URL-per-connected-app remains a separate concern not blocking close." -2697,cli,B,bug,INCONCLUSIVE-needs-scratch-slot,namespaced field is sourced from cci config not auto-derived from SFDX qa.json; keychain create_scratch_org defaults namespaced=False (base_project_keychain.py:74). Requires scratch org to confirm cli/org.py 'org info' output behavior matches reporter's expectation,,closed:stale-24mo,"bug,stale,needs-info",v4.10.0,User expectation conflicts with cci design; field is cci-controlled not derived from SFDX def. Scratch creation skipped (DevHub limit prudence); behavior likely unchanged -2826,metadata-etl,B,bug,REPRODUCED-on-dev,PackageXmlGenerator.parse_types (cumulusci/tasks/metadata/package.py:107) calls os.listdir(self.directory) without a pre-check; UpdatePackageXml._run_task (line 612) does not guard. Unit repro raises FileNotFoundError when path is missing rather than silently no-opping the way the issue title says deploy_unmanaged 'is supposed to',/tmp/repro/5/tests/issue-2826/repro_unit.py,keep-open,"bug,good-first-issue",dev,"Behavior unchanged from 2021. Smallest change: in UpdatePackageXml._init_task (or _run_task) skip with logger.info('No package directory at {path}; skipping') when not Path(path).exists(). Could also be done at the deploy_unmanaged flow level via a `when:` clause, e.g. when: project_config.has_package_directory.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d)." -2951,bulkdata,A,bug,REPRODUCED-on-v4.10.0,"Loader has no special PricebookEntry sequencing logic. Within a single Insert PricebookEntry mapping step, records (whether targeting Standard Price Book or custom) are sent to Bulk/REST in mixed order, hitting STANDARD_PRICE_NOT_DEFINED. Mitigation: hardcoded_default_declarations.py:14-18 filters out Standard Price Book during extract_dataset by default, so the typical extract->load round-trip avoids this. But manually-authored mappings (like reporter's) still hit it.",,keep-open,"bug,bulkdata,load_dataset,pricebook,documentation",v4.10.0,"Could be addressed by either (a) auto-splitting PricebookEntry into two implicit steps (standard first, custom second), or (b) documenting that PricebookEntries against Standard pricebook must be in a separate, earlier mapping step." -2979,packaging,A,feature,REPRODUCED-on-v4.10.0,deploy task in cumulusci.yml still hardcodes path: src; default_package_path exists but is not wired into Deploy task,,keep-open,"severity:low,area:packaging,area:sfdx,state:needs-design",v4.10.0,default_package_path is wired only into create_package_version; would need backwards-compat design (per davisagli comment) -3015,cli,A,feature,REPRODUCED-on-v4.10.0,cli/org.py:519-543 org_remove always calls delete_org() if can_delete; no --keep-org or -o flag,,closed:stale-24mo,"enhancement,stale",v4.10.0,Stale 4yr; tracked as W-10502512; davisagli workaround (delete .org file directly) still applies -3024,cli,A,feature,REPRODUCED-on-v4.10.0,Flow groups in cumulusci/cumulusci.yml still appear in original order: Metadata Transformations first; Continuous Integration appears at position ~23. User-requested 'Org Setup' group does not exist (uses 'Setup' instead),,closed:stale-24mo,"enhancement,stale",v4.10.0,Stale 4yr cosmetic VS Code extension request -3137,metadata-etl,A,feature,REPRODUCED-on-v4.10.0,CustomObjectParser at package.py:443-461 still skips non-__c/__mdt/__e/__b objects; no opt-in option added to UpdatePackageXml,,keep-open,"severity:low,area:metadata-etl,type:enhancement,state:needs-design",v4.10.0,Maintainer agreed in 2022 it's by-design; needs design for an include_standard_objects option -3161,cli,A,feature,REPRODUCED-on-v4.10.0,flowrunner.py:317-320 _obfuscate_if_sensitive masks if task_options info.sensitive==True; partial implementation. No CLI-time hide flag for ad-hoc values like robot__vars; robot vars option not marked sensitive,,closed:stale-24mo,"enhancement,stale,partially-implemented",v4.10.0,Infrastructure exists for sensitive task option metadata; user's ad-hoc CLI -o hiding still missing -3165,metadata-etl,B,bug,REPRODUCED-on-v4.10.0,"_expand_package_xml_objects (which adds objects referenced by record_types to the retrieve package.xml) is only invoked from inside _expand_package_xml, which is gated on include_packaged_objects=True (update_profile.py:137-138 and 182). When include_packaged_objects is False (the default unless project's minimum_cumulusci_version >= 3.9.0), record_types referencing standard objects not already in admin_profile.xml (e.g. Case) are never added to the retrieve, the retrieved Admin profile lacks those recordTypeVisibilities, and _set_record_types raises TaskOptionsError 'Record Type X not found in retrieved Admin.profile'. Existing test test_init_options__include_packaged_objects asserts _expand_package_xml.assert_not_called() in that branch (test_ProfileGrantAllAccess.py:609-615) which proves the gating",/tmp/repro/5/tests/issue-3165/repro_unit.py,keep-open,bug,v4.10.0,"Smallest fix: in update_profile.py:137 always call self._expand_package_xml_objects(package_xml) (regardless of include_packaged_objects), and only call self._expand_package_xml when include_packaged_objects is True. _expand_package_xml_objects only walks the user-supplied record_types option; it does not need a Tooling API query." -3167,metadata-etl,B,feature,NOT-REPRODUCED-on-v4.10.0,"page_layout key on record_types is fully implemented in ProfileGrantAllAccess._set_record_types (update_profile.py:280-298). Documented in the record_types task option description (update_profile.py:32-34). Landed in PR #3243 (commit f2ff04bd5) in June 2022, well before v4.10.0",,close-as-implemented,enhancement,v4.10.0,Feature is shipped; documentation is in cci task info `update_admin_profile`. Could add a CHANGES note or a docs example showing the page_layout usage. -3283,bulkdata,A,bug,NOT-REPRODUCED-on-v4.10.0,"PR #3361 (commit b0bfb70e0, ""Support updates and upserts with blank dates represented by strings"") is in v4.10.0 (verified via `git merge-base --is-ancestor`). Fix at step.py:795-796: for UPDATE/UPSERT, empty strings are converted to None. Repro test confirms empty Birthdate -> JSON null for both UPDATE and UPSERT, and is dropped entirely for INSERT.",/tmp/repro/9/tests/test_3283_empty_date.py,closed:fixed-by-pr-#3361,"resolved,bulkdata,load_dataset",v4.10.0,"Reporter's own last comment (""Fixed in #3361"") confirms this; repro test now verifies behavior on v4.10.0 source." -3306,scratch-org-config,feature,no-test-feature-request,NOT-REPRODUCED-on-dev,"`cci org scratch ... --release preview` exists in cumulusci/cli/org.py:567 but `cci flow run` has no `--release`/`--preview` flag (cumulusci/cli/flow.py 119-150). Internally tracked as W-11486409; no PR landed. Issue is a never-implemented enhancement, not a regression.",,keep-open,"enhancement,needs-spec",dev,"Workaround today is `cci org scratch --release preview` then `cci flow run dev_org --org `. No test written — API/UX (--preview vs --release flag, semantics for non-scratch orgs) not yet specced." -3307,cli,A,feature,REPRODUCED-on-v4.10.0,cli/project.py project_init only renders internal Jinja templates from cumulusci/files/templates/project; no --template option exists,,closed:stale-24mo,"enhancement,stale",v4.10.0,Stale 4yr; user marked 'low priority/nice to have' -3320,metadata-etl,A,feature,NOT-REPRODUCED-on-v4.10.0,deactivate_flow task is shipped in cumulusci/cumulusci.yml:10-15 using ActivateFlow class with status:False,,closed:feature-implemented,"area:metadata-etl,type:enhancement,resolution:already-implemented",v4.10.0,Reporter likely missed that deactivate_flow exists; ActivateFlow.status:False does the work -3331,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,metadata_map.yml line 46 maps assignmentRules folder to type AssignmentRule (singular); MDAPI requires AssignmentRules plural,/tmp/repro/2/tests/test_issues_bucket_a.py::test_issue_3331_assignment_rules_metadata_type_plural,keep-open,"severity:medium,area:metadata-etl,type:bug,good-first-issue",v4.10.0,One-line fix in metadata_map.yml; reporter offered a PR; cross-cutting hint: autoResponseRules already plural in same file -3347,release-unlocked-beta-typeerror,C,code-only,NOT-REPRODUCED-on-v4.10.0,create_package_version.py:158-159 now raises TaskOptionsError(PERSISTENT_ORG_ERROR) early when org_config.config_file is None; replaces the cryptic TypeError reported. Fix landed in commit 2a9cadcb1 on 2023-10-12. Existing test at cumulusci/tasks/tests/test_create_package_version.py::TestPackageConfig::test_org_config validates the new behavior (passes on HEAD).,cumulusci/tasks/tests/test_create_package_version.py::TestPackageConfig::test_org_config,close-with-comment,resolved-by-clear-error-message,v4.10.0,Cryptic TypeError replaced by clear actionable TaskOptionsError. Underlying limitation (cannot use persistent org for 2GP package upload) is documented now. -3349,bulkdata,A,bug,REPRODUCED-on-v4.10.0,"mapping_parser.py:177-179 still names recordtype tables as f""{self.sf_object}_rt_mapping"" (and ""_rt_target_mapping""). Two MappingStep entries for the same sf_object (e.g. Account business vs PersonAccount) collide on the same SQLite table when extracted/loaded together. load.py:552 and extract.py:259/393 both use the sf_object-derived names with no per-step disambiguation.",/tmp/repro/10/tests/test_3349_recordtype_table_collision.py,keep-open,"keep-open,bug,area:bulkdata,severity:major,v5-candidate:yes",v4.10.0,"Has maintainer label wi-created (W-11466074). Real bug, fix would change get_source/destination_record_type_table to use self.table when present. Active community impact (Person Accounts + Business Accounts a common case)." -3353,bulkdata,B,feature,REPRODUCED-on-v4.10.0,snowfakery.py:159-162 validates recipe via Path(recipe).exists() with no SOURCE_NAME:path resolution. No call to project_config.sources / source_url anywhere in snowfakery.py. Recipe string is passed straight to Snowfakery as a filesystem path.,none — code-only,keep-open,"keep-open,enhancement,area:bulkdata,severity:minor,v5-candidate:maybe",v4.10.0,"Community resurfaced this in 2024-08 (davidjray, jnesong). Workaround: cci org import. Fix would resolve SOURCE_NAME:path via project_config.get_source(name).fetch().path before Path() validation." -3360,bulkdata,A,feature,NOT-REPRODUCED-on-v4.10.0,"action: select was added by commit b15945203 (Aug 2024) — well before v4.10.0. select_utils.py + step.py SELECT branch + mapping_select.yml fixture confirm full implementation. select_options supports strategy/filter/priority_fields. This is exactly the requested ""read-only object lookup"" feature — populates the lookup table from existing org records without DML.",none — code-only,closed:feature-implemented,"closed:feature-implemented,enhancement,area:bulkdata",v4.10.0,SELECT action lets you reference existing records by similarity / external-id without inserting. Documented in mapping_select.yml. Issue should be closed citing select feature. -3407,keychain,bug,type-bug,REPRODUCED-on-dev,"`BaseProjectKeychain.set_service` (base_project_keychain.py:202-209) annotates `service_config: ServiceConfig`, but `EncryptedFileProjectKeychain._load_service_files` (encrypted_file_project_keychain.py:717) calls it with a raw `str` (encrypted file body) plus `config_encrypted=True`. `_set_service` (line 583-605) explicitly branches on `config_encrypted` and stores the raw blob without ever constructing a ServiceConfig. Annotation is therefore wrong. Two-test repro xfails on dev: (a) annotation-vs-caller introspection; (b) runtime call with a string succeeds, contradicting the type.",/tmp/repro/16/tests/test_issue_3407.py,keep-open,"area/keychain,good-first-issue,type/typing",dev,"Trivial fix: change annotation to `Union[ServiceConfig, str]` or `ServiceConfig | bytes | str` and update docstring. Optionally split into `set_service` (validated ServiceConfig) and `set_encrypted_service` (raw blob) for cleaner API." -3418,packaging,B,bug,INCONCLUSIVE-needs-cumulus-actions-workflow,cci has no auth:sfdxurl:store path; error originates from SFDO-Community/standard-workflows action; comment from davidmreed in 2022 indicated planned external fix,,unchanged,"needs-info,needs-repro",v4.10.0,"Bug is in the third-party github action (SFDO-Community/standard-workflows production-1gp.yml), not in cci. davidmreed promised to address externally; verify SFDO-Community fix landed before triaging." -3429,packaging,A,feature,REPRODUCED-on-v4.10.0,No CUMULUSCI_YML env var or --config-file CLI flag in v4.10.0; config_filename hardcoded; PR #3969 (extra-yaml-cli-flag) is in flight but not merged,,keep-open,"severity:medium,area:packaging,area:cli,state:in-progress",v4.10.0,PR #3969 on branch extra-yaml-cli-flag adds --extra-yaml + CUMULUSCI_EXTRA_YAML; not yet in v4.10.0; close once #3969 merges -3440,packaging,A,feature,REPRODUCED-on-v4.10.0,default_package_path in project_config.py:517 only honors first packageDirectory with default:true; no name-based lookup or multi-package warnings,,keep-open,"severity:low,area:packaging,area:sfdx,area:multi-package",v4.10.0,Same multi-package theme as #2979 and #3429; could be solved jointly with a multi-package config story -3441,packaging,A,feature,REPRODUCED-on-v4.10.0,version_base accepts None / 'latest_github_release' / literal version; no syntax to reset back to default after a flow override; CCI lacks generic null-override mechanism,,keep-open,"severity:low,area:packaging,area:flow-overrides,area:cli",v4.10.0,yippie's comment generalizes the request to a CCI-wide null-override feature; could be solved by a 'default' sentinel string in create_package_version._get_base_version_number -3446,packaging,B,bug,REPRODUCED-on-v4.10.0,_parse_version(None) raises NoneType.split when push_qa is run with --metadata_package_id but no --version/--version_id; user comment about Push API activation is a downstream concern,/tmp/repro/3/tests/repro_3446_push_qa_no_version.py,keep-open,"bug,good-first-issue",v4.10.0,Two-part fix is wanted: (1) validate that version or version_id is required in _init_options; (2) wrap MetadataPackage SOQL in a check that surfaces a friendlier error if Push API is not activated on the org. -3464,docs,feature-with-doc-component,doc-gap,REPRODUCED-on-dev,"yippie (2022) asked for ALL ``cumulusci.yml`` ``project:`` keys to be defined with at least one sentence each in https://cumulusci.readthedocs.io/en/stable/config.html. On dev, the ``Project`` Pydantic model (``cumulusci/utils/yaml/cumulusci_yml.py:135``) declares 9 fields: ``name``, ``package``, ``test``, ``git``, ``dependencies``, ``dependency_resolutions``, ``dependency_pins``, ``source_format``, ``custom``. ``docs/config.md`` shows ONE example YAML block at line 281 covering only ``name`` + ``package``. Substring scan of the file: ``dependency_resolutions`` 0 hits, ``dependency_pins`` 0 hits — those are documented only in ``docs/dev.md`` (lines 499, 509, 535, 596, 724, 727), which is precisely the ""docs are scattered to the wind"" complaint in the issue. ``source_format`` is mentioned in flow examples but not as a project-level key reference. Sub-models (``Package``, ``Git``, ``Test``, ``DependencyResolutions``) have additional second-level fields with no reference at all in ``config.md``. jstvz acknowledged the gap in 2022.",/tmp/repro/17/tests/test_issue_3464.py,keep-open,"area/docs,type/enhancement",dev,"Pass-2: still actionable; significant doc work. Fix sketch: add a ``## Project Configuration Reference`` (or expand the existing ``### Project Configurations`` at line 673) to ``docs/config.md`` that enumerates every ``project:`` key with one-sentence semantics. Source the enumeration from the ``Project``/``Package``/``Git``/``Test``/``DependencyResolutions`` Pydantic models so it stays in sync. Alternative low-effort path: generate the reference from the Pydantic ``__fields__`` + field descriptions at docs-build time (Sphinx extension) — this requires backfilling ``Field(description=...)`` calls on each model attribute, but produces an always-accurate page. Cross-link to the in-depth dependency pages in ``docs/dev.md`` rather than duplicating their content." -3466,packaging,A,feature,NOT-REPRODUCED-on-v4.10.0,RunApexTests in cumulusci/tasks/apex/testrunner.py exposes test_suite_names option (line 173); fully wired through _get_test_classes_from_test_suite_names,/tmp/repro/1/tests/test_issue_3466.py,closed:feature-implemented,"area:packaging,area:apex,state:resolved",v4.10.0,Implemented at some point after the 2022-12 request; W-12214520 backlog item appears completed -3470,cli,A,feature,REPRODUCED-on-v4.10.0,cumulusci.yml:823 only ci_master flow defined; no ci_main alias. davidmreed acknowledged backlog need for flow aliasing first,,closed:stale-24mo,"enhancement,stale,inclusive-language",v4.10.0,Naming/inclusivity request; needs flow aliasing infra -3471,ci-integration,A,bug,REPRODUCED-on-dev,"cumulusci/tasks/github/merge.py line 251 still emits f""Merged {compare.behind_by} commits into branch: {branch_name}"" using github3's compare.behind_by. ""behind_by"" is computed by GitHub's compare-commits API and reflects how many commits the merged commit is behind the destination tip after the comparison ref-point; for some merges (e.g. when the merge target shares an ancestor at the same ref or when GitHub's compare picks the same head), this can return 0 even though the merge POST at line 249 succeeded and shipped a real commit. git log shows the line was last touched as part of the original MergeBranch implementation; no fix has landed since the issue was filed (2022-12). Pattern reported (README/test.txt vs source-code changes) is consistent with how GitHub's compare API treats ""effectively no-op"" merges where the file content already matches downstream content via merge-base.",,keep-open,"bug,github,merge,low-priority",dev,"Fix: replace compare.behind_by with len(list(compare.commits)) or report the actual merged commit SHA returned from self.repo.merge(...). Existing test_merge.py asserts ""Merged 1 commits"" in normal cases but has no test for the behind_by=0 case.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d)." -3479,ci-integration,A,bug,NOT-REPRODUCED-on-v4.10.0,"Reported error ""Expecting value: line 1 column 1 (char 0)"" is the bare json.JSONDecodeError. In v4.10.0 cumulusci/core/config/sfdx_org_config.py lines 38-55 wrap both nonzero return codes AND JSON parse failures from `sfdx org display --json` in SfdxOrgException with explicit ""Failed to parse json from output. Exception: ... Output: ..."" message (wrapping landed in commit 017bc49f4 on 2020-11-24, predating the 2023-01 issue, so the symptom may have come from a different code path or be a regression in the user's specific 3.71.0 environment). davidmreed's only reply (2023-02-22) correctly diagnoses the root cause as shell-expansion of the multiline GHA secret (echo ${{ secrets.DEV_AUTH_URL }} without quotes). Reporter never responded. The issue is a user CI/workflow-config problem; cci's only contribution is the wrapper message, which is already in place on v4.10.0.",,closed:not-reproducible-on-v4.10.0,"awaiting-more-details,external-config",v4.10.0,"No reporter response in 3+ years; root cause is in user's GHA workflow (unquoted multiline secret), not cci. Improved SfdxOrgException wrapping is already in v4.10.0." -3485,cli,A,bug,REPRODUCED-on-dev,cumulusci/tasks/apex/testrunner.py:803-834 still writes a single tag with no declaration and no wrapper; matches user-reported invalid JUnit format exactly.,,keep-open,"bug,area:apex,good-first-issue",dev,Fix is mechanical: prepend XML declaration and wrap in . Old issue but bug still reproducible against v4.10.0.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). -3492,cli,A,feature,REPRODUCED-on-dev,cumulusci/cli/flow.py:152-162 splits -o key on '__' into exactly 2 parts; passing project__custom__attr would actually error with 'too many values to unpack'. No project-level option override path exists from -o.,,keep-open,"enhancement,area:cli",dev,Feature still missing. Would need new -p / --project-option flag or smarter -o parser.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). -3506,cli,A,feature,REPRODUCED-on-dev,"cumulusci/core/flowrunner.py:660-672 sets when=step_config.get('when') only on the task: branch. The flow: branch at lines 674-697 never reads when from step_config, so when on a flow-call step is silently ignored.",,keep-open,"enhancement,area:flows",dev,Confirmed silent-ignore behavior the user complained about.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). -3518,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,picklists.py:177 stores str.lower bound method (not call) so if-default check at line 214 always truthy; every entry overrides record-type default,/tmp/repro/2/tests/test_issues_bucket_a.py::test_issue_3518_picklist_record_type_default_logic_bug,keep-open,"severity:high,area:metadata-etl,type:bug",v4.10.0,Two-line fix at picklists.py:177 (call .lower()) plus rewrite assignment to avoid shadowing -3541,keychain,bug,bug,REPRODUCED-on-dev,"`BaseProjectKeychain.create_scratch_org` (base_project_keychain.py:77-79) builds `sfdx_alias = f""{project_config.project__name}__{org_name}""`. When `project__name` is None (no `project.name` in cumulusci.yml, or project not yet resolved during the eager `_load_scratch_orgs` pass invoked at keychain init, line 45), the resulting alias is the literal string ""None__dev"" \u2014 exactly matching the reporter. Repro builds a BaseProjectConfig without project.name, calls create_scratch_org, asserts alias doesn't contain literal 'None'; xfails on dev. Second test exercises the eager-load path via __init__.",/tmp/repro/16/tests/test_issue_3541.py,keep-open,"area/keychain,area/scratch-orgs,bug",dev,Issue currently labelled `cannot-reproduce` \u2014 evidence here contradicts that label. Recommend removing it. Fix: guard against None (raise CumulusCIException with clear message OR fall back to org_name). Mind the upgrade path \u2014 existing keychains may already contain `None__*` aliases needing migration. -3542,packaging,B,bug,INCONCLUSIVE-needs-2GP-CI-pipeline,github_package_data uses self.project_config.repo_commit (local SHA) verbatim; if the upstream workflow recorded version_id under a merge-commit SHA from pull_request trigger; locally checked-out PR head SHA will not match; cci-side code path unchanged on v4.10.0,,unchanged,"needs-repro,2gp",v4.10.0,Root cause is workflow-vs-local SHA mismatch. May need a docs/CI fix in cumulus-actions/standard-workflows rather than cci. Could add a fallback: search by SHA on parent commits. -3543,metadata-etl,A,feature,REPRODUCED-on-v4.10.0,DxConvertFrom in cumulusci/tasks/dx_convert_from.py only exposes extra and src_dir options; no load_sfdx_project_paths or resolve_sfdx_package_dirs,,keep-open,"severity:low,area:metadata-etl,type:enhancement",v4.10.0,Reporter offered draft PR; could be folded into multi-path support across deploy/uninstall_packaged_incremental too -3544,update-admin-profile-person-accounts-namespaced,C,e2e-config-required,INCONCLUSIVE-needs-namespaced-project,Provisioned scratch org repro-special-c-pa from orgs/person_accounts.json (PersonAccounts + Communities + ContactsToMultipleAccounts features). update_admin_profile task ran SUCCESSFULLY against this non-namespaced person_accounts org on v4.10.0. Bug condition requires BOTH PersonAccounts AND namespaced:true on the project; CumulusCI itself has no project namespace so the second condition cannot be satisfied without registering a namespace in CCIDevHub. No code fix found referencing #3544 or W-12589033 in update_profile.py / admin_profile.xml since 2023.,,needs-info,needs-namespaced-project,v4.10.0,Tracked internally as W-12589033 per davidmreed comment 2023-02-22. Discovered adjacent latent bug at cumulusci/utils/__init__.py:229 where namespaced_org=True with no project namespace raises TypeError: unsupported operand type(s) for + 'NoneType' and 'str' — distinct from #3544 but worth a separate ticket. -3549,cli,A,feature,REPRODUCED-on-v4.10.0,"cumulusci/tasks/salesforce/Deploy.py exposes test_level/specified_tests but does not capture or write JUnit/JSON test output (no junit_output option, no _write_output for tests).",,keep-open,"enhancement,area:metadata-deploy",v4.10.0,Related to #3564. Reasonable feature ask; not implemented. -3561,metadata-etl,B,bug,NOT-REPRODUCED-on-v4.10.0,"Bug was reported by yippie (who is also the PR author). Fix landed in commit 56e10665e (PR #3566, May 2024) by the original reporter. RetrieveUnpackaged._init_options now stores file content under options['package_xml_content'] and leaves the file-path option intact (RetrieveUnpackaged.py:29-31), so the second _init_options invocation in MetaDeploy no longer corrupts the path",,close-as-fixed,,v4.10.0,Suggest closing with a back-reference to PR #3566 in case the original reporter never got back to flip the issue state. -3570,cli,A,feature,REPRODUCED-on-dev,cumulusci/core/flowrunner.py supports per-step ignore_failure (StepSpec.allow_failure) but has no concept of finally:/on_error:/cleanup: steps in a flow definition. No 'always-run' or post-error step type exists.,,keep-open,"enhancement,area:flows",dev,Big design change; unlikely to ship without strong demand.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). -3585,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,PackageXmlGenerator on .object containing unbound xsi:nil='true' raises XML parse error; no namespace shim added,/tmp/repro/2/tests/test_issues_bucket_a.py::test_issue_3585_xsi_nil_true_breaks_update_package_xml,keep-open,"severity:medium,area:metadata-etl,type:bug,sfdx-compat",v4.10.0,Fix: register xsi namespace before parsing or pre-strip xsi:nil attributes; also fixes #3692 class of issues -3587,packaging,B,feature,NOT-REPRODUCED-on-v4.10.0,PackageXmlGenerator only emits / when self.managed is truthy; no warning is logged when install_class set with managed=False; live cci task run update_package_xml --install_class X confirms silent drop,/tmp/repro/3/tests/repro_3587_update_package_xml_no_warning.py,keep-open,"enhancement,good-first-issue",v4.10.0,Feature still missing. Smallest implementation: in UpdatePackageXml._init_task; if install_class/uninstall_class set but not self.options.get('managed'); emit self.logger.warning(...). -3593,packaging,A,bug,REPRODUCED-on-dev,SFDXOrgTask._get_command in cumulusci/tasks/sfdx.py:50 unconditionally appends ' -o ' for ScratchOrgConfig; no opt-out option,/tmp/repro/1/tests/test_issue_3593.py,keep-open,"severity:medium,area:packaging,area:sfdx,area:dx-task,state:needs-design",dev,Repro test confirms command becomes 'sf project convert source ... -o test@example.com'; sf cli rejects -o for subcommands like 'project convert source'; suggested fix is an opt-out option or auto-detect; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). -3600,packaging,B,feature,NOT-REPRODUCED-on-v4.10.0,cci task option processing only substitutes $project_config. via PROJECT_CONFIG_RE; YAML loader uses plain yaml.safe_load with no env-var resolver; live install_managed --version '${MY_FAKE_VERSION}' shows literal string in interactive prompt,/tmp/repro/3/tests/repro_3600_install_managed_no_env_var.py,keep-open,enhancement,v4.10.0,Feature not implemented. Scope likely larger than install_managed (would touch all task options); design decision needed: $env:VAR vs ${VAR} syntax; backwards-compat impact on literal $-strings. -3602,robotframework,feature-request,feature,REPRODUCED-on-dev,"cumulusci/robotframework/SalesforcePlaywright.py:60 open_test_browser signature is (self, size=None, useralias=None, wait=True, record_video=None) — no kwarg accepts browser options or **kwargs. cumulusci/robotframework/Salesforce.robot:103 ""Open Test Browser"" robot keyword only takes size/alias/wait/useralias. Chrome options are constructed by Get Chrome Options (Salesforce.robot:157) which hard-codes --disable-notifications with no extension hook.",cumulusci/tests/triage/test_issue_3602.py,keep-open,"enhancement,robotframework,playwright,good-second-issue",dev,"Small-medium feature: add browser_options/extra_options kwarg to both Selenium and Playwright open_test_browser implementations, forward to webdriver options / new_browser kwargs. Pytest asserts signature exposes such a hook." -3603,dependencies,A,bug,REPRODUCED-on-v4.10.0,"Source ref/tag not found leaks raw `404 [No message]` from GitHubSource.resolve() (cumulusci/core/source/github.py L126). Repo-not-found cases (1,2) and `release:` strategy fail (case 5) are already wrapped in DependencyResolutionError; ref-not-found case (3) is not, and dep strategy fall-through (case 4) names the dep but not the strategies tried.",/tmp/repro/11/tests/test_3603_404_messages.py,keep-open,"theme:dependencies,error-handling,good-first-issue",v4.10.0,"Partial repro. Cases 1,2,5 were addressed by commit 738d4a8a4 (2021); cases 3 and 4 remain." -3604,dependencies,A,feature,REPRODUCED-on-v4.10.0,No CCI task exists to write computed dependencies into `sfdx-project.json`. Confirmed via `cci task list` and grep: zero references to writing/updating sfdx-project.json. W-13504384 was filed by maintainer in 2023 but no implementation has shipped through v4.10.0.,,keep-open,"theme:dependencies,enhancement,wi-created",v4.10.0,Pure feature request; gap persists. wi-created label already present. -3605,packaging,A,feature,NOT-REPRODUCED-on-v4.10.0,PackageUpload (upload_production backing class) exposes major_version and minor_version options (cumulusci/tasks/salesforce/package_upload.py:39-46); _validate_versions handles major bump,/tmp/repro/1/tests/test_issue_3605.py,closed:fixed-by-pr-#3651,"area:packaging,area:1gp,state:resolved",v4.10.0,Implemented in commit 87b94440e (PR #3651 'Deploy Major and Minor Version option in upload_production task') -3607,cli,A,bug,INCONCLUSIVE-needs-org-with-managed-package,"Code path traced in cumulusci/tasks/apex/testrunner.py: retry_failures regex compiled at line 209-222, _is_retriable_failure (line 405) checks Message and StackTrace via re.search. Repro test at /tmp/repro/8/tests/test_3607_retry.py confirms 'UNABLE_TO_LOCK_ROW' regex DOES match the user's quoted message in pure Python. Likely user-side: wrapped exception so Message lacks the literal token, or managed-class symbol-table skip at line 448-452.",/tmp/repro/8/tests/test_3607_retry.py,closed:stale-24mo,"bug,area:apex,needs-info",v4.10.0,Code logic is correct as written. To definitively reproduce we need a managed package and an org producing the exact failure shape. 30+ months no follow-up from reporter. -3609,cli,A,bug,INCONCLUSIVE-needs-live-cli-test,"cumulusci/tasks/sfdx.py is now a thin shell wrapper around 'sf {command}' (SFDX_CLI = 'sf' in v4.x; was 'sfdx' in 3.76.0 when reported). The user's syntax 'plugins:install ...' is sfdx-style with colon; 'sf' uses 'plugins install' (space). Underlying timeout originates from the sfdx/sf CLI itself, not CCI.",,closed:stale-24mo,"bug,upstream:sf-cli",v4.10.0,"Not a CCI bug. CCI faithfully shells out. Old issue, CLI changed substantially since." -3610,apex,Fixed-on-dev,negative-test,NOT-REPRODUCED-on-dev,Fixed by PR #3681 (commit 84389d998); cumulusci/tasks/apex/testrunner.py:500-510 handles None method name; regression tests already exist on dev,,closed:pr-resolved-#3681,,dev,"Fixed by PR #3681 (commit 84389d998b4783ddd2ff062f486a2366709cac27, ""Handling exception when the Tooling API returns a test result with a null method name""). cumulusci/tasks/apex/testrunner.py lines 500-510 detect None in method_names, remove the None key, enqueue the affected class for retry, and bump counts['Retriable']. Regression tests test_run_task_None_methodname_fail / test_run_task_None_methodname_pass pass on origin/dev@1925a3083." -3612,cli,A,feature,NOT-REPRODUCED-on-v4.10.0,"Issue is about the SFDO-Tooling/cci-vscode VSCode extension repo, not CumulusCI itself. Out of scope for this repository.",,closed:not-reproducible-on-v4.10.0,"enhancement,wontfix,wrong-repo",v4.10.0,Should be filed against SFDO-Tooling/cci-vscode. -3613,metadata-etl,B,bug,REPRODUCED-on-v4.10.0,Live repro: `cci task run add_page_layout_fields --org repro-etl-b-dev -o api_names Account` -> 'Cannot find metadata file ...layouts/Account.layout' from MetadataSingleEntityTransformTask (base.py:332). Same task with correct API name format `Account-Account Layout` succeeds. Underlying functionality works; the user-visible bug is the unhelpful error when the api_name does not match the Layout file naming convention -,/tmp/repro/5/tests/issue-3613/output-just-object.txt,improve-error-message,"bug,good-first-issue",v4.10.0,"Original report has no log of the exact api_names value passed; the cropped screenshot only shows 'page layouts'. Two improvements would help: (1) in _transform; if path does not exist, log the list of files actually retrieved into source_metadata_dir to help users identify naming mismatch; (2) in AddFieldsToPageLayout._init_options; warn when api_name does not contain '-'." -3615,dependencies,A,bug,NOT-REPRODUCED-on-v4.10.0,"`--resolution_strategy preproduction` is documented in cumulusci.yml as an alias for `latest_release` (which contains [tag, latest_release, unmanaged] and intentionally omits `latest_beta`). User wanted `include_beta`. Tests confirm preproduction == production == latest_release stack. Working as documented.",/tmp/repro/11/tests/test_3615_preproduction_strategy.py,closed:not-reproducible-on-v4.10.0,"theme:dependencies,docs",v4.10.0,"Naming is confusing -- ""preproduction"" sounds like ""beta-friendly"" but it isn't. Docs-improvement candidate; no code bug." -3618,cli,A,feature,REPRODUCED-on-dev,"cumulusci/cli/org.py:519-545 (org_remove) and 605-625 (org_scratch_delete) accept a single org_name argument via orgname_option_or_argument. No comma-separated list, no batch mode.",,keep-open,"enhancement,area:cli,good-first-issue",dev,Modest feature; could be implemented by accepting nargs=-1 or comma-split arg.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). -3619,dependencies,A,bug,REPRODUCED-on-v4.10.0,"Two-part bug confirmed. (A) `parse_pins()` raises DependencyParseError if a `dependency_pins` entry includes `password_env_name:` -- because GitHubDependencyPin only declares `github` and `tag`. (B) When a dynamic dep has `password_env_name` and a pin matches, `pin.pin()` calls GitHubTagResolver().resolve() directly, bypassing resolve_dependency()'s password-propagation logic; resulting `package_dependency.password_env_name` is None.",/tmp/repro/11/tests/test_3619_pin_password.py,keep-open,"theme:dependencies,bug",v4.10.0,Strong repro. Fix needs both (A) add password_env_name field to GitHubDependencyPin and (B) propagate it onto package_dependency in pin.pin() -- mirroring resolvers.py L644-654. -3649,bulkdata,A,feature,REPRODUCED-on-v4.10.0,"update_data.py:184 and :211 both pass api_options={} hardcoded to get_dml_operation. No task option exposes bulk job concurrency mode (Serial/Parallel). step.py BulkApiDmlOperation honors api_options[""bulk_mode""] but UpdateData never sets it. Other tasks (snowfakery, load_dataset) DO let users pick bulk_mode; update_data is the gap.",none — code-only,keep-open,"keep-open,enhancement,area:bulkdata,severity:minor,good-first-issue,v5-candidate:yes",v4.10.0,Author offered to contribute. Small fix: add bulk_mode option to UpdateData.task_options and pipe it through to api_options. Mirrors LoadData pattern. -3663,cli,A,feature,REPRODUCED-on-dev,cumulusci/core/flowrunner.py:510-516 _run_step builds the when Jinja context from only project_config and org_config. No prior-task return values are exposed to the when expression.,,keep-open,"enhancement,area:flows",dev,Would need to thread results dict (or ^^ resolver) into the when context.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). -3692,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,digitalExperiences key absent from metadata_map.yml; PackageXmlGenerator raises MetadataParserMissingError on Enhanced LWR sites,/tmp/repro/2/tests/test_issues_bucket_a.py::test_issue_3692_digital_experiences_in_metadata_map,keep-open,"severity:medium,area:metadata-etl,type:bug",v4.10.0,Add digitalExperiences/digitalExperienceConfigs entries to metadata_map.yml; needed for Winter '24+ LWR sites -3699,bulkdata,A,feature,REPRODUCED-on-v4.10.0,"extract.py _soql_for_mapping does not append ORDER BY. mapping_parser MappingStep has no order_by/sort field. soql_filter however allows arbitrary trailing SOQL so users CAN write soql_filter: ""Name != 'X' ORDER BY CreatedDate"" — this works because append_filter_clause just concatenates after WHERE. So a workaround exists; an explicit field would be a UX win.",none — code-only,closed:stale-24mo,"closed:stale-24mo,enhancement,area:bulkdata",v4.10.0,Workaround via soql_filter ORDER BY makes this lower priority. Author hasn't followed up. Closing as stale is fine; can reopen if explicit order_by becomes a v5 ask. -3700,bulkdata,A,bug,REPRODUCED-on-v4.10.0,"mapping_parser.py:373-377 _get_required_permission_types returns (""updateable"", ""createable"") for any UPSERT. Master-detail lookup fields in Salesforce are createable but NOT updateable, so _check_field_permission rejects them, raising ""Field xxx__c does not have the correct permissions ('updateable', 'createable') for this operation."" Repro test confirms with simulated MD describe.",/tmp/repro/10/tests/test_3700_master_detail_upsert_perm.py,keep-open,"keep-open,bug,area:bulkdata,severity:major,good-first-issue,v5-candidate:yes",v4.10.0,"Real bug, applies to any upsert involving an MD child. Fix should detect master-detail fields (relationshipName + cascadeDelete) and require only createable for those, OR loosen the upsert lookup-field check to ""createable OR updateable""." -3701,bulkdata,A,feature,REPRODUCED-on-v4.10.0,"mapping_parser.py:171/190/228/241/422 special-case ""Id"" — it always represents the SF Id and goes to sf_id-typed columns. There is no mechanism to make a different field (e.g. an external-id like BCM_Unique_Id__c) act as the row primary key in the extracted SQLite. The ""Id : OtherField"" mapping the user wrote is interpreted as ""extract SF Id into column OtherField"", not ""make OtherField the primary key"".",none — code-only,closed:stale-24mo,"closed:stale-24mo,enhancement,area:bulkdata",v4.10.0,"Closely tied to #3699 (sort/diff motivation). Author hasn't followed up. Workaround: extract SF Id into a chosen column, then post-process. The deeper PK-replacement feature would touch many places." -3717,ci-integration,A,bug,INCONCLUSIVE-needs-cumulus-actions-workflow,"cumulusci/core/config/project_config.py repo_info property (lines 220-255) only auto-detects from environment when CUMULUSCI_AUTO_DETECT is set, and only handles Heroku CI (HEROKU_TEST_RUN_ID/BRANCH/COMMIT_VERSION). Repo-wide grep for ""GITHUB_REF"" / ""GITHUB_HEAD_REF"" / ""GITHUB_SHA"" / ""GITHUB_ACTIONS"" returns ZERO matches in cci source. So when run inside a GitHub Actions job the only way for repo_branch to be populated is (a) CUMULUSCI_REPO_BRANCH env var set by the workflow, or (b) git inference via current_branch(self.repo_root). On push events GHA checks out a detached HEAD, so (b) returns None. The reporter's symptom (repo_branch=None for push-triggered ci_feature, but works on workflow_dispatch where the branch ref is checked out by name) is exactly what this code path produces. The fix lives in the cumulus-actions/standard-workflows YAMLs (set CUMULUSCI_REPO_BRANCH from github.event.ref or github.head_ref before invoking cci) — not in the cci codebase. Same precedent as #3418.",,unchanged,"external-config,cumulus-actions,needs-info",v4.10.0,"Mirrors #3418 precedent (INCONCLUSIVE-needs-cumulus-actions-workflow). Could optionally be addressed inside cci by adding GitHub Actions auto-detection in repo_info (similar to Heroku block), reading GITHUB_REF/GITHUB_SHA — that would be a separate enhancement." -3721,packaging,A,feature,REPRODUCED-on-v4.10.0,create_package_version.py:184 still defaults version_name to literal 'Release'; upload_production hardcodes name: Release in cumulusci.yml:685,,keep-open,"severity:low,area:packaging,area:1gp,area:2gp",v4.10.0,muselab-d2x fork commit 7aaf348f3 implements jinja2 templating for PackageUpload; not merged upstream; would need port + design for create_package_version too -3734,packaging,B,bug,REPRODUCED-on-v4.10.0,PackageUpload._validate_versions SOQL ORDER BY ... PatchVersion DESC; ReleaseState DESC LIMIT 1 returns a Beta patch (e.g. 6.13.1 Beta) as latest; then minor_version is set to the patch's MinorVersion (13); colliding with already-Released 6.13 server-side,/tmp/repro/3/tests/repro_3734_upload_production_beta_patch.py,keep-open,bug,v4.10.0,User's own analysis in last 3 comments is correct; current 'cannot-reproduce' label is stale; should be removed. Fix candidates: filter out Beta+Patch from the latest-version query; or filter ReleaseState='Released' for minor-detection and use a separate query for Beta. -3745,packaging,B,code-review,NOT-REPRODUCED-on-v4.10.0,latest_beta resolver looks up GitHub Releases (include_beta strategy) per install_package_version.py L96-100; reporter ran create_package_version standalone without release_2gp_beta which publishes the beta tag. Working as designed; reporter accepted the explanation 2024-02-13 and indicated closure intent.,/tmp/repro/4/evidence/3745-source-and-design.txt,closed:stale-24mo,n/a,v4.10.0,"No code defect; doc-improvement opportunity. Original closed:stale-24mo proposal stands. Could optionally add closed:not-a-bug if that vocabulary exists, but stale-24mo is fine." -3746,packaging,B,code-review,REPRODUCED-on-dev,"create_package_version._get_base_version_number SOQL at L535-541 of cumulusci/tasks/create_package_version.py selects highest Package2Version with no IsDeprecated filter. The same file at L297 DOES filter IsDeprecated=FALSE for Package2 lookups, confirming the omission at L535 is asymmetric and matches the report verbatim.",/tmp/repro/4/evidence/3746-source-soql.txt,kept-open,"severity:medium,area:packaging,target:v4-patch,needs-fix-trivial",dev,Trivial 1-line fix (add 'AND IsDeprecated = false' to the SOQL WHERE clause). Currently proposed closed:stale-24mo; recommend flip to kept-open + target:v4-patch given low fix cost and clear customer impact (wrong version numbers on next package version create after a delete).; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). -3754,cli,A,feature,REPRODUCED-on-v4.10.0,cumulusci/cli/utils.py:65-79 hardcodes 'https://pypi.org/pypi/cumulusci/json' with no env-var override or config flag. check_latest_version (line 82) cannot be disabled or redirected.,,keep-open,"enhancement,area:cli",v4.10.0,"User-suggested options (env flag to disable, custom URL) are all viable." -3758,packaging,A,bug,REPRODUCED-on-v4.10.0,push_upgrade_org flow in cumulusci/cumulusci.yml:1161-1177 still calls 'flow: config_qa' as final step; should be config_managed per bug report,/tmp/repro/1/tests/test_issue_3758.py,keep-open,"severity:medium,area:packaging,area:flows,good-first-issue",v4.10.0,Single-line YAML fix; both flows have same steps so behavior is currently equivalent but semantically wrong -3762,metadata-etl,B,bug,closed:duplicate-of-#3544,"Reporter (noahisapilot) explicitly self-identifies as duplicate of #3544 in their first comment on 2024-03-06. Both report the same root cause: update_admin_profile fails on a namespaced scratch org with PersonAccounts because the retrieved profile contains 'Account.Business_Account' record type with no namespace, but the namespace gets injected onto recordType references. The reporter's analysis even links the offending line at update_profile.py L238 (now L236 in v4.10.0)",,close-as-duplicate,,v4.10.0,Self-confirmed duplicate. No live repro performed per dup-confirm protocol. Canonical #3544 is still OPEN at v4.10.0 with a 'wi-created' label (W-12589033). -3768,bulkdata,B,bug,REPRODUCED-on-v4.10.0,"snowfakery.py architecturally creates a separate working dir per batch via shutil.copytree(template_path, data_dir) (queue_manager.py:322). _cleanup_object_tables (snowfakery.py:721) drops every non-sf_ids table from the template before it is copied to subsequent batch dirs, so just_once Account rows are gone from batch_2+. random_reference: Account in batch_2+ would resolve only against rows generated within that batch; with just_once: true, no Accounts are generated, so the random_reference cannot pick anything. The user's observed first-batch-works / later-batches-don't matches this exactly.",none — code-only,keep-open,"keep-open,bug,area:bulkdata,severity:major,v5-candidate:maybe",v4.10.0,Mixed CCI/Snowfakery responsibility. Could be fixed in CCI by preserving just_once-referenced object data (not just sf_ids) in the template carried to subsequent batches. Coordination with snowfakery dev branch likely needed. -3771,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,transforms.py transform_xpath() wraps tags in *[local-name()=...] but leaves predicate inner refs (e.g. price>40) namespace-bound; PR #3772 from leboff fork not merged,/tmp/repro/2/tests/test_issues_bucket_a.py::test_issue_3771_xpath_predicate_with_xmlns_resolves,keep-open,"severity:medium,area:source-transforms,type:bug,has-pr",v4.10.0,PR #3772 from external fork rewrites approach to strip xmlns; consider rebasing or implementing reporter's suggested 'remove xmlns then re-add' approach -3773,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,retrieve_profile_api.py _queries_retrieve_permissions never queries FieldPermissions table; only ObjectPermissions/SetupEntityAccess/PermissionSetTabSetting,/tmp/repro/2/tests/test_issues_bucket_a.py::test_issue_3773_retrieve_profile_queries_field_permissions,keep-open,"severity:medium,area:retrieve-profile,type:bug",v4.10.0,Architectural gap; field perms on standard objects without object perms are silently dropped; would benefit from org-side end-to-end verification but code evidence is conclusive -3849,python-modernization,Active-regression,import-only,REPRODUCED-on-dev,pyproject.toml pins selenium<4 + robotframework-seleniumlibrary<6 with no urllib3<2 cap; fresh pip resolves urllib3>=2 and breaks selenium 3.141.0,/tmp/repro/18/tests/test_issue_3849.py,keep-open,"needs:dependency-modernization,target:v5",dev,"pyproject.toml still pins selenium<4 and robotframework-seleniumlibrary<6 (lines 50, 54) with no urllib3 upper bound; requests permits urllib3<3,>=1.26 so a fresh pip install picks urllib3>=2.x. Selenium 3.141.0's connection pool uses the pre-2.0 Timeout sentinel API and breaks at Robot import. The local .venv survives only because uv.lock pins urllib3==1.26.20. The modernization (drop selenium<4 / robotframework-seleniumlibrary<6 OR add explicit urllib3<2) has not landed." -3852,cli,A,bug,REPRODUCED-on-v4.10.0,"pyproject.toml:52 still pins 'sarge' unconstrained; installed sarge 0.1.7.post1 lacks Capture.flush (verified: hasattr(sarge.Capture,'flush')==False). cumulusci/core/config/sfdx_org_config.py:212 still calls self.sfdx_info inside refresh_oauth_token, which triggers the AttributeError on Python 3.13 logging path.",,keep-open,"bug,upstream:sarge,py313",v4.10.0,"Per maintainer note in thread: cosmetic only (no functional impact), waiting on sarge 0.1.8 release. Could pin sarge to a git rev (gabrielrholl's note) but not preferred." -3854,cli,A,bug,REPRODUCED-on-v4.10.0,cumulusci/tasks/bulkdata/extract.py:371-374 still raises ConfigError 'Total mapping operations (X) do not match total non-empty rows (Y) for lookup_key' identical to user report. Validation introduced in PR #3741 / commit 2c5d0056e per swirkens' comment is still active in v4.10.0.,,keep-open,"bug,area:bulkdata,regression",v4.10.0,Workaround in thread: downgrade to 3.84.1. Real fix needed for polymorphic lookups. -3873,robotframework,feature-request,feature,REPRODUCED-on-dev,"cumulusci/robotframework/Salesforce.py and SalesforcePlaywright.py both subclass BaseLibrary (base_library.py) which imports cumulusci-internal services (CumulusCI, SalesforceAPI); the libraries cannot be used standalone without a CumulusCI project context",,keep-open,"enhancement,robotframework,scope-large",dev,Large architectural ask. No PR submitted in 16 months. Would require decoupling FakerMixin/BaseLibrary/Salesforce from cumulusci.core. No concrete API to test; tagging as feature-still-missing. Reasonable to keep open for future Copado-QForce-style refactor or close as wont-fix if scope is out-of-charter. -3884,packaging,B,partial-runtime,INCONCLUSIVE-needs-project-with-managed-deps,"Source review: PackageNamespaceVersionDependency.install (dependencies.py L437-475) and PackageVersionIdDependency.install (L499-528) BOTH guard with skip-if-already-at-this-or-newer-version logic. CumulusCI repo itself has no project__dependencies block, so end-to-end dev_org rerun cannot exercise the path. Likely the report conflates 'Resolving dependencies...' log noise or unmanaged-metadata redeploys with reinstalls.",/tmp/repro/4/evidence/3884-source-skip-logic.txt,closed:missing-fields,n/a,v4.10.0,"Original closed:missing-fields (rule 3 missing cci-version) is appropriate. Source review shows skip logic is in place; report may reflect unmanaged-metadata redeploy or user perception of log output. Without a customer project to reproduce on, no further action." -3886,dependencies,A,bug,REPRODUCED-on-v4.10.0,"Warning ""Optional dependencies are missing... cumulusci[select]"" emits at import time of cumulusci/tasks/bulkdata/select_utils.py whenever numpy/pandas/annoy/sklearn aren't installed. extract.py -> mapping_parser/step -> select_utils import chain triggers it on every extract_dataset run, even when no select strategy is configured. Behavior added in PR #3858 (89a5b5ddb) and unchanged through v4.10.0. Extraction itself works fine; only the noise persists.",/tmp/repro/11/tests/test_3886_select_warning.py,keep-open,"theme:dependencies,bulkdata,ux,log-noise",v4.10.0,"Dual-themed (bulkdata + dependencies); classified under dependencies per the bundle instructions. Fix candidates: defer warning until select strategy is actually used, or downgrade to debug-level." -3889,packaging,A,feature,REPRODUCED-on-v4.10.0,UninstallPackage only accepts namespace (1GP); UninstallPackageZipBuilder uses InstalledPackage destructive changes; no 04t/SubscriberPackageVersion-based uninstall task,,keep-open,"severity:medium,area:packaging,area:2gp,area:unlocked-package",v4.10.0,sf cli 'package uninstall -p 04t...' is the underlying API; new UninstallPackageVersion task could wrap Tooling API SubscriberPackageVersion delete -3899,packaging,B,partial-runtime,INCONCLUSIVE-needs-1gp-packaging-org,"unschedule_apex (cumulusci.yml L646-651) sends 1 line of trivial Apex via Tooling API: 'for (CronTrigger t : [SELECT Id FROM CronTrigger]) { System.abortJob(t.Id); }'. Ran cleanly on scratch org repro-pkg-b2-dev. Reporter's error references Salesforce platform-internal Java classes (system.scheduler.cron.JobType, common.udd.constants.CronJobTypeEnum) — root cause is upstream Salesforce platform NPE, not CCI.",/tmp/repro/4/evidence/3899-task-and-error-analysis.txt,kept-open,"severity:minor,area:packaging,external/upstream-salesforce,v5-candidate:no",v4.10.0,CCI sends correct trivial Apex; the System.UnexpectedException originates inside Salesforce's scheduler subsystem. Cannot fix in CCI. Recommend annotating with external/upstream-salesforce label (or equivalent) and considering close-as-not-our-bug after a brief look for any Salesforce known-issue reference. -3902,install-managed-security-type-04t,C,code-only,INCONCLUSIVE-needs-managed-package-04t,v4.10.0 install_package_version.py:162-167 routes 04t versions through PackageVersionIdDependency.install -> install_package_by_version_id -> _install_package_by_version_id which posts {'SecurityType': options.security_type} to the Tooling API PackageInstallRequest (package_install.py:170). Verified runtime serialization: SecurityType.ADMIN serializes to JSON 'NONE'. Both 04t and namespace+version paths pass security_type identically. No code-side defect found.,,needs-info,needs-managed-package-fixture,v4.10.0,"Could not provision a real managed package 04t to validate runtime API behavior. Code path is correct; observed user behavior (tab visible to non-admins) likely originates from Salesforce Tooling API treatment of SecurityType=NONE for upgrades or from package metadata, not from CumulusCI." -3910,scratch-org-config,bug,unit-pytest,REPRODUCED-on-dev,"ScratchOrg.namespaced declared as ``str`` in cumulusci/utils/yaml/cumulusci_yml.py:150; auto-generated cumulusci/schema/cumulusci.jsonschema.json:424 has ""type"": ""string""; ScratchOrg.parse_obj({""namespaced"": True}) silently coerces to ""True"" string. Open PR #3911 fixes both. Six XFAIL assertions added.",cumulusci/tests/triage/test_issue_3910.py,keep-open,"bug,has-open-pr",dev,Fixing the schema alone is insufficient because make schema regenerates it from the Pydantic model. PR #3911 correctly updates both files; recommend nudging it through review. -3929,packaging,B,runtime,NOT-REPRODUCED-on-v4.10.0,"Ran create_community with name=TestWebsite template='Customer Service' url_path_prefix=testwebsite against scratch org repro-pkg-b2-dev (orgs/dev.json with Communities feature). Community 0DBRK000000QtNR4A0 created in ~117s with normal polling escalation (1->2->3->...->8s) and exited the poll loop cleanly — no 300s timeout, no retry. Matches OP comment 2025-10-22 that the underlying SF CLI/server-side issue is fixed.",/tmp/repro/4/evidence/3929-create_community.log,closed:not-reproducible-on-v4.10.0,n/a,v4.10.0,Currently kept-open with needs-repro label; recommend flip to closed:not-reproducible-on-v4.10.0 (NEW vocabulary per spec amendment). Confirmed working end-to-end. Original cause was upstream SF CLI/Communities API bug now fixed. -3931,metadata-etl,B,bug,REPRODUCED-on-v4.10.0,Unit repro (with synthetic profile XML containing a layoutAssignments element that has a child but no child) raises 'AttributeError: NoneType object has no attribute text' at update_profile.py:291 inside _set_record_types. The buggy line is `if elem.find('recordType').text == rt['record_type']:` which assumes every layoutAssignments element has a recordType child; this is not true (a layoutAssignments without recordType applies to records without a record-type binding),/tmp/repro/5/tests/issue-3931/repro_unit.py,keep-open,bug,v4.10.0,Reported on cci 4.6.0 and reproduces unchanged on 4.10.0. Minimal fix at update_profile.py:290-293: change to `rt_elem = elem.find('recordType'); if rt_elem is not None and rt_elem.text == rt['record_type']: ...`. Also worth scanning sibling code in _set_record_types for similar None-deref patterns on optional children. -3936,bulkdata,B,bug,INCONCLUSIVE-needs-flaky-network,"salesforce_api/utils.py get_simple_salesforce_connection (lines 30-43) constructs Salesforce() with no timeout kwarg and only retries 502/503/504 via Retry(total=5). No CCI-side option exposes connect/read timeout for SF API calls. The reported error ""HTTPSConnectionPool ... Read timed out. (read timeout=None)"" with timeout=None usually means the proxy/VPN closed the socket; CCI cannot mitigate without exposing a configurable timeout AND a retry policy for read timeouts.",none — code-only,unchanged,"keep-open,bug,area:bulkdata,severity:major,needs-repro,v5-candidate:yes",v4.10.0,Already kept-open by maintainer (recent 2025-12-03). Environment-specific reproduction (corporate VPN). Confirmed structural gap: no exposed timeout option. v5 candidate: add timeout option + read-timeout retry to get_simple_salesforce_connection and to bulk job HTTP polling. -3938,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,rest_deploy.py _monitor_deploy_status (line 119) returns silently on Failed; __call__ also only logs on non-201 status_code; no exception raised,/tmp/repro/2/tests/test_issues_bucket_a.py::test_issue_3938_rest_deploy_failure_does_not_raise,keep-open,"severity:critical,area:rest-deploy,type:bug,silent-failure",v4.10.0,CRITICAL: rest_deploy:True silently passes failed deploys; flows continue thinking deploy succeeded. Recently filed (2025-12-16). Likely affects MetaDeploy plans -3939,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,metadata.py BaseMetadataApiCall.__call__ wraps every Exception from _process_response (incl. ApexTestException at line 540) in MetadataParseError losing original message,/tmp/repro/2/tests/test_issues_bucket_a.py::test_issue_3939_deploy_apex_test_failure_swallowed,keep-open,"severity:high,area:salesforce-api,type:bug,error-handling",v4.10.0,"Fix: re-raise CCI exception classes (MetadataApiError, MetadataComponentFailure, ApexTestException) without wrapping. Also recently filed; same reporter as #3938; both block production deploys" -3951,metadata-etl,B,bug,REPRODUCED-on-v4.10.0,Live repro: `cci task run set_duplicate_rule_status -o api_names Standard_Rule_for_Leads_with_Duplicate_Contacts -o active False` -> 'Cannot find metadata file .../duplicateRules/Standard_Rule_for_Leads_with_Duplicate_Contacts.duplicateRule'. Same command with the canonical API name format `Lead.Standard_Rule_for_Leads_with_Duplicate_Contacts` succeeds end-to-end (extract -> transform -> deploy -> Success). The functional task is not actually broken; the bug is the unhelpful error when the user omits the Object prefix that the Metadata API requires for DuplicateRule,/tmp/repro/5/tests/issue-3951/output-no-prefix.txt,improve-error-message,"bug,good-first-issue,documentation",v4.10.0,"Two improvements: (1) update set_duplicate_rule_status docs and task option help to show that api_names need the . format; (2) in MetadataSingleEntityTransformTask._transform (base.py:332), when the file is missing, list the files actually retrieved so users can spot the naming gap. Could also pre-validate api_names contain a dot for entity types that require it." -3953,metadata-etl,B,bug,REPRODUCED-on-v4.10.0,"Live CLI repro: `cci task run add_picklist_entries --org X -o picklists 'Account.Status__c' -o entries '[{""fullName"": ""TestValue"", ""label"": ""Test Value""}]'` -> 'The fullName key is required on all picklist values'. AddPicklistEntries._init_options (picklists.py:68) checks `'fullName' in entry for entry in self.options['entries']` directly, but no JSON parser is run on the CLI value first; the CLI passes 'entries' through as a string, so iteration walks the characters of the JSON string, none of which contain the substring 'fullName'. process_list_arg is run on 'picklists' but not on 'entries'",/tmp/repro/5/tests/issue-3953/output.txt,keep-open,"bug,good-first-issue",v4.10.0,"Minimal fix in AddPicklistEntries._init_options: if isinstance(self.options.get('entries'), str): self.options['entries'] = json.loads(self.options['entries']). Apply same pattern to record_types option for consistency. Same class of bug exists in AddFieldsToPageLayout (`fields` and `pages` options); see line 'value is not a valid list' from issue-3613 testing." -3955,robotframework,bug-in-source,bug,REPRODUCED-on-dev,"cumulusci/robotframework/SalesforcePlaywright.py:106 splits size with str.split('x', 1) yielding two strings, then passes them directly to browser.new_context(viewport={""width"": width, ""height"": height}) on line 109-111 without int casting; Playwright rejects strings with ""viewport.width: expected integer, got string""",cumulusci/tests/triage/test_issue_3955.py,keep-open,"bug,robotframework,playwright,good-first-issue",dev,Trivial 1-line fix: cast width/height to int. Pytest stubs the Browser library and asserts new_context receives int dimensions. +number,theme,bucket,repro_type,verdict,evidence_summary,repro_test_path,recommended_pass1,recommended_pass2_labels,verdict_source,notes +675,robotframework,feature-request,feature,REPRODUCED-on-dev,cumulusci/tasks/robotframework/robotframework.py does not configure traceback logging; rg 'traceback|format_exc|format_tb' in cumulusci/robotframework returns 0 matches. Default robot output shows only the exception's str(); full Python tracebacks require --loglevel TRACE or a custom listener which cumulusci does not provide.,,closed:stale-24mo,"cli-usability,robotframework,stale",dev,"Issue from 2018-07, last activity 2018-09, no activity for ~8 years. Two pragmatic workarounds exist today: (1) users can pass options=loglevel:TRACE to the robot task; (2) python keywords can wrap with traceback.format_exc() and log themselves. Workarounds make this low-priority. Close as stale." +710,scratch-org-config,feature,unit-pytest,REPRODUCED-on-dev,"The four+ default scratch org configs in cumulusci/cumulusci.yml:1559 cannot be disabled by a project. `merge_config` (cumulusci/core/utils.py:158, via dictmerge) drops ``None`` overrides, and BaseProjectKeychain._load_scratch_orgs (cumulusci/core/keychain/base_project_keychain.py:149) iterates every key unconditionally. Two XFAIL assertions added showing the issue's proposed `config_file: None` syntax has no effect today.",,keep-open,"enhancement,needs-spec",dev,"API question: should disabling use `config_file: None`, an explicit `disabled: true` flag, or sentinel removal? Tests assert end-state (`dev not in keychain.orgs`) so any of those implementations would pass." +733,cli,A,feature,REPRODUCED-on-v4.10.0,runtime.py:131-133 still raises ClickException with same hard error message; no interactive prompt path,,closed:stale-24mo,"enhancement,cli-usability,stale",v4.10.0,Stale 7yr feature request; confirm dry-run proposal stands +773,docs,feature-with-doc-component,doc-gap,REPRODUCED-on-dev,"cdcarter (2018) asked for tasks to declare ``return_values``/``result`` and for ``cci task info`` plus the web docs to surface them. On dev (1925a3083), ``BaseTask`` (``cumulusci/core/tasks.py:51``) only declares ``return_values`` as a runtime dict (line 64, populated as ``self.return_values = {}`` at line 92) - no declarative schema attribute. ``doc_task()`` in ``cumulusci/utils/__init__.py:354`` walks ``task_options`` and a free-form ``task_docs`` string but emits no ""Return Values"" / ""Returns"" section. The docs themselves admit the gap: ``docs/config.md:740-744`` literally says ""Current task return values are _not_ documented, so finding return values set by a specific task (if any) requires you to read the source code"". 8 years stale but still 100% accurate.",cumulusci/tests/triage/test_issue_773.py,keep-open,"area/docs,area/tasks,type/enhancement",dev,"Pass-2: still actionable. Fix sketch: add a class attr like ``return_values_schema: Dict[str, str]`` (key -> one-line description) on BaseTask, extend ``doc_task`` to render a ""Return Values"" RST section when the attr is non-empty, and backfill the common return-value-emitting tasks (PackageUpload, GithubRelease, PromotePackageVersion, etc.). Same convention can power web docs since web docs use the same ``doc_task``." +808,metadata-etl,B,bug,REPRODUCED-on-dev,UninstallPackaged._init_options (cumulusci/tasks/salesforce/UninstallPackaged.py:25) defaults the 'package' option to project__package__name only; project__package__name_managed is never consulted (compare InstallPackageVersion which does fall back through name_managed -> name -> namespace at install_package_version.py:75-79). uninstall_packaged_incremental therefore retrieves the wrong package when name_managed is set,,keep-open,"bug,good-first-issue",dev,"Static-analysis confirmation; live repro needs a packaging org with a managed package whose name differs from project__package__name. Minimal fix: in UninstallPackaged._init_options, do `self.project_config.project__package__name_managed or self.project_config.project__package__name`. Also revisit jlantz's 2018 follow-up about deprecating name_managed entirely.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d)." +987,robotframework,user-error-or-stale,bug,NOT-REPRODUCED-on-dev,"Issue is Spring 19 Salesforce + Chromedriver 2.46 + Selenium ~3.x shadow-DOM-specific. Reporter explicitly stated workaround works (""I figured out a work-around. Use firefox with geckodriver. Everything works as intended now."") and the underlying Chrome/Selenium/Salesforce stack has changed substantially. cumulusci/robotframework/Salesforce.py:154 click_object_button still uses _jsclick but the upstream shadow-DOM bug it depends on no longer manifests the same way.",,closed:stale-24mo,"stale,user-error",dev,"Reporter found workaround within days; last meaningful activity 2022-06. Spring 19 UI no longer exists. 7 years stale, ineligible for repro without specific reproducible scenario." +1348,cli,A,feature,REPRODUCED-on-v4.10.0,No 'gitlab' or 'bitbucket' references anywhere in cumulusci/; ci_feature flow still uses github_parent_pr_notes/github_automerge_feature tasks,,closed:stale-24mo,"enhancement,stale,wontfix-candidate",v4.10.0,Architectural change scoped to GitHub only; stale 6yr +1350,cli,A,bug,NOT-REPRODUCED-on-v4.10.0,project_config.py:52-57 sets up synthetic 'tasks' namespace package; include_source() at line 662 calls _add_tasks_directory_to_python_path() which extends tasks.__path__ for each loaded source,,closed:not-reproducible-on-v4.10.0,fixed,v4.10.0,Original ModuleNotFoundError fixed via tasks namespace package; collision concern raised in 2022 comments is separate +1432,cli,A,bug,REPRODUCED-on-v4.10.0,core/tasks.py:186-196 _validate_options() only checks required; old-style task_options dict path silently accepts unknown keys (test passed). Pydantic Options class path now rejects extras.,,closed:stale-24mo,"bug,stale,partially-fixed",v4.10.0,Partially mitigated for tasks using new Pydantic Options class; old task_options dict still vulnerable +1769,bulkdata,A,bug,REPRODUCED-on-v4.10.0,"Test code-smell: `lookups[""Id""] = MappingLookup(name=""Id"", table=""accounts"", key_field=""sf_id"")` pattern still present in test_load.py:736 (was line 352 in 2020). davidmreed acknowledged ""horrible hack"" but never refactored. Pattern repeats at lines 754, 773, 801. Used to express UPDATE-on-Id dependency in `_expand_mapping` after_steps fixtures.",,closed:stale-24mo,"test-cleanup,low-priority",v4.10.0,"Issue is a test-fixture style question, never escalated to bug. 6 yrs old." +2013,bulkdata,A,bug,REPRODUCED-on-v4.10.0,"`create_table_if_needed` (utils.py:133-139) calls `Table(tablename, metadata, *fields)` then checks `inspector.has_table()` for the BulkDataException. SQLAlchemy raises `InvalidRequestError: Table 'X' is already defined for this MetaData instance` BEFORE the inspector check fires. Reproduced exact 2020 traceback verbatim with two MappingStep(sf_object=Account, table=Account) entries.",,keep-open,"bug,bulkdata,extract_dataset,error-handling",v4.10.0,"Trivial fix: try/except around Table() to convert to BulkDataException, or use `extend_existing=True`. Or detect the duplicate-table case in mapping_parser at validation time." +2096,bulkdata,A,bug,NOT-REPRODUCED-on-v4.10.0,REST DML (`step.py:778-784 RestApiDmlOperation._record_to_json`) calls `process_bool_arg` for boolean fields. `process_bool_arg` (core/utils.py:53-83) accepts the full Salesforce Data Loader spectrum: yes/y/true/on/1 -> True; no/n/false/off/0 -> False (case-insensitive). Tested all 20 spectrum values; all pass.,,closed:not-reproducible-on-v4.10.0,"resolved,bulkdata",v4.10.0,Fix predates v4.10.0; the spec referenced in the issue is now followed. +2126,keychain,feature,feature,NOT-REPRODUCED-on-dev,"Feature request for `encrypt_all_encryptable_fields` Metadata-ETL task using probabilistic Shield encryption. Author (davidmreed, 2022-01-28) wrote ""feature has been developed but is blocked by bugs in the underlying platform functionality"". No matching task exists in cumulusci/ today (grep for `encryptionScheme`/`encrypt_all_encryptable`/`probabilistic` returns 0 hits in cumulusci/). 5+ years stale, still labelled `blocked`. Not a keychain bug \u2014 theme misclassification (encryption-via-Shield, not encryption-at-rest).",,closed:stale-24mo,"area/metadata-etl,blocked",dev,"Theme mislabel: this is metadata-etl/Shield, not keychain. Pass-2: relabel before closing; if owner still wants it, keep-open with `blocked`." +2140,cli,A,feature,REPRODUCED-on-v4.10.0,runtime.py get_org() calls keychain.get_org which raises OrgNotFound; cli/org.py:530-531 just shows 'Org X does not exist'; no interactive prompt offering scratch configs,,closed:stale-24mo,"enhancement,cli-usability,stale",v4.10.0,Stale 5yr feature request +2153,ci-integration,A,feature,REPRODUCED-on-dev,"Code scan of cumulusci/tasks/github/merge.py shows _create_conflict_pull_request (lines 264-288) only calls self.repo.create_pull(...) for the new auto-generated ""Merge into "" PR. There is no call to comment on the original (source) PR or its branch's open PR. Repo-wide grep for ""create_comment"" / ""issue_comment"" in cumulusci/tasks/github returns no matches in production code (only in test fixture util_github_api.py). Feature is still unimplemented on v4.10.0.",,keep-open,"enhancement,github,merge-conflict",dev,"Small enhancement; could be implemented inside _create_conflict_pull_request after pull = self.repo.create_pull(...). Need design decision on how to find the ""original PR"" (search open PRs whose head==branch_name?).; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d)." +2325,bulkdata,A,feature,REPRODUCED-on-v4.10.0,"No `set_validation_rule_status` or `disable_validation_rules` task in cumulusci.yml. Analogs exist for triggers (`disable_tdtm_trigger_handlers`/`restore_tdtm_trigger_handlers` lines 738-747) and DuplicateRules (`set_duplicate_rule_status` -> tasks/metadata_etl/duplicate_rules.py). Implementation pattern is established: a `MetadataSingleEntityTransformTask` subclass with `entity = ""ValidationRule""` would satisfy this.",,keep-open,"enhancement,bulkdata,metadata_etl,good-first-issue",v4.10.0,Clear pattern to follow from SetDuplicateRuleStatus. Small implementation effort. +2402,cli,A,feature,REPRODUCED-on-v4.10.0,cli/flow.py:119-145 flow_run only has --delete-org flag; no --rebuild-org option; no rg matches anywhere,,closed:stale-24mo,"enhancement,stale",v4.10.0,Stale 5yr +2500,docs,feature-with-doc-component,doc-gap,REPRODUCED-on-dev,"prescod (2021) flagged that ``ignore_failure`` is not documented. On dev, the option is real and supported: ``Step.ignore_failure: bool = False`` (``cumulusci/utils/yaml/cumulusci_yml.py:45``), used in ``flowrunner.py:667`` as ``allow_failure=step_config.get(""ignore_failure"", False)``, and present in the JSON schema (``cumulusci/schema/cumulusci.jsonschema.json:149``). In the docs directory, the only mentions are (a) a single example YAML at ``docs/config.md:800`` (in a release-flow snippet) and (b) a one-line changelog blurb at ``docs/history.md:5993``. The ""Flow Configurations"" chapter has subsections for ""Add a Flow Step"", ""Skip a Flow Step"", ""Replace a Flow Step"", ""Conditionally Run a Flow Step"" (``when:``), but no parallel subsection for ``ignore_failure``. The follow-up GUS ticket [internal-ID-redacted] (davidmreed, 2022-03-28) was created but nothing landed.",cumulusci/tests/triage/test_issue_2500.py,keep-open,"area/docs,area/flows,good-first-issue",dev,"Pass-2: trivial documentation PR. Fix sketch: add a ``### Ignore a Failed Step`` (or ``Continue on Step Failure``) subsection under ``## Flow Configurations`` in ``docs/config.md``, parallel to ""Conditionally Run a Flow Step"". Cover: (1) what the option does (don't raise the task's exception; the flow continues with the next step); (2) interaction with ``result`` / ``return_values`` for downstream steps that conditioned on success; (3) when NOT to use it (silently swallowing failures hides regressions in CI); (4) link to the ``when:`` mechanism for branching instead of swallowing." +2505,bulkdata,A,feature,NOT-REPRODUCED-on-v4.10.0,"`MappingStep.soql_filter` field added (mapping_parser.py:120). `extract.py:142-147` applies it via `append_filter_clause` (extract.py:420). Also surfaced in extract-mapping generator (extract_mapping_file_generator.py:26 reads `where:` from declarations into `soql_filter`). Tests cover plain filter, filter prefixed with WHERE, and no-record-type variants (test_extract.py:1216,1248,1280).",,closed:feature-implemented,"resolved,bulkdata,extract_dataset",v4.10.0,WHERE-clause filtering for extraction is implemented via `soql_filter` per mapping step. +2506,bulkdata,A,feature,REPRODUCED-on-v4.10.0,"Snowfakery task DOES respect `get_debug_mode()` (snowfakery.py:241,355,385,565) and prints the working tempdir on each loop iteration. But the core bulk operations (extract.py, load.py, step.py) have no `--debug` mode that retains tempfiles or logs their paths. extract.py and step.py have ZERO matches for debug_mode/get_debug_mode/delete=False.",,keep-open,"enhancement,bulkdata,extract_dataset,load_dataset,debugging",v4.10.0,Partial: Snowfakery only. Could be extended to load_dataset/extract_dataset by wiring `get_debug_mode` and using TemporaryDirectory(delete=False) when set. +2507,cli,A,feature,REPRODUCED-on-v4.10.0,"No undo_insert task in repo; bulkdata/load.py and snowfakery have enable_rollback option but only triggers on error, not the requested ad-hoc undo",,closed:stale-24mo,"enhancement,stale,partially-fixed",v4.10.0,Partial mitigation via enable_rollback (rollback on error); standalone undo task still missing +2508,bulkdata,A,feature,REPRODUCED-on-v4.10.0,"No retry-only-failed-records feature in v4.10.0. `cci task list` shows zero retry-named tasks. There is an `enable_rollback` option on load_dataset (load.py:97-98, RollbackType enum at load.py:1051) but that performs the OPPOSITE: undoes successful inserts when failures occur. RowErrorChecker (utils.py:158) only logs/raises; it does not persist failed rows for retry.",,keep-open,"enhancement,bulkdata,load_dataset,reliability",v4.10.0,Distinct from rollback. Would require persisting failed-record CSV/SQL output and a new task that consumes it. +2667,auth,enhancement,cli-output,NOT-REPRODUCED-on-dev,"cumulusci/cli/org.py:204 already emits ""Connecting org using the {connected_app_name} connected app..."" before connecting. Implemented by commit 40520bee4 (2022-01-31, post-issue-filing). Existing tests at cumulusci/cli/tests/test_org.py:135 and :191 assert the connected-app name is present in CLI output for both default (""built-in"") and non-default (""other"") connected apps. All 10 org_connect tests pass on dev (1925a3083). Issue description requested ""Using connected_app 'xyzzy'""; current implementation produces functionally equivalent message.",,close-stale,"resolved,implemented",dev,"Originally requested by prescod 2021-06-08; davidmreed noted [internal-ID-redacted] covering on 2022-01-28. Implementation landed shortly after. davisagli's follow-up suggestions (storing connected_app on OrgConfig, configurable login URLs per connected app) are partially addressed: org_config.config[""connected_app""] is now stored (line 155). Login-URL-per-connected-app remains a separate concern not blocking close." +2697,cli,B,bug,INCONCLUSIVE-needs-scratch-slot,namespaced field is sourced from cci config not auto-derived from SFDX qa.json; keychain create_scratch_org defaults namespaced=False (base_project_keychain.py:74). Requires scratch org to confirm cli/org.py 'org info' output behavior matches reporter's expectation,,closed:stale-24mo,"bug,stale,needs-info",v4.10.0,User expectation conflicts with cci design; field is cci-controlled not derived from SFDX def. Scratch creation skipped (DevHub limit prudence); behavior likely unchanged +2826,metadata-etl,B,bug,REPRODUCED-on-dev,PackageXmlGenerator.parse_types (cumulusci/tasks/metadata/package.py:107) calls os.listdir(self.directory) without a pre-check; UpdatePackageXml._run_task (line 612) does not guard. Unit repro raises FileNotFoundError when path is missing rather than silently no-opping the way the issue title says deploy_unmanaged 'is supposed to',,keep-open,"bug,good-first-issue",dev,"Behavior unchanged from 2021. Smallest change: in UpdatePackageXml._init_task (or _run_task) skip with logger.info('No package directory at {path}; skipping') when not Path(path).exists(). Could also be done at the deploy_unmanaged flow level via a `when:` clause, e.g. when: project_config.has_package_directory.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d)." +2951,bulkdata,A,bug,REPRODUCED-on-v4.10.0,"Loader has no special PricebookEntry sequencing logic. Within a single Insert PricebookEntry mapping step, records (whether targeting Standard Price Book or custom) are sent to Bulk/REST in mixed order, hitting STANDARD_PRICE_NOT_DEFINED. Mitigation: hardcoded_default_declarations.py:14-18 filters out Standard Price Book during extract_dataset by default, so the typical extract->load round-trip avoids this. But manually-authored mappings (like reporter's) still hit it.",,keep-open,"bug,bulkdata,load_dataset,pricebook,documentation",v4.10.0,"Could be addressed by either (a) auto-splitting PricebookEntry into two implicit steps (standard first, custom second), or (b) documenting that PricebookEntries against Standard pricebook must be in a separate, earlier mapping step." +2979,packaging,A,feature,REPRODUCED-on-v4.10.0,deploy task in cumulusci.yml still hardcodes path: src; default_package_path exists but is not wired into Deploy task,,keep-open,"severity:low,area:packaging,area:sfdx,state:needs-design",v4.10.0,default_package_path is wired only into create_package_version; would need backwards-compat design (per davisagli comment) +3015,cli,A,feature,REPRODUCED-on-v4.10.0,cli/org.py:519-543 org_remove always calls delete_org() if can_delete; no --keep-org or -o flag,,closed:stale-24mo,"enhancement,stale",v4.10.0,Stale 4yr; davisagli workaround (delete .org file directly) still applies +3024,cli,A,feature,REPRODUCED-on-v4.10.0,Flow groups in cumulusci/cumulusci.yml still appear in original order: Metadata Transformations first; Continuous Integration appears at position ~23. User-requested 'Org Setup' group does not exist (uses 'Setup' instead),,closed:stale-24mo,"enhancement,stale",v4.10.0,Stale 4yr cosmetic VS Code extension request +3137,metadata-etl,A,feature,REPRODUCED-on-v4.10.0,CustomObjectParser at package.py:443-461 still skips non-__c/__mdt/__e/__b objects; no opt-in option added to UpdatePackageXml,,keep-open,"severity:low,area:metadata-etl,type:enhancement,state:needs-design",v4.10.0,Maintainer agreed in 2022 it's by-design; needs design for an include_standard_objects option +3161,cli,A,feature,REPRODUCED-on-v4.10.0,flowrunner.py:317-320 _obfuscate_if_sensitive masks if task_options info.sensitive==True; partial implementation. No CLI-time hide flag for ad-hoc values like robot__vars; robot vars option not marked sensitive,,closed:stale-24mo,"enhancement,stale,partially-implemented",v4.10.0,Infrastructure exists for sensitive task option metadata; user's ad-hoc CLI -o hiding still missing +3165,metadata-etl,B,bug,REPRODUCED-on-v4.10.0,"_expand_package_xml_objects (which adds objects referenced by record_types to the retrieve package.xml) is only invoked from inside _expand_package_xml, which is gated on include_packaged_objects=True (update_profile.py:137-138 and 182). When include_packaged_objects is False (the default unless project's minimum_cumulusci_version >= 3.9.0), record_types referencing standard objects not already in admin_profile.xml (e.g. Case) are never added to the retrieve, the retrieved Admin profile lacks those recordTypeVisibilities, and _set_record_types raises TaskOptionsError 'Record Type X not found in retrieved Admin.profile'. Existing test test_init_options__include_packaged_objects asserts _expand_package_xml.assert_not_called() in that branch (test_ProfileGrantAllAccess.py:609-615) which proves the gating",,keep-open,bug,v4.10.0,"Smallest fix: in update_profile.py:137 always call self._expand_package_xml_objects(package_xml) (regardless of include_packaged_objects), and only call self._expand_package_xml when include_packaged_objects is True. _expand_package_xml_objects only walks the user-supplied record_types option; it does not need a Tooling API query." +3167,metadata-etl,B,feature,NOT-REPRODUCED-on-v4.10.0,"page_layout key on record_types is fully implemented in ProfileGrantAllAccess._set_record_types (update_profile.py:280-298). Documented in the record_types task option description (update_profile.py:32-34). Landed in PR #3243 (commit f2ff04bd5) in June 2022, well before v4.10.0",,close-as-implemented,enhancement,v4.10.0,Feature is shipped; documentation is in cci task info `update_admin_profile`. Could add a CHANGES note or a docs example showing the page_layout usage. +3283,bulkdata,A,bug,NOT-REPRODUCED-on-v4.10.0,"PR #3361 (commit b0bfb70e0, ""Support updates and upserts with blank dates represented by strings"") is in v4.10.0 (verified via `git merge-base --is-ancestor`). Fix at step.py:795-796: for UPDATE/UPSERT, empty strings are converted to None. Repro test confirms empty Birthdate -> JSON null for both UPDATE and UPSERT, and is dropped entirely for INSERT.",,closed:fixed-by-pr-#3361,"resolved,bulkdata,load_dataset",v4.10.0,"Reporter's own last comment (""Fixed in #3361"") confirms this; repro test now verifies behavior on v4.10.0 source." +3306,scratch-org-config,feature,no-test-feature-request,NOT-REPRODUCED-on-dev,"`cci org scratch ... --release preview` exists in cumulusci/cli/org.py:567 but `cci flow run` has no `--release`/`--preview` flag (cumulusci/cli/flow.py 119-150). Internally tracked as [internal-ID-redacted]; no PR landed. Issue is a never-implemented enhancement, not a regression.",,keep-open,"enhancement,needs-spec",dev,"Workaround today is `cci org scratch --release preview` then `cci flow run dev_org --org `. No test written - API/UX (--preview vs --release flag, semantics for non-scratch orgs) not yet specced." +3307,cli,A,feature,REPRODUCED-on-v4.10.0,cli/project.py project_init only renders internal Jinja templates from cumulusci/files/templates/project; no --template option exists,,closed:stale-24mo,"enhancement,stale",v4.10.0,Stale 4yr; user marked 'low priority/nice to have' +3320,metadata-etl,A,feature,NOT-REPRODUCED-on-v4.10.0,deactivate_flow task is shipped in cumulusci/cumulusci.yml:10-15 using ActivateFlow class with status:False,,closed:feature-implemented,"area:metadata-etl,type:enhancement,resolution:already-implemented",v4.10.0,Reporter likely missed that deactivate_flow exists; ActivateFlow.status:False does the work +3331,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,metadata_map.yml line 46 maps assignmentRules folder to type AssignmentRule (singular); MDAPI requires AssignmentRules plural,,keep-open,"severity:medium,area:metadata-etl,type:bug,good-first-issue",v4.10.0,One-line fix in metadata_map.yml; reporter offered a PR; cross-cutting hint: autoResponseRules already plural in same file +3347,release-unlocked-beta-typeerror,C,code-only,NOT-REPRODUCED-on-v4.10.0,create_package_version.py:158-159 now raises TaskOptionsError(PERSISTENT_ORG_ERROR) early when org_config.config_file is None; replaces the cryptic TypeError reported. Fix landed in commit 2a9cadcb1 on 2023-10-12. Existing test at cumulusci/tasks/tests/test_create_package_version.py::TestPackageConfig::test_org_config validates the new behavior (passes on HEAD).,,close-with-comment,resolved-by-clear-error-message,v4.10.0,Cryptic TypeError replaced by clear actionable TaskOptionsError. Underlying limitation (cannot use persistent org for 2GP package upload) is documented now. +3349,bulkdata,A,bug,REPRODUCED-on-v4.10.0,"mapping_parser.py:177-179 still names recordtype tables as f""{self.sf_object}_rt_mapping"" (and ""_rt_target_mapping""). Two MappingStep entries for the same sf_object (e.g. Account business vs PersonAccount) collide on the same SQLite table when extracted/loaded together. load.py:552 and extract.py:259/393 both use the sf_object-derived names with no per-step disambiguation.",,keep-open,"keep-open,bug,area:bulkdata,severity:major,v5-candidate:yes",v4.10.0,"Has maintainer label wi-created . Real bug, fix would change get_source/destination_record_type_table to use self.table when present. Active community impact (Person Accounts + Business Accounts a common case)." +3353,bulkdata,B,feature,REPRODUCED-on-v4.10.0,snowfakery.py:159-162 validates recipe via Path(recipe).exists() with no SOURCE_NAME:path resolution. No call to project_config.sources / source_url anywhere in snowfakery.py. Recipe string is passed straight to Snowfakery as a filesystem path.,,keep-open,"keep-open,enhancement,area:bulkdata,severity:minor,v5-candidate:maybe",v4.10.0,"Community resurfaced this in 2024-08 (davidjray, jnesong). Workaround: cci org import. Fix would resolve SOURCE_NAME:path via project_config.get_source(name).fetch().path before Path() validation." +3360,bulkdata,A,feature,NOT-REPRODUCED-on-v4.10.0,"action: select was added by commit b15945203 (Aug 2024) - well before v4.10.0. select_utils.py + step.py SELECT branch + mapping_select.yml fixture confirm full implementation. select_options supports strategy/filter/priority_fields. This is exactly the requested ""read-only object lookup"" feature - populates the lookup table from existing org records without DML.",,closed:feature-implemented,"closed:feature-implemented,enhancement,area:bulkdata",v4.10.0,SELECT action lets you reference existing records by similarity / external-id without inserting. Documented in mapping_select.yml. Issue should be closed citing select feature. +3407,keychain,bug,type-bug,REPRODUCED-on-dev,"`BaseProjectKeychain.set_service` (base_project_keychain.py:202-209) annotates `service_config: ServiceConfig`, but `EncryptedFileProjectKeychain._load_service_files` (encrypted_file_project_keychain.py:717) calls it with a raw `str` (encrypted file body) plus `config_encrypted=True`. `_set_service` (line 583-605) explicitly branches on `config_encrypted` and stores the raw blob without ever constructing a ServiceConfig. Annotation is therefore wrong. Two-test repro xfails on dev: (a) annotation-vs-caller introspection; (b) runtime call with a string succeeds, contradicting the type.",cumulusci/tests/triage/test_issue_3407.py,keep-open,"area/keychain,good-first-issue,type/typing",dev,"Trivial fix: change annotation to `Union[ServiceConfig, str]` or `ServiceConfig | bytes | str` and update docstring. Optionally split into `set_service` (validated ServiceConfig) and `set_encrypted_service` (raw blob) for cleaner API." +3418,packaging,B,bug,INCONCLUSIVE-needs-cumulus-actions-workflow,cci has no auth:sfdxurl:store path; error originates from SFDO-Community/standard-workflows action; comment from davidmreed in 2022 indicated planned external fix,,unchanged,"needs-info,needs-repro",v4.10.0,"Bug is in the third-party github action (SFDO-Community/standard-workflows production-1gp.yml), not in cci. davidmreed promised to address externally; verify SFDO-Community fix landed before triaging." +3429,packaging,A,feature,REPRODUCED-on-v4.10.0,No CUMULUSCI_YML env var or --config-file CLI flag in v4.10.0; config_filename hardcoded; PR #3969 (extra-yaml-cli-flag) is in flight but not merged,,keep-open,"severity:medium,area:packaging,area:cli,state:in-progress",v4.10.0,PR #3969 on branch extra-yaml-cli-flag adds --extra-yaml + CUMULUSCI_EXTRA_YAML; not yet in v4.10.0; close once #3969 merges +3440,packaging,A,feature,REPRODUCED-on-v4.10.0,default_package_path in project_config.py:517 only honors first packageDirectory with default:true; no name-based lookup or multi-package warnings,,keep-open,"severity:low,area:packaging,area:sfdx,area:multi-package",v4.10.0,Same multi-package theme as #2979 and #3429; could be solved jointly with a multi-package config story +3441,packaging,A,feature,REPRODUCED-on-v4.10.0,version_base accepts None / 'latest_github_release' / literal version; no syntax to reset back to default after a flow override; CCI lacks generic null-override mechanism,,keep-open,"severity:low,area:packaging,area:flow-overrides,area:cli",v4.10.0,yippie's comment generalizes the request to a CCI-wide null-override feature; could be solved by a 'default' sentinel string in create_package_version._get_base_version_number +3446,packaging,B,bug,REPRODUCED-on-v4.10.0,_parse_version(None) raises NoneType.split when push_qa is run with --metadata_package_id but no --version/--version_id; user comment about Push API activation is a downstream concern,,keep-open,"bug,good-first-issue",v4.10.0,Two-part fix is wanted: (1) validate that version or version_id is required in _init_options; (2) wrap MetadataPackage SOQL in a check that surfaces a friendlier error if Push API is not activated on the org. +3464,docs,feature-with-doc-component,doc-gap,REPRODUCED-on-dev,"yippie (2022) asked for ALL ``cumulusci.yml`` ``project:`` keys to be defined with at least one sentence each in https://cumulusci.readthedocs.io/en/stable/config.html. On dev, the ``Project`` Pydantic model (``cumulusci/utils/yaml/cumulusci_yml.py:135``) declares 9 fields: ``name``, ``package``, ``test``, ``git``, ``dependencies``, ``dependency_resolutions``, ``dependency_pins``, ``source_format``, ``custom``. ``docs/config.md`` shows ONE example YAML block at line 281 covering only ``name`` + ``package``. Substring scan of the file: ``dependency_resolutions`` 0 hits, ``dependency_pins`` 0 hits - those are documented only in ``docs/dev.md`` (lines 499, 509, 535, 596, 724, 727), which is precisely the ""docs are scattered to the wind"" complaint in the issue. ``source_format`` is mentioned in flow examples but not as a project-level key reference. Sub-models (``Package``, ``Git``, ``Test``, ``DependencyResolutions``) have additional second-level fields with no reference at all in ``config.md``. jstvz acknowledged the gap in 2022.",cumulusci/tests/triage/test_issue_3464.py,keep-open,"area/docs,type/enhancement",dev,"Pass-2: still actionable; significant doc work. Fix sketch: add a ``## Project Configuration Reference`` (or expand the existing ``### Project Configurations`` at line 673) to ``docs/config.md`` that enumerates every ``project:`` key with one-sentence semantics. Source the enumeration from the ``Project``/``Package``/``Git``/``Test``/``DependencyResolutions`` Pydantic models so it stays in sync. Alternative low-effort path: generate the reference from the Pydantic ``__fields__`` + field descriptions at docs-build time (Sphinx extension) - this requires backfilling ``Field(description=...)`` calls on each model attribute, but produces an always-accurate page. Cross-link to the in-depth dependency pages in ``docs/dev.md`` rather than duplicating their content." +3466,packaging,A,feature,NOT-REPRODUCED-on-v4.10.0,RunApexTests in cumulusci/tasks/apex/testrunner.py exposes test_suite_names option (line 173); fully wired through _get_test_classes_from_test_suite_names,,closed:feature-implemented,"area:packaging,area:apex,state:resolved",v4.10.0,Implemented at some point after the 2022-12 request; [internal-ID-redacted] backlog item appears completed +3470,cli,A,feature,REPRODUCED-on-v4.10.0,cumulusci.yml:823 only ci_master flow defined; no ci_main alias. davidmreed acknowledged backlog need for flow aliasing first,,closed:stale-24mo,"enhancement,stale,inclusive-language",v4.10.0,Naming/inclusivity request; needs flow aliasing infra +3471,ci-integration,A,bug,REPRODUCED-on-dev,"cumulusci/tasks/github/merge.py line 251 still emits f""Merged {compare.behind_by} commits into branch: {branch_name}"" using github3's compare.behind_by. ""behind_by"" is computed by GitHub's compare-commits API and reflects how many commits the merged commit is behind the destination tip after the comparison ref-point; for some merges (e.g. when the merge target shares an ancestor at the same ref or when GitHub's compare picks the same head), this can return 0 even though the merge POST at line 249 succeeded and shipped a real commit. git log shows the line was last touched as part of the original MergeBranch implementation; no fix has landed since the issue was filed (2022-12). Pattern reported (README/test.txt vs source-code changes) is consistent with how GitHub's compare API treats ""effectively no-op"" merges where the file content already matches downstream content via merge-base.",,keep-open,"bug,github,merge,low-priority",dev,"Fix: replace compare.behind_by with len(list(compare.commits)) or report the actual merged commit SHA returned from self.repo.merge(...). Existing test_merge.py asserts ""Merged 1 commits"" in normal cases but has no test for the behind_by=0 case.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d)." +3479,ci-integration,A,bug,NOT-REPRODUCED-on-v4.10.0,"Reported error ""Expecting value: line 1 column 1 (char 0)"" is the bare json.JSONDecodeError. In v4.10.0 cumulusci/core/config/sfdx_org_config.py lines 38-55 wrap both nonzero return codes AND JSON parse failures from `sfdx org display --json` in SfdxOrgException with explicit ""Failed to parse json from output. Exception: ... Output: ..."" message (wrapping landed in commit 017bc49f4 on 2020-11-24, predating the 2023-01 issue, so the symptom may have come from a different code path or be a regression in the user's specific 3.71.0 environment). davidmreed's only reply (2023-02-22) correctly diagnoses the root cause as shell-expansion of the multiline GHA secret (echo ${{ secrets.DEV_AUTH_URL }} without quotes). Reporter never responded. The issue is a user CI/workflow-config problem; cci's only contribution is the wrapper message, which is already in place on v4.10.0.",,closed:not-reproducible-on-v4.10.0,"awaiting-more-details,external-config",v4.10.0,"No reporter response in 3+ years; root cause is in user's GHA workflow (unquoted multiline secret), not cci. Improved SfdxOrgException wrapping is already in v4.10.0." +3485,cli,A,bug,REPRODUCED-on-dev,cumulusci/tasks/apex/testrunner.py:803-834 still writes a single tag with no declaration and no wrapper; matches user-reported invalid JUnit format exactly.,,keep-open,"bug,area:apex,good-first-issue",dev,Fix is mechanical: prepend XML declaration and wrap in . Old issue but bug still reproducible against v4.10.0.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). +3492,cli,A,feature,REPRODUCED-on-dev,cumulusci/cli/flow.py:152-162 splits -o key on '__' into exactly 2 parts; passing project__custom__attr would actually error with 'too many values to unpack'. No project-level option override path exists from -o.,,keep-open,"enhancement,area:cli",dev,Feature still missing. Would need new -p / --project-option flag or smarter -o parser.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). +3506,cli,A,feature,REPRODUCED-on-dev,"cumulusci/core/flowrunner.py:660-672 sets when=step_config.get('when') only on the task: branch. The flow: branch at lines 674-697 never reads when from step_config, so when on a flow-call step is silently ignored.",,keep-open,"enhancement,area:flows",dev,Confirmed silent-ignore behavior the user complained about.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). +3518,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,picklists.py:177 stores str.lower bound method (not call) so if-default check at line 214 always truthy; every entry overrides record-type default,,keep-open,"severity:high,area:metadata-etl,type:bug",v4.10.0,Two-line fix at picklists.py:177 (call .lower()) plus rewrite assignment to avoid shadowing +3541,keychain,bug,bug,REPRODUCED-on-dev,"`BaseProjectKeychain.create_scratch_org` (base_project_keychain.py:77-79) builds `sfdx_alias = f""{project_config.project__name}__{org_name}""`. When `project__name` is None (no `project.name` in cumulusci.yml, or project not yet resolved during the eager `_load_scratch_orgs` pass invoked at keychain init, line 45), the resulting alias is the literal string ""None__dev"" \u2014 exactly matching the reporter. Repro builds a BaseProjectConfig without project.name, calls create_scratch_org, asserts alias doesn't contain literal 'None'; xfails on dev. Second test exercises the eager-load path via __init__.",cumulusci/tests/triage/test_issue_3541.py,keep-open,"area/keychain,area/scratch-orgs,bug",dev,Issue currently labelled `cannot-reproduce` \u2014 evidence here contradicts that label. Recommend removing it. Fix: guard against None (raise CumulusCIException with clear message OR fall back to org_name). Mind the upgrade path \u2014 existing keychains may already contain `None__*` aliases needing migration. +3542,packaging,B,bug,INCONCLUSIVE-needs-2GP-CI-pipeline,github_package_data uses self.project_config.repo_commit (local SHA) verbatim; if the upstream workflow recorded version_id under a merge-commit SHA from pull_request trigger; locally checked-out PR head SHA will not match; cci-side code path unchanged on v4.10.0,,unchanged,"needs-repro,2gp",v4.10.0,Root cause is workflow-vs-local SHA mismatch. May need a docs/CI fix in cumulus-actions/standard-workflows rather than cci. Could add a fallback: search by SHA on parent commits. +3543,metadata-etl,A,feature,REPRODUCED-on-v4.10.0,DxConvertFrom in cumulusci/tasks/dx_convert_from.py only exposes extra and src_dir options; no load_sfdx_project_paths or resolve_sfdx_package_dirs,,keep-open,"severity:low,area:metadata-etl,type:enhancement",v4.10.0,Reporter offered draft PR; could be folded into multi-path support across deploy/uninstall_packaged_incremental too +3544,update-admin-profile-person-accounts-namespaced,C,e2e-config-required,INCONCLUSIVE-needs-namespaced-project,Provisioned scratch org [scratch-org] from orgs/person_accounts.json (PersonAccounts + Communities + ContactsToMultipleAccounts features). update_admin_profile task ran SUCCESSFULLY against this non-namespaced person_accounts org on v4.10.0. Bug condition requires BOTH PersonAccounts AND namespaced:true on the project; CumulusCI itself has no project namespace so the second condition cannot be satisfied without registering a namespace in the configured DevHub. No code fix found referencing #3544 or [internal-ID-redacted] in update_profile.py / admin_profile.xml since 2023.,,needs-info,needs-namespaced-project,v4.10.0,Tracked internally as [internal-ID-redacted] per davidmreed comment 2023-02-22. Discovered adjacent latent bug at cumulusci/utils/__init__.py:229 where namespaced_org=True with no project namespace raises TypeError: unsupported operand type(s) for + 'NoneType' and 'str' - distinct from #3544 but worth a separate ticket. +3549,cli,A,feature,REPRODUCED-on-v4.10.0,"cumulusci/tasks/salesforce/Deploy.py exposes test_level/specified_tests but does not capture or write JUnit/JSON test output (no junit_output option, no _write_output for tests).",,keep-open,"enhancement,area:metadata-deploy",v4.10.0,Related to #3564. Reasonable feature ask; not implemented. +3561,metadata-etl,B,bug,NOT-REPRODUCED-on-v4.10.0,"Bug was reported by yippie (who is also the PR author). Fix landed in commit 56e10665e (PR #3566, May 2024) by the original reporter. RetrieveUnpackaged._init_options now stores file content under options['package_xml_content'] and leaves the file-path option intact (RetrieveUnpackaged.py:29-31), so the second _init_options invocation in MetaDeploy no longer corrupts the path",,close-as-fixed,,v4.10.0,Suggest closing with a back-reference to PR #3566 in case the original reporter never got back to flip the issue state. +3570,cli,A,feature,REPRODUCED-on-dev,cumulusci/core/flowrunner.py supports per-step ignore_failure (StepSpec.allow_failure) but has no concept of finally:/on_error:/cleanup: steps in a flow definition. No 'always-run' or post-error step type exists.,,keep-open,"enhancement,area:flows",dev,Big design change; unlikely to ship without strong demand.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). +3585,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,PackageXmlGenerator on .object containing unbound xsi:nil='true' raises XML parse error; no namespace shim added,,keep-open,"severity:medium,area:metadata-etl,type:bug,sfdx-compat",v4.10.0,Fix: register xsi namespace before parsing or pre-strip xsi:nil attributes; also fixes #3692 class of issues +3587,packaging,B,feature,NOT-REPRODUCED-on-v4.10.0,PackageXmlGenerator only emits / when self.managed is truthy; no warning is logged when install_class set with managed=False; live cci task run update_package_xml --install_class X confirms silent drop,,keep-open,"enhancement,good-first-issue",v4.10.0,Feature still missing. Smallest implementation: in UpdatePackageXml._init_task; if install_class/uninstall_class set but not self.options.get('managed'); emit self.logger.warning(...). +3593,packaging,A,bug,REPRODUCED-on-dev,SFDXOrgTask._get_command in cumulusci/tasks/sfdx.py:50 unconditionally appends ' -o ' for ScratchOrgConfig; no opt-out option,cumulusci/tests/triage/test_issue_3593.py,keep-open,"severity:medium,area:packaging,area:sfdx,area:dx-task,state:needs-design",dev,Repro test confirms command becomes 'sf project convert source ... -o test@example.com'; sf cli rejects -o for subcommands like 'project convert source'; suggested fix is an opt-out option or auto-detect; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). +3600,packaging,B,feature,NOT-REPRODUCED-on-v4.10.0,cci task option processing only substitutes $project_config. via PROJECT_CONFIG_RE; YAML loader uses plain yaml.safe_load with no env-var resolver; live install_managed --version '${MY_FAKE_VERSION}' shows literal string in interactive prompt,,keep-open,enhancement,v4.10.0,Feature not implemented. Scope likely larger than install_managed (would touch all task options); design decision needed: $env:VAR vs ${VAR} syntax; backwards-compat impact on literal $-strings. +3602,robotframework,feature-request,feature,REPRODUCED-on-dev,"cumulusci/robotframework/SalesforcePlaywright.py:60 open_test_browser signature is (self, size=None, useralias=None, wait=True, record_video=None) - no kwarg accepts browser options or **kwargs. cumulusci/robotframework/Salesforce.robot:103 ""Open Test Browser"" robot keyword only takes size/alias/wait/useralias. Chrome options are constructed by Get Chrome Options (Salesforce.robot:157) which hard-codes --disable-notifications with no extension hook.",,keep-open,"enhancement,robotframework,playwright,good-second-issue",dev,"Small-medium feature: add browser_options/extra_options kwarg to both Selenium and Playwright open_test_browser implementations, forward to webdriver options / new_browser kwargs. Pytest asserts signature exposes such a hook." +3603,dependencies,A,bug,REPRODUCED-on-v4.10.0,"Source ref/tag not found leaks raw `404 [No message]` from GitHubSource.resolve() (cumulusci/core/source/github.py L126). Repo-not-found cases (1,2) and `release:` strategy fail (case 5) are already wrapped in DependencyResolutionError; ref-not-found case (3) is not, and dep strategy fall-through (case 4) names the dep but not the strategies tried.",,keep-open,"theme:dependencies,error-handling,good-first-issue",v4.10.0,"Partial repro. Cases 1,2,5 were addressed by commit 738d4a8a4 (2021); cases 3 and 4 remain." +3604,dependencies,A,feature,REPRODUCED-on-v4.10.0,No CCI task exists to write computed dependencies into `sfdx-project.json`. Confirmed via `cci task list` and grep: zero references to writing/updating sfdx-project.json. [internal-ID-redacted] was filed by maintainer in 2023 but no implementation has shipped through v4.10.0.,,keep-open,"theme:dependencies,enhancement,wi-created",v4.10.0,Pure feature request; gap persists. wi-created label already present. +3605,packaging,A,feature,NOT-REPRODUCED-on-v4.10.0,PackageUpload (upload_production backing class) exposes major_version and minor_version options (cumulusci/tasks/salesforce/package_upload.py:39-46); _validate_versions handles major bump,,closed:fixed-by-pr-#3651,"area:packaging,area:1gp,state:resolved",v4.10.0,Implemented in commit 87b94440e (PR #3651 'Deploy Major and Minor Version option in upload_production task') +3607,cli,A,bug,INCONCLUSIVE-needs-org-with-managed-package,"Code path traced in cumulusci/tasks/apex/testrunner.py: retry_failures regex compiled at line 209-222, _is_retriable_failure (line 405) checks Message and StackTrace via re.search. Repro test at _(repro evidence; see narrative)_ confirms 'UNABLE_TO_LOCK_ROW' regex DOES match the user's quoted message in pure Python. Likely user-side: wrapped exception so Message lacks the literal token, or managed-class symbol-table skip at line 448-452.",,closed:stale-24mo,"bug,area:apex,needs-info",v4.10.0,Code logic is correct as written. To definitively reproduce we need a managed package and an org producing the exact failure shape. 30+ months no follow-up from reporter. +3609,cli,A,bug,INCONCLUSIVE-needs-live-cli-test,"cumulusci/tasks/sfdx.py is now a thin shell wrapper around 'sf {command}' (SFDX_CLI = 'sf' in v4.x; was 'sfdx' in 3.76.0 when reported). The user's syntax 'plugins:install ...' is sfdx-style with colon; 'sf' uses 'plugins install' (space). Underlying timeout originates from the sfdx/sf CLI itself, not CCI.",,closed:stale-24mo,"bug,upstream:sf-cli",v4.10.0,"Not a CCI bug. CCI faithfully shells out. Old issue, CLI changed substantially since." +3610,apex,Fixed-on-dev,negative-test,NOT-REPRODUCED-on-dev,Fixed by PR #3681 (commit 84389d998); cumulusci/tasks/apex/testrunner.py:500-510 handles None method name; regression tests already exist on dev,,closed:pr-resolved-#3681,,dev,"Fixed by PR #3681 (commit 84389d998b4783ddd2ff062f486a2366709cac27, ""Handling exception when the Tooling API returns a test result with a null method name""). cumulusci/tasks/apex/testrunner.py lines 500-510 detect None in method_names, remove the None key, enqueue the affected class for retry, and bump counts['Retriable']. Regression tests test_run_task_None_methodname_fail / test_run_task_None_methodname_pass pass on origin/dev@1925a3083." +3612,cli,A,feature,NOT-REPRODUCED-on-v4.10.0,"Issue is about the SFDO-Tooling/cci-vscode VSCode extension repo, not CumulusCI itself. Out of scope for this repository.",,closed:not-reproducible-on-v4.10.0,"enhancement,wontfix,wrong-repo",v4.10.0,Should be filed against SFDO-Tooling/cci-vscode. +3613,metadata-etl,B,bug,REPRODUCED-on-v4.10.0,Live repro: `cci task run add_page_layout_fields --org [scratch-org] -o api_names Account` -> 'Cannot find metadata file ...layouts/Account.layout' from MetadataSingleEntityTransformTask (base.py:332). Same task with correct API name format `Account-Account Layout` succeeds. Underlying functionality works; the user-visible bug is the unhelpful error when the api_name does not match the Layout file naming convention -,,improve-error-message,"bug,good-first-issue",v4.10.0,"Original report has no log of the exact api_names value passed; the cropped screenshot only shows 'page layouts'. Two improvements would help: (1) in _transform; if path does not exist, log the list of files actually retrieved into source_metadata_dir to help users identify naming mismatch; (2) in AddFieldsToPageLayout._init_options; warn when api_name does not contain '-'." +3615,dependencies,A,bug,NOT-REPRODUCED-on-v4.10.0,"`--resolution_strategy preproduction` is documented in cumulusci.yml as an alias for `latest_release` (which contains [tag, latest_release, unmanaged] and intentionally omits `latest_beta`). User wanted `include_beta`. Tests confirm preproduction == production == latest_release stack. Working as documented.",,closed:not-reproducible-on-v4.10.0,"theme:dependencies,docs",v4.10.0,"Naming is confusing -- ""preproduction"" sounds like ""beta-friendly"" but it isn't. Docs-improvement candidate; no code bug." +3618,cli,A,feature,REPRODUCED-on-dev,"cumulusci/cli/org.py:519-545 (org_remove) and 605-625 (org_scratch_delete) accept a single org_name argument via orgname_option_or_argument. No comma-separated list, no batch mode.",,keep-open,"enhancement,area:cli,good-first-issue",dev,Modest feature; could be implemented by accepting nargs=-1 or comma-split arg.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). +3619,dependencies,A,bug,REPRODUCED-on-v4.10.0,"Two-part bug confirmed. (A) `parse_pins()` raises DependencyParseError if a `dependency_pins` entry includes `password_env_name:` -- because GitHubDependencyPin only declares `github` and `tag`. (B) When a dynamic dep has `password_env_name` and a pin matches, `pin.pin()` calls GitHubTagResolver().resolve() directly, bypassing resolve_dependency()'s password-propagation logic; resulting `package_dependency.password_env_name` is None.",,keep-open,"theme:dependencies,bug",v4.10.0,Strong repro. Fix needs both (A) add password_env_name field to GitHubDependencyPin and (B) propagate it onto package_dependency in pin.pin() -- mirroring resolvers.py L644-654. +3649,bulkdata,A,feature,REPRODUCED-on-v4.10.0,"update_data.py:184 and :211 both pass api_options={} hardcoded to get_dml_operation. No task option exposes bulk job concurrency mode (Serial/Parallel). step.py BulkApiDmlOperation honors api_options[""bulk_mode""] but UpdateData never sets it. Other tasks (snowfakery, load_dataset) DO let users pick bulk_mode; update_data is the gap.",,keep-open,"keep-open,enhancement,area:bulkdata,severity:minor,good-first-issue,v5-candidate:yes",v4.10.0,Author offered to contribute. Small fix: add bulk_mode option to UpdateData.task_options and pipe it through to api_options. Mirrors LoadData pattern. +3663,cli,A,feature,REPRODUCED-on-dev,cumulusci/core/flowrunner.py:510-516 _run_step builds the when Jinja context from only project_config and org_config. No prior-task return values are exposed to the when expression.,,keep-open,"enhancement,area:flows",dev,Would need to thread results dict (or ^^ resolver) into the when context.; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). +3692,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,digitalExperiences key absent from metadata_map.yml; PackageXmlGenerator raises MetadataParserMissingError on Enhanced LWR sites,,keep-open,"severity:medium,area:metadata-etl,type:bug",v4.10.0,Add digitalExperiences/digitalExperienceConfigs entries to metadata_map.yml; needed for Winter '24+ LWR sites +3699,bulkdata,A,feature,REPRODUCED-on-v4.10.0,"extract.py _soql_for_mapping does not append ORDER BY. mapping_parser MappingStep has no order_by/sort field. soql_filter however allows arbitrary trailing SOQL so users CAN write soql_filter: ""Name != 'X' ORDER BY CreatedDate"" - this works because append_filter_clause just concatenates after WHERE. So a workaround exists; an explicit field would be a UX win.",,closed:stale-24mo,"closed:stale-24mo,enhancement,area:bulkdata",v4.10.0,Workaround via soql_filter ORDER BY makes this lower priority. Author hasn't followed up. Closing as stale is fine; can reopen if explicit order_by becomes a v5 ask. +3700,bulkdata,A,bug,REPRODUCED-on-v4.10.0,"mapping_parser.py:373-377 _get_required_permission_types returns (""updateable"", ""createable"") for any UPSERT. Master-detail lookup fields in Salesforce are createable but NOT updateable, so _check_field_permission rejects them, raising ""Field xxx__c does not have the correct permissions ('updateable', 'createable') for this operation."" Repro test confirms with simulated MD describe.",,keep-open,"keep-open,bug,area:bulkdata,severity:major,good-first-issue,v5-candidate:yes",v4.10.0,"Real bug, applies to any upsert involving an MD child. Fix should detect master-detail fields (relationshipName + cascadeDelete) and require only createable for those, OR loosen the upsert lookup-field check to ""createable OR updateable""." +3701,bulkdata,A,feature,REPRODUCED-on-v4.10.0,"mapping_parser.py:171/190/228/241/422 special-case ""Id"" - it always represents the SF Id and goes to sf_id-typed columns. There is no mechanism to make a different field (e.g. an external-id like BCM_Unique_Id__c) act as the row primary key in the extracted SQLite. The ""Id : OtherField"" mapping the user wrote is interpreted as ""extract SF Id into column OtherField"", not ""make OtherField the primary key"".",,closed:stale-24mo,"closed:stale-24mo,enhancement,area:bulkdata",v4.10.0,"Closely tied to #3699 (sort/diff motivation). Author hasn't followed up. Workaround: extract SF Id into a chosen column, then post-process. The deeper PK-replacement feature would touch many places." +3717,ci-integration,A,bug,INCONCLUSIVE-needs-cumulus-actions-workflow,"cumulusci/core/config/project_config.py repo_info property (lines 220-255) only auto-detects from environment when CUMULUSCI_AUTO_DETECT is set, and only handles Heroku CI (HEROKU_TEST_RUN_ID/BRANCH/COMMIT_VERSION). Repo-wide grep for ""GITHUB_REF"" / ""GITHUB_HEAD_REF"" / ""GITHUB_SHA"" / ""GITHUB_ACTIONS"" returns ZERO matches in cci source. So when run inside a GitHub Actions job the only way for repo_branch to be populated is (a) CUMULUSCI_REPO_BRANCH env var set by the workflow, or (b) git inference via current_branch(self.repo_root). On push events GHA checks out a detached HEAD, so (b) returns None. The reporter's symptom (repo_branch=None for push-triggered ci_feature, but works on workflow_dispatch where the branch ref is checked out by name) is exactly what this code path produces. The fix lives in the cumulus-actions/standard-workflows YAMLs (set CUMULUSCI_REPO_BRANCH from github.event.ref or github.head_ref before invoking cci) - not in the cci codebase. Same precedent as #3418.",,unchanged,"external-config,cumulus-actions,needs-info",v4.10.0,"Mirrors #3418 precedent (INCONCLUSIVE-needs-cumulus-actions-workflow). Could optionally be addressed inside cci by adding GitHub Actions auto-detection in repo_info (similar to Heroku block), reading GITHUB_REF/GITHUB_SHA - that would be a separate enhancement." +3721,packaging,A,feature,REPRODUCED-on-v4.10.0,create_package_version.py:184 still defaults version_name to literal 'Release'; upload_production hardcodes name: Release in cumulusci.yml:685,,keep-open,"severity:low,area:packaging,area:1gp,area:2gp",v4.10.0,muselab-d2x fork commit 7aaf348f3 implements jinja2 templating for PackageUpload; not merged upstream; would need port + design for create_package_version too +3734,packaging,B,bug,REPRODUCED-on-v4.10.0,PackageUpload._validate_versions SOQL ORDER BY ... PatchVersion DESC; ReleaseState DESC LIMIT 1 returns a Beta patch (e.g. 6.13.1 Beta) as latest; then minor_version is set to the patch's MinorVersion (13); colliding with already-Released 6.13 server-side,,keep-open,bug,v4.10.0,User's own analysis in last 3 comments is correct; current 'cannot-reproduce' label is stale; should be removed. Fix candidates: filter out Beta+Patch from the latest-version query; or filter ReleaseState='Released' for minor-detection and use a separate query for Beta. +3745,packaging,B,code-review,NOT-REPRODUCED-on-v4.10.0,latest_beta resolver looks up GitHub Releases (include_beta strategy) per install_package_version.py L96-100; reporter ran create_package_version standalone without release_2gp_beta which publishes the beta tag. Working as designed; reporter accepted the explanation 2024-02-13 and indicated closure intent.,,closed:stale-24mo,n/a,v4.10.0,"No code defect; doc-improvement opportunity. Original closed:stale-24mo proposal stands. Could optionally add closed:not-a-bug if that vocabulary exists, but stale-24mo is fine." +3746,packaging,B,code-review,REPRODUCED-on-dev,"create_package_version._get_base_version_number SOQL at L535-541 of cumulusci/tasks/create_package_version.py selects highest Package2Version with no IsDeprecated filter. The same file at L297 DOES filter IsDeprecated=FALSE for Package2 lookups, confirming the omission at L535 is asymmetric and matches the report verbatim.",,kept-open,"severity:medium,area:packaging,target:v4-patch,needs-fix-trivial",dev,Trivial 1-line fix (add 'AND IsDeprecated = false' to the SOQL WHERE clause). Currently proposed closed:stale-24mo; recommend flip to kept-open + target:v4-patch given low fix cost and clear customer impact (wrong version numbers on next package version create after a delete).; Task 4 reverify: bug still present on origin/dev@1925a3083 (only commit touching root-cause file since v4.10.0 was ruff refactor 3d620762d). +3754,cli,A,feature,REPRODUCED-on-v4.10.0,cumulusci/cli/utils.py:65-79 hardcodes 'https://pypi.org/pypi/cumulusci/json' with no env-var override or config flag. check_latest_version (line 82) cannot be disabled or redirected.,,keep-open,"enhancement,area:cli",v4.10.0,"User-suggested options (env flag to disable, custom URL) are all viable." +3758,packaging,A,bug,REPRODUCED-on-v4.10.0,push_upgrade_org flow in cumulusci/cumulusci.yml:1161-1177 still calls 'flow: config_qa' as final step; should be config_managed per bug report,cumulusci/tests/triage/test_issue_3758.py,keep-open,"severity:medium,area:packaging,area:flows,good-first-issue",v4.10.0,Single-line YAML fix; both flows have same steps so behavior is currently equivalent but semantically wrong +3762,metadata-etl,B,bug,closed:duplicate-of-#3544,"Reporter (noahisapilot) explicitly self-identifies as duplicate of #3544 in their first comment on 2024-03-06. Both report the same root cause: update_admin_profile fails on a namespaced scratch org with PersonAccounts because the retrieved profile contains 'Account.Business_Account' record type with no namespace, but the namespace gets injected onto recordType references. The reporter's analysis even links the offending line at update_profile.py L238 (now L236 in v4.10.0)",,close-as-duplicate,,v4.10.0,Self-confirmed duplicate. No live repro performed per dup-confirm protocol. Canonical #3544 is still OPEN at v4.10.0 with a 'wi-created' label . +3768,bulkdata,B,bug,REPRODUCED-on-v4.10.0,"snowfakery.py architecturally creates a separate working dir per batch via shutil.copytree(template_path, data_dir) (queue_manager.py:322). _cleanup_object_tables (snowfakery.py:721) drops every non-sf_ids table from the template before it is copied to subsequent batch dirs, so just_once Account rows are gone from batch_2+. random_reference: Account in batch_2+ would resolve only against rows generated within that batch; with just_once: true, no Accounts are generated, so the random_reference cannot pick anything. The user's observed first-batch-works / later-batches-don't matches this exactly.",,keep-open,"keep-open,bug,area:bulkdata,severity:major,v5-candidate:maybe",v4.10.0,Mixed CCI/Snowfakery responsibility. Could be fixed in CCI by preserving just_once-referenced object data (not just sf_ids) in the template carried to subsequent batches. Coordination with snowfakery dev branch likely needed. +3771,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,transforms.py transform_xpath() wraps tags in *[local-name()=...] but leaves predicate inner refs (e.g. price>40) namespace-bound; PR #3772 from leboff fork not merged,,keep-open,"severity:medium,area:source-transforms,type:bug,has-pr",v4.10.0,PR #3772 from external fork rewrites approach to strip xmlns; consider rebasing or implementing reporter's suggested 'remove xmlns then re-add' approach +3773,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,retrieve_profile_api.py _queries_retrieve_permissions never queries FieldPermissions table; only ObjectPermissions/SetupEntityAccess/PermissionSetTabSetting,,keep-open,"severity:medium,area:retrieve-profile,type:bug",v4.10.0,Architectural gap; field perms on standard objects without object perms are silently dropped; would benefit from org-side end-to-end verification but code evidence is conclusive +3849,python-modernization,Active-regression,import-only,REPRODUCED-on-dev,pyproject.toml pins selenium<4 + robotframework-seleniumlibrary<6 with no urllib3<2 cap; fresh pip resolves urllib3>=2 and breaks selenium 3.141.0,cumulusci/tests/triage/test_issue_3849.py,keep-open,"needs:dependency-modernization,target:v5",dev,"pyproject.toml still pins selenium<4 and robotframework-seleniumlibrary<6 (lines 50, 54) with no urllib3 upper bound; requests permits urllib3<3,>=1.26 so a fresh pip install picks urllib3>=2.x. Selenium 3.141.0's connection pool uses the pre-2.0 Timeout sentinel API and breaks at Robot import. The local .venv survives only because uv.lock pins urllib3==1.26.20. The modernization (drop selenium<4 / robotframework-seleniumlibrary<6 OR add explicit urllib3<2) has not landed." +3852,cli,A,bug,REPRODUCED-on-v4.10.0,"pyproject.toml:52 still pins 'sarge' unconstrained; installed sarge 0.1.7.post1 lacks Capture.flush (verified: hasattr(sarge.Capture,'flush')==False). cumulusci/core/config/sfdx_org_config.py:212 still calls self.sfdx_info inside refresh_oauth_token, which triggers the AttributeError on Python 3.13 logging path.",,keep-open,"bug,upstream:sarge,py313",v4.10.0,"Per maintainer note in thread: cosmetic only (no functional impact), waiting on sarge 0.1.8 release. Could pin sarge to a git rev (gabrielrholl's note) but not preferred." +3854,cli,A,bug,REPRODUCED-on-v4.10.0,cumulusci/tasks/bulkdata/extract.py:371-374 still raises ConfigError 'Total mapping operations (X) do not match total non-empty rows (Y) for lookup_key' identical to user report. Validation introduced in PR #3741 / commit 2c5d0056e per swirkens' comment is still active in v4.10.0.,,keep-open,"bug,area:bulkdata,regression",v4.10.0,Workaround in thread: downgrade to 3.84.1. Real fix needed for polymorphic lookups. +3873,robotframework,feature-request,feature,REPRODUCED-on-dev,"cumulusci/robotframework/Salesforce.py and SalesforcePlaywright.py both subclass BaseLibrary (base_library.py) which imports cumulusci-internal services (CumulusCI, SalesforceAPI); the libraries cannot be used standalone without a CumulusCI project context",,keep-open,"enhancement,robotframework,scope-large",dev,Large architectural ask. No PR submitted in 16 months. Would require decoupling FakerMixin/BaseLibrary/Salesforce from cumulusci.core. No concrete API to test; tagging as feature-still-missing. Reasonable to keep open for future Copado-QForce-style refactor or close as wont-fix if scope is out-of-charter. +3884,packaging,B,partial-runtime,INCONCLUSIVE-needs-project-with-managed-deps,"Source review: PackageNamespaceVersionDependency.install (dependencies.py L437-475) and PackageVersionIdDependency.install (L499-528) BOTH guard with skip-if-already-at-this-or-newer-version logic. CumulusCI repo itself has no project__dependencies block, so end-to-end dev_org rerun cannot exercise the path. Likely the report conflates 'Resolving dependencies...' log noise or unmanaged-metadata redeploys with reinstalls.",,closed:missing-fields,n/a,v4.10.0,"Original closed:missing-fields (rule 3 missing cci-version) is appropriate. Source review shows skip logic is in place; report may reflect unmanaged-metadata redeploy or user perception of log output. Without a customer project to reproduce on, no further action." +3886,dependencies,A,bug,REPRODUCED-on-v4.10.0,"Warning ""Optional dependencies are missing... cumulusci[select]"" emits at import time of cumulusci/tasks/bulkdata/select_utils.py whenever numpy/pandas/annoy/sklearn aren't installed. extract.py -> mapping_parser/step -> select_utils import chain triggers it on every extract_dataset run, even when no select strategy is configured. Behavior added in PR #3858 (89a5b5ddb) and unchanged through v4.10.0. Extraction itself works fine; only the noise persists.",,keep-open,"theme:dependencies,bulkdata,ux,log-noise",v4.10.0,"Dual-themed (bulkdata + dependencies); classified under dependencies per the bundle instructions. Fix candidates: defer warning until select strategy is actually used, or downgrade to debug-level." +3889,packaging,A,feature,REPRODUCED-on-v4.10.0,UninstallPackage only accepts namespace (1GP); UninstallPackageZipBuilder uses InstalledPackage destructive changes; no 04t/SubscriberPackageVersion-based uninstall task,,keep-open,"severity:medium,area:packaging,area:2gp,area:unlocked-package",v4.10.0,sf cli 'package uninstall -p 04t...' is the underlying API; new UninstallPackageVersion task could wrap Tooling API SubscriberPackageVersion delete +3899,packaging,B,partial-runtime,INCONCLUSIVE-needs-1gp-packaging-org,"unschedule_apex (cumulusci.yml L646-651) sends 1 line of trivial Apex via Tooling API: 'for (CronTrigger t : [SELECT Id FROM CronTrigger]) { System.abortJob(t.Id); }'. Ran cleanly on scratch org [scratch-org]. Reporter's error references Salesforce platform-internal Java classes (system.scheduler.cron.JobType, common.udd.constants.CronJobTypeEnum) - root cause is upstream Salesforce platform NPE, not CCI.",,kept-open,"severity:minor,area:packaging,external/upstream-salesforce,v5-candidate:no",v4.10.0,CCI sends correct trivial Apex; the System.UnexpectedException originates inside Salesforce's scheduler subsystem. Cannot fix in CCI. Recommend annotating with external/upstream-salesforce label (or equivalent) and considering close-as-not-our-bug after a brief look for any Salesforce known-issue reference. +3902,install-managed-security-type-04t,C,code-only,INCONCLUSIVE-needs-managed-package-04t,v4.10.0 install_package_version.py:162-167 routes 04t versions through PackageVersionIdDependency.install -> install_package_by_version_id -> _install_package_by_version_id which posts {'SecurityType': options.security_type} to the Tooling API PackageInstallRequest (package_install.py:170). Verified runtime serialization: SecurityType.ADMIN serializes to JSON 'NONE'. Both 04t and namespace+version paths pass security_type identically. No code-side defect found.,,needs-info,needs-managed-package-fixture,v4.10.0,"Could not provision a real managed package 04t to validate runtime API behavior. Code path is correct; observed user behavior (tab visible to non-admins) likely originates from Salesforce Tooling API treatment of SecurityType=NONE for upgrades or from package metadata, not from CumulusCI." +3910,scratch-org-config,bug,unit-pytest,REPRODUCED-on-dev,"ScratchOrg.namespaced declared as ``str`` in cumulusci/utils/yaml/cumulusci_yml.py:150; auto-generated cumulusci/schema/cumulusci.jsonschema.json:424 has ""type"": ""string""; ScratchOrg.parse_obj({""namespaced"": True}) silently coerces to ""True"" string. Open PR #3911 fixes both. Six XFAIL assertions added.",,keep-open,"bug,has-open-pr",dev,Fixing the schema alone is insufficient because make schema regenerates it from the Pydantic model. PR #3911 correctly updates both files; recommend nudging it through review. +3929,packaging,B,runtime,NOT-REPRODUCED-on-v4.10.0,"Ran create_community with name=TestWebsite template='Customer Service' url_path_prefix=testwebsite against scratch org [scratch-org] (orgs/dev.json with Communities feature). Community 0DBRK000000QtNR4A0 created in ~117s with normal polling escalation (1->2->3->...->8s) and exited the poll loop cleanly - no 300s timeout, no retry. Matches OP comment 2025-10-22 that the underlying SF CLI/server-side issue is fixed.",,closed:not-reproducible-on-v4.10.0,n/a,v4.10.0,Currently kept-open with needs-repro label; recommend flip to closed:not-reproducible-on-v4.10.0 (NEW vocabulary per spec amendment). Confirmed working end-to-end. Original cause was upstream SF CLI/Communities API bug now fixed. +3931,metadata-etl,B,bug,REPRODUCED-on-v4.10.0,Unit repro (with synthetic profile XML containing a layoutAssignments element that has a child but no child) raises 'AttributeError: NoneType object has no attribute text' at update_profile.py:291 inside _set_record_types. The buggy line is `if elem.find('recordType').text == rt['record_type']:` which assumes every layoutAssignments element has a recordType child; this is not true (a layoutAssignments without recordType applies to records without a record-type binding),,keep-open,bug,v4.10.0,Reported on cci 4.6.0 and reproduces unchanged on 4.10.0. Minimal fix at update_profile.py:290-293: change to `rt_elem = elem.find('recordType'); if rt_elem is not None and rt_elem.text == rt['record_type']: ...`. Also worth scanning sibling code in _set_record_types for similar None-deref patterns on optional children. +3936,bulkdata,B,bug,INCONCLUSIVE-needs-flaky-network,"salesforce_api/utils.py get_simple_salesforce_connection (lines 30-43) constructs Salesforce() with no timeout kwarg and only retries 502/503/504 via Retry(total=5). No CCI-side option exposes connect/read timeout for SF API calls. The reported error ""HTTPSConnectionPool ... Read timed out. (read timeout=None)"" with timeout=None usually means the proxy/VPN closed the socket; CCI cannot mitigate without exposing a configurable timeout AND a retry policy for read timeouts.",,unchanged,"keep-open,bug,area:bulkdata,severity:major,needs-repro,v5-candidate:yes",v4.10.0,Already kept-open by maintainer (recent 2025-12-03). Environment-specific reproduction (corporate VPN). Confirmed structural gap: no exposed timeout option. v5 candidate: add timeout option + read-timeout retry to get_simple_salesforce_connection and to bulk job HTTP polling. +3938,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,rest_deploy.py _monitor_deploy_status (line 119) returns silently on Failed; __call__ also only logs on non-201 status_code; no exception raised,,keep-open,"severity:critical,area:rest-deploy,type:bug,silent-failure",v4.10.0,CRITICAL: rest_deploy:True silently passes failed deploys; flows continue thinking deploy succeeded. Recently filed (2025-12-16). Likely affects MetaDeploy plans +3939,metadata-etl,A,bug,REPRODUCED-on-v4.10.0,metadata.py BaseMetadataApiCall.__call__ wraps every Exception from _process_response (incl. ApexTestException at line 540) in MetadataParseError losing original message,,keep-open,"severity:high,area:salesforce-api,type:bug,error-handling",v4.10.0,"Fix: re-raise CCI exception classes (MetadataApiError, MetadataComponentFailure, ApexTestException) without wrapping. Also recently filed; same reporter as #3938; both block production deploys" +3951,metadata-etl,B,bug,REPRODUCED-on-v4.10.0,Live repro: `cci task run set_duplicate_rule_status -o api_names Standard_Rule_for_Leads_with_Duplicate_Contacts -o active False` -> 'Cannot find metadata file .../duplicateRules/Standard_Rule_for_Leads_with_Duplicate_Contacts.duplicateRule'. Same command with the canonical API name format `Lead.Standard_Rule_for_Leads_with_Duplicate_Contacts` succeeds end-to-end (extract -> transform -> deploy -> Success). The functional task is not actually broken; the bug is the unhelpful error when the user omits the Object prefix that the Metadata API requires for DuplicateRule,,improve-error-message,"bug,good-first-issue,documentation",v4.10.0,"Two improvements: (1) update set_duplicate_rule_status docs and task option help to show that api_names need the . format; (2) in MetadataSingleEntityTransformTask._transform (base.py:332), when the file is missing, list the files actually retrieved so users can spot the naming gap. Could also pre-validate api_names contain a dot for entity types that require it." +3953,metadata-etl,B,bug,REPRODUCED-on-v4.10.0,"Live CLI repro: `cci task run add_picklist_entries --org X -o picklists 'Account.Status__c' -o entries '[{""fullName"": ""TestValue"", ""label"": ""Test Value""}]'` -> 'The fullName key is required on all picklist values'. AddPicklistEntries._init_options (picklists.py:68) checks `'fullName' in entry for entry in self.options['entries']` directly, but no JSON parser is run on the CLI value first; the CLI passes 'entries' through as a string, so iteration walks the characters of the JSON string, none of which contain the substring 'fullName'. process_list_arg is run on 'picklists' but not on 'entries'",,keep-open,"bug,good-first-issue",v4.10.0,"Minimal fix in AddPicklistEntries._init_options: if isinstance(self.options.get('entries'), str): self.options['entries'] = json.loads(self.options['entries']). Apply same pattern to record_types option for consistency. Same class of bug exists in AddFieldsToPageLayout (`fields` and `pages` options); see line 'value is not a valid list' from issue-3613 testing." +3955,robotframework,bug-in-source,bug,REPRODUCED-on-dev,"cumulusci/robotframework/SalesforcePlaywright.py:106 splits size with str.split('x', 1) yielding two strings, then passes them directly to browser.new_context(viewport={""width"": width, ""height"": height}) on line 109-111 without int casting; Playwright rejects strings with ""viewport.width: expected integer, got string""",,keep-open,"bug,robotframework,playwright,good-first-issue",dev,Trivial 1-line fix: cast width/height to int. Pytest stubs the Browser library and asserts new_context receives int dimensions. diff --git a/docs/triage/v5/repro-results.md b/docs/triage/v5/repro-results.md index 33e22273e2..a9c0d1700c 100644 --- a/docs/triage/v5/repro-results.md +++ b/docs/triage/v5/repro-results.md @@ -1,13 +1,13 @@ -# Reproducibility Pass Results — Task 2.5c +# Reproducibility Pass Results - the reproducibility pass ## Scope Two rounds of subagents: -- **Round 1** (subagents 1-6): packaging + metadata-etl themes (45 issues; pre-v4.0.0 dropped per user; #3544 included as Cluster A canonical). -- **Round 2** (subagents 7-12): cli + bulkdata + dependencies + ci-integration themes (53 issues; pre-v4.0.0 dropped; cross-theme dups assigned to one subagent). +- **the initial reproducibility pass** (the triage): packaging + metadata-etl themes (45 issues; pre-v4.0.0 dropped per user; #3544 included as Cluster A canonical). +- **the follow-up reproducibility pass** (the triage): cli + bulkdata + dependencies + ci-integration themes (53 issues; pre-v4.0.0 dropped; cross-theme dups assigned to one subagent). - **Total**: 98 of 142 open issues triaged via live v4.10.0 verification. -- Method: each subagent in an isolated git worktree pinned to `origin/main` (= release v4.10.0 at commit `129238663`); per-bucket org provisioning via DevHub `CCIDevHub`. +- Method: each subagent in an isolated git worktree pinned to `origin/main` (= release v4.10.0 at commit `129238663`); per-bucket org provisioning via DevHub `the configured DevHub`. - See `themes.md` for the prior dry-run baseline; this file augments those proposals with v4.10.0 verdicts. ## Totals (98 issues) @@ -30,8 +30,6 @@ Two rounds of subagents: ## Per-round tally -### Round 1 (packaging+metadata-etl, 45 issues) - | Verdict | Count | | ---------------------------------------------- | ----: | | `REPRODUCED-on-v4.10.0` | 28 | @@ -44,8 +42,6 @@ Two rounds of subagents: | `INCONCLUSIVE-needs-project-with-managed-deps` | 1 | | `closed:duplicate-of-#3544` | 1 | -### Round 2 (cli+bulkdata+dependencies+ci-integration, 53 issues) - | Verdict | Count | | --------------------------------------------- | ----: | | `REPRODUCED-on-v4.10.0` | 40 | @@ -56,11 +52,11 @@ Two rounds of subagents: | `INCONCLUSIVE-needs-org-with-managed-package` | 1 | | `INCONCLUSIVE-needs-scratch-slot` | 1 | -## Quick-action shortlist (high-confidence — proposed-pass1 deviates from dry-run baseline) +## Quick-action shortlist (high-confidence - proposed-pass1 deviates from dry-run baseline) Subagents surfaced the following items where the v4.10.0 verdict suggests a clear change from the dry-run proposed action: -| # | Theme | Verdict | Subagent recommendation | Note | +| # | Theme | Verdict | Recommendation | Note | | ----- | ------------------------------- | ---------------------------------------------- | ------------------------------------ | -------------------------------------------------------------------------------------------- | | #733 | cli | `REPRODUCED-on-v4.10.0` | `closed:stale-24mo` | runtime.py:131-133 still raises ClickException with same hard error message; no interactiv… | | #1348 | cli | `REPRODUCED-on-v4.10.0` | `closed:stale-24mo` | No 'gitlab' or 'bitbucket' references anywhere in cumulusci/; ci_feature flow still uses g… | @@ -81,7 +77,7 @@ Subagents surfaced the following items where the v4.10.0 verdict suggests a clea | #3307 | cli | `REPRODUCED-on-v4.10.0` | `closed:stale-24mo` | cli/project.py project_init only renders internal Jinja templates from cumulusci/files/tem… | | #3320 | metadata-etl | `NOT-REPRODUCED-on-v4.10.0` | `closed:feature-implemented` | deactivate_flow task is shipped in cumulusci/cumulusci.yml:10-15 using ActivateFlow class … | | #3347 | release-unlocked-beta-typeerror | `NOT-REPRODUCED-on-v4.10.0` | `close-with-comment` | create_package_version.py:158-159 now raises TaskOptionsError(PERSISTENT_ORG_ERROR) early … | -| #3360 | bulkdata | `NOT-REPRODUCED-on-v4.10.0` | `closed:feature-implemented` | action: select was added by commit b15945203 (Aug 2024) — well before v4.10.0. select_util… | +| #3360 | bulkdata | `NOT-REPRODUCED-on-v4.10.0` | `closed:feature-implemented` | action: select was added by commit b15945203 (Aug 2024) - well before v4.10.0. select_util… | | #3466 | packaging | `NOT-REPRODUCED-on-v4.10.0` | `closed:feature-implemented` | RunApexTests in cumulusci/tasks/apex/testrunner.py exposes test_suite_names option (line 1… | | #3470 | cli | `REPRODUCED-on-v4.10.0` | `closed:stale-24mo` | cumulusci.yml:823 only ci_master flow defined; no ci_main alias. davidmreed acknowledged b… | | #3479 | ci-integration | `NOT-REPRODUCED-on-v4.10.0` | `closed:not-reproducible-on-v4.10.0` | Reported error "Expecting value: line 1 column 1 (char 0)" is the bare json.JSONDecodeErro… | @@ -92,7 +88,7 @@ Subagents surfaced the following items where the v4.10.0 verdict suggests a clea | #3612 | cli | `NOT-REPRODUCED-on-v4.10.0` | `closed:not-reproducible-on-v4.10.0` | Issue is about the SFDO-Tooling/cci-vscode VSCode extension repo, not CumulusCI itself. Ou… | | #3615 | dependencies | `NOT-REPRODUCED-on-v4.10.0` | `closed:not-reproducible-on-v4.10.0` | `--resolution_strategy preproduction` is documented in cumulusci.yml as an alias for `late… | | #3699 | bulkdata | `REPRODUCED-on-v4.10.0` | `closed:stale-24mo` | extract.py \_soql_for_mapping does not append ORDER BY. mapping_parser MappingStep has no o… | -| #3701 | bulkdata | `REPRODUCED-on-v4.10.0` | `closed:stale-24mo` | mapping_parser.py:171/190/228/241/422 special-case "Id" — it always represents the SF Id a… | +| #3701 | bulkdata | `REPRODUCED-on-v4.10.0` | `closed:stale-24mo` | mapping_parser.py:171/190/228/241/422 special-case "Id" - it always represents the SF Id a… | | #3745 | packaging | `NOT-REPRODUCED-on-v4.10.0` | `closed:stale-24mo` | latest*beta resolver looks up GitHub Releases (include_beta strategy) per install_package*… | | #3762 | metadata-etl | `closed:duplicate-of-#3544` | `close-as-duplicate` | Reporter (noahisapilot) explicitly self-identifies as duplicate of #3544 in their first co… | | #3884 | packaging | `INCONCLUSIVE-needs-project-with-managed-deps` | `closed:missing-fields` | Source review: PackageNamespaceVersionDependency.install (dependencies.py L437-475) and Pa… | @@ -100,9 +96,9 @@ Subagents surfaced the following items where the v4.10.0 verdict suggests a clea ## Per-subagent SUMMARY chunks -#### Bucket A — Packaging triage summary +#### Bucket A - Packaging triage summary -Subagent 1 (`pkg-bucket-a`). Worktree pinned at `v4.10.0` / commit `129238663`. +Triage pass for packaging bucket A. Worktree pinned at `v4.10.0` / commit `129238663`. 10 issues processed; no GitHub mutations; no Salesforce org used. #### Verdict counts @@ -111,10 +107,10 @@ Subagent 1 (`pkg-bucket-a`). Worktree pinned at `v4.10.0` / commit `129238663`. | ------------------------- | ----- | ------------------------------------------------------ | | REPRODUCED-on-v4.10.0 | 8 | #2979, #3429, #3440, #3441, #3593, #3721, #3758, #3889 | | NOT-REPRODUCED-on-v4.10.0 | 2 | #3466, #3605 | -| INCONCLUSIVE-\* | 0 | — | -| SKIPPED | 0 | — | +| INCONCLUSIVE-\* | 0 | - | +| SKIPPED | 0 | - | -#### Repro tests written (under `/tmp/repro/1/tests/`) +#### Repro tests written (under `_(repro evidence)_`) | Test file | Purpose | Result on v4.10.0 | | -------------------- | ------------------------------------------------------------------------ | ---------------------------- | @@ -135,23 +131,23 @@ Subagent 1 (`pkg-bucket-a`). Worktree pinned at `v4.10.0` / commit `129238663`. #### Cross-cutting findings -1. **Multi-package SFDX umbrella (#2979, #3429, #3440)** — three open enhancements all point at the same gap: CumulusCI assumes a single package per repo. `default_package_path` exists but is only consumed by `create_package_version`. A single small design refactor (Deploy gets a `path: $project_config.default_package_path` default, `default_package_path` becomes name-aware, and a `cumulusci.yml` override mechanism is added) could resolve all three. Worth folding them into one umbrella issue or theme on the pass-2 labeling pass. +1. **Multi-package SFDX umbrella (#2979, #3429, #3440)** - three open enhancements all point at the same gap: CumulusCI assumes a single package per repo. `default_package_path` exists but is only consumed by `create_package_version`. A single small design refactor (Deploy gets a `path: $project_config.default_package_path` default, `default_package_path` becomes name-aware, and a `cumulusci.yml` override mechanism is added) could resolve all three. Worth folding them into one umbrella issue or theme on the pass-2 labeling pass. -2. **Null/sentinel overrides in flow steps (#3441)** — yippie's comment generalizes the request: CCI lacks any way to "unset" or "reset to default" an option that a flow step has set. This is a CCI-wide ergonomics gap (not just `version_base`), and probably belongs as its own meta-issue. +2. **Null/sentinel overrides in flow steps (#3441)** - yippie's comment generalizes the request: CCI lacks any way to "unset" or "reset to default" an option that a flow step has set. This is a CCI-wide ergonomics gap (not just `version_base`), and probably belongs as its own meta-issue. -3. **PR #3969 (`extra-yaml-cli-flag`) is in flight for #3429** — adds `--extra-yaml` and `CUMULUSCI_EXTRA_YAML`. Not yet in v4.10.0. Recommend the parent agent flip #3429 to `closed:fixed-by-pr-#3969` once that PR merges; until then `keep-open` is correct. +3. **PR #3969 (`extra-yaml-cli-flag`) is in flight for #3429** - adds `--extra-yaml` and `CUMULUSCI_EXTRA_YAML`. Not yet in v4.10.0. Recommend the parent agent flip #3429 to `closed:fixed-by-pr-#3969` once that PR merges; until then `keep-open` is correct. -4. **muselab-d2x fork has a fix for #3721** — commit `7aaf348f3` ("Change version naming on PackageUpload task to use the predicted version number and a jinja2 template expression") implements jinja2 templating for `PackageUpload.version_name`. Lives only on `d2x/*` remotes. Could be ported upstream as a small PR; would also need a sibling change in `create_package_version.py:184` for 2GP coverage. +4. **muselab-d2x fork has a fix for #3721** - commit `7aaf348f3` ("Change version naming on PackageUpload task to use the predicted version number and a jinja2 template expression") implements jinja2 templating for `PackageUpload.version_name`. Lives only on `d2x/*` remotes. Could be ported upstream as a small PR; would also need a sibling change in `create_package_version.py:184` for 2GP coverage. -5. **One-line YAML fix candidate (#3758)** — `push_upgrade_org` last step should be `config_managed`, not `config_qa`. Currently both expand to the same task list, so it's not a behavior regression today, but the docs link customers to the wrong page. Excellent `good-first-issue` for an external contributor; explicitly out of scope for this triage pass. +5. **One-line YAML fix candidate (#3758)** - `push_upgrade_org` last step should be `config_managed`, not `config_qa`. Currently both expand to the same task list, so it's not a behavior regression today, but the docs link customers to the wrong page. Excellent `good-first-issue` for an external contributor; explicitly out of scope for this triage pass. -6. **`SFDXOrgTask` org-flag append (#3593)** — recurring pain point as sf cli surface evolves; a generic `pass_org` / `no_org` opt-out option (or a curated whitelist of no-org subcommands) is a more durable fix than the user's `#` workaround. Verifying actual sf cli behavior of `project convert source` would need an org/sf cli; the CCI side of the bug is unchanged on v4.10.0. +6. **`SFDXOrgTask` org-flag append (#3593)** - recurring pain point as sf cli surface evolves; a generic `pass_org` / `no_org` opt-out option (or a curated whitelist of no-org subcommands) is a more durable fix than the user's `#` workaround. Verifying actual sf cli behavior of `project convert source` would need an org/sf cli; the CCI side of the bug is unchanged on v4.10.0. -7. **2GP unlocked uninstall (#3889)** — natural shape is a new `UninstallPackageVersion` task that calls Tooling API `SubscriberPackageVersion` delete directly, avoiding the sf cli stability concern the user calls out. Aligns with broader 2GP investment. +7. **2GP unlocked uninstall (#3889)** - natural shape is a new `UninstallPackageVersion` task that calls Tooling API `SubscriberPackageVersion` delete directly, avoiding the sf cli stability concern the user calls out. Aligns with broader 2GP investment. -#### Bucket A — metadata-etl summary (Subagent 2) +#### Bucket A - metadata-etl summary -**Worktree**: `/Users/jestevez/work/rel/CumulusCI/.worktrees/repro-etl-bucket-a` +**Worktree**: `/Users/jestevez/work/rel/CumulusCI/.worktrees/[scratch-org]` **Pinned commit**: `129238663` (Release v4.10.0) **Issues processed**: 11 / 11 @@ -161,27 +157,27 @@ Subagent 1 (`pkg-bucket-a`). Worktree pinned at `v4.10.0` / commit `129238663`. | ------------------------- | ----- | -------------------------------------------------------------------- | | REPRODUCED-on-v4.10.0 | 10 | #3137, #3331, #3518, #3543, #3585, #3692, #3771, #3773, #3938, #3939 | | NOT-REPRODUCED-on-v4.10.0 | 1 | #3320 | -| INCONCLUSIVE | 0 | — | -| SKIPPED | 0 | — | +| INCONCLUSIVE | 0 | - | +| SKIPPED | 0 | - | #### Severity / urgency picks (most worth flagging in pass-1) -- **#3938 (CRITICAL, recently filed 2025-12-16)** — `rest_deploy: True` silently +- **#3938 (CRITICAL, recently filed 2025-12-16)** - `rest_deploy: True` silently swallows failed deployments and reports success. Affects MetaDeploy plans and any flow using `rest_deploy`. Same reporter as #3939; likely both blocking the same production-deploy workflow. -- **#3939 (HIGH, recently filed 2025-12-16)** — Even SOAP-path deploys lose +- **#3939 (HIGH, recently filed 2025-12-16)** - Even SOAP-path deploys lose their actual error text because `BaseMetadataApiCall.__call__` wraps every exception in the generic "Could not process MDAPI response" message. Apex test failures, component failures, and API errors are all clobbered. -- **#3518 (HIGH)** — `add_picklist_entries` always marks a default for record +- **#3518 (HIGH)** - `add_picklist_entries` always marks a default for record types because of a missing `()` after `.lower` (picklists.py:177); blocks any non-default picklist additions on objects with record types. #### Cross-cutting findings - **Error-handling pattern (#3938 + #3939)**: Both critical bugs come from - the same anti-pattern — an outer try/except at the orchestration layer + the same anti-pattern - an outer try/except at the orchestration layer swallows exceptions raised by inner code that was correctly trying to surface a user-actionable error. Worth a single PR that audits both code paths and keeps `CumulusCIException` subclasses unwrapped. @@ -197,20 +193,20 @@ Subagent 1 (`pkg-bucket-a`). Worktree pinned at `v4.10.0` / commit `129238663`. the issue. - **#3320 mismatch**: Reporter asked for a `deactivate_flow` task; one is already shipped in `cumulusci/cumulusci.yml:10-15`. Likely a docs / - discoverability issue rather than a code one — worth flagging in pass-2 + discoverability issue rather than a code one - worth flagging in pass-2 as `closed:feature-implemented` plus a small doc improvement. - **Architectural gap for #3773**: `RetrieveProfileApi._queries_retrieve_permissions` doesn't query `FieldPermissions` at all. This is a class-of-omission bug: any object that has profile field-perms but no object-perms (very common for standard objects like `AccountContactRelation`) is silently dropped. Likely there are other under-queried permission - surfaces too — worth a focused review. + surfaces too - worth a focused review. #### Output artifacts -- `/tmp/repro/2/repro-results.csv` — machine-readable results (12 rows) -- `/tmp/repro/2/narrative.md` — per-issue evidence and recommended actions -- `/tmp/repro/2/tests/test_issues_bucket_a.py` — 11 throwaway repro tests; +- `_(repro evidence)_` - machine-readable results (12 rows) +- `_(repro evidence)_` - per-issue evidence and recommended actions +- `_(repro evidence; see narrative)_` - 11 throwaway repro tests; all 11 currently fail on v4.10.0 (= bugs reproduced). #### Constraint compliance @@ -218,7 +214,7 @@ Subagent 1 (`pkg-bucket-a`). Worktree pinned at `v4.10.0` / commit `129238663`. - No `git push` from worktree. - No GitHub mutations (only read-only inspection of bundled JSON). - No writes under `cumulusci/robotframework/`. -- All repro tests live under `/tmp/repro/2/tests/`, not in the worktree +- All repro tests live under `_(repro evidence)_`, not in the worktree source tree. - No third-party packages added; tests use only `pytest`, `pyyaml`, and in-tree CCI modules. @@ -228,7 +224,7 @@ Subagent 1 (`pkg-bucket-a`). Worktree pinned at `v4.10.0` / commit `129238663`. **Theme**: packaging **Bucket**: B (scratch-org-required) -**Worktree**: `.worktrees/repro-pkg-bucket-b1` @ `129238663` (release v4.10.0) +**Worktree**: the triage worktree @ `129238663` (release v4.10.0) **Issues processed**: 6 / 6 #### Verdict tally @@ -255,20 +251,26 @@ Subagent 1 (`pkg-bucket-a`). Worktree pinned at `v4.10.0` / commit `129238663`. #### Cross-cutting findings 1. **Two clear bugs reproducing on v4.10.0 (#3446, #3734)** with well-localized root causes: - - #3446 is a missing-validation bug in `cumulusci/tasks/push/tasks.py` `_run_task` / `_parse_version`. - - #3734 is a logic bug in `cumulusci/tasks/salesforce/package_upload.py` `_validate_versions` where a Beta patch on a previous minor is treated as the latest version. + +- #3446 is a missing-validation bug in `cumulusci/tasks/push/tasks.py` `_run_task` / `_parse_version`. +- #3734 is a logic bug in `cumulusci/tasks/salesforce/package_upload.py` `_validate_versions` where a Beta patch on a previous minor is treated as the latest version. + 2. **Two unimplemented features (#3587, #3600)** suitable for "good-first-issue" tagging: - - #3587 wants a one-line warning in `UpdatePackageXml._init_task`. - - #3600 wants env-var substitution in task options — broader scope (touches all options, not just `install_managed`); needs design. + +- #3587 wants a one-line warning in `UpdatePackageXml._init_task`. +- #3600 wants env-var substitution in task options - broader scope (touches all options, not just `install_managed`); needs design. + 3. **Two issues that escape cci's repo boundary (#3418, #3542)**: - - #3418 is in `SFDO-Community/standard-workflows`; cci has no `auth:sfdxurl:store` code path. - - #3542 is a SHA-mismatch problem between the workflow that posts a commit status and the local checkout that reads it; could be fixed in `cumulus-actions/standard-workflows` or by adding a parent-commit fallback in `get_version_id_from_commit`. + +- #3418 is in `SFDO-Community/standard-workflows`; cci has no `auth:sfdxurl:store` code path. +- #3542 is a SHA-mismatch problem between the workflow that posts a commit status and the local checkout that reads it; could be fixed in `cumulus-actions/standard-workflows` or by adding a parent-commit fallback in `get_version_id_from_commit`. + 4. **Mislabeled triage state on #3734**: the user's last three comments contain a correct, fully-localized root-cause analysis. The `cannot-reproduce` and `awaiting-more-details` labels are stale and should be dropped in pass2 in favor of `bug`. 5. **Code stability**: none of the relevant code paths for these six issues have changed materially between the issue dates and v4.10.0 (verified via `git log` for `cumulusci/tasks/push/`, `cumulusci/tasks/salesforce/package_upload.py`, `cumulusci/tasks/github/commit_status.py`, `cumulusci/tasks/metadata/package.py`, `cumulusci/utils/yaml/safer_loader.py`, `cumulusci/core/tasks.py`). #### Scratch orgs used -- `repro-pkg-b1-dev` (cci alias) / `CumulusCI__repro-pkg-b1-dev` (sf alias) — config `dev`, used for live `install_managed` and `push_qa` invocations. +- `[scratch-org]` (cci alias) / `[scratch-org-alias]` (sf alias) - config `dev`, used for live `install_managed` and `push_qa` invocations. No second alias was needed; `feature` config was not required. @@ -278,24 +280,24 @@ No second alias was needed; `feature` config was not required. ``` $ uv run cci org list 2>&1 | grep -i 'pkg-b1' - (no rows match) + (no rows match) $ sf org list 2>&1 | grep -i 'pkg-b1' - (no rows match) + (no rows match) ``` Steps taken: -1. `uv run cci org scratch_delete repro-pkg-b1-dev` — sf-side org deleted via `sf org delete scratch -p -o test-ra9moqy3oqup@example.com`. -2. `uv run cci org remove repro-pkg-b1-dev` — cci keychain alias removed (cci was still listing the alias even after `scratch_delete` because the alias entry persists locally). +1. `uv run cci org scratch_delete [scratch-org]` - sf-side org deleted via `sf org delete scratch -p -o test-ra9moqy3oqup@example.com`. +2. `uv run cci org remove [scratch-org]` - cci keychain alias removed (cci was still listing the alias even after `scratch_delete` because the alias entry persists locally). -#### Output files (under `/tmp/repro/3/`) +#### Output files (under `_(repro evidence)_`) -- `repro-results.csv` — one row per issue (header + 6 data rows). -- `narrative.md` — per-issue method/evidence/recommendation. -- `tests/repro_3446_push_qa_no_version.py` — reproduces NoneType.split. -- `tests/repro_3587_update_package_xml_no_warning.py` — confirms install_class silently dropped. -- `tests/repro_3600_install_managed_no_env_var.py` — confirms no env-var substitution. -- `tests/repro_3734_upload_production_beta_patch.py` — confirms Beta-patch sets colliding minor. +- `repro-results.csv` - one row per issue (header + 6 data rows). +- `narrative.md` - per-issue method/evidence/recommendation. +- `tests/repro_3446_push_qa_no_version.py` - reproduces NoneType.split. +- `tests/repro_3587_update_package_xml_no_warning.py` - confirms install_class silently dropped. +- `tests/repro_3600_install_managed_no_env_var.py` - confirms no env-var substitution. +- `tests/repro_3734_upload_production_beta_patch.py` - confirms Beta-patch sets colliding minor. #### Deviations from constraints @@ -311,13 +313,13 @@ None. | `NOT-REPRODUCED-on-v4.10.0` | 2 | #3745, #3929 | | `INCONCLUSIVE-needs-project-with-managed-deps` | 1 | #3884 | | `INCONCLUSIVE-needs-1gp-packaging-org` | 1 | #3899 | -| `SKIPPED-policy-*` | 0 | — | +| `SKIPPED-policy-*` | 0 | - | Total: 5 / 5 (100%). #### Cross-cutting findings -1. **Two of five issues had already self-resolved upstream**: #3745 (user-confusion about ci_beta requiring release_2gp_beta to publish the GitHub release tag — accepted by the reporter in-thread) and #3929 (an upstream Salesforce CLI / Communities API bug that is now fixed per OP comment 2025-10-22 and confirmed end-to-end against scratch org). The triage policy's stale-24mo and needs-repro proposals respectively were defensible at proposal time but #3929 should now flip to `closed:not-reproducible-on-v4.10.0`. +1. **Two of five issues had already self-resolved upstream**: #3745 (user-confusion about ci_beta requiring release_2gp_beta to publish the GitHub release tag - accepted by the reporter in-thread) and #3929 (an upstream Salesforce CLI / Communities API bug that is now fixed per OP comment 2025-10-22 and confirmed end-to-end against scratch org). The triage policy's stale-24mo and needs-repro proposals respectively were defensible at proposal time but #3929 should now flip to `closed:not-reproducible-on-v4.10.0`. 2. **One real, trivially-fixable v4.10 bug surfaced**: #3746 (`create_package_version._get_base_version_number` SOQL has no `IsDeprecated = false` filter). The same file has the filter on a parallel `Package2` lookup at line 297, so the omission at line 535 is asymmetric and the fix is one clause. This is a `target:v4-patch` candidate hidden under a stale-24mo proposal. @@ -325,49 +327,49 @@ Total: 5 / 5 (100%). 4. **One issue is plausibly user-misperception of log noise**: #3884 (dev_org "reinstalls" same package version). Source review confirms skip-if-already-installed logic is present in v4.10.0 for both managed-package install paths. Without a customer project that has managed deps, we cannot disprove a corner case, but the proposed `closed:missing-fields` (rule 3) is the right disposition because the report lacks the `cumulusci.yml` excerpt that would let us identify which dependency type they observed. -5. **Methodology note**: 2 of 5 verdicts were reachable by code review alone (#3745, #3746), 1 required a brief scratch-org runtime check that succeeded (#3899 partial; #3929 full), and 1 required a runtime check that fully resolved the question (#3929). The scratch org was reused across all runs — quota cost: 1 dev-config scratch (already provisioned, not torn down per "Scratch org cleanup" below since other subagents may still be relying on the DevHub quota math). +5. **Methodology note**: 2 of 5 verdicts were reachable by code review alone (#3745, #3746), 1 required a brief scratch-org runtime check that succeeded (#3899 partial; #3929 full), and 1 required a runtime check that fully resolved the question (#3929). The scratch org was reused across all runs - quota cost: 1 dev-config scratch (already provisioned, not torn down per "Scratch org cleanup" below since other subagents may still be relying on the DevHub quota math). #### Scratch org aliases used -- `repro-pkg-b2-dev` (config: `orgs/dev.json`, expires 2026-05-15 08:51 PT, instance `customization-java-47-dev-ed.scratch`). - - Used for: #3899 unschedule_apex runtime check, #3929 create_community runtime check. - - Already existed at session start (presumably from a prior controller run); reused, not recreated, so no fresh DevHub-create quota was consumed by this subagent. +- `[scratch-org]` (config: `orgs/dev.json`, expires 2026-05-15 08:51 PT, instance `customization-java-47-dev-ed.scratch`). +- Used for: #3899 unschedule_apex runtime check, #3929 create_community runtime check. +- Already existed at session start (presumably from a prior controller run); reused, not recreated, so no fresh DevHub-create quota was consumed by this subagent. #### Output files written -- [`/tmp/repro/4/repro-results.csv`](/tmp/repro/4/repro-results.csv) — 5 rows + header, full triage CSV schema per plan §2.5c step 5. -- [`/tmp/repro/4/narrative.md`](/tmp/repro/4/narrative.md) — per-issue narrative, sorted by verdict (REPRODUCED first). -- [`/tmp/repro/4/SUMMARY.md`](/tmp/repro/4/SUMMARY.md) — this file. -- [`/tmp/repro/4/evidence/`](/tmp/repro/4/evidence/) — 5 evidence files, one per issue, referenced from `repro-results.csv` and `narrative.md`. +- [`_(repro evidence)_`](_(repro evidence)_) - 5 rows + header, full triage CSV schema per plan §2.5c step 5. +- [`_(repro evidence)_`](_(repro evidence)_) - per-issue narrative, sorted by verdict (REPRODUCED first). +- [`_(repro evidence)_`](_(repro evidence)_) - this file. +- [`_(repro evidence)_`](_(repro evidence)_) - 5 evidence files, one per issue, referenced from `repro-results.csv` and `narrative.md`. #### Deviations from the prompt -- The scratch org `repro-pkg-b2-dev` was already provisioned at session start (left over from a prior run, healthy and unexpired). Reused it directly rather than creating a new one. Documented above; conserves DevHub quota. -- Cleanup decision deferred to the controller — see "Scratch org cleanup" note below. +- The a scratch org was already provisioned at session start (left over from a prior run, healthy and unexpired). Reused it directly rather than creating a new one. Documented above; conserves DevHub quota. +- Cleanup decision deferred to the controller - see "Scratch org cleanup" note below. #### Scratch org cleanup (executed) ``` -$ uv run cci org scratch_delete repro-pkg-b2-dev +$ uv run cci org scratch_delete [scratch-org] [05/14/26 02:07:26] Deleting scratch org with command: sf org delete scratch -p - -o test-qu66hqqypnu3@example.com + -o test-qu66hqqypnu3@example.com [05/14/26 02:07:28] (success) -$ uv run cci org remove repro-pkg-b2-dev +$ uv run cci org remove [scratch-org] (silently removes the cci keychain entry) -$ sf org list scratch --target-dev-hub CCIDevHub | grep qu66hqqypnu3 || echo "absent" +$ sf org list scratch --target-dev-hub the configured DevHub | grep qu66hqqypnu3 || echo "absent" absent -$ uv run cci org list | grep repro-pkg-b2 || echo "absent" +$ uv run cci org list | grep [scratch-org] || echo "absent" absent ``` -DevHub `CCIDevHub` quota slot returned. No worktree branch pushed. No GitHub mutations performed. No files written under `cumulusci/robotframework/`. +DevHub `the configured DevHub` quota slot returned. No worktree branch pushed. No GitHub mutations performed. No files written under `cumulusci/robotframework/`. # -Theme: **metadata-etl** · Bucket **B** · Worktree `.worktrees/repro-etl-bucket-b` @ commit `129238663` (release v4.10.0) +Theme: **metadata-etl** · Bucket **B** · Worktree the triage worktree @ commit `129238663` (release v4.10.0) #### Verdict tally (10 issues processed) @@ -381,8 +383,8 @@ Theme: **metadata-etl** · Bucket **B** · Worktree `.worktrees/repro-etl-bucket Of the 7 REPRODUCED: - 4 are real correctness bugs (#808, #2826, #3165, #3931) -- 2 are UX/error-message bugs (#3613, #3951) — underlying functionality works with correct input -- 1 is a CLI option-parsing bug (#3953) — task is unusable from CLI +- 2 are UX/error-message bugs (#3613, #3951) - underlying functionality works with correct input +- 1 is a CLI option-parsing bug (#3953) - task is unusable from CLI #### Cross-cutting findings @@ -406,7 +408,7 @@ Suggested fix: when the file is missing, also log the list of files actually ret ##### 3. `update_admin_profile`'s `record_types` plus `_expand_package_xml` gating is fragile -The `record_types` -> `_expand_package_xml_objects` dependency is buried inside `_expand_package_xml`, which is gated on `include_packaged_objects=True`. This means a user who specifies `record_types` for an object outside the default `admin_profile.xml` package list — without also setting `include_packaged_objects: true` — silently skips the package.xml expansion needed for their record types. +The `record_types` -> `_expand_package_xml_objects` dependency is buried inside `_expand_package_xml`, which is gated on `include_packaged_objects=True`. This means a user who specifies `record_types` for an object outside the default `admin_profile.xml` package list - without also setting `include_packaged_objects: true` - silently skips the package.xml expansion needed for their record types. Issues affected: **#3165** (record_type for Case fails). Probably also a contributing factor in **#3544 / #3762** (the namespaced-org Person Accounts crash). @@ -414,27 +416,27 @@ The fix is a one-line refactor: always call `_expand_package_xml_objects` (which ##### 4. Several issues are "long-tail" enhancement requests still open -**#808** (2018), **#2826** (2021), **#3167** (2022, now implemented), **#3561** (2023, now fixed). The pattern suggests value in periodic dup/staleness sweeps that pair issues with PRs (#3167 ↔ #3243, #3561 ↔ #3566) — both were closed by a PR but the issue was never auto-closed. +**#808** (2018), **#2826** (2021), **#3167** (2022, now implemented), **#3561** (2023, now fixed). The pattern suggests value in periodic dup/staleness sweeps that pair issues with PRs (#3167 ↔ #3243, #3561 ↔ #3566) - both were closed by a PR but the issue was never auto-closed. #### Scratch org aliases used -- `repro-etl-b-dev` — used for live repros of #3613, #3951, #3953. Pre-existed from a prior subagent setup; reused as instructed. Will be deleted in the cleanup step. Created 2026-05-14 with `dev.json`, expires 2026-05-15. +- `[scratch-org]` - used for live repros of #3613, #3951, #3953. Pre-existed from a prior subagent setup; reused as instructed. Will be deleted in the cleanup step. Created 2026-05-14 with `dev.json`, expires 2026-05-15. No additional scratch orgs created. #### Output files -- `/tmp/repro/5/repro-results.csv` — verdict CSV (10 rows + header) -- `/tmp/repro/5/narrative.md` — per-issue narrative (10 sections) -- `/tmp/repro/5/SUMMARY.md` — this file -- `/tmp/repro/5/tests/issue-2826/repro_unit.py` — Python repro (FileNotFoundError) -- `/tmp/repro/5/tests/issue-3165/repro_unit.py` — Python repro (package.xml expansion gap) -- `/tmp/repro/5/tests/issue-3613/output-just-object.txt` — CLI output (Cannot find metadata file) -- `/tmp/repro/5/tests/issue-3613/output-good-name.txt` — CLI output (success with correct API name) -- `/tmp/repro/5/tests/issue-3931/repro_unit.py` — Python repro (NoneType.text) -- `/tmp/repro/5/tests/issue-3931/repro-output.txt` — captured output -- `/tmp/repro/5/tests/issue-3951/output-no-prefix.txt` — CLI output (Cannot find metadata file) -- `/tmp/repro/5/tests/issue-3953/output.txt` — CLI output (fullName key required) +- `_(repro evidence)_` - verdict CSV (10 rows + header) +- `_(repro evidence)_` - per-issue narrative (10 sections) +- `_(repro evidence)_` - this file +- `_(repro evidence; see narrative)_` - Python repro (FileNotFoundError) +- `_(repro evidence; see narrative)_` - Python repro (package.xml expansion gap) +- `_(repro evidence)_` - CLI output (Cannot find metadata file) +- `_(repro evidence)_` - CLI output (success with correct API name) +- `_(repro evidence; see narrative)_` - Python repro (NoneType.text) +- `_(repro evidence)_` - captured output +- `_(repro evidence)_` - CLI output (Cannot find metadata file) +- `_(repro evidence)_` - CLI output (fullName key required) #### Deviations @@ -449,37 +451,37 @@ None. All 10 issues processed within the protocol. No GitHub mutations. No commi | `NOT-REPRODUCED-on-v4.10.0` | 1 | #3347 | | `INCONCLUSIVE-needs-managed-package-04t` | 1 | #3902 | | `INCONCLUSIVE-needs-namespaced-project` | 1 | #3544 | -| `REPRODUCED-on-v4.10.0` | 0 | — | +| `REPRODUCED-on-v4.10.0` | 0 | - | | **Total processed** | **3** | | #### Scratch org aliases used -| Alias | Config | DevHub | Status | -| -------------------- | ----------------- | --------- | ------------------------------------------------------------------------------ | -| `repro-special-c-pa` | `person_accounts` | CCIDevHub | Created (existed at session start, reused), used for #3544, slated for cleanup | +| Alias | Config | DevHub | Status | +| --------------- | ----------------- | --------------------- | ------------------------------------------------------------------------------ | +| `[scratch-org]` | `person_accounts` | the configured DevHub | Created (existed at session start, reused), used for #3544, slated for cleanup | No other aliases created. #3902 and #3347 were code-only investigations. #### Per-issue outcomes -##### #3347 — `release_unlocked_beta` TypeError → fixed +##### #3347 - `release_unlocked_beta` TypeError → fixed Cryptic `TypeError: expected str, bytes or os.PathLike object, not NoneType` is replaced on v4.10.0 by an early `TaskOptionsError(PERSISTENT_ORG_ERROR)` at `cumulusci/tasks/create_package_version.py:158-159`, fix landed in commit `2a9cadcb1` (2023-10-12). Existing test `test_create_package_version.py::TestPackageConfig::test_org_config` validates the new behavior and passes. **Recommend close-with-comment.** -##### #3902 — `install_managed` security_type with 04t → code looks correct, runtime not validatable +##### #3902 - `install_managed` security_type with 04t → code looks correct, runtime not validatable -Code path inspection on v4.10.0 confirms `install_managed` faithfully passes `security_type` to the Salesforce Tooling API `PackageInstallRequest.SecurityType` for both 04t and namespace+version code paths. `SecurityType.ADMIN` correctly serializes to JSON `"NONE"`. No CumulusCI defect identified; observed user behavior likely originates from Salesforce platform behavior (upgrade vs fresh install, App-level tab visibility, etc.). **Cannot fully validate without a reusable managed package 04t fixture — verdict INCONCLUSIVE-needs-managed-package-04t.** +Code path inspection on v4.10.0 confirms `install_managed` faithfully passes `security_type` to the Salesforce Tooling API `PackageInstallRequest.SecurityType` for both 04t and namespace+version code paths. `SecurityType.ADMIN` correctly serializes to JSON `"NONE"`. No CumulusCI defect identified; observed user behavior likely originates from Salesforce platform behavior (upgrade vs fresh install, App-level tab visibility, etc.). **Cannot fully validate without a reusable managed package 04t fixture - verdict INCONCLUSIVE-needs-managed-package-04t.** -##### #3544 — `update_admin_profile` with PersonAccounts + namespacing → not validatable in CumulusCI repo +##### #3544 - `update_admin_profile` with PersonAccounts + namespacing → not validatable in CumulusCI repo -Bug requires the intersection of PersonAccounts AND a namespaced project. CumulusCI itself has no project namespace, so the repro condition cannot be fully satisfied without registering a namespace in CCIDevHub (out of scope). Partial repro: `update_admin_profile` ran SUCCESSFULLY against a non-namespaced PersonAccounts scratch on v4.10.0, confirming the bug is specific to the namespaced+PersonAccounts intersection. No code-level fix found referencing #3544 / W-12589033 in `update_profile.py` since 2023. **Verdict INCONCLUSIVE-needs-namespaced-project.** +Bug requires the intersection of PersonAccounts AND a namespaced project. CumulusCI itself has no project namespace, so the repro condition cannot be fully satisfied without registering a namespace in the configured DevHub (out of scope). Partial repro: `update_admin_profile` ran SUCCESSFULLY against a non-namespaced PersonAccounts scratch on v4.10.0, confirming the bug is specific to the namespaced+PersonAccounts intersection. No code-level fix found referencing #3544 / [internal-ID-redacted] in `update_profile.py` since 2023. **Verdict INCONCLUSIVE-needs-namespaced-project.** #### Per-issue blocker explanations | Issue | Blocker | Mitigation | | ----- | ----------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | -| #3347 | None — code-only verifiable | Existing pytest passes on HEAD | -| #3902 | No reusable managed package 04t fixture available within CCIDevHub workflow | Recommend Pass 2 label `needs-managed-package-fixture` | +| #3347 | None - code-only verifiable | Existing pytest passes on HEAD | +| #3902 | No reusable managed package 04t fixture available within the configured DevHub workflow | Recommend Pass 2 label `needs-managed-package-fixture` | | #3544 | CumulusCI repo has no project namespace; cannot satisfy `namespaced:true` repro condition | Recommend Pass 2 label `needs-namespaced-project` and ask reporter to retest on v4.10.0 | #### Adjacent finding (not in scope but worth recording) @@ -487,17 +489,17 @@ Bug requires the intersection of PersonAccounts AND a namespaced project. Cumulu While exercising `-o namespaced_org True` on a non-namespaced project for #3544, surfaced a latent `TypeError: unsupported operand type(s) for +: 'NoneType' and 'str'` at `cumulusci/utils/__init__.py:229`: ```229:229:cumulusci/utils/__init__.py - namespaced_org = namespace + "__" if namespaced_org else "" + namespaced_org = namespace + "__" if namespaced_org else "" ``` Distinct from #3544 (init-time vs deploy-time). Suggest a separate small cleanup ticket. #### Outputs -- `/tmp/repro/6/repro-results.csv` — header-conforming CSV with 3 rows -- `/tmp/repro/6/narrative.md` — per-issue narrative sections -- `/tmp/repro/6/SUMMARY.md` — this file -- `/tmp/repro/6/tests/` — directory created but no new test files written (used existing in-repo test for #3347; manual cci command for #3544; pure code inspection for #3902) +- `_(repro evidence)_` - header-conforming CSV with 3 rows +- `_(repro evidence)_` - per-issue narrative sections +- `_(repro evidence)_` - this file +- `_(repro evidence)_` - directory created but no new test files written (used existing in-repo test for #3347; manual cci command for #3544; pure code inspection for #3902) #### Constraints honored @@ -506,12 +508,12 @@ Distinct from #3544 (init-time vs deploy-time). Suggest a separate small cleanup - No edits under `cumulusci/robotframework/`. - No edits to `pyproject.toml`/`uv.lock`. - All commands run via `uv run …` from the worktree. -- DevHub: `CCIDevHub` only. -- Scratch alias prefix: `repro-special-c-`. +- DevHub: `the configured DevHub` only. +- Scratch alias prefix: `[scratch-org]-`. # -Worktree: `.worktrees/repro-cli-part1` @ `129238663` = release v4.10.0. +Worktree: the triage worktree @ `129238663` = release v4.10.0. #### Verdict tally (13 issues) @@ -534,15 +536,15 @@ So **12 of 13 dry-run `closed:stale-24mo` proposals stand**. One should be re-ca #### Cross-cutting findings -1. **Most of the bundle is stable feature requests with very little movement** (#733 from 2018, #1348 from 2019, #2140 from 2020, etc.). The `closed:stale-24mo` action is appropriate; the work-items in some cases (W-028291, W-10502624, W-10502512) have been tracked for years without delivery. +1. **Most of the bundle is stable feature requests with very little movement** (#733 from 2018, #1348 from 2019, #2140 from 2020, etc.). The `closed:stale-24mo` action is appropriate; the work-items in some cases ([internal-ID-redacted], [internal-ID-redacted], [internal-ID-redacted]) have been tracked for years without delivery. 2. **#1350 is the only clear "we shipped a fix" issue**: a synthetic `tasks` namespace package was added (`cumulusci/core/config/project_config.py:52-57`) plus `_add_tasks_directory_to_python_path()` so cross-project task imports now resolve. The follow-up _name-collision_ concern raised by `prescod` in 2022 is a separate concern and would warrant its own issue if anyone hit it again. -3. **#1432 and #2507 and #3161 each show "partial mitigation"** — infrastructure has landed but the original ergonomic request is not fully satisfied. Worth flagging in `notes` so these don't get re-triaged as still-open feature debt without context. Adding `partially-fixed` / `partially-implemented` labels in pass2 surfaces this. +3. **#1432 and #2507 and #3161 each show "partial mitigation"** - infrastructure has landed but the original ergonomic request is not fully satisfied. Worth flagging in `notes` so these don't get re-triaged as still-open feature debt without context. Adding `partially-fixed` / `partially-implemented` labels in pass2 surfaces this. 4. **Inclusive-language angle (#3470)**: the rename remains undone but the underlying need (flow aliasing) is acknowledged. If pass2 includes a `inclusive-language` label, this is the only candidate. -5. **No issues should remain open** — all 13 are either fixed, stale, or design-as-intended (the design-as-intended one, #2697, is best closed with a `needs-info` framing if anyone reopens). +5. **No issues should remain open** - all 13 are either fixed, stale, or design-as-intended (the design-as-intended one, #2697, is best closed with a `needs-info` framing if anyone reopens). #### Scratch org aliases used @@ -550,10 +552,10 @@ So **12 of 13 dry-run `closed:stale-24mo` proposals stand**. One should be re-ca #### Output files -- `/tmp/repro/7/repro-results.csv` — 13 rows, header included. -- `/tmp/repro/7/narrative.md` — H3 section per issue. -- `/tmp/repro/7/SUMMARY.md` — this file. -- `/tmp/repro/7/tests/test_1432_options_validation.py` — unit repro for #1432 (passes on v4.10.0). +- `_(repro evidence)_` - 13 rows, header included. +- `_(repro evidence)_` - H3 section per issue. +- `_(repro evidence)_` - this file. +- `_(repro evidence; see narrative)_` - unit repro for #1432 (passes on v4.10.0). #### Deviations @@ -562,10 +564,10 @@ None. # **Pinned commit**: `129238663` (Release v4.10.0) -**Branch**: `worktree/repro/cli-part2` -**Worktree**: `.worktrees/repro-cli-part2` +**Branch**: the triage worktree +**Worktree**: the triage worktree **Issues processed**: 13 / 13 -**Scratch orgs provisioned**: none — all repros completed via Bucket A (code-scan + one isolated unit test) +**Scratch orgs provisioned**: none - all repros completed via Bucket A (code-scan + one isolated unit test) #### Verdict tally @@ -584,11 +586,11 @@ None. | `closed:stale-24mo` | 2 | #3607, #3609 | | `closed:not-reproducible-on-v4.10.0` | 1 | #3612 | -Both kept-open issues from the dry-run (#3852, #3854) remain `keep-open` here — verdicts confirm the maintainer's label. +Both kept-open issues from the dry-run (#3852, #3854) remain `keep-open` here - verdicts confirm the maintainer's label. #### Cross-cutting findings -1. **Flow `when:` clause is structurally limited.** Three issues in this batch (#3506, #3570, #3663) all expose the same surface: the `when:` evaluator at `cumulusci/core/flowrunner.py:510-516` only sees `project_config` + `org_config`, and `when:` is only honored on `task:` steps (line 669) — never on `flow:` steps (lines 674-697). A single epic could absorb #3506 + #3663 and is adjacent to #3570's "finally/error path" request. +1. **Flow `when:` clause is structurally limited.** Three issues in this batch (#3506, #3570, #3663) all expose the same surface: the `when:` evaluator at `cumulusci/core/flowrunner.py:510-516` only sees `project_config` + `org_config`, and `when:` is only honored on `task:` steps (line 669) - never on `flow:` steps (lines 674-697). A single epic could absorb #3506 + #3663 and is adjacent to #3570's "finally/error path" request. 2. **`-o` / option-parsing surface is rigid.** #3492 (project-level overrides) and #3618 (multi-org operations) are both small CLI parser improvements. Both landed in this batch with `keep-open` and `good-first-issue`-eligible scope. @@ -598,8 +600,8 @@ Both kept-open issues from the dry-run (#3852, #3854) remain `keep-open` here 5. **Two genuine regressions are still active**: - - #3852 (sarge `Capture.flush`) is upstream-dependent (sarge 0.1.8 unreleased). Cosmetic only on Python 3.13. - - #3854 (`capture_sample_data` validation) is a regression introduced by PR #3741 / `2c5d0056e`. Workaround documented (downgrade to 3.84.1) but the bug is real for polymorphic-lookup users. +- #3852 (sarge `Capture.flush`) is upstream-dependent (sarge 0.1.8 unreleased). Cosmetic only on Python 3.13. +- #3854 (`capture_sample_data` validation) is a regression introduced by PR #3741 / `2c5d0056e`. Workaround documented (downgrade to 3.84.1) but the bug is real for polymorphic-lookup users. 6. **#3609 (dx plugins:install) is upstream-only.** `cumulusci/tasks/sfdx.py` is now a 5-line shell wrapper around `sf {command}`; any `Timed out` error originates in the SF CLI itself. @@ -607,14 +609,14 @@ Both kept-open issues from the dry-run (#3852, #3854) remain `keep-open` here #### Output files -- `/tmp/repro/8/repro-results.csv` — 13 rows, header validated, parses cleanly. -- `/tmp/repro/8/narrative.md` — H3 section per issue with verdict + evidence + pass-1/pass-2 recs. -- `/tmp/repro/8/SUMMARY.md` — this file. -- `/tmp/repro/8/tests/test_3607_retry.py` — one repro test (passes, confirming retry regex logic is correct in isolation). +- `_(repro evidence)_` - 13 rows, header validated, parses cleanly. +- `_(repro evidence)_` - H3 section per issue with verdict + evidence + pass-1/pass-2 recs. +- `_(repro evidence)_` - this file. +- `_(repro evidence; see narrative)_` - one repro test (passes, confirming retry regex logic is correct in isolation). #### Scratch-org cleanup -No scratch orgs provisioned — Bucket A sufficed for all 13. Nothing to delete. +No scratch orgs provisioned - Bucket A sufficed for all 13. Nothing to delete. #### Deviations @@ -630,7 +632,7 @@ None. | ------------------------- | ----- | ---------------------------------------- | | REPRODUCED-on-v4.10.0 | 6 | #1769, #2013, #2325, #2506, #2508, #2951 | | NOT-REPRODUCED-on-v4.10.0 | 3 | #2096, #2505, #3283 | -| INCONCLUSIVE | 0 | — | +| INCONCLUSIVE | 0 | - | #### Pass-1 recommendations @@ -651,7 +653,7 @@ None. 1. **Pattern of extending metadata-toggle tasks is fertile**: `disable_tdtm_trigger_handlers`, `restore_tdtm_trigger_handlers`, `set_duplicate_rule_status` form a clear template (`MetadataSingleEntityTransformTask` subclass). #2325 (ValidationRule), and historical asks for similar toggles, can all be solved by ~25-line additions following this pattern. 2. **`MappingStep.soql_filter` is mature**: per-step WHERE-clause filtering is now first-class, used by extract.py, the new declarative extract generator, and the hardcoded extract defaults. This closes #2505 cleanly and could be a reusable answer for any future "filter at extract time" requests. -3. **`hardcoded_default_declarations.py` quietly mitigates several historic data-shape bugs**: PricebookEntry filtering (#2951), sample-account exclusion, business hours, etc. Worth surfacing this file to triage doc readers — many "I extracted my org and it broke" issues are now invisibly handled here. +3. **`hardcoded_default_declarations.py` quietly mitigates several historic data-shape bugs**: PricebookEntry filtering (#2951), sample-account exclusion, business hours, etc. Worth surfacing this file to triage doc readers - many "I extracted my org and it broke" issues are now invisibly handled here. 4. **Snowfakery has a working `get_debug_mode` integration; load/extract do not**: #2506 is half-complete. Wiring `get_debug_mode()` into `load.py`/`extract.py` and conditionally retaining tempdirs would close the gap with negligible risk. 5. **Rollback ≠ retry**: `enable_rollback` (added since 2021) is sometimes confused with the retry asked for in #2508. They are orthogonal: rollback undoes successful inserts on failure; retry would re-attempt failed records. Both have value. 6. **REST loader has caught up with Bulk on type coercion** (`process_bool_arg` is now used by `RestApiDmlOperation._record_to_json`); the empty-string→null fix (#3361) for upsert/update is also in place. Several "REST is stricter than Bulk" historic complaints are likely resolved by these two changes alone. @@ -662,9 +664,9 @@ None. #### Repro test artifacts -- `/tmp/repro/9/tests/test_2013_multistep.py` — confirms #2013 SQLAlchemy error -- `/tmp/repro/9/tests/test_2096_rest_booleans.py` — confirms #2096 spec compliance (20/20) -- `/tmp/repro/9/tests/test_3283_empty_date.py` — confirms #3283 fix in v4.10.0 (3/3) +- `_(repro evidence; see narrative)_` - confirms #2013 SQLAlchemy error +- `_(repro evidence; see narrative)_` - confirms #2096 spec compliance (20/20) +- `_(repro evidence; see narrative)_` - confirms #3283 fix in v4.10.0 (3/3) All three test files run green against the v4.10.0 source via `uv run pytest ` from this worktree. @@ -675,9 +677,9 @@ None. No GitHub mutations. No git pushes. No edits under `cumulusci/robotframewo # - **Theme**: bulkdata -- **Worktree**: `.worktrees/repro-bulk-part2` @ `129238663` (= v4.10.0) +- **Worktree**: the triage worktree @ `129238663` (= v4.10.0) - **Issues processed**: 9 / 9 -- **Scratch orgs provisioned**: 1 — `repro-bulk-p2-dev` (created 2026-05-14 09:48:57 UTC, username `test-9oxwkamse2zq@example.com`, Org Id `00DRt00000Q7HYE`). Provisioned during initial triage but ultimately not needed because all 9 issues turned out to be conclusive from code review and/or in-process unit tests against `cumulusci/tasks/bulkdata/`. Already cleaned up — see "Scratch org cleanup" section below. +- **Scratch orgs provisioned**: 1 - `repro-bulk-p2-dev` (created 2026-05-14 09:48:57 UTC, username `test-9oxwkamse2zq@example.com`, Org Id `00DRt00000Q7HYE`). Provisioned during initial triage but ultimately not needed because all 9 issues turned out to be conclusive from code review and/or in-process unit tests against `cumulusci/tasks/bulkdata/`. Already cleaned up - see "Scratch org cleanup" section below. #### Verdict tally @@ -686,7 +688,7 @@ None. No GitHub mutations. No git pushes. No edits under `cumulusci/robotframewo | `REPRODUCED-on-v4.10.0` | 7 | #3349, #3353, #3649, #3699, #3700, #3701, #3768 | | `NOT-REPRODUCED-on-v4.10.0` | 1 | #3360 | | `INCONCLUSIVE-needs-flaky-network` | 1 | #3936 | -| `closed:duplicate-of-#NNNN` | 0 | — | +| `closed:duplicate-of-#NNNN` | 0 | - | #### Pass-1 recommendations @@ -700,13 +702,13 @@ None. No GitHub mutations. No git pushes. No edits under `cumulusci/robotframewo #### Bug vs feature breakdown - **Bugs** (4): #3349, #3700, #3768, #3936 - - All four still present in v4.10.0 (with #3936 environment-dependent for the actual timeout, but the underlying missing-timeout-config gap is confirmed). - - 2 are good-first-issue candidates (#3700 small fix; #3349 medium). +- All four still present in v4.10.0 (with #3936 environment-dependent for the actual timeout, but the underlying missing-timeout-config gap is confirmed). +- 2 are good-first-issue candidates (#3700 small fix; #3349 medium). - **Features** (5): #3353, #3360, #3649, #3699, #3701 - - 1 already implemented and should close: #3360 (`action: select`). - - 1 small good-first-issue: #3649 (add `bulk_mode` option to `update_data`). - - 1 active community ask: #3353 (cross-source recipe paths). - - 2 low-priority with workarounds: #3699 (workaround via `soql_filter ORDER BY`), #3701 (related to #3699). +- 1 already implemented and should close: #3360 (`action: select`). +- 1 small good-first-issue: #3649 (add `bulk_mode` option to `update_data`). +- 1 active community ask: #3353 (cross-source recipe paths). +- 2 low-priority with workarounds: #3699 (workaround via `soql_filter ORDER BY`), #3701 (related to #3699). #### Cross-cutting findings @@ -714,7 +716,7 @@ None. No GitHub mutations. No git pushes. No edits under `cumulusci/robotframewo 2. **`MappingStep._get_required_permission_types` is too conservative for upserts.** #3700 is the master-detail variant; the same logic also affects formula fields (read-only) and other intentionally-non-updateable fields used as upsert lookups. A field-shape-aware permission check (using `cascadeDelete` / `relationshipName` / `nillable` from describe) would handle multiple field categories at once. -3. **RecordType-table naming derives from `sf_object` not `table` (#3349) and the same problem caused #2013 (Subagent 9).** Both bugs share a root cause: the code assumes a 1:1 mapping between `sf_object` and SQLite table within an extract run. A v5 refactor of mapping_parser to make the `table:` key the unambiguous primary key would fix both. +3. **RecordType-table naming derives from `sf_object` not `table` (#3349) and the same problem caused #2013.** Both bugs share a root cause: the code assumes a 1:1 mapping between `sf_object` and SQLite table within an extract run. A v5 refactor of mapping_parser to make the `table:` key the unambiguous primary key would fix both. 4. **Snowfakery `just_once` + `batch_size` (#3768) reflects a deliberate cleanup choice.** `_cleanup_object_tables` drops all object tables from the template before propagating it to subsequent batches, keeping only `_sf_ids`. To fix #3768, CCI needs to detect which objects are referenced via `random_reference`+`just_once` and preserve their rows in the template DB. This is non-trivial and intersects with the Snowfakery dev cutover (see master plan `snowfakery-coordination`). @@ -722,10 +724,10 @@ None. No GitHub mutations. No git pushes. No edits under `cumulusci/robotframewo 6. **`action: select` (added Aug 2024) resolves #3360 and likely overlaps several closed enhancement requests not in this bundle.** A grep of historical issues for "lookup existing records" / "reference existing data" might find more candidates to close. -#### Repro tests written (under `/tmp/repro/10/tests/`) +#### Repro tests written (under `_(repro evidence)_`) -- `test_3349_recordtype_table_collision.py` — proves `MappingStep` collides record-type table names for two steps sharing `sf_object`. -- `test_3700_master_detail_upsert_perm.py` — proves `_check_field_permission` rejects MD lookup fields under UPSERT. +- `test_3349_recordtype_table_collision.py` - proves `MappingStep` collides record-type table names for two steps sharing `sf_object`. +- `test_3700_master_detail_upsert_perm.py` - proves `_check_field_permission` rejects MD lookup fields under UPSERT. Both tests exercise `cumulusci.tasks.bulkdata.mapping_parser` only, no org needed, ~0.3s each. @@ -735,7 +737,7 @@ Both tests exercise `cumulusci.tasks.bulkdata.mapping_parser` only, no org neede - `uv run cci org list` shows no `repro-bulk-p2-*` entries. - `uv run cci org scratch_delete repro-bulk-p2-dev` returns `Org with name 'repro-bulk-p2-dev' does not exist.` (= already cleaned). -- `sf data query --query "SELECT Id, ScratchOrg, SignupUsername FROM ActiveScratchOrg" --target-org CCIDevHub` returns one row whose username does NOT match `test-9oxwkamse2zq@example.com` — i.e. our scratch org is no longer active on the DevHub. +- `sf data query --query "SELECT Id, ScratchOrg, SignupUsername FROM ActiveScratchOrg" --target-org the configured DevHub` returns one row whose username does NOT match `test-9oxwkamse2zq@example.com` - i.e. our scratch org is no longer active on the DevHub. - `sf org list --json` filtered for `repro-bulk-p2` / `test-9oxwkamse2zq` returns `[]`. No `repro-bulk-p2-*` aliases or scratch orgs remain. @@ -757,8 +759,8 @@ None. | ------------------------- | ----- | -------------------------- | | REPRODUCED-on-v4.10.0 | 4 | #3603, #3604, #3619, #3886 | | NOT-REPRODUCED-on-v4.10.0 | 1 | #3615 | -| INCONCLUSIVE | 0 | — | -| closed:duplicate-of-#NNNN | 0 | — | +| INCONCLUSIVE | 0 | - | +| closed:duplicate-of-#NNNN | 0 | - | Note: #3604 is a feature request; "REPRODUCED" here means the requested capability is still missing in v4.10.0. @@ -782,7 +784,7 @@ capability is still missing in v4.10.0. would resolve this cleanly. 2. **Pin model is missing fields that are routine on dependencies**. - `GitHubDependencyPin` (#3619) only carries `github`/`tag` — but a real + `GitHubDependencyPin` (#3619) only carries `github`/`tag` - but a real pinned dep often needs `password_env_name`. The pin-resolution path (`pin.pin()`) also bypasses the password-propagation block in `resolve_dependency()`, so even when a dep declares the password, it gets @@ -813,42 +815,42 @@ No scratch orgs were provisioned; no cleanup required. #### Output files -- `/tmp/repro/11/repro-results.csv` -- `/tmp/repro/11/narrative.md` -- `/tmp/repro/11/SUMMARY.md` -- `/tmp/repro/11/tests/test_3603_404_messages.py` (4 tests, all passing) -- `/tmp/repro/11/tests/test_3615_preproduction_strategy.py` (3 tests, all passing) -- `/tmp/repro/11/tests/test_3619_pin_password.py` (4 tests, all passing) -- `/tmp/repro/11/tests/test_3886_select_warning.py` (2 tests, all passing) +- `_(repro evidence)_` +- `_(repro evidence)_` +- `_(repro evidence)_` +- `_(repro evidence; see narrative)_` (4 tests, all passing) +- `_(repro evidence; see narrative)_` (3 tests, all passing) +- `_(repro evidence; see narrative)_` (4 tests, all passing) +- `_(repro evidence; see narrative)_` (2 tests, all passing) #### Deviations None against bundle constraints. Two observations worth noting: 1. Mid-session, `git status -sb` briefly showed the branch label as - `worktree/repro/bulk-part2`; by end-of-session it had updated to the - expected `worktree/repro/deps`. The HEAD SHA was always `129238663` + the triage worktree; by end-of-session it had updated to the + expected the triage worktree. The HEAD SHA was always `129238663` (= v4.10.0), so all repro evidence is valid against the intended source state. -2. `/tmp/repro/11/tests/` already contained 3 stale repro files from a prior +2. `_(repro evidence)_` already contained 3 stale repro files from a prior subagent run (`test_3603_404_messaging.py`, `test_3619_pin_no_password.py`, `test_3886_select_optional_deps_warning.py`) that conflicted with my own tests by sharing module-level imports of `select_utils`. I deleted those stale files and re-ran my tests cleanly (13/13 passing). Other subagents' - outputs in adjacent `/tmp/repro//` directories were not touched. + outputs in adjacent `_(repro evidence)_` directories were not touched. #### Final test verification ``` -$ uv run pytest /tmp/repro/11/tests/ -v +$ uv run pytest _(repro evidence)_ -v ======================== 13 passed, 1 warning in 0.35s ========================= ``` # Worktree: `/Users/jestevez/work/rel/CumulusCI/.worktrees/repro-ci-int` @ `129238663` (= v4.10.0) -Theme: `ci-integration` (mixed bucket — issues span Heroku/CI workflow, GitHub Actions, sfdx CLI integration) +Theme: `ci-integration` (mixed bucket - issues span Heroku/CI workflow, GitHub Actions, sfdx CLI integration) Issues processed: 4 (all 4 in bundle-12.json) #### Verdict tally @@ -862,7 +864,7 @@ Issues processed: 4 (all 4 in bundle-12.json) Bug vs feature breakdown: -- 1 feature (#2153) — REPRODUCED (still unimplemented) +- 1 feature (#2153) - REPRODUCED (still unimplemented) - 3 bugs (#3471 REPRODUCED, #3479 NOT-REPRODUCED, #3717 INCONCLUSIVE) #### Recommended pass1 actions @@ -878,24 +880,25 @@ Bug vs feature breakdown: 1. **`MergeBranch` (`cumulusci/tasks/github/merge.py`) is the locus of two of the four issues** (#2153 and #3471). Both have small, well-localized fixes: - - #2153: After `self.repo.create_pull(...)` in `_create_conflict_pull_request`, look up open PRs whose `head==branch_name` (the conflicted child branch) and post a comment linking back to the auto-generated conflict PR with resolution steps. - - #3471: Replace `compare.behind_by` in the success log line with `len(list(compare.commits))` (or report the merge SHA returned by `self.repo.merge`). Add a unit test in `test_merge.py` that mocks a `compare` with `behind_by=0` but `files=[…]` to lock in the new behavior. +- #2153: After `self.repo.create_pull(...)` in `_create_conflict_pull_request`, look up open PRs whose `head==branch_name` (the conflicted child branch) and post a comment linking back to the auto-generated conflict PR with resolution steps. +- #3471: Replace `compare.behind_by` in the success log line with `len(list(compare.commits))` (or report the merge SHA returned by `self.repo.merge`). Add a unit test in `test_merge.py` that mocks a `compare` with `behind_by=0` but `files=[…]` to lock in the new behavior. 2. **cci has no GitHub Actions environment auto-detection.** `project_config.py::repo_info` only handles Heroku CI plus generic `CUMULUSCI_REPO_*` overrides. Repo-wide grep for `GITHUB_REF|GITHUB_HEAD_REF|GITHUB_SHA|GITHUB_ACTIONS` returns zero matches. This is the structural cause behind #3717 (and a contributing factor any time a `push`-triggered GHA job runs cci against a detached HEAD). Two viable directions, both out of scope for triage: - - Fix in `cumulus-actions/standard-workflows`: set `CUMULUSCI_REPO_BRANCH` from `${{ github.head_ref || github.ref_name }}` and `CUMULUSCI_REPO_COMMIT` from `${{ github.sha }}` before invoking cci. - - Add a `# GitHub Actions` block in `repo_info` parallel to the existing Heroku block. +- Fix in `cumulus-actions/standard-workflows`: set `CUMULUSCI_REPO_BRANCH` from `${{ github.head_ref || github.ref_name }}` and `CUMULUSCI_REPO_COMMIT` from `${{ github.sha }}` before invoking cci. +- Add a `# GitHub Actions` block in `repo_info` parallel to the existing Heroku block. 3. **Stale 2023-era user-config issues with no reporter follow-up** (#3479) are good `closed:not-reproducible-on-v4.10.0` candidates when (a) the symptom is improved or wrapped in v4.10.0 and (b) the reviewer's clarifying question went unanswered for 2+ years. #3479 fits both criteria. 4. **Code stability for this theme is high.** Between the issue dates (2020-2023) and v4.10.0: - - `cumulusci/tasks/github/merge.py` has had only refactors (ruff migration, `create_pull_request_on_conflict` option, `skip_future_releases` fixes) — no change to the `compare.behind_by` reporting line or to PR-creation behavior on conflict. - - `cumulusci/core/config/sfdx_org_config.py` has had the JSON-error wrapper since 2020-11-24. - - `cumulusci/core/config/project_config.py::repo_info` still only auto-detects Heroku. + +- `cumulusci/tasks/github/merge.py` has had only refactors (ruff migration, `create_pull_request_on_conflict` option, `skip_future_releases` fixes) - no change to the `compare.behind_by` reporting line or to PR-creation behavior on conflict. +- `cumulusci/core/config/sfdx_org_config.py` has had the JSON-error wrapper since 2020-11-24. +- `cumulusci/core/config/project_config.py::repo_info` still only auto-detects Heroku. #### Scratch org aliases used -**No scratch needed** — all 4 issues resolved by code-scan against the worktree (Bucket A). DevHub `CCIDevHub` was not touched. +**No scratch needed** - all 4 issues resolved by code-scan against the worktree (Bucket A). DevHub `the configured DevHub` was not touched. #### Deviations from instructions @@ -903,16 +906,14 @@ None. No GitHub mutations, no pushes, no edits under `cumulusci/robotframework/` #### Output files -- `/tmp/repro/12/repro-results.csv` -- `/tmp/repro/12/narrative.md` -- `/tmp/repro/12/SUMMARY.md` +- `_(repro evidence)_` +- `_(repro evidence)_` +- `_(repro evidence)_` ## Per-issue narratives Concatenated from each subagent's `narrative.md`. Sorted by issue number. Headings normalized to `### #NNNN`. - - ### #733: Prompt to delete scratch org when creating one that already exists **Verdict**: REPRODUCED-on-v4.10.0 @@ -922,34 +923,32 @@ Concatenated from each subagent's `narrative.md`. Sorted by issue number. Headin **Evidence**: ```126:140:cumulusci/cli/runtime.py - def check_org_overwrite(self, org_name): - try: - org = self.keychain.get_org(org_name) - if org.scratch: - if org.created: - raise click.ClickException( - f"Scratch org has already been created. Use `cci org scratch_delete {org_name}`" - ) - else: - raise click.ClickException( - f"Org {org_name} already exists. Use `cci org remove` to delete it." - ) - except OrgNotFound: - pass - return True + def check_org_overwrite(self, org_name): + try: + org = self.keychain.get_org(org_name) + if org.scratch: + if org.created: + raise click.ClickException( + f"Scratch org has already been created. Use `cci org scratch_delete {org_name}`" + ) + else: + raise click.ClickException( + f"Org {org_name} already exists. Use `cci org remove` to delete it." + ) + except OrgNotFound: + pass + return True ``` -Behaviour identical to the 2018 report — hard error, no interactive Y/N prompt. +Behaviour identical to the 2018 report - hard error, no interactive Y/N prompt. **Recommended action**: -- pass1: `closed:stale-24mo` — 7-year-old `cli-usability` enhancement, no traction, original tracking W-028291. +- pass1: `closed:stale-24mo` - 7-year-old `cli-usability` enhancement, no traction. - pass2 labels: `enhancement,cli-usability,stale` --- - - ### #808: deploy_packaging flow runs uninstall_packaged_incremental with wrong package name **Verdict**: REPRODUCED-on-v4.10.0 @@ -964,10 +963,10 @@ Read `cumulusci/tasks/salesforce/UninstallPackaged.py` and compared with `cumulu - `UninstallPackaged._init_options` (UninstallPackaged.py:22-25): ```22:25:cumulusci/tasks/salesforce/UninstallPackaged.py - def _init_options(self, kwargs): - super(UninstallPackaged, self)._init_options(kwargs) - if "package" not in self.options: - self.options["package"] = self.project_config.project__package__name + def _init_options(self, kwargs): + super(UninstallPackaged, self)._init_options(kwargs) + if "package" not in self.options: + self.options["package"] = self.project_config.project__package__name ``` - Compare to `InstallPackageVersion._init_options` (install_package_version.py:75-79) which DOES use the fall-back chain `name_managed -> name -> namespace`. The asymmetry is the bug. @@ -975,15 +974,13 @@ Read `cumulusci/tasks/salesforce/UninstallPackaged.py` and compared with `cumulu **Recommended action**: -- pass1: `keep-open` — small, contained fix. +- pass1: `keep-open` - small, contained fix. - pass2 labels: `bug`, `good-first-issue` **Notes**: jlantz's 2018 follow-up about deprecating `project__package__name_managed` (legacy NPSP-only feature) is a separate, larger conversation; for this triage the minimal symmetric fix is enough. --- - - ### #1348: Multiple Git Provider Support **Verdict**: REPRODUCED-on-v4.10.0 @@ -995,26 +992,24 @@ Read `cumulusci/tasks/salesforce/UninstallPackaged.py` and compared with `cumulu `rg -li "gitlab" cumulusci/` and `rg -li "bitbucket" cumulusci/` both return zero matches. The `ci_feature` flow still hardcodes GitHub-specific tasks: ```767:789:cumulusci/cumulusci.yml - ci_feature: - group: Continuous Integration - ... - steps: - 0.5: - task: github_parent_pr_notes - ... - 5: - task: github_automerge_feature + ci_feature: + group: Continuous Integration + ... + steps: + 0.5: + task: github_parent_pr_notes + ... + 5: + task: github_automerge_feature ``` **Recommended action**: -- pass1: `closed:stale-24mo` — large architectural change (multi-VCS abstraction); 6yr no traction; user `zenibako` confirmed using cci on GitLab via custom flows is feasible. +- pass1: `closed:stale-24mo` - large architectural change (multi-VCS abstraction); 6yr no traction; user `zenibako` confirmed using cci on GitLab via custom flows is feasible. - pass2 labels: `enhancement,stale,wontfix-candidate` --- - - ### #1350: Unable to run tasks in remote projects **Verdict**: NOT-REPRODUCED-on-v4.10.0 @@ -1027,7 +1022,7 @@ The original `ModuleNotFoundError: No module named 'tasks'` is fixed via a synth ```52:57:cumulusci/core/config/project_config.py sys.modules.setdefault( - "tasks", types.ModuleType("tasks", "Synthetic package for all repo tasks") + "tasks", types.ModuleType("tasks", "Synthetic package for all repo tasks") ) import tasks @@ -1035,37 +1030,35 @@ tasks.__path__ = [] ``` ```657:679:cumulusci/core/config/project_config.py - # If I can't load remote code, make sure that my - # included repos can't either. - if not self.allow_remote_code: - spec.allow_remote_code = False - else: - project_config._add_tasks_directory_to_python_path() - - return project_config - - def _add_tasks_directory_to_python_path(self): - # https://stackoverflow.com/a/2700924/113477 - if not self.allow_remote_code: - return False - - directory = str(Path(self.repo_root) / "tasks") - if directory not in tasks.__path__: - self.logger.debug(f"Adding {directory} to tasks.__path__") - tasks.__path__.append(directory) + # If I can't load remote code, make sure that my + # included repos can't either. + if not self.allow_remote_code: + spec.allow_remote_code = False + else: + project_config._add_tasks_directory_to_python_path() + + return project_config + + def _add_tasks_directory_to_python_path(self): + # https://stackoverflow.com/a/2700924/113477 + if not self.allow_remote_code: + return False + + directory = str(Path(self.repo_root) / "tasks") + if directory not in tasks.__path__: + self.logger.debug(f"Adding {directory} to tasks.__path__") + tasks.__path__.append(directory) ``` The follow-up name-collision concern raised by `prescod` in 2022 (NPSP and EDA both registering `tasks.is_rd2_enabled`) is a **separate** issue from the original report. **Recommended action**: -- pass1: `closed:not-reproducible-on-v4.10.0` — original bug is fixed. +- pass1: `closed:not-reproducible-on-v4.10.0` - original bug is fixed. - pass2 labels: `fixed` --- - - ### #1432: CCI Inconsistencies in validating arguments **Verdict**: REPRODUCED-on-v4.10.0 @@ -1077,45 +1070,43 @@ The follow-up name-collision concern raised by `prescod` in 2022 (NPSP and EDA b Old-style `task_options` dict still does not validate unknown keys: ```186:196:cumulusci/core/tasks.py - def _validate_options(self): - missing_required = [] - for name, config in list(self.task_options.items()): - if config.get("required") is True and name not in self.options: - missing_required.append(name) - - if missing_required: - required_opts = ",".join(missing_required) - raise TaskOptionsError( - f"{self.__class__.__name__} requires the options ({required_opts}) and no values were provided" - ) + def _validate_options(self): + missing_required = [] + for name, config in list(self.task_options.items()): + if config.get("required") is True and name not in self.options: + missing_required.append(name) + + if missing_required: + required_opts = ",".join(missing_required) + raise TaskOptionsError( + f"{self.__class__.__name__} requires the options ({required_opts}) and no values were provided" + ) ``` Repro test passes (= unknown `colour` typo is silently accepted via YAML/Python path): ``` -$ uv run pytest /tmp/repro/7/tests/test_1432_options_validation.py -q -. [100%] +$ uv run pytest _(repro evidence; see narrative)_ -q +. [100%] 1 passed in 0.25s ``` -Test path: `/tmp/repro/7/tests/test_1432_options_validation.py`. +Test path: `_(repro evidence; see narrative)_`. **Mitigation**: Tasks that opted into the new Pydantic `Options` class (lines 159-184) now reject extras with `"extra options"`. So the bug is partially fixed for new-style tasks but persists for legacy ones. **Recommended action**: -- pass1: `closed:stale-24mo` — 5yr; partial mitigation in place; full fix would require reworking every legacy `task_options` dict task. +- pass1: `closed:stale-24mo` - 5yr; partial mitigation in place; full fix would require reworking every legacy `task_options` dict task. - pass2 labels: `bug,stale,partially-fixed` --- - - ### #1769: Unusual case in test_load **Verdict**: REPRODUCED-on-v4.10.0 **Repro type**: bug (test code-smell) -**Org used**: none — code-only +**Org used**: none - code-only **Method**: `git show` of the original 2020 commit referenced in the issue + grep of the current `test_load.py`. **Evidence**: @@ -1128,28 +1119,26 @@ lookups["Id"] = {"table": "accounts", "key_field": "sf_id"} In v4.10.0 the same pattern survives, just wrapped in `MappingLookup`: ```736:739:cumulusci/tasks/bulkdata/tests/test_load.py - lookups["Id"] = MappingLookup(name="Id", table="accounts", key_field="sf_id") - lookups["Primary_Contact__c"] = MappingLookup( - table="contacts", name="Primary_Contact__c" - ) + lookups["Id"] = MappingLookup(name="Id", table="accounts", key_field="sf_id") + lookups["Primary_Contact__c"] = MappingLookup( + table="contacts", name="Primary_Contact__c" + ) ``` -The pattern repeats at lines 754, 773, 801, 1119, 1187, 1255 — declaring `Id` as a "lookup" key inside the `lookups` dict so `_expand_mapping` can express the after-step's UPDATE-on-Id dependency. davidmreed acknowledged in 2020 it was "a horrible hack" he intended to clean up, but six years later it is still there, with zero downstream complaints. +The pattern repeats at lines 754, 773, 801, 1119, 1187, 1255 - declaring `Id` as a "lookup" key inside the `lookups` dict so `_expand_mapping` can express the after-step's UPDATE-on-Id dependency. davidmreed acknowledged in 2020 it was "a horrible hack" he intended to clean up, but six years later it is still there, with zero downstream complaints. **Recommended action**: -- pass1: `closed:stale-24mo` — pure test-fixture nit; never escalated to a real bug; original commenters have moved on. +- pass1: `closed:stale-24mo` - pure test-fixture nit; never escalated to a real bug; original commenters have moved on. - pass2 labels: `test-cleanup, low-priority` --- - - ### #2013: Mapping files with steps that are not 1-1 with SObjects are unreliable for extraction **Verdict**: REPRODUCED-on-v4.10.0 **Repro type**: bug -**Org used**: none — code-only +**Org used**: none - code-only **Method**: Direct unit test against `cumulusci.tasks.bulkdata.utils.create_table` with two `MappingStep` instances both named `Account`. **Evidence**: @@ -1157,15 +1146,15 @@ The pattern repeats at lines 754, 773, 801, 1119, 1187, 1255 — declaring `Id` ```133:139:cumulusci/tasks/bulkdata/utils.py def create_table_if_needed(tablename, metadata, fields: T.List[Column]) -> Table: - t = Table(tablename, metadata, *fields) - inspector = inspect(metadata.bind) - if inspector.has_table(tablename): - raise BulkDataException(f"Table already exists: {tablename}") - t.create(metadata.bind) - return t + t = Table(tablename, metadata, *fields) + inspector = inspect(metadata.bind) + if inspector.has_table(tablename): + raise BulkDataException(f"Table already exists: {tablename}") + t.create(metadata.bind) + return t ``` -Reproduction (`/tmp/repro/9/tests/test_2013_multistep.py`) yields the exact 2020 traceback: +Reproduction (`_(repro evidence; see narrative)_`) yields the exact 2020 traceback: ``` Exception type: InvalidRequestError @@ -1176,34 +1165,32 @@ Table object. **Recommended action**: -- pass1: `keep-open` — bug is real, easy to reproduce, easy to fix (catch the SQLAlchemy error and re-raise as `BulkDataException`, or validate at mapping-parse time). +- pass1: `keep-open` - bug is real, easy to reproduce, easy to fix (catch the SQLAlchemy error and re-raise as `BulkDataException`, or validate at mapping-parse time). - pass2 labels: `bug, bulkdata, extract_dataset, error-handling` --- - - ### #2096: REST dataloads throw errors that Bulk loads do not **Verdict**: NOT-REPRODUCED-on-v4.10.0 **Repro type**: bug -**Org used**: none — code-only +**Org used**: none - code-only **Method**: Inspect `RestApiDmlOperation._record_to_json` and `process_bool_arg`; parametric unit test against the full Data Loader spectrum. **Evidence**: REST DML pre-converts boolean columns: ```778:784:cumulusci/tasks/bulkdata/step.py - def _record_to_json(self, rec): - result = dict(zip(self.fields, rec)) - for boolean_field in self.boolean_fields: - try: - result[boolean_field] = process_bool_arg(result[boolean_field] or False) - except TypeError as e: - raise BulkDataException(e) + def _record_to_json(self, rec): + result = dict(zip(self.fields, rec)) + for boolean_field in self.boolean_fields: + try: + result[boolean_field] = process_bool_arg(result[boolean_field] or False) + except TypeError as e: + raise BulkDataException(e) ``` -`process_bool_arg` (`core/utils.py:75-83`) accepts the entire spectrum from the Data Loader guide cited in the issue (yes/y/true/on/1 → True; no/n/false/off/0 → False; case-insensitive). Test `/tmp/repro/9/tests/test_2096_rest_booleans.py` confirms 20/20 spectrum values pass. +`process_bool_arg` (`core/utils.py:75-83`) accepts the entire spectrum from the Data Loader guide cited in the issue (yes/y/true/on/1 → True; no/n/false/off/0 → False; case-insensitive). Test `_(repro evidence; see narrative)_` confirms 20/20 spectrum values pass. **Recommended action**: @@ -1212,8 +1199,6 @@ REST DML pre-converts boolean columns: --- - - ### #2140: Prompt Org Configs when Org Does Not Exist and Command Runs Against It **Verdict**: REPRODUCED-on-v4.10.0 @@ -1223,83 +1208,79 @@ REST DML pre-converts boolean columns: **Evidence**: ```95:104:cumulusci/cli/runtime.py - def get_org(self, org_name=None, fail_if_missing=True): - if org_name: - org_config = self.keychain.get_org(org_name) - else: - org_name, org_config = self.keychain.get_default_org() - if org_config: - org_config = self.check_org_expired(org_name, org_config) - elif fail_if_missing: - raise click.UsageError("No org specified and no default org set.") - return org_name, org_config + def get_org(self, org_name=None, fail_if_missing=True): + if org_name: + org_config = self.keychain.get_org(org_name) + else: + org_name, org_config = self.keychain.get_default_org() + if org_config: + org_config = self.check_org_expired(org_name, org_config) + elif fail_if_missing: + raise click.UsageError("No org specified and no default org set.") + return org_name, org_config ``` `keychain.get_org` raises `OrgNotFound` -> `cli/org.py:530-531` shows `"Org {name} does not exist in the keychain"`. No interactive prompt offering available scratch configs. **Recommended action**: -- pass1: `closed:stale-24mo` — 5yr `cli-usability` enhancement with no traction. +- pass1: `closed:stale-24mo` - 5yr `cli-usability` enhancement with no traction. - pass2 labels: `enhancement,cli-usability,stale` --- - - ### #2153: Add comment to original PR which tags all branch subscribers when a merge **Verdict**: REPRODUCED-on-v4.10.0 **Repro type**: feature -**Method**: Bucket A — code-scan against `cumulusci/tasks/github/merge.py` and grep for `create_comment` / `issue_comment` across `cumulusci/tasks/github`. +**Method**: Bucket A - code-scan against `cumulusci/tasks/github/merge.py` and grep for `create_comment` / `issue_comment` across `cumulusci/tasks/github`. **Evidence**: `cumulusci/tasks/github/merge.py` `_create_conflict_pull_request` (the only place an auto-merge PR is created): ```264:288:cumulusci/tasks/github/merge.py - def _create_conflict_pull_request(self, branch_name, source): - """Attempt to create a pull request from source into branch_name if merge operation encounters a conflict""" - if branch_name in self._get_existing_prs( - self.options["source_branch"], self.options["branch_prefix"] - ): - self.logger.info( - f"Merge conflict on branch {branch_name}: merge PR already exists" - ) - return - - try: - pull = self.repo.create_pull( - title=f"Merge {source} into {branch_name}", - base=branch_name, - head=source, - body="This pull request was automatically generated because " - "an automated merge hit a merge conflict", - ) - self.logger.info( - f"Merge conflict on branch {branch_name}: created pull request #{pull.number}" - ) - except github3.exceptions.UnprocessableEntity as e: - self.logger.error( - f"Error creating merge conflict pull request to merge {source} into {branch_name}:\n{e.response.text}" - ) + def _create_conflict_pull_request(self, branch_name, source): + """Attempt to create a pull request from source into branch_name if merge operation encounters a conflict""" + if branch_name in self._get_existing_prs( + self.options["source_branch"], self.options["branch_prefix"] + ): + self.logger.info( + f"Merge conflict on branch {branch_name}: merge PR already exists" + ) + return + + try: + pull = self.repo.create_pull( + title=f"Merge {source} into {branch_name}", + base=branch_name, + head=source, + body="This pull request was automatically generated because " + "an automated merge hit a merge conflict", + ) + self.logger.info( + f"Merge conflict on branch {branch_name}: created pull request #{pull.number}" + ) + except github3.exceptions.UnprocessableEntity as e: + self.logger.error( + f"Error creating merge conflict pull request to merge {source} into {branch_name}:\n{e.response.text}" + ) ``` The method only creates the conflict PR; it never opens a comment on any PR (the original child PR or otherwise). Repo-wide grep for `create_comment|issue_comment|pr.create_comment|comment.*pull_request` under `cumulusci/tasks/github` returns no hits in production code (only test fixtures). Davis Agli's response in the thread agreed with the issue reporter that the appropriate place would be a comment on the original PR. Feature is unimplemented in v4.10.0. **Recommended action**: -- pass1: `keep-open` — small, well-scoped enhancement; reasonable "good-second-issue". +- pass1: `keep-open` - small, well-scoped enhancement; reasonable "good-second-issue". - pass2 labels: `enhancement, github, merge-conflict` --- - - ### #2325: Task to turn off validation rules to allow data insert **Verdict**: REPRODUCED-on-v4.10.0 **Repro type**: feature -**Org used**: none — code-only +**Org used**: none - code-only **Method**: Grep cumulusci.yml + `cci task list` for any `validation_rule` / `disable_*` task. **Evidence**: @@ -1312,13 +1293,11 @@ The pattern to copy is trivially established. The user's specific use case (rela **Recommended action**: -- pass1: `keep-open` — feature still missing, clear implementation pattern, modest scope. +- pass1: `keep-open` - feature still missing, clear implementation pattern, modest scope. - pass2 labels: `enhancement, bulkdata, metadata_etl, good-first-issue` --- - - ### #2402: Create a --rebuild-org parameter for cci flow run **Verdict**: REPRODUCED-on-v4.10.0 @@ -1330,7 +1309,7 @@ The pattern to copy is trivially established. The user's specific use case (rela ```119:145:cumulusci/cli/flow.py @flow.command(name="run", help="Runs a flow") @click.argument("flow_name") -@click.option("--org", help="Specify the target org. By default, runs against the current default org") +@click.option("--org", help="Specify the target org. By default, runs against the current default org") @click.option("--delete-org", is_flag=True, help="If set, deletes the scratch org after the flow completes") @click.option("--debug", is_flag=True, help="Drops into pdb, the Python debugger, on an exception") @click.option("-o", nargs=2, multiple=True, help="...") @@ -1343,32 +1322,30 @@ Only `--delete-org` exists. `rg -i "rebuild.org"` returns zero hits. **Recommended action**: -- pass1: `closed:stale-24mo` — 5yr; tracked W-10502624 (no movement); user can accomplish via `cci org scratch_delete X && cci flow run`. +- pass1: `closed:stale-24mo` - 5yr; (no movement); user can accomplish via `cci org scratch_delete X && cci flow run`. - pass2 labels: `enhancement,stale` --- - - ### #2505: Filtering records to be extracted **Verdict**: NOT-REPRODUCED-on-v4.10.0 **Repro type**: feature -**Org used**: none — code-only +**Org used**: none - code-only **Method**: Grep `mapping_parser.py` and `extract.py` for `soql_filter` / WHERE-clause support. **Evidence**: Per-step SOQL filter is now first-class: ```120:120:cumulusci/tasks/bulkdata/mapping_parser.py - soql_filter: Optional[str] = None # soql_filter property + soql_filter: Optional[str] = None # soql_filter property ``` ```142:147:cumulusci/tasks/bulkdata/extract.py - if mapping.soql_filter is not None: - soql = self.append_filter_clause( - soql=soql, filter_clause=mapping.soql_filter - ) + if mapping.soql_filter is not None: + soql = self.append_filter_clause( + soql=soql, filter_clause=mapping.soql_filter + ) ``` The new extract-mapping generator wires user-declared `where:` into `soql_filter` (`extract_mapping_file_generator.py:26`), and the existing hardcoded extract declarations (`extract_dataset_utils/hardcoded_default_declarations.py`) already use this for per-sObject filtering. Tests exercise the plain filter, the WHERE-prefixed variant, and combinations with record_type (`test_extract.py:1216, 1248, 1280`). @@ -1380,32 +1357,28 @@ The new extract-mapping generator wires user-declared `where:` into `soql_filter --- - - ### #2506: Bulk Operations should have a --debug mode which maintains logs and tempfiles **Verdict**: REPRODUCED-on-v4.10.0 (partial) **Repro type**: feature -**Org used**: none — code-only +**Org used**: none - code-only **Method**: Grep all bulkdata modules for `get_debug_mode` / `delete=False` / `TemporaryDirectory` usage. **Evidence**: - Snowfakery task (`snowfakery.py:241,355,385,565`) calls `get_debug_mode()` and at `:386` logs `f"Working Directory: {tempdir}"` per loop iteration. -- `extract.py`, `step.py` — **zero** references to `debug_mode` or `get_debug_mode`. +- `extract.py`, `step.py` - **zero** references to `debug_mode` or `get_debug_mode`. - `load.py:283` uses `tempfile.TemporaryFile` with no debug-mode override; the file is auto-deleted on context exit regardless of debug. So the ask is half-met: Snowfakery cooperates with debug mode; the workhorse `load_dataset` / `extract_dataset` tasks do not. **Recommended action**: -- pass1: `keep-open` — partial implementation; remaining work is straightforward (wire `get_debug_mode()` into load/extract, conditionally use `TemporaryDirectory(delete=False)` and emit path). +- pass1: `keep-open` - partial implementation; remaining work is straightforward (wire `get_debug_mode()` into load/extract, conditionally use `TemporaryDirectory(delete=False)` and emit path). - pass2 labels: `enhancement, bulkdata, extract_dataset, load_dataset, debugging` --- - - ### #2507: Undo mode for CumulusCI Insert **Verdict**: REPRODUCED-on-v4.10.0 @@ -1417,44 +1390,40 @@ So the ask is half-met: Snowfakery cooperates with debug mode; the workhorse `lo No `undo_insert` task exists (`rg -l undo_insert` returns nothing). Closest functionality is `enable_rollback` on `load_dataset` and `snowfakery` tasks: ```97:99:cumulusci/tasks/bulkdata/load.py - "enable_rollback": { - "description": "When True, performs rollback operation incase of error. Defaults to False" - }, + "enable_rollback": { + "description": "When True, performs rollback operation incase of error. Defaults to False" + }, ``` That only triggers rollback on error during the load; it does not provide the post-hoc "delete everything we ever inserted" capability the requester described. **Recommended action**: -- pass1: `closed:stale-24mo` — 4yr feature with partial mitigation already shipped. +- pass1: `closed:stale-24mo` - 4yr feature with partial mitigation already shipped. - pass2 labels: `enhancement,stale,partially-fixed` --- - - ### #2508: Manual load retries **Verdict**: REPRODUCED-on-v4.10.0 **Repro type**: feature -**Org used**: none — code-only +**Org used**: none - code-only **Method**: `cci task list | grep -i retry` and grep load.py for retry/failed-record persistence. **Evidence**: - `cci task list` returns no retry-named task. -- `load.py` has an `enable_rollback` option (`:97-98`, `RollbackType` enum at `:1051`) but rollback **undoes successful inserts when failures occur** — the opposite of "retry the failures." +- `load.py` has an `enable_rollback` option (`:97-98`, `RollbackType` enum at `:1051`) but rollback **undoes successful inserts when failures occur** - the opposite of "retry the failures." - `RowErrorChecker` (`utils.py:158`) only logs and optionally raises; it does not persist a failed-rows artifact that could be replayed. **Recommended action**: -- pass1: `keep-open` — distinct from rollback; would need (a) failed-row CSV/SQL persistence + (b) a new `retry_failed_load` task that consumes it. +- pass1: `keep-open` - distinct from rollback; would need (a) failed-row CSV/SQL persistence + (b) a new `retry_failed_load` task that consumes it. - pass2 labels: `enhancement, bulkdata, load_dataset, reliability` --- - - ### #2697: 'namespaced' field stale in `cci org info` after switching org def **Verdict**: INCONCLUSIVE-needs-scratch-slot @@ -1466,14 +1435,14 @@ That only triggers rollback on error during the load; it does not provide the po The cci `namespaced` field is set from the cci YAML config, not derived from the SFDX scratch def file: ```57:75:cumulusci/core/keychain/base_project_keychain.py - def create_scratch_org( - self, org_name, config_name, days=None, set_password=True, release=None - ): - """Adds/Updates a scratch org config to the keychain from a named config""" - scratch_config = self.project_config.lookup(f"orgs__scratch__{config_name}") - ... - scratch_config["scratch"] = True - scratch_config.setdefault("namespaced", False) + def create_scratch_org( + self, org_name, config_name, days=None, set_password=True, release=None + ): + """Adds/Updates a scratch org config to the keychain from a named config""" + scratch_config = self.project_config.lookup(f"orgs__scratch__{config_name}") + ... + scratch_config["scratch"] = True + scratch_config.setdefault("namespaced", False) ``` This means `cci org info` reflects the cci `orgs__scratch__qa.namespaced` value, not whatever the SFDX `qa.json` says. Since the user changed only the SFDX `qa.json` (not the cci YAML), cci's view of `namespaced` is unchanged. This is **likely working as designed** but conflicts with the user's mental model. @@ -1482,13 +1451,11 @@ I did not provision a scratch org to confirm because (a) the code reading is una **Recommended action**: -- pass1: `closed:stale-24mo` — 5yr stale; design/docs friction rather than a defect; request more info if reopened. +- pass1: `closed:stale-24mo` - 5yr stale; design/docs friction rather than a defect; request more info if reopened. - pass2 labels: `bug,stale,needs-info` --- - - ### #2826: deploy_unmanaged flow is supposed to silently do nothing if there's not actually a package directory **Verdict**: REPRODUCED-on-v4.10.0 @@ -1501,24 +1468,22 @@ Inspected `cumulusci/tasks/metadata/package.py`: - `PackageXmlGenerator.parse_types` (line 107) calls `os.listdir(self.directory)` without checking existence. - `UpdatePackageXml._init_task` (line 590) and `_run_task` (line 612) do not guard for missing path. -Wrote a unit-level repro at `/tmp/repro/5/tests/issue-2826/repro_unit.py` that instantiates `UpdatePackageXml` against a temp dir containing no `src/`. Result: raises `FileNotFoundError: [Errno 2] No such file or directory: '/var/.../src'`. Bug present. +Wrote a unit-level repro at `_(repro evidence; see narrative)_` that instantiates `UpdatePackageXml` against a temp dir containing no `src/`. Result: raises `FileNotFoundError: [Errno 2] No such file or directory: '/var/.../src'`. Bug present. **Recommended action**: -- pass1: `keep-open` — small, contained fix. +- pass1: `keep-open` - small, contained fix. - pass2 labels: `bug`, `good-first-issue` **Notes**: Could be fixed at the task layer (skip with logger.info when path missing) or at the flow layer (`when:` guard on the deploy_unmanaged steps). Task-layer is more defensible because the same task may be referenced from custom flows. --- - - ### #2951: Error in task load_dataset - Standard_price_not_defined **Verdict**: REPRODUCED-on-v4.10.0 (with mitigation) **Repro type**: bug -**Org used**: none — code-only +**Org used**: none - code-only **Method**: Grep load.py / step.py for any PricebookEntry-specific sequencing logic; inspect `hardcoded_default_declarations.py`. **Evidence**: @@ -1527,24 +1492,22 @@ No special handling exists in the loader to sequence Standard-Price-Book Pricebo Mitigation already in place for the `extract_dataset` → `load_dataset` round-trip: ```14:18:cumulusci/tasks/bulkdata/extract_dataset_utils/hardcoded_default_declarations.py - ExtractDeclaration( - sf_object="PricebookEntry", - where="Pricebook2.Id != NULL and Pricebook2.Name != 'Standard Price Book'", - ), - ExtractDeclaration(sf_object="Pricebook2", where="Name != 'Standard Price Book'"), + ExtractDeclaration( + sf_object="PricebookEntry", + where="Pricebook2.Id != NULL and Pricebook2.Name != 'Standard Price Book'", + ), + ExtractDeclaration(sf_object="Pricebook2", where="Name != 'Standard Price Book'"), ``` So default extracts skip the Standard Price Book entirely, and the typical flow doesn't hit the bug. But the reporter built a mapping by hand that included both, and that path is still broken. **Recommended action**: -- pass1: `keep-open` — bug is latent. Fix options: (a) loader auto-splits PricebookEntry into two implicit batches (standard pricebook first); (b) document the requirement and validate at parse time that PricebookEntry steps are not "mixed." +- pass1: `keep-open` - bug is latent. Fix options: (a) loader auto-splits PricebookEntry into two implicit batches (standard pricebook first); (b) document the requirement and validate at parse time that PricebookEntry steps are not "mixed." - pass2 labels: `bug, bulkdata, load_dataset, pricebook, documentation` --- - - ### #2979: deploy task should deploy from default entry in packageDirectories **Verdict**: REPRODUCED-on-v4.10.0 @@ -1555,19 +1518,17 @@ Inspected the `deploy` task definition in `cumulusci/cumulusci.yml` and the `def **Evidence**: -- `cumulusci/cumulusci.yml:227-229` — the `deploy` task still hard-codes `path: src` for `cumulusci.tasks.salesforce.Deploy`. -- `cumulusci/core/config/project_config.py:517-525` — `default_package_path` correctly reads `packageDirectories[*].default` from `sfdx-project.json` when `project__source_format == "sfdx"`. +- `cumulusci/cumulusci.yml:227-229` - the `deploy` task still hard-codes `path: src` for `cumulusci.tasks.salesforce.Deploy`. +- `cumulusci/core/config/project_config.py:517-525` - `default_package_path` correctly reads `packageDirectories[*].default` from `sfdx-project.json` when `project__source_format == "sfdx"`. - The only consumer of `default_package_path` is `cumulusci/tasks/create_package_version.py:230`. The Deploy task does not consult it. **Recommended action**: -- pass1: `keep-open` — feature still missing; davisagli's 2021 design comment (3-tier fallback `path` -> sfdx default -> `src`) remains the natural plan. +- pass1: `keep-open` - feature still missing; davisagli's 2021 design comment (3-tier fallback `path` -> sfdx default -> `src`) remains the natural plan. - pass2 labels: `severity:low,area:packaging,area:sfdx,state:needs-design` --- - - ### #3015: Remove imported dx org from cci list without deleting actual scratch **Verdict**: REPRODUCED-on-v4.10.0 @@ -1582,30 +1543,28 @@ Inspected the `deploy` task definition in `cumulusci/cumulusci.yml` and the `def @click.option("--global-org", is_flag=True, help="...") @pass_runtime(require_project=False, require_keychain=True) def org_remove(runtime, org_name, global_org): - try: - org_config = runtime.keychain.get_org(org_name) - except OrgNotFound: - raise click.ClickException(f"Org {org_name} does not exist in the keychain") - - if org_config.can_delete(): - click.echo("A scratch org was already created, attempting to delete...") - try: - org_config.delete_org() - ... - runtime.keychain.remove_org(org_name, global_org) + try: + org_config = runtime.keychain.get_org(org_name) + except OrgNotFound: + raise click.ClickException(f"Org {org_name} does not exist in the keychain") + + if org_config.can_delete(): + click.echo("A scratch org was already created, attempting to delete...") + try: + org_config.delete_org() + ... + runtime.keychain.remove_org(org_name, global_org) ``` No `--keep-org` flag. davisagli's manual workaround (delete `~/.cumulusci//.org` directly) still applies. **Recommended action**: -- pass1: `closed:stale-24mo` — 4yr; tracked W-10502512. +- pass1: `closed:stale-24mo` - 4yr; . - pass2 labels: `enhancement,stale` --- - - ### #3024: Order of flow groups in `cumulusci/cumulusci.yml` **Verdict**: REPRODUCED-on-v4.10.0 @@ -1645,13 +1604,11 @@ Dependency Management **Recommended action**: -- pass1: `closed:stale-24mo` — 4yr cosmetic VS Code extension request; the true fix is sorting at the consumer (the extension) rather than rearranging the canonical YAML. +- pass1: `closed:stale-24mo` - 4yr cosmetic VS Code extension request; the true fix is sorting at the consumer (the extension) rather than rearranging the canonical YAML. - pass2 labels: `enhancement,stale` --- - - ### #3137: cci task run update_package_xml and Salesforce Case Custom Object **Verdict**: REPRODUCED-on-v4.10.0 (treated as feature request) @@ -1659,9 +1616,9 @@ Dependency Management **Method**: Inspected `cumulusci/tasks/metadata/package.py` `CustomObjectParser` (lines -443–482). It explicitly skips any object file that doesn't end in `__c`, +443-482). It explicitly skips any object file that doesn't end in `__c`, `__mdt`, `__e`, or `__b`. Inspected `UpdatePackageXml` task_options -(package.py:563–584) — no opt-in option such as `include_standard_objects`. +(package.py:563-584) - no opt-in option such as `include_standard_objects`. The maintainer's response on the issue agreed the behavior is by-design (holdover from managed-package world) and committed only to "investigate"; no design has landed. @@ -1675,13 +1632,11 @@ no design has landed. **Recommended action**: -- pass1: keep-open — a real product gap remains; mark for design discussion. +- pass1: keep-open - a real product gap remains; mark for design discussion. - pass2 labels: `severity:low,area:metadata-etl,type:enhancement,state:needs-design` --- - - ### #3161: Ability to Hide Option Values When Using Task Options **Verdict**: REPRODUCED-on-v4.10.0 @@ -1691,20 +1646,20 @@ no design has landed. **Evidence**: ```300:320:cumulusci/core/flowrunner.py - def _log_options(self, task: "BaseTask"): - ... - for key, info in task.task_options.items(): - value = task.options.get(key) - if value is not None: - if type(value) is not list: - value = self._obfuscate_if_sensitive(value, info) - task.logger.info(f" {key}: {value}") - ... - - def _obfuscate_if_sensitive(self, value: str, info: dict) -> str: - if info.get("sensitive"): - value = 8 * "*" - return value + def _log_options(self, task: "BaseTask"): + ... + for key, info in task.task_options.items(): + value = task.options.get(key) + if value is not None: + if type(value) is not list: + value = self._obfuscate_if_sensitive(value, info) + task.logger.info(f" {key}: {value}") + ... + + def _obfuscate_if_sensitive(self, value: str, info: dict) -> str: + if info.get("sensitive"): + value = 8 * "*" + return value ``` A masking infrastructure was added (task-option metadata can opt in via `sensitive: True`), but: @@ -1716,13 +1671,11 @@ So the user's specific request (mask multi-line GitHub Actions secrets passed vi **Recommended action**: -- pass1: `closed:stale-24mo` — 4yr; partial fix in place. +- pass1: `closed:stale-24mo` - 4yr; partial fix in place. - pass2 labels: `enhancement,stale,partially-implemented` --- - - ### #3165: Update Admin Profile task fails when specifying record types without custom package.xml **Verdict**: REPRODUCED-on-v4.10.0 @@ -1738,22 +1691,22 @@ Read `cumulusci/tasks/salesforce/update_profile.py` carefully: - Therefore: when `include_packaged_objects` is False (the default unless `minimum_cumulusci_version >= 3.9.0`), record_types referencing objects not in the default `cumulusci/files/admin_profile.xml` (e.g. `Case`) never get added. - Confirmed by the existing test `test_init_options__include_packaged_objects` (test_ProfileGrantAllAccess.py:609-615) which explicitly asserts `task._expand_package_xml.assert_not_called()` in the False branch. -Wrote `/tmp/repro/5/tests/issue-3165/repro_unit.py`. Output (key parts): +Wrote `_(repro evidence; see narrative)_`. Output (key parts): ``` include_packaged_objects = False --- generated package.xml --- - - * - Account - Campaign - ... - Opportunity - CustomObject - - ... + + * + Account + Campaign + ... + Opportunity + CustomObject + + ... --- end --- REPRODUCED: 'Case' is NOT in CustomObject members. @@ -1761,15 +1714,13 @@ REPRODUCED: 'Case' is NOT in CustomObject members. **Recommended action**: -- pass1: `keep-open` — single-line refactor. +- pass1: `keep-open` - single-line refactor. - pass2 labels: `bug` -**Notes**: Smallest fix at update_profile.py:137 — always call `self._expand_package_xml_objects(package_xml)` regardless of `include_packaged_objects`, and only call the broader `self._expand_package_xml` (which does the Tooling API query) when `include_packaged_objects=True`. `_expand_package_xml_objects` itself only walks the user-supplied options, no API call. +**Notes**: Smallest fix at update_profile.py:137 - always call `self._expand_package_xml_objects(package_xml)` regardless of `include_packaged_objects`, and only call the broader `self._expand_package_xml` (which does the Tooling API query) when `include_packaged_objects=True`. `_expand_package_xml_objects` itself only walks the user-supplied options, no API call. --- - - ### #3167: Add ability to define page layout assignments with record types using the update_admin_profile task **Verdict**: NOT-REPRODUCED-on-v4.10.0 (feature implemented) @@ -1782,7 +1733,7 @@ Read `cumulusci/tasks/salesforce/update_profile.py`: - `task_options['record_types']` description (lines 32-34) explicitly documents the `page_layout` key. - `_set_record_types` lines 280-298 handle `page_layout`: locate any existing `` matching the record type and update its ``, or append a new `` block. -`git log -S "page_layout" -- cumulusci/tasks/salesforce/update_profile.py` shows the feature landed in commit `f2ff04bd5` (PR #3243 by davidmreed, merged 2022-06-16) — well before v4.10.0. +`git log -S "page_layout" -- cumulusci/tasks/salesforce/update_profile.py` shows the feature landed in commit `f2ff04bd5` (PR #3243 by davidmreed, merged 2022-06-16) - well before v4.10.0. **Recommended action**: @@ -1793,38 +1744,34 @@ Read `cumulusci/tasks/salesforce/update_profile.py`: --- - - ### #3283: json parser error when empty string passed for date field during upsert or update **Verdict**: NOT-REPRODUCED-on-v4.10.0 **Repro type**: bug -**Org used**: none — code-only +**Org used**: none - code-only **Method**: Verify PR #3361 (commit `b0bfb70e0`) is in `129238663` via `git merge-base --is-ancestor`; small unit test against `RestApiDmlOperation._record_to_json` for UPDATE/UPSERT/INSERT operations. **Evidence**: Fix is in place at `step.py:795-796`: ```789:797:cumulusci/tasks/bulkdata/step.py - if self.operation is DataOperationType.INSERT: - result = { - k: result[k] - for k in result - if result[k] is not None and result[k] != "" - } - elif self.operation in (DataOperationType.UPDATE, DataOperationType.UPSERT): - result = {k: (result[k] if result[k] != "" else None) for k in result} + if self.operation is DataOperationType.INSERT: + result = { + k: result[k] + for k in result + if result[k] is not None and result[k] != "" + } + elif self.operation in (DataOperationType.UPDATE, DataOperationType.UPSERT): + result = {k: (result[k] if result[k] != "" else None) for k in result} ``` -Repro test (`/tmp/repro/9/tests/test_3283_empty_date.py`) verifies: empty `Birthdate` becomes JSON null on UPDATE and UPSERT (no longer triggering JSON_PARSER_ERROR), and is omitted entirely for INSERT. The reporter's own final comment ("Fixed in #3361") aligns. +Repro test (`_(repro evidence; see narrative)_`) verifies: empty `Birthdate` becomes JSON null on UPDATE and UPSERT (no longer triggering JSON_PARSER_ERROR), and is omitted entirely for INSERT. The reporter's own final comment ("Fixed in #3361") aligns. **Recommended action**: - pass1: `closed:fixed-by-pr-#3361` - pass2 labels: `resolved, bulkdata, load_dataset` - - ### #3307: Project Template Support for `cci project init` **Verdict**: REPRODUCED-on-v4.10.0 @@ -1837,13 +1784,11 @@ Repro test (`/tmp/repro/9/tests/test_3283_empty_date.py`) verifies: empty `Birth **Recommended action**: -- pass1: `closed:stale-24mo` — 4yr; explicitly described by the requester as "low priority / nice to have". +- pass1: `closed:stale-24mo` - 4yr; explicitly described by the requester as "low priority / nice to have". - pass2 labels: `enhancement,stale` --- - - ### #3320: Metadata ETL task to Deactivate a Flow **Verdict**: NOT-REPRODUCED-on-v4.10.0 @@ -1863,14 +1808,12 @@ codebase and inspected `cumulusci/cumulusci.yml`. **Recommended action**: -- pass1: closed:feature-implemented — `cci task run deactivate_flow` is +- pass1: closed:feature-implemented - `cci task run deactivate_flow` is shipped; reporter likely missed it. - pass2 labels: `area:metadata-etl,type:enhancement,resolution:already-implemented` --- - - ### #3331: Task update_package_xml does not write correct package.xml for AssignmentRules **Verdict**: REPRODUCED-on-v4.10.0 @@ -1893,13 +1836,11 @@ emitted `` element is `AssignmentRules` (plural). **Recommended action**: -- pass1: keep-open — one-line YAML fix; reporter offered a PR. +- pass1: keep-open - one-line YAML fix; reporter offered a PR. - pass2 labels: `severity:medium,area:metadata-etl,type:bug,good-first-issue` --- - - ### #3347: Cannot release an unlocked beta package with `release_unlocked_beta` **Verdict:** `NOT-REPRODUCED-on-v4.10.0` @@ -1910,15 +1851,15 @@ User on CumulusCI 3.64.0 (2022-08) ran `cci flow run release_unlocked_beta` and ``` TypeError: expected str, bytes or os.PathLike object, not NoneType - at create_package_version.py line 377: - with open(self.org_config.config_file, "r") as f: + at create_package_version.py line 377: + with open(self.org_config.config_file, "r") as f: ``` Root cause: `org_config.config_file` is `None` for persistent orgs (DevHub, Developer Edition, etc.), but the user (likely) ran the flow against the DevHub directly. `release_unlocked_beta` requires a scratch target org; the old code fell through with an opaque error. ### Evidence on v4.10.0 -`cumulusci/tasks/create_package_version.py` lines 44–46 and 158–159: +`cumulusci/tasks/create_package_version.py` lines 44-46 and 158-159: ```44:46:cumulusci/tasks/create_package_version.py PERSISTENT_ORG_ERROR = """ @@ -1927,8 +1868,8 @@ Target org scratch org definition file missing. Persistent orgs like a Dev Hub c ``` ```158:159:cumulusci/tasks/create_package_version.py - if not self.org_config.config_file: - raise TaskOptionsError(PERSISTENT_ORG_ERROR) + if not self.org_config.config_file: + raise TaskOptionsError(PERSISTENT_ORG_ERROR) ``` The early `_init_options` check raises a clear `TaskOptionsError` before any `open()` is attempted. Fix landed in commit `2a9cadcb1` on 2023-10-12 (`added_clear_error`), refined in `8f62d3153` and `8328bfb9d`. @@ -1940,33 +1881,29 @@ $ uv run pytest "cumulusci/tasks/tests/test_create_package_version.py::TestPacka 1 passed in 0.22s ``` -The test (`test_create_package_version.py:159–167`) explicitly sets `org_config.config_file = None` and asserts that `CreatePackageVersion` raises `TaskOptionsError` matching `PERSISTENT_ORG_ERROR`. +The test (`test_create_package_version.py:159-167`) explicitly sets `org_config.config_file = None` and asserts that `CreatePackageVersion` raises `TaskOptionsError` matching `PERSISTENT_ORG_ERROR`. ### Recommendation - **Pass 1:** close-with-comment ("Fixed by commit `2a9cadcb1` (PR adding clear error message). v4.10.0 raises a clear `TaskOptionsError` directing users to use a scratch org target.") - **Pass 2 label:** `resolved-by-clear-error-message` -- The underlying limitation — cannot use a persistent (DevHub) org as the target for 2GP package upload — is preserved by design and now communicated clearly. +- The underlying limitation - cannot use a persistent (DevHub) org as the target for 2GP package upload - is preserved by design and now communicated clearly. --- - - ### #3349: Make generated dataset recordType tables unique based on table instead of sf_object -**Verdict:** `REPRODUCED-on-v4.10.0` — bug, structural +**Verdict:** `REPRODUCED-on-v4.10.0` - bug, structural `MappingStep.get_source_record_type_table()` and `get_destination_record_type_table()` in `cumulusci/tasks/bulkdata/mapping_parser.py:177-179` build the SQLite table name solely from `self.sf_object` (`f"{self.sf_object}_rt_mapping"` and `f"{self.sf_object}_rt_target_mapping"`). Two mapping steps targeting the same `sf_object` (the canonical case is `Account` Person vs Business with different `record_type:` values) thus produce the same table name. `load.py:552` and `extract.py:259/393` both use those names without per-step disambiguation. -Repro test (`/tmp/repro/10/tests/test_3349_recordtype_table_collision.py`) constructs two `MappingStep` objects with `sf_object="Account"` and different `record_type` values and asserts that both source and target table names collide — assertion passes, confirming the bug. - -The maintainer label `wi-created` (W-11466074) is present, so this is exempt from the stale-24mo close. **Recommended pass1: `keep-open`.** Suggested fix: include `self.table` (or a hash of `record_type`+`filter`) in the generated table name when more than one mapping step shares an `sf_object`. +Repro test (`_(repro evidence; see narrative)_`) constructs two `MappingStep` objects with `sf_object="Account"` and different `record_type` values and asserts that both source and target table names collide - assertion passes, confirming the bug. - +The maintainer label `wi-created` is present, so this is exempt from the stale-24mo close. **Recommended pass1: `keep-open`.** Suggested fix: include `self.table` (or a hash of `record_type`+`filter`) in the generated table name when more than one mapping step shares an `sf_object`. ### #3353: Enable Snowfakery task to use recipes from other repositories -**Verdict:** `REPRODUCED-on-v4.10.0` — feature still unimplemented +**Verdict:** `REPRODUCED-on-v4.10.0` - feature still unimplemented `Snowfakery._validate_options` in `cumulusci/tasks/bulkdata/snowfakery.py:159-162` validates the `recipe` option via `Path(recipe).exists()` only. There is no `SOURCE_NAME:path` parsing, and no call to `project_config.sources` / `project_config.get_source(...)` anywhere in `snowfakery.py`. The recipe string is passed straight to Snowfakery as a filesystem path. @@ -1974,18 +1911,14 @@ This is a documented community ask (resurfaced in 2024-08 by `davidjray` and `jn **Recommended pass1: `keep-open`.** Suggested fix: pre-process the `recipe` option to detect a `SOURCE_NAME:path` prefix and resolve it via `project_config.get_source(name).fetch().path` before existence check. - - ### #3360: Read Only Object Lookup for Load_Dataset -**Verdict:** `NOT-REPRODUCED-on-v4.10.0` — feature implemented +**Verdict:** `NOT-REPRODUCED-on-v4.10.0` - feature implemented The `action: select` mapping step (added by commit `b15945203`, "Core Logic for Selecting Records from Target Org", 2024-08-19, well before v4.10.0) provides exactly this behavior. It is fully wired through `cumulusci/tasks/bulkdata/select_utils.py`, the `SELECT` branch in `step.py`, and the `mapping_select.yml` test fixture. `select_options.strategy` (`similarity`, etc.), `select_options.filter`, and `select_options.priority_fields` allow the user to populate a lookup table from existing org records without DML, which is precisely the "read-only" semantic the issue requested. **Recommended pass1: `closed:feature-implemented`.** Close-comment should cite the SELECT action and `mapping_select.yml`. - - ### #3418: Error creating 1gp release **Verdict**: INCONCLUSIVE-needs-cumulus-actions-workflow @@ -1993,24 +1926,22 @@ The `action: select` mapping step (added by commit `b15945203`, "Core Logic for **Org used**: none (no cci code path under test) **Method**: -Read the cci docs and source for any code that would invoke `auth:sfdxurl:store` or otherwise parse the `PACKAGING_ORG_AUTH_URL` secret. The error message in the issue is verbatim text from the sfdx CLI (`auth:sfdxurl:store`), invoked by the `SFDO-Community/standard-workflows/.github/workflows/production-1gp.yml` workflow before cci ever runs. Searched the repo for `sfdxurl|SFDX_AUTH_URL|PACKAGING_ORG_AUTH_URL` — only hit is `docs/github-actions.md` (documentation pointing users at the standard-workflows repo). +Read the cci docs and source for any code that would invoke `auth:sfdxurl:store` or otherwise parse the `PACKAGING_ORG_AUTH_URL` secret. The error message in the issue is verbatim text from the sfdx CLI (`auth:sfdxurl:store`), invoked by the `SFDO-Community/standard-workflows/.github/workflows/production-1gp.yml` workflow before cci ever runs. Searched the repo for `sfdxurl|SFDX_AUTH_URL|PACKAGING_ORG_AUTH_URL` - only hit is `docs/github-actions.md` (documentation pointing users at the standard-workflows repo). **Evidence**: -- `docs/github-actions.md:101-119` — examples reference `SFDO-Community/standard-workflows/.github/workflows/{beta,production}-1gp.yml@main` and the `packaging-org-auth-url` secret. +- `docs/github-actions.md:101-119` - examples reference `SFDO-Community/standard-workflows/.github/workflows/{beta,production}-1gp.yml@main` and the `packaging-org-auth-url` secret. - No occurrence of `auth:sfdxurl:store` anywhere in the cci tree. -- davidmreed's 2022 comment on the issue: "I believe I know the issue here and I will seek to address it this evening" — implies the fix landed in the third-party workflow, not in cci. +- davidmreed's 2022 comment on the issue: "I believe I know the issue here and I will seek to address it this evening" - implies the fix landed in the third-party workflow, not in cci. - Issue is still OPEN on GitHub but no `closedByPullRequestsReferences`. **Recommended action**: -- pass1: `unchanged` — keep open until we can confirm whether SFDO-Community fix is in place; transfer or cross-link there if appropriate. +- pass1: `unchanged` - keep open until we can confirm whether SFDO-Community fix is in place; transfer or cross-link there if appropriate. - pass2 labels: `needs-info`, `needs-repro` --- - - ### #3429: Support overriding `cumulusci.yml` to be used for configuration **Verdict**: REPRODUCED-on-v4.10.0 @@ -2021,20 +1952,18 @@ Searched for `CUMULUSCI_YML`, `CUMULUSCI_EXTRA_YAML`, `extra_yaml`, `--extra-yam **Evidence**: -- `cumulusci/core/config/project_config.py:82` — `config_filename = "cumulusci.yml"` is hardcoded. -- `cumulusci/core/config/project_config.py:118-184` — only an `additional_yaml` kwarg (programmatic, used by MetaCI) is supported; no env var or CLI plumbing. -- `git merge-base --is-ancestor 9d650ace2 HEAD` returns non-zero — PR #3969 (commits prefixed `feat(cli): add resolve_extra_yaml helper for --extra-yaml flag`) is in flight on branch `extra-yaml-cli-flag` but not merged. +- `cumulusci/core/config/project_config.py:82` - `config_filename = "cumulusci.yml"` is hardcoded. +- `cumulusci/core/config/project_config.py:118-184` - only an `additional_yaml` kwarg (programmatic, used by MetaCI) is supported; no env var or CLI plumbing. +- `git merge-base --is-ancestor 9d650ace2 HEAD` returns non-zero - PR #3969 (commits prefixed `feat(cli): add resolve_extra_yaml helper for --extra-yaml flag`) is in flight on branch `extra-yaml-cli-flag` but not merged. - Bundle records `closedByPullRequestsReferences = [#3969]`. **Recommended action**: -- pass1: `keep-open` — feature is genuinely actionable on v4.10.0; auto-close once #3969 merges via `closed:fixed-by-pr-#3969`. +- pass1: `keep-open` - feature is genuinely actionable on v4.10.0; auto-close once #3969 merges via `closed:fixed-by-pr-#3969`. - pass2 labels: `severity:medium,area:packaging,area:cli,state:in-progress` --- - - ### #3440: Enhance `default_package_path` to serve multi-package projects better **Verdict**: REPRODUCED-on-v4.10.0 @@ -2045,17 +1974,15 @@ Re-read `default_package_path` against the request. The user wants name-based lo **Evidence**: -- `cumulusci/core/config/project_config.py:517-525` — implementation is the simple "first packageDirectory with `default: true`" pattern; falls back to `force-app`, then `src`. No name-based lookup, no multi-package warning, no hard fail when both are missing. +- `cumulusci/core/config/project_config.py:517-525` - implementation is the simple "first packageDirectory with `default: true`" pattern; falls back to `force-app`, then `src`. No name-based lookup, no multi-package warning, no hard fail when both are missing. **Recommended action**: -- pass1: `keep-open` — same multi-package umbrella as #2979 / #3429; would best be solved together. +- pass1: `keep-open` - same multi-package umbrella as #2979 / #3429; would best be solved together. - pass2 labels: `severity:low,area:packaging,area:sfdx,area:multi-package` --- - - ### #3441: `cci task run create_package_version` should allow `version_base: default` **Verdict**: REPRODUCED-on-v4.10.0 @@ -2066,75 +1993,69 @@ Inspected `version_base` handling in `cumulusci/tasks/create_package_version.py` **Evidence**: -- `cumulusci/tasks/create_package_version.py:63-112` — `version_base: Optional[str]`; documented values are `None`, a literal version number, or `latest_github_release`. -- `cumulusci/tasks/create_package_version.py:529-563` — `_get_base_version_number` only branches on `None` (default) and `"latest_github_release"`; any other string is parsed as a literal version. There is no `"default"`/`"highest"` sentinel and no support for unsetting via flow override. -- `cumulusci/cumulusci.yml:1216-1225` — `release_unlocked_beta` hard-codes `version_base: latest_github_release` for `create_package_version`. Per yippie's comment, CCI lacks a generic null-override mechanism for flow steps. +- `cumulusci/tasks/create_package_version.py:63-112` - `version_base: Optional[str]`; documented values are `None`, a literal version number, or `latest_github_release`. +- `cumulusci/tasks/create_package_version.py:529-563` - `_get_base_version_number` only branches on `None` (default) and `"latest_github_release"`; any other string is parsed as a literal version. There is no `"default"`/`"highest"` sentinel and no support for unsetting via flow override. +- `cumulusci/cumulusci.yml:1216-1225` - `release_unlocked_beta` hard-codes `version_base: latest_github_release` for `create_package_version`. Per yippie's comment, CCI lacks a generic null-override mechanism for flow steps. **Recommended action**: -- pass1: `keep-open` — could be solved minimally with a `default`/`highest` sentinel in `_get_base_version_number`, or generalized as a CCI null-override feature. +- pass1: `keep-open` - could be solved minimally with a `default`/`highest` sentinel in `_get_base_version_number`, or generalized as a CCI null-override feature. - pass2 labels: `severity:low,area:packaging,area:flow-overrides,area:cli` --- - - ### #3446: CCI task push_qa crashes for Unlocked package with no namespace **Verdict**: REPRODUCED-on-v4.10.0 **Repro type**: bug -**Org used**: `repro-pkg-b1-dev` (dev) — used to confirm push_qa even runs against a non-packaging org; the user's actual NoneType crash happens before the SOQL would succeed on a real packaging org. +**Org used**: `[scratch-org]` (dev) - used to confirm push_qa even runs against a non-packaging org; the user's actual NoneType crash happens before the SOQL would succeed on a real packaging org. **Method**: -The user's command omitted `--version` and `--version_id`. Inspected `cumulusci/tasks/push/tasks.py` `_run_task`: when neither is set, it calls `self._get_version(package, self.options.get("version"))`, which calls `self._parse_version(version)` on `version=None`, which calls `version.split(".")`. This raises `AttributeError: 'NoneType' object has no attribute 'split'` — exactly the error from the linked gist in the issue. Verified by direct unit-style invocation: +The user's command omitted `--version` and `--version_id`. Inspected `cumulusci/tasks/push/tasks.py` `_run_task`: when neither is set, it calls `self._get_version(package, self.options.get("version"))`, which calls `self._parse_version(version)` on `version=None`, which calls `version.split(".")`. This raises `AttributeError: 'NoneType' object has no attribute 'split'` - exactly the error from the linked gist in the issue. Verified by direct unit-style invocation: ```python -BaseSalesforcePushTask._parse_version(None, None) # -> AttributeError +BaseSalesforcePushTask._parse_version(None, None) # -> AttributeError ``` -Also ran `cci task run push_qa --orgs /tmp/repro_pkg_orgs.txt --metadata_package_id 0337S000000DUMMY --org repro-pkg-b1-dev` against the scratch org; the path failed earlier on the org (no Push API on a dev scratch — `sObject type 'MetadataPackage' is not supported`), but on a real Push-API-enabled DevHub it would surface the NoneType crash. +Also ran `cci task run push_qa --orgs --metadata_package_id 0337S000000DUMMY` against a scratch org; the path failed earlier on the org (no Push API on a dev scratch - `sObject type 'MetadataPackage' is not supported`), but on a real Push-API-enabled DevHub it would surface the NoneType crash. The user's follow-up comment ("Push API not activated by default") is a separate UX issue: when Push API is disabled, the SOQL `SELECT ... FROM MetadataPackage` fails with `INVALID_TYPE`. They'd like a friendlier error. **Evidence**: -- `cumulusci/tasks/push/tasks.py:33` — `version_parts = version.split(".")` (no None-guard above). -- `cumulusci/tasks/push/tasks.py:283-297` — `_run_task` does not validate `version` before calling `_get_version`. -- Test: `/tmp/repro/3/tests/repro_3446_push_qa_no_version.py` passes on v4.10.0. +- `cumulusci/tasks/push/tasks.py:33` - `version_parts = version.split(".")` (no None-guard above). +- `cumulusci/tasks/push/tasks.py:283-297` - `_run_task` does not validate `version` before calling `_get_version`. +- Test: `_(repro evidence; see narrative)_` passes on v4.10.0. - Live invocation against scratch org: `Error: Malformed request ... sObject type 'MetadataPackage' is not supported` (orthogonal to the NoneType but illustrates the second comment). **Recommended action**: -- pass1: `keep-open` — real bug, simple fix. +- pass1: `keep-open` - real bug, simple fix. - pass2 labels: `bug`, `good-first-issue` --- - - ### #3466: Ability to specify a test suite to run instead of just `test_name_match` **Verdict**: NOT-REPRODUCED-on-v4.10.0 **Repro type**: feature **Method**: -Searched for `test_suite_names` in `cumulusci/tasks/apex/testrunner.py`. Wrote `/tmp/repro/1/tests/test_issue_3466.py` to assert the option exists, has a sensible description, and is mutually exclusive with `test_name_match`. +Searched for `test_suite_names` in `cumulusci/tasks/apex/testrunner.py`. Wrote `_(test pending harvest)_` to assert the option exists, has a sensible description, and is mutually exclusive with `test_name_match`. **Evidence**: -- `cumulusci/tasks/apex/testrunner.py:173-175` — `test_suite_names` is a documented `task_options` field accepting a comma-separated list of ApexTestSuite names. -- `cumulusci/tasks/apex/testrunner.py:188-190, 246-253, 308-376` — option is wired through `_init_options`, validated as mutually exclusive with `test_name_match`, and used by `_get_test_classes_from_test_suite_names` (queries ApexTestSuite + TestSuiteMembership). +- `cumulusci/tasks/apex/testrunner.py:173-175` - `test_suite_names` is a documented `task_options` field accepting a comma-separated list of ApexTestSuite names. +- `cumulusci/tasks/apex/testrunner.py:188-190, 246-253, 308-376` - option is wired through `_init_options`, validated as mutually exclusive with `test_name_match`, and used by `_get_test_classes_from_test_suite_names` (queries ApexTestSuite + TestSuiteMembership). - Repro test passes (2/2) on v4.10.0. **Recommended action**: -- pass1: `closed:feature-implemented` — the request is fully covered. davidmreed's reply linked W-12214520; that backlog item appears to have shipped. +- pass1: `closed:feature-implemented` - the request is fully covered. davidmreed's reply linked [internal-ID-redacted]; that backlog item appears to have shipped. - pass2 labels: `area:packaging,area:apex,state:resolved` --- - - ### #3470: Rename `ci_master` to `ci_main` (or alias) **Verdict**: REPRODUCED-on-v4.10.0 @@ -2144,55 +2065,53 @@ Searched for `test_suite_names` in `cumulusci/tasks/apex/testrunner.py`. Wrote ` **Evidence**: ```823:835:cumulusci/cumulusci.yml - ci_master: - group: Continuous Integration - description: Deploy the package metadata to the packaging org and prepare for managed package version upload. Intended for use against main branch commits. - steps: - ... + ci_master: + group: Continuous Integration + description: Deploy the package metadata to the packaging org and prepare for managed package version upload. Intended for use against main branch commits. + steps: + ... ``` `rg "ci_main"` returns no matches. davidmreed's 2022 reply indicated this requires flow-aliasing infrastructure first. **Recommended action**: -- pass1: `closed:stale-24mo` — 4yr stale; preserve as `closed:stale-24mo` rather than dismiss; the inclusive-language motivation is real and could be revisited if flow aliasing lands. +- pass1: `closed:stale-24mo` - 4yr stale; preserve as `closed:stale-24mo` rather than dismiss; the inclusive-language motivation is real and could be revisited if flow aliasing lands. - pass2 labels: `enhancement,stale,inclusive-language` - - ### #3471: `Merged 0 commits into branch:` message displays when a non-Source Code change is **Verdict**: REPRODUCED-on-v4.10.0 **Repro type**: bug -**Method**: Bucket A — code-scan and `git log` against `cumulusci/tasks/github/merge.py`. +**Method**: Bucket A - code-scan and `git log` against `cumulusci/tasks/github/merge.py`. **Evidence**: The reported log message originates from `_merge`: ```241:262:cumulusci/tasks/github/merge.py - def _merge(self, branch_name, source, commit): - """Attempt to merge a commit from source to branch with branch_name""" - compare = self.repo.compare_commits(branch_name, commit) - if not compare or not compare.files: - self.logger.info(f"Skipping branch {branch_name}: no file diffs found") - return - - try: - self.repo.merge(branch_name, commit) - self.logger.info( - f"Merged {compare.behind_by} commits into branch: {branch_name}" - ) - except GitHubError as e: - if e.code != http.client.CONFLICT: - raise - - if self.options["create_pull_request_on_conflict"]: - self._create_conflict_pull_request(branch_name, source) - else: - self.logger.info( - f"Merge conflict on branch {branch_name}: skipping pull request creation" - ) + def _merge(self, branch_name, source, commit): + """Attempt to merge a commit from source to branch with branch_name""" + compare = self.repo.compare_commits(branch_name, commit) + if not compare or not compare.files: + self.logger.info(f"Skipping branch {branch_name}: no file diffs found") + return + + try: + self.repo.merge(branch_name, commit) + self.logger.info( + f"Merged {compare.behind_by} commits into branch: {branch_name}" + ) + except GitHubError as e: + if e.code != http.client.CONFLICT: + raise + + if self.options["create_pull_request_on_conflict"]: + self._create_conflict_pull_request(branch_name, source) + else: + self.logger.info( + f"Merge conflict on branch {branch_name}: skipping pull request creation" + ) ``` The log line at 251 reports `compare.behind_by` from github3's CompareCommits. `behind_by` is computed from the GitHub compare-commits endpoint and reflects how many commits the destination branch is behind the merged commit _as of the comparison's chosen merge-base_; for "effectively no-op" content merges (e.g. README/test.txt scenarios where downstream content already matches via merge-base), the API can return 0 even though `self.repo.merge(branch_name, commit)` at line 249 just shipped a real commit. The reporter's pattern (README and `test.txt` reproduce; cumulusci.yml / source-code changes do not) is consistent with this hypothesis. @@ -2201,18 +2120,16 @@ The log line at 251 reports `compare.behind_by` from github3's CompareCommits. ` **Recommended action**: -- pass1: `keep-open` — small, well-localized fix (replace `compare.behind_by` with `len(list(compare.commits))` or report the SHA returned from `self.repo.merge(...)`); add a test covering the `behind_by=0` case. +- pass1: `keep-open` - small, well-localized fix (replace `compare.behind_by` with `len(list(compare.commits))` or report the SHA returned from `self.repo.merge(...)`); add a test covering the `behind_by=0` case. - pass2 labels: `bug, github, merge, low-priority` --- - - ### #3479: Error with "cci org import" in github action **Verdict**: NOT-REPRODUCED-on-v4.10.0 **Repro type**: bug -**Method**: Bucket A — code-scan of `cumulusci/cli/org.py` `org_import`, `cumulusci/core/config/sfdx_org_config.py` `sfdx_info`, and `git log` for the relevant wrapping fix. +**Method**: Bucket A - code-scan of `cumulusci/cli/org.py` `org_import`, `cumulusci/core/config/sfdx_org_config.py` `sfdx_info`, and `git log` for the relevant wrapping fix. **Evidence**: @@ -2226,57 +2143,55 @@ The reported error is the bare `Expecting value: line 1 column 1 (char 0)` (raw @orgname_option_or_argument(required=True) @pass_runtime(require_keychain=True) def org_import(runtime: CliRuntime, username_or_alias: str, org_name: str): - # Import the org from the SFDX keychain as an SfdxOrgConfig - # The `sfdx` key ensures we can reload using the right class. - org_config = SfdxOrgConfig( - {"username": username_or_alias, "sfdx": True}, - org_name, - runtime.keychain, - global_org=False, - ) - - # Determine if we received a locally-created scratch org - # or some other org (which we'll treat as persistent) - - info = org_config.sfdx_info + # Import the org from the SFDX keychain as an SfdxOrgConfig + # The `sfdx` key ensures we can reload using the right class. + org_config = SfdxOrgConfig( + {"username": username_or_alias, "sfdx": True}, + org_name, + runtime.keychain, + global_org=False, + ) + + # Determine if we received a locally-created scratch org + # or some other org (which we'll treat as persistent) + + info = org_config.sfdx_info ``` `cumulusci/core/config/sfdx_org_config.py`: ```38:55:cumulusci/core/config/sfdx_org_config.py - if p.returncode: - self.logger.error(f"Return code: {p.returncode}") - for line in stderr_list: - self.logger.error(line) - for line in stdout_list: - self.logger.error(line) - message = f"\nstderr:\n{nl.join(stderr_list)}" - message += f"\nstdout:\n{nl.join(stdout_list)}" - raise SfdxOrgException(message) - - else: - try: - org_info = json.loads("".join(stdout_list)) - except Exception as e: - raise SfdxOrgException( - "Failed to parse json from output.\n " - f"Exception: {e.__class__.__name__}\n Output: {''.join(stdout_list)}" - ) + if p.returncode: + self.logger.error(f"Return code: {p.returncode}") + for line in stderr_list: + self.logger.error(line) + for line in stdout_list: + self.logger.error(line) + message = f"\nstderr:\n{nl.join(stderr_list)}" + message += f"\nstdout:\n{nl.join(stdout_list)}" + raise SfdxOrgException(message) + + else: + try: + org_info = json.loads("".join(stdout_list)) + except Exception as e: + raise SfdxOrgException( + "Failed to parse json from output.\n " + f"Exception: {e.__class__.__name__}\n Output: {''.join(stdout_list)}" + ) ``` -Both nonzero return codes and JSON parse failures from `sfdx org display --json` are wrapped in `SfdxOrgException` with explicit context (this wrapping landed in commit `017bc49f4` on 2020-11-24, well before the 2023-01-06 issue). The bare `Expecting value: line 1 column 1 (char 0)` symptom is therefore not what a v4.10.0 user would see for this scenario — they would get the `Failed to parse json from output. Exception: JSONDecodeError. Output: ...` message instead, which directly reveals the empty/garbled sfdx output and points to the upstream auth/shell problem. +Both nonzero return codes and JSON parse failures from `sfdx org display --json` are wrapped in `SfdxOrgException` with explicit context (this wrapping landed in commit `017bc49f4` on 2020-11-24, well before the 2023-01-06 issue). The bare `Expecting value: line 1 column 1 (char 0)` symptom is therefore not what a v4.10.0 user would see for this scenario - they would get the `Failed to parse json from output. Exception: JSONDecodeError. Output: ...` message instead, which directly reveals the empty/garbled sfdx output and points to the upstream auth/shell problem. -David Reed's only reply (2023-02-22, never answered by the reporter) correctly identifies the root cause as GHA shell interpolation: `echo ${{ secrets.DEV_AUTH_URL }} > sfdx_auth` without quotes mangles multiline secrets, so `sfdx force:auth:sfdxurl:store` either fails silently or produces an invalid auth — then `sfdx org display --json` returns empty/non-JSON. Fix is in the user's workflow, not in cci. +David Reed's only reply (2023-02-22, never answered by the reporter) correctly identifies the root cause as GHA shell interpolation: `echo ${{ secrets.DEV_AUTH_URL }} > sfdx_auth` without quotes mangles multiline secrets, so `sfdx force:auth:sfdxurl:store` either fails silently or produces an invalid auth - then `sfdx org display --json` returns empty/non-JSON. Fix is in the user's workflow, not in cci. **Recommended action**: -- pass1: `closed:not-reproducible-on-v4.10.0` — root cause is user GHA workflow (unquoted multiline secret); cci's only relevant code path (`sfdx_info`) already wraps the error with a user-actionable message in v4.10.0; reporter never responded for 3+ years. +- pass1: `closed:not-reproducible-on-v4.10.0` - root cause is user GHA workflow (unquoted multiline secret); cci's only relevant code path (`sfdx_info`) already wraps the error with a user-actionable message in v4.10.0; reporter never responded for 3+ years. - pass2 labels: `awaiting-more-details, external-config` --- - - ### #3485: "cci task run run_tests" generates incorrect test_results.xml format **Verdict**: REPRODUCED-on-v4.10.0 @@ -2285,17 +2200,15 @@ David Reed's only reply (2023-02-22, never answered by the reporter) correctly i **Evidence**: -- `cumulusci/tasks/apex/testrunner.py:803-834` — `_write_output` opens `junit_output` and writes `'\n'` with no `` declaration and no enclosing `` element. +- `cumulusci/tasks/apex/testrunner.py:803-834` - `_write_output` opens `junit_output` and writes `'\n'` with no `` declaration and no enclosing `` element. - The closing tag at line 834 is ``. This exactly matches the malformed XML the reporter showed. - `junit_output` defaults to `test_results.xml` (line 201-203), unchanged. **Recommended action**: -- pass1: `keep-open` — small mechanical fix, still affects users producing JUnit reports for CI. +- pass1: `keep-open` - small mechanical fix, still affects users producing JUnit reports for CI. - pass2 labels: `bug, area:apex, good-first-issue` - - ### #3492: Enhance the "-o" option of "cci flow run" to accept "project\_\_custom" attribute values **Verdict**: REPRODUCED-on-v4.10.0 @@ -2304,17 +2217,15 @@ David Reed's only reply (2023-02-22, never answered by the reporter) correctly i **Evidence**: -- `cumulusci/cli/flow.py:152-162` — parses `-o` pairs by splitting key on `"__"` and unpacking into exactly two parts (`task_name, option_name = key.split("__")`). +- `cumulusci/cli/flow.py:152-162` - parses `-o` pairs by splitting key on `"__"` and unpacking into exactly two parts (`task_name, option_name = key.split("__")`). - A user passing `-o project__custom__myattr value` would actually error with "too many values to unpack" because the split yields three elements; even worded as `-o project__custom value` there is no codepath that writes into `project_config.config["project"]["custom"]`. - `coordinator = runtime.get_flow(flow_name, options=options)` (line 166) receives a `{task_name: {option_name: value}}` dict; project-level overrides have no entry point here. **Recommended action**: -- pass1: `keep-open` — legitimate usability gap for matrix-style CI. +- pass1: `keep-open` - legitimate usability gap for matrix-style CI. - pass2 labels: `enhancement, area:cli` - - ### #3506: when clause support for flow steps which call other flows **Verdict**: REPRODUCED-on-v4.10.0 @@ -2323,16 +2234,14 @@ David Reed's only reply (2023-02-22, never answered by the reporter) correctly i **Evidence**: -- `cumulusci/core/flowrunner.py:660-672` — when the step has a `task:` key, the StepSpec is built with `when=step_config.get("when")`. -- `cumulusci/core/flowrunner.py:674-697` — the `flow:` branch recurses via `_visit_step(...)` passing only `parent_options`, `parent_ui_options`, and `from_flow`; it never reads or propagates `step_config.get("when")`. Any `when:` clause attached to a flow-call step is silently dropped. +- `cumulusci/core/flowrunner.py:660-672` - when the step has a `task:` key, the StepSpec is built with `when=step_config.get("when")`. +- `cumulusci/core/flowrunner.py:674-697` - the `flow:` branch recurses via `_visit_step(...)` passing only `parent_options`, `parent_ui_options`, and `from_flow`; it never reads or propagates `step_config.get("when")`. Any `when:` clause attached to a flow-call step is silently dropped. **Recommended action**: -- pass1: `keep-open` — confirmed silent-failure foot-gun the user reported. +- pass1: `keep-open` - confirmed silent-failure foot-gun the user reported. - pass2 labels: `enhancement, area:flows` - - ### #3518: Task add_picklist_entries always sets a default value for record types **Verdict**: REPRODUCED-on-v4.10.0 @@ -2341,12 +2250,13 @@ David Reed's only reply (2023-02-22, never answered by the reporter) correctly i **Method**: Read `cumulusci/tasks/metadata_etl/picklists.py`. The smoking gun is at line 177: `default = str(process_bool_arg(entry.get("default", False))).lower` -— `.lower` is referenced as an attribute, not invoked. The resulting bound -method is truthy, so the `if default:` guard at line 214 always runs the -default-clobbering loop, marking the new entry as default for every record -type. Wrote two tests: a unit-level repro of the truthy bound-method, and a -function-level repro driving `_add_single_record_type_entries` directly via -`MetadataElement` to observe the mutated XML. + +- `.lower` is referenced as an attribute, not invoked. The resulting bound + method is truthy, so the `if default:` guard at line 214 always runs the + default-clobbering loop, marking the new entry as default for every record + type. Wrote two tests: a unit-level repro of the truthy bound-method, and a + function-level repro driving `_add_single_record_type_entries` directly via + `MetadataElement` to observe the mutated XML. **Evidence**: @@ -2354,20 +2264,18 @@ function-level repro driving `_add_single_record_type_entries` directly via - `cumulusci/tasks/metadata_etl/picklists.py:214-221` unconditionally sets defaults whenever `default` is truthy. - Test output: `test_issue_3518_picklist_record_type_default_logic_bug` - asserts the value is callable (it is) — fails as expected. + asserts the value is callable (it is) - fails as expected. - Test output: `test_issue_3518_record_type_default_not_set_when_default_false` observed `true` on a value that was passed `default: False`. **Recommended action**: -- pass1: keep-open — small targeted fix. +- pass1: keep-open - small targeted fix. - pass2 labels: `severity:high,area:metadata-etl,type:bug` --- - - ### #3542: 2GP flows fail locally with "Could not find package version id" **Verdict**: INCONCLUSIVE-needs-2GP-CI-pipeline @@ -2375,7 +2283,7 @@ function-level repro driving `_add_single_record_type_entries` directly via **Org used**: none (cannot easily fabricate a github status posted under a different SHA) **Method**: -Read `cumulusci/tasks/github/commit_status.py` `GetPackageDataFromCommitStatus._run_task` and `cumulusci/core/github.py:get_version_id_from_commit`. The lookup uses `self.project_config.repo_commit` (the local checkout's git HEAD SHA) verbatim, then iterates `commit.status().statuses` for one matching the configured context. No fallback to parent commits or to `pull_request.head.sha`. If the upstream workflow posted the status under a different SHA — most commonly the synthetic merge SHA used by `actions/checkout` on `pull_request` triggers — the local lookup returns no version_id and the user sees the exact error from the issue. +Read `cumulusci/tasks/github/commit_status.py` `GetPackageDataFromCommitStatus._run_task` and `cumulusci/core/github.py:get_version_id_from_commit`. The lookup uses `self.project_config.repo_commit` (the local checkout's git HEAD SHA) verbatim, then iterates `commit.status().statuses` for one matching the configured context. No fallback to parent commits or to `pull_request.head.sha`. If the upstream workflow posted the status under a different SHA - most commonly the synthetic merge SHA used by `actions/checkout` on `pull_request` triggers - the local lookup returns no version_id and the user sees the exact error from the issue. git log shows several "github_package_data" commits since 2022 (last directly related: `33bb24197 Update default API version to v59.0`; `7686731b2 Use commit_status resolution strategy when building non-SkipValidation 2GPs`) but none change the SHA-resolution semantics. The cci-side code path is **unchanged** at v4.10.0. @@ -2383,18 +2291,16 @@ Cannot fully reproduce in this run because that requires (a) a private repo conf **Evidence**: -- `cumulusci/tasks/github/commit_status.py:20` — `commit_sha = self.project_config.repo_commit` -- `cumulusci/core/github.py:361-368` — `get_version_id_from_commit` only checks the exact SHA's statuses; no fallback. +- `cumulusci/tasks/github/commit_status.py:20` - `commit_sha = self.project_config.repo_commit` +- `cumulusci/core/github.py:361-368` - `get_version_id_from_commit` only checks the exact SHA's statuses; no fallback. **Recommended action**: -- pass1: `unchanged` — needs the reporter (or someone with a 2GP CI pipeline) to confirm whether their workflow posts under merge-commit SHA vs head-commit SHA. If the latter, this is a cci bug; if the former, it's a workflow alignment bug in `cumulus-actions`. +- pass1: `unchanged` - needs the reporter (or someone with a 2GP CI pipeline) to confirm whether their workflow posts under merge-commit SHA vs head-commit SHA. If the latter, this is a cci bug; if the former, it's a workflow alignment bug in `cumulus-actions`. - pass2 labels: `needs-repro`, `2gp` --- - - ### #3543: New Option `load_sfdx_project_paths` for dx_convert_from Task **Verdict**: REPRODUCED-on-v4.10.0 @@ -2415,13 +2321,11 @@ codebase. **Recommended action**: -- pass1: keep-open — feature still unimplemented; reporter offered a draft PR. +- pass1: keep-open - feature still unimplemented; reporter offered a draft PR. - pass2 labels: `severity:low,area:metadata-etl,type:enhancement` --- - - ### #3544: `update_admin_profile` errors when org has Person Accounts AND a namespace **Verdict:** `INCONCLUSIVE-needs-namespaced-project` @@ -2435,25 +2339,25 @@ When `cci flow run dev_org --org dev` is run against a scratch org that has both …then the `update_admin_profile` step of `config_dev` fails. The reporter cited stackoverflow Q 206310 noting "Entity of type 'RecordType' named 'Account.Business_Account' cannot be found", indicating the deployed Profile XML references a record type that has been renamed or removed by SFDX/MetadataAPI behavior in PersonAccounts orgs. -Internal tracking: davidmreed filed W-12589033 (2023-02-22) but stated "I can't make any promises about delivering a behavior change." +Internal tracking: davidmreed filed [internal-ID-redacted] (2023-02-22) but stated "I can't make any promises about delivering a behavior change." ### Provisioning attempted ```text -$ uv run cci org info repro-special-c-pa +$ uv run cci org info [scratch-org] config_file: orgs/person_accounts.json config_name: person_accounts -namespaced: False -features: Communities, PersonAccounts, ContactsToMultipleAccounts +namespaced: False +features: Communities, PersonAccounts, ContactsToMultipleAccounts instance_url: https://drive-inspiration-9525.scratch.my.salesforce.com ``` -CumulusCI's own `cumulusci.yml` declares no `project__package__namespace`. Setting `namespaced: true` on the scratch config has no effect without a registered namespace, and registering a CumulusCI namespace in CCIDevHub is out of scope for this triage pass. +CumulusCI's own `cumulusci.yml` declares no `project__package__namespace`. Setting `namespaced: true` on the scratch config has no effect without a registered namespace, and registering a CumulusCI namespace in the configured DevHub is out of scope for this triage pass. ### Partial repro on v4.10.0 ```text -$ uv run cci task run update_admin_profile --org repro-special-c-pa +$ uv run cci task run update_admin_profile --org [scratch-org] Beginning task: ProfileGrantAllAccess Extracting existing metadata... [Done] @@ -2464,12 +2368,12 @@ Beginning task: Deploy [Success]: Succeeded ``` -The task **succeeded** against a non-namespaced PersonAccounts scratch org — confirming that the bug requires the _intersection_ of PersonAccounts + namespacing, not PersonAccounts alone. +The task **succeeded** against a non-namespaced PersonAccounts scratch org - confirming that the bug requires the _intersection_ of PersonAccounts + namespacing, not PersonAccounts alone. ### Code search for fixes -- `git log --since=2023-02-01 -- cumulusci/tasks/salesforce/update_profile.py cumulusci/files/admin_profile.xml` shows only one commit (entrypoints refactor 23295c0a2) — no functional change to PersonAccounts handling. -- `git log --grep "person.account|business_account|3544|W-12589033" -i` returns nothing relevant in `update_profile.py`. +- `git log --since=2023-02-01 -- cumulusci/tasks/salesforce/update_profile.py cumulusci/files/admin_profile.xml` shows only one commit (entrypoints refactor 23295c0a2) - no functional change to PersonAccounts handling. +- `git log --grep "person.account|business_account|3544|[internal-ID-redacted]" -i` returns nothing relevant in `update_profile.py`. - `update_profile.py` retains a generic `person_account_default` option (line 242, 277) for explicit recordType configuration but no automatic detection or filtering of `Account.Business_Account` for PersonAccounts orgs. ### Adjacent finding (not the same bug) @@ -2477,19 +2381,17 @@ The task **succeeded** against a non-namespaced PersonAccounts scratch org — c `cumulusci/utils/__init__.py:229`: ```229:229:cumulusci/utils/__init__.py - namespaced_org = namespace + "__" if namespaced_org else "" + namespaced_org = namespace + "__" if namespaced_org else "" ``` Passing `-o namespaced_org True` against a project with `namespace=None` raises `TypeError: unsupported operand type(s) for +: 'NoneType' and 'str'`. Distinct from #3544's bug (which is a deploy-time RecordType-not-found error, not an init-time TypeError). Worth filing as a separate cleanup issue. ### Recommendation -- **Pass 1:** needs-info — ask reporter to validate against v4.10.0 with their namespaced project and confirm whether the issue persists. Include `wi-created` already on the issue (W-12589033). -- **Pass 2 label:** `needs-namespaced-project` — repro requires a namespaced project that this triage pipeline cannot synthesize. +- **Pass 1:** needs-info - ask reporter to validate against v4.10.0 with their namespaced project and confirm whether the issue persists. Include `wi-created` already on the issue . +- **Pass 2 label:** `needs-namespaced-project` - repro requires a namespaced project that this triage pipeline cannot synthesize. - Alternative: consider treating as `wontfix` per davidmreed's recommendation (use `flows.config_dev.steps.2: task: None` workaround) until SFDC fixes the underlying SFDX/MetadataAPI Account.Business_Account renaming issue. - - ### #3549: Deploy to Salesforce does not create a test output **Verdict**: REPRODUCED-on-v4.10.0 @@ -2498,17 +2400,15 @@ Passing `-o namespaced_org True` against a project with `namespace=None` raises **Evidence**: -- `cumulusci/tasks/salesforce/Deploy.py:49-94` — exposes `test_level` and `specified_tests` options and validates them. -- `cumulusci/tasks/salesforce/Deploy.py:150-154` — passes them through to the metadata API call but never captures `runTestResult`/`runTestsResult` from the response. +- `cumulusci/tasks/salesforce/Deploy.py:49-94` - exposes `test_level` and `specified_tests` options and validates them. +- `cumulusci/tasks/salesforce/Deploy.py:150-154` - passes them through to the metadata API call but never captures `runTestResult`/`runTestsResult` from the response. - `rg "junit_output|test_results"` against `cumulusci/tasks/salesforce/Deploy.py` and `cumulusci/salesforce_api/metadata.py` returns no test-output writer for the deploy path. **Recommended action**: -- pass1: `keep-open` — natural feature; tracks #3564. +- pass1: `keep-open` - natural feature; tracks #3564. - pass2 labels: `enhancement, area:metadata-deploy` - - ### #3561: Retrieve_unpackaged unusable in MetaDeploy **Verdict**: NOT-REPRODUCED-on-v4.10.0 (fix landed) @@ -2519,17 +2419,17 @@ Passing `-o namespaced_org True` against a project with `namespace=None` raises Read `cumulusci/tasks/salesforce/RetrieveUnpackaged.py`. Current code: ```26:36:cumulusci/tasks/salesforce/RetrieveUnpackaged.py - def _init_options(self, kwargs): - super(RetrieveUnpackaged, self)._init_options(kwargs) + def _init_options(self, kwargs): + super(RetrieveUnpackaged, self)._init_options(kwargs) - if "package_xml" in self.options: - with open(self.options["package_xml"], "r") as f: - self.options["package_xml_content"] = f.read() + if "package_xml" in self.options: + with open(self.options["package_xml"], "r") as f: + self.options["package_xml_content"] = f.read() - def _get_api(self): - return self.api_class( - self, self.options["package_xml_content"], self.options.get("api_version") - ) + def _get_api(self): + return self.api_class( + self, self.options["package_xml_content"], self.options.get("api_version") + ) ``` `git log -S "package_xml_content" -- cumulusci/tasks/salesforce/RetrieveUnpackaged.py` -> commit `56e10665e` "Fix retrieve unpackaged so it is usable in metadeploy (#3566)" merged 2024-05-20 by yippie (the original issue reporter). The fix introduces `package_xml_content` as a separate option so the path-typed `package_xml` is preserved across multiple `_init_options` invocations. @@ -2543,8 +2443,6 @@ Read `cumulusci/tasks/salesforce/RetrieveUnpackaged.py`. Current code: --- - - ### #3570: Feature Request: Flow "finally" or "error" path **Verdict**: REPRODUCED-on-v4.10.0 @@ -2553,16 +2451,14 @@ Read `cumulusci/tasks/salesforce/RetrieveUnpackaged.py`. Current code: **Evidence**: -- `cumulusci/core/flowrunner.py` — only `ignore_failure` (mapped to `StepSpec.allow_failure`, line 122/144) and the `finally:` Python clause inside `flow.run()` (line 500) handle failures. There is no flow-step type for `finally:` / `on_error:` / `cleanup:` / `always_run`. `rg "finally|on_error|on_failure|always_run"` confirms. +- `cumulusci/core/flowrunner.py` - only `ignore_failure` (mapped to `StepSpec.allow_failure`, line 122/144) and the `finally:` Python clause inside `flow.run()` (line 500) handle failures. There is no flow-step type for `finally:` / `on_error:` / `cleanup:` / `always_run`. `rg "finally|on_error|on_failure|always_run"` confirms. - `_run_step` (line 503-536) re-raises on `result.exception` if not `allow_failure`, which is the only failure handling. **Recommended action**: -- pass1: `keep-open` — design-level feature, but problem is real (rollback, notify on partial failure). +- pass1: `keep-open` - design-level feature, but problem is real (rollback, notify on partial failure). - pass2 labels: `enhancement, area:flows` - - ### #3585: Error Occurs when Using `update_package_xml` on object with `xsi:nil="true"` **Verdict**: REPRODUCED-on-v4.10.0 @@ -2576,7 +2472,7 @@ parse error because the `xsi:` prefix is unbound. **Evidence**: -- `cumulusci/tasks/metadata/package.py:115-130` — when a folder has objects +- `cumulusci/tasks/metadata/package.py:115-130` - when a folder has objects it instantiates the registered parser; for `objects/` the parser uses the metadata tree which is strict about namespaces. - Test output: `test_issue_3585_xsi_nil_true_breaks_update_package_xml` fails @@ -2585,14 +2481,12 @@ parse error because the `xsi:` prefix is unbound. **Recommended action**: -- pass1: keep-open — needs either a namespace-shim before parsing or +- pass1: keep-open - needs either a namespace-shim before parsing or pre-stripping of `xsi:nil` attributes. - pass2 labels: `severity:medium,area:metadata-etl,type:bug,sfdx-compat` --- - - ### #3587: Warning when install_class/uninstall_class set with managed=false on update_package_xml **Verdict**: NOT-REPRODUCED-on-v4.10.0 (feature still unimplemented) @@ -2612,9 +2506,9 @@ Confirmed live by running: uv run cci task run update_package_xml --install_class MyInstall --uninstall_class MyUninstall ``` -Output (full): `Beginning task: UpdatePackageXml; Generating src/package.xml from metadata in src` — **no warning**. (src/package.xml ended up empty because src/ has no metadata in the cci repo, but the relevant signal is the absence of any warning about install_class being silently dropped.) +Output (full): `Beginning task: UpdatePackageXml; Generating src/package.xml from metadata in src` - **no warning**. (src/package.xml ended up empty because src/ has no metadata in the cci repo, but the relevant signal is the absence of any warning about install_class being silently dropped.) -Also confirmed via direct generator test (`/tmp/repro/3/tests/repro_3587_update_package_xml_no_warning.py`): +Also confirmed via direct generator test (`_(repro evidence; see narrative)_`): - `managed=False, install_class="X"` → output XML has neither `` nor ``. - `managed=True, install_class="X"` → output XML has them. @@ -2627,83 +2521,77 @@ Also confirmed via direct generator test (`/tmp/repro/3/tests/repro_3587_update_ **Recommended action**: -- pass1: `keep-open` — feature still missing. +- pass1: `keep-open` - feature still missing. - pass2 labels: `enhancement`, `good-first-issue` --- - - ### #3593: `dx` task doesn't work for some commands like `project convert source` **Verdict**: REPRODUCED-on-v4.10.0 **Repro type**: bug **Method**: -Read `cumulusci/tasks/sfdx.py` end-to-end. Wrote `/tmp/repro/1/tests/test_issue_3593.py` that constructs an `SFDXOrgTask` with command `"project convert source -r src -d force-app"` and a `ScratchOrgConfig`, then asserts the resulting command would not append a target-org flag. +Read `cumulusci/tasks/sfdx.py` end-to-end. Wrote `cumulusci/tests/triage/test_issue_3593.py` that constructs an `SFDXOrgTask` with command `"project convert source -r src -d force-app"` and a `ScratchOrgConfig`, then asserts the resulting command would not append a target-org flag. **Evidence**: -- `cumulusci/tasks/sfdx.py:46-51` — `SFDXOrgTask._get_command` unconditionally appends `" -o {username}"` for any `ScratchOrgConfig`, regardless of whether the underlying sf subcommand accepts a target-org flag. -- Repro test FAILS with the resulting command: `sf project convert source -r src -d force-app -o test@example.com` — the same shape that the issue reporter said sf cli rejects. +- `cumulusci/tasks/sfdx.py:46-51` - `SFDXOrgTask._get_command` unconditionally appends `" -o {username}"` for any `ScratchOrgConfig`, regardless of whether the underlying sf subcommand accepts a target-org flag. +- Repro test FAILS with the resulting command: `sf project convert source -r src -d force-app -o test@example.com` - the same shape that the issue reporter said sf cli rejects. - Note: `cumulusci/tasks/dx_convert_from.py` (which backs the OOTB `dx_convert_from` task) was switched to extend `SFDXBaseTask` (no org), so the OOTB task is fine; the bug remains for any user-defined task that uses `SFDXOrgTask` with a no-org sf subcommand. **Recommended action**: -- pass1: `keep-open` — needs an opt-out option (e.g. `pass_org: False` or a `no_org_command` whitelist). Verifying actual sf cli rejection of `-o` for `project convert source` would need an org/sf cli; the CCI side of the bug is unchanged. +- pass1: `keep-open` - needs an opt-out option (e.g. `pass_org: False` or a `no_org_command` whitelist). Verifying actual sf cli rejection of `-o` for `project convert source` would need an org/sf cli; the CCI side of the bug is unchanged. - pass2 labels: `severity:medium,area:packaging,area:sfdx,area:dx-task,state:needs-design` --- - - ### #3600: Allow install_managed to use environment variables **Verdict**: NOT-REPRODUCED-on-v4.10.0 (feature still unimplemented) **Repro type**: feature -**Org used**: `repro-pkg-b1-dev` (dev) — used to confirm cci accepts the literal `${VAR}` value at runtime. +**Org used**: `[scratch-org]` (dev) - used to confirm cci accepts the literal `${VAR}` value at runtime. **Method**: Inspected the option-processing path: -- `cumulusci/core/tasks.py:35` — `PROJECT_CONFIG_RE = re.compile(r"\$project_config.(\w+)")`. This is the only substitution pattern. -- `cumulusci/core/tasks.py:127-157` — `_init_options.process_options` only calls `PROJECT_CONFIG_RE.sub(...)`; no env-var lookup. -- `cumulusci/utils/yaml/safer_loader.py:60` — uses plain `yaml.safe_load(...)` with no custom resolver. -- `cumulusci/tasks/salesforce/install_package_version.py:31-34` — `version` option description does not mention env-var support. +- `cumulusci/core/tasks.py:35` - `PROJECT_CONFIG_RE = re.compile(r"\$project_config.(\w+)")`. This is the only substitution pattern. +- `cumulusci/core/tasks.py:127-157` - `_init_options.process_options` only calls `PROJECT_CONFIG_RE.sub(...)`; no env-var lookup. +- `cumulusci/utils/yaml/safer_loader.py:60` - uses plain `yaml.safe_load(...)` with no custom resolver. +- `cumulusci/tasks/salesforce/install_package_version.py:31-34` - `version` option description does not mention env-var support. Confirmed live by: ```bash export MY_FAKE_VERSION='1.2.3' uv run cci task run install_managed --version '${MY_FAKE_VERSION}' \ - --namespace npsp --org repro-pkg-b1-dev --interactive True + --namespace npsp --org [scratch-org] --interactive True ``` -Interactive prompt printed: `Package to install: npsp ${MY_FAKE_VERSION}` — literal, **not** expanded. +Interactive prompt printed: `Package to install: npsp ${MY_FAKE_VERSION}` - literal, **not** expanded. **Evidence**: -- `cumulusci/core/tasks.py:35` — only substitution pattern. -- `cumulusci/utils/yaml/safer_loader.py:60` — plain yaml load. -- Test: `/tmp/repro/3/tests/repro_3600_install_managed_no_env_var.py` passes. +- `cumulusci/core/tasks.py:35` - only substitution pattern. +- `cumulusci/utils/yaml/safer_loader.py:60` - plain yaml load. +- Test: `_(repro evidence; see narrative)_` passes. - Live interactive output: `Package to install: npsp ${MY_FAKE_VERSION}`. **Recommended action**: -- pass1: `keep-open` — feature still missing. Note design decision required: `$env:VAR` (consistent with `$project_config.X`) vs `${VAR}` (POSIX) vs `os.path.expandvars` semantics; backwards-compat for any literal `$`-strings. +- pass1: `keep-open` - feature still missing. Note design decision required: `$env:VAR` (consistent with `$project_config.X`) vs `${VAR}` (POSIX) vs `os.path.expandvars` semantics; backwards-compat for any literal `$`-strings. - pass2 labels: `enhancement` --- - - ### #3603: Any issue with git results in the unhelpful "404 not found" error **Bucket**: A. **Type**: bug. **Verdict**: REPRODUCED-on-v4.10.0 (partial). The user enumerated five situations (1) source repo missing, (2) dep repo missing, (3) source ref/tag/branch missing, (4) dep resolution strategy fails, -(5) source resolution strategy fails — all collapsing into a generic 404 with +(5) source resolution strategy fails - all collapsing into a generic 404 with no source/URL/ref context. Code-scan + targeted unit test confirm: - Cases **1, 2** are already wrapped: both `cumulusci/core/dependencies/github.py::get_repo` @@ -2717,28 +2605,26 @@ no source/URL/ref context. Code-scan + targeted unit test confirm: bubble out. The repro test (`test_case3_source_ref_not_found_message_quality`) prints the actual exception: - ``` - Exception type: NotFoundError - Message: '404 [No message]' - ``` +``` +Exception type: NotFoundError +Message: '404 [No message]' +``` - Neither the repo URL nor the missing ref/tag is present. +Neither the repo URL nor the missing ref/tag is present. - Case **4** raises `DependencyResolutionError(f"Unable to resolve dependency {dependency}")` (resolvers.py:663). The dependency description is included, but the list of - attempted strategies is not — so the user can't immediately tell which + attempted strategies is not - so the user can't immediately tell which strategy fell through. Recommendation: keep-open. Two clean, scoped fixes available (wrap `repo.ref()` in `source/github.py`; enrich the resolvers.py:663 message with strategy names). Good-first-issue territory. -Repro: `/tmp/repro/11/tests/test_3603_404_messages.py` (4 tests; all pass). +Repro: `_(repro evidence; see narrative)_` (4 tests; all pass). --- - - ### #3604: Task request: Update sfdx-project.json dependencies based off of computed cumulusci dependencies **Bucket**: A. **Type**: feature. **Verdict**: REPRODUCED-on-v4.10.0 (gap still @@ -2746,7 +2632,7 @@ present). `uv run cci task list` returns 0 tasks that write `sfdx-project.json`. A project-wide grep for `unpackagedMetadata` returns no matches. Maintainer -acknowledged the request as W-13504384 in a 2023 reply, label `wi-created` +acknowledged the request as [internal-ID-redacted] in a 2023 reply, label `wi-created` already on the issue, but no implementation has shipped through v4.10.0. Recommendation: keep-open (`enhancement`, `wi-created` already attached). @@ -2755,32 +2641,28 @@ Repro: code-scan only; no test file (feature gap, nothing to assert against). --- - - ### #3605: Ability to Increment Major Versions when running `upload_production` **Verdict**: NOT-REPRODUCED-on-v4.10.0 **Repro type**: feature **Method**: -Inspected `cumulusci/tasks/salesforce/package_upload.py`. Wrote `/tmp/repro/1/tests/test_issue_3605.py` to assert `major_version` and `minor_version` task options exist and the major-bump branch is wired in `_validate_versions`. +Inspected `cumulusci/tasks/salesforce/package_upload.py`. Wrote `_(test pending harvest)_` to assert `major_version` and `minor_version` task options exist and the major-bump branch is wired in `_validate_versions`. **Evidence**: -- `cumulusci/tasks/salesforce/package_upload.py:39-46` — `major_version` and `minor_version` are documented `task_options`. -- `cumulusci/tasks/salesforce/package_upload.py:101-140` — `_validate_versions` honors a major-version bump, defaulting `minor_version` to `"0"` when the user supplies a higher major. +- `cumulusci/tasks/salesforce/package_upload.py:39-46` - `major_version` and `minor_version` are documented `task_options`. +- `cumulusci/tasks/salesforce/package_upload.py:101-140` - `_validate_versions` honors a major-version bump, defaulting `minor_version` to `"0"` when the user supplies a higher major. - Repro test passes (3/3). -- Closing PR identified by `git log` history: commit `87b94440e` — "Deploy Major and Minor Version option in upload_production task (#3651)". +- Closing PR identified by `git log` history: commit `87b94440e` - "Deploy Major and Minor Version option in upload_production task (#3651)". **Recommended action**: -- pass1: `closed:fixed-by-pr-#3651` — feature shipped; user can run `cci task run upload_production -o major_version 34 -o minor_version 0`. +- pass1: `closed:fixed-by-pr-#3651` - feature shipped; user can run `cci task run upload_production -o major_version 34 -o minor_version 0`. - pass2 labels: `area:packaging,area:1gp,state:resolved` --- - - ### #3607: The `retry_failures` from the task `run_tests` is not working for me **Verdict**: INCONCLUSIVE-needs-org-with-managed-package @@ -2789,20 +2671,18 @@ Inspected `cumulusci/tasks/salesforce/package_upload.py`. Wrote `/tmp/repro/1/te **Evidence**: -- `cumulusci/tasks/apex/testrunner.py:209-222` — `retry_failures` strings are compiled into regexes at task init. -- `cumulusci/tasks/apex/testrunner.py:400-408` — `_is_retriable_failure` checks both `Message` and `StackTrace` via `re.search`. -- `cumulusci/tasks/apex/testrunner.py:475-490` — increments `counts["Retriable"]` for each matching failure. -- `cumulusci/tasks/apex/testrunner.py:548` — printed as `Retried: {Retriable}`. -- Repro test `/tmp/repro/8/tests/test_3607_retry.py` confirms in pure Python that `re.compile("UNABLE_TO_LOCK_ROW").search(user_message)` returns a match for the exact message body the user pasted. Both tests pass. -- One escape hatch in code: `cumulusci/tasks/apex/testrunner.py:448-452` — for class-level errors with `managed: true` (which the user has), retries are explicitly skipped. The user's failure shows per-test details, so this should not have been the cause. +- `cumulusci/tasks/apex/testrunner.py:209-222` - `retry_failures` strings are compiled into regexes at task init. +- `cumulusci/tasks/apex/testrunner.py:400-408` - `_is_retriable_failure` checks both `Message` and `StackTrace` via `re.search`. +- `cumulusci/tasks/apex/testrunner.py:475-490` - increments `counts["Retriable"]` for each matching failure. +- `cumulusci/tasks/apex/testrunner.py:548` - printed as `Retried: {Retriable}`. +- Repro test `_(repro evidence; see narrative)_` confirms in pure Python that `re.compile("UNABLE_TO_LOCK_ROW").search(user_message)` returns a match for the exact message body the user pasted. Both tests pass. +- One escape hatch in code: `cumulusci/tasks/apex/testrunner.py:448-452` - for class-level errors with `managed: true` (which the user has), retries are explicitly skipped. The user's failure shows per-test details, so this should not have been the cause. **Recommended action**: -- pass1: `closed:stale-24mo` — code logic is correct as written; reporter has not engaged in 30+ months; cannot reproduce without their managed package + org. +- pass1: `closed:stale-24mo` - code logic is correct as written; reporter has not engaged in 30+ months; cannot reproduce without their managed package + org. - pass2 labels: `bug, area:apex, needs-info` - - ### #3609: Command 'cci task run dx --command "plugins:install ..."' fails **Verdict**: INCONCLUSIVE-needs-live-cli-test @@ -2811,18 +2691,16 @@ Inspected `cumulusci/tasks/salesforce/package_upload.py`. Wrote `/tmp/repro/1/te **Evidence**: -- `cumulusci/tasks/sfdx.py:20` — `SFDX_CLI = "sf"` (changed from `sfdx` in the v4.x cutover; reporter was on 3.76.0). -- `cumulusci/tasks/sfdx.py:34-40` — `_get_command` is a thin wrapper: `f"sf {self.options['command']}"`. The CCI layer adds nothing that could introduce the "Timed out after 30000 ms" error the user saw. -- `cumulusci/cumulusci.yml:273-275` — `dx` task is registered as `cumulusci.tasks.sfdx.SFDXOrgTask` with description "Execute an arbitrary Salesforce DX command". +- `cumulusci/tasks/sfdx.py:20` - `SFDX_CLI = "sf"` (changed from `sfdx` in the v4.x cutover; reporter was on 3.76.0). +- `cumulusci/tasks/sfdx.py:34-40` - `_get_command` is a thin wrapper: `f"sf {self.options['command']}"`. The CCI layer adds nothing that could introduce the "Timed out after 30000 ms" error the user saw. +- `cumulusci/cumulusci.yml:273-275` - `dx` task is registered as `cumulusci.tasks.sfdx.SFDXOrgTask` with description "Execute an arbitrary Salesforce DX command". - Reporter's literal command `--command "plugins:install ..."` uses the colon syntax that `sfdx` accepted; `sf` typically wants `plugins install`. Different CLI now. **Recommended action**: -- pass1: `closed:stale-24mo` — not a CCI bug; CCI faithfully shells out. CLI in question has changed substantially since. +- pass1: `closed:stale-24mo` - not a CCI bug; CCI faithfully shells out. CLI in question has changed substantially since. - pass2 labels: `bug, upstream:sf-cli` - - ### #3612: Maintain the CumulusCI for VSCode Extension **Verdict**: NOT-REPRODUCED-on-v4.10.0 @@ -2835,25 +2713,23 @@ Inspected `cumulusci/tasks/salesforce/package_upload.py`. Wrote `/tmp/repro/1/te **Recommended action**: -- pass1: `closed:not-reproducible-on-v4.10.0` — should be re-filed against `SFDO-Tooling/cci-vscode`. +- pass1: `closed:not-reproducible-on-v4.10.0` - should be re-filed against `SFDO-Tooling/cci-vscode`. - pass2 labels: `enhancement, wontfix, wrong-repo` - - -### #3613: AddFieldsToPageLayout — "Cannot find metadata file" +### #3613: AddFieldsToPageLayout - "Cannot find metadata file" **Verdict**: REPRODUCED-on-v4.10.0 **Repro type**: bug (UX/error-message) -**Org used**: `repro-etl-b-dev` +**Org used**: `[scratch-org]` **Method**: -Live repro: `uv run cci task run add_page_layout_fields --org repro-etl-b-dev -o api_names "Account"` against the scratch org. Saved at `/tmp/repro/5/tests/issue-3613/output-just-object.txt`. Result: `Error: Cannot find metadata file /var/.../retrieve/layouts/Account.layout`. Same task with `-o api_names "Account-Account Layout"` succeeds end-to-end (deploy succeeds). The functionality is intact; the user-visible bug is the unhelpful error when the api_name does not match the Metadata API's `-` file naming convention. +Live repro: `uv run cci task run add_page_layout_fields --org [scratch-org] -o api_names "Account"` against the scratch org. Saved at `_(repro evidence)_`. Result: `Error: Cannot find metadata file /var/.../retrieve/layouts/Account.layout`. Same task with `-o api_names "Account-Account Layout"` succeeds end-to-end (deploy succeeds). The functionality is intact; the user-visible bug is the unhelpful error when the api_name does not match the Metadata API's `-` file naming convention. The error originates from `MetadataSingleEntityTransformTask._transform` (base.py:332): `if not path.exists(): raise CumulusCIException(f"Cannot find metadata file {path}")`. The retrieve actually succeeded (the user's report says "metadata is getting downloaded"), but `_transform` looks for the user's typed api_names verbatim as filenames. **Recommended action**: -- pass1: `improve-error-message` — keep open as a UX bug. +- pass1: `improve-error-message` - keep open as a UX bug. - pass2 labels: `bug`, `good-first-issue` **Notes**: Two complementary improvements would help: @@ -2861,12 +2737,10 @@ The error originates from `MetadataSingleEntityTransformTask._transform` (base.p 1. In `_transform` (base.py:332), include the actual list of files retrieved into `source_metadata_dir` in the error message so the user can spot the naming mismatch. 2. In `AddFieldsToPageLayout._init_options`, warn when an api_name does not contain `-` (Layout API names always do). -The user was on Windows in 2023 — note that the user might also have been hitting a backslash path issue, but the underlying class of bug is the same: api_name format mismatch. +The user was on Windows in 2023 - note that the user might also have been hitting a backslash path issue, but the underlying class of bug is the same: api_name format mismatch. --- - - ### #3615: update_dependencies does not honor resolution strategy **Bucket**: A. **Type**: bug (filed). **Verdict**: NOT-REPRODUCED-on-v4.10.0. @@ -2879,8 +2753,8 @@ dependency_resolutions: preproduction: latest_release production: latest_release resolution_strategies: - latest_release: [tag, latest_release, unmanaged] # no latest_beta - include_beta: [tag, latest_beta, latest_release, unmanaged] + latest_release: [tag, latest_release, unmanaged] # no latest_beta + include_beta: [tag, latest_beta, latest_release, unmanaged] ``` So `preproduction` is an alias for the `latest_release` stack and intentionally @@ -2893,13 +2767,11 @@ Recommendation: closed:not-reproducible-on-v4.10.0. Possible follow-up: docs/UX improvement (the name `preproduction` is misleading; consider clarifying in docs/data.md or renaming to `release_only` in a future major). -Repro: `/tmp/repro/11/tests/test_3615_preproduction_strategy.py` (3 tests; all +Repro: `_(repro evidence; see narrative)_` (3 tests; all pass). --- - - ### #3618: Allow for list when deleting/removing CumulusCI orgs **Verdict**: REPRODUCED-on-v4.10.0 @@ -2908,17 +2780,15 @@ pass). **Evidence**: -- `cumulusci/cli/org.py:519-545` — `org_remove` decorated with `@orgname_option_or_argument(required=True)`, takes a single `org_name`. -- `cumulusci/cli/org.py:605-625` — `org_scratch_delete` same pattern, single `org_name`. +- `cumulusci/cli/org.py:519-545` - `org_remove` decorated with `@orgname_option_or_argument(required=True)`, takes a single `org_name`. +- `cumulusci/cli/org.py:605-625` - `org_scratch_delete` same pattern, single `org_name`. - No `nargs=-1`, no comma-split helper; passing `org1,org2` would be treated as a single literal alias and fail keychain lookup. **Recommended action**: -- pass1: `keep-open` — legitimately useful for cleanup workflows; small implementation surface. +- pass1: `keep-open` - legitimately useful for cleanup workflows; small implementation surface. - pass2 labels: `enhancement, area:cli, good-first-issue` - - ### #3619: Dependency_pins does not honor passwords **Bucket**: A. **Type**: bug. **Verdict**: REPRODUCED-on-v4.10.0. @@ -2934,7 +2804,7 @@ Two distinct reproducible defects in `cumulusci/core/dependencies/dependencies.p 2. **Silent password drop (Part B)**: When a dynamic dependency carries a `password_env_name`, the pin path at L171-187 short-circuits to `pin.pin(self, context)`, which (L100) calls - `GitHubTagResolver().resolve(d, context)` directly — bypassing + `GitHubTagResolver().resolve(d, context)` directly - bypassing `resolve_dependency()`'s password-propagation block (resolvers.py L644-654). The resulting `package_dependency.password_env_name` is `None`, so `PackageNamespaceVersionDependency.install()`'s @@ -2951,15 +2821,13 @@ Recommendation: keep-open. Two-line fix sketch: block from resolvers.py L644-654 to copy `d.password_env_name` (or the pin's own) onto `d.package_dependency`. -Repro: `/tmp/repro/11/tests/test_3619_pin_password.py` (4 tests; all pass). +Repro: `_(repro evidence; see narrative)_` (4 tests; all pass). --- - - ### #3649: Support serial loads with update_data task -**Verdict:** `REPRODUCED-on-v4.10.0` — feature still unimplemented +**Verdict:** `REPRODUCED-on-v4.10.0` - feature still unimplemented `UpdateData.load_data` and the rollback path in `cumulusci/tasks/bulkdata/update_data.py:184` and `:211` both call `get_dml_operation(..., api_options={}, ...)` with the `api_options` dict hardcoded empty. `BulkApiDmlOperation` in `step.py` honors `api_options["bulk_mode"]` for Serial/Parallel selection, but `UpdateData` never sets it. `LoadData` and the snowfakery channel runner DO let users pick `bulk_mode`; `update_data` is the gap. @@ -2967,8 +2835,6 @@ The author offered to implement. Fix is small (~10 lines): add `bulk_mode` (or ` **Recommended pass1: `keep-open`** with `good-first-issue` label. - - ### #3663: When clause | Ability to pass in prior task response values **Verdict**: REPRODUCED-on-v4.10.0 @@ -2977,23 +2843,21 @@ The author offered to implement. Fix is small (~10 lines): add `bulk_mode` (or ` **Evidence**: -- `cumulusci/core/flowrunner.py:510-516` — the `when` Jinja context is hardcoded to `{"project_config": ..., "org_config": ...}`. Prior step results (`self.results`) are not exposed. +- `cumulusci/core/flowrunner.py:510-516` - the `when` Jinja context is hardcoded to `{"project_config": ..., "org_config": ...}`. Prior step results (`self.results`) are not exposed. - The `^^task.return_value` resolver lives elsewhere (option resolution path) and is not threaded into the `when` evaluator. **Recommended action**: -- pass1: `keep-open` — natural extension of `when`; complements #3506. +- pass1: `keep-open` - natural extension of `when`; complements #3506. - pass2 labels: `enhancement, area:flows` - - ### #3692: No parser configuration found for subdirectory digitalExperiences **Verdict**: REPRODUCED-on-v4.10.0 **Repro type**: bug **Method**: -Greped `digitalExperiences|digitalExperience` across the codebase — zero +Greped `digitalExperiences|digitalExperience` across the codebase - zero hits. Wrote two tests: a static one asserting `digitalExperiences` is a key in `metadata_map.yml`, and a runtime one that creates the folder structure and runs `PackageXmlGenerator`. @@ -3011,42 +2875,36 @@ subdirectory %s")`. **Recommended action**: -- pass1: keep-open — add `digitalExperiences` (and likely +- pass1: keep-open - add `digitalExperiences` (and likely `digitalExperienceConfigs`) entries to `metadata_map.yml` with appropriate parser classes (probably a bundle parser). - pass2 labels: `severity:medium,area:metadata-etl,type:bug` --- - - ### #3699: Sort of the data during extraction -**Verdict:** `REPRODUCED-on-v4.10.0` — feature missing, but workaround exists +**Verdict:** `REPRODUCED-on-v4.10.0` - feature missing, but workaround exists -`ExtractData._soql_for_mapping` (extract.py:133-147) builds the SOQL with `WHERE` only — no `ORDER BY`. `MappingStep` has no `order_by`/`sort` field. However, `append_filter_clause` strips a leading `WHERE` from `soql_filter` and concatenates the remainder onto the query, which means a user can write `soql_filter: "Active__c = true ORDER BY CreatedDate"` and it produces valid SOQL. So the missing capability is "first-class `order_by` field for parity with `where`", not "ability to sort at all". +`ExtractData._soql_for_mapping` (extract.py:133-147) builds the SOQL with `WHERE` only - no `ORDER BY`. `MappingStep` has no `order_by`/`sort` field. However, `append_filter_clause` strips a leading `WHERE` from `soql_filter` and concatenates the remainder onto the query, which means a user can write `soql_filter: "Active__c = true ORDER BY CreatedDate"` and it produces valid SOQL. So the missing capability is "first-class `order_by` field for parity with `where`", not "ability to sort at all". The author hasn't followed up since 2023-11; with a working workaround, this is low-priority. **Recommended pass1: `closed:stale-24mo`.** Reopen later if a v5 effort wants explicit `order_by` for declaration ergonomics. - - ### #3700: Trying to do an upsert on a master-detail child object gets an error around permission -**Verdict:** `REPRODUCED-on-v4.10.0` — bug +**Verdict:** `REPRODUCED-on-v4.10.0` - bug `MappingStep._get_required_permission_types(operation)` in `mapping_parser.py:373-377` returns `("updateable", "createable")` for any operation in `(UPSERT, ETL_UPSERT)` (or any mapping action of the same). Master-detail lookup fields in Salesforce are `createable: True` but `updateable: False` (you cannot reparent a master-detail child after creation). `_check_field_permission` therefore returns `False` for the MD lookup field on an upsert mapping, and `_validate_field_dict` errors out with the exact message the user reported: "Field xxx\_\_c does not have the correct permissions ('updateable', 'createable') for this operation." -Repro test (`/tmp/repro/10/tests/test_3700_master_detail_upsert_perm.py`) constructs an `UPSERT` mapping for an `Order__c` with an `Account__c` master-detail lookup, simulates a `{createable: True, updateable: False}` describe, and asserts that `_check_field_permission` returns `False` — assertion passes. +Repro test (`_(repro evidence; see narrative)_`) constructs an `UPSERT` mapping for an `Order__c` with an `Account__c` master-detail lookup, simulates a `{createable: True, updateable: False}` describe, and asserts that `_check_field_permission` returns `False` - assertion passes. **Recommended pass1: `keep-open`** with `good-first-issue`. Fix: when validating an MD lookup field for an upsert, accept `createable` alone (the lookup never gets updated post-insert anyway). A field-shape detector can use `relationshipName` + `cascadeDelete: True` from describe. - - ### #3701: set a mapping to the id instead of it being either a number or the salesforce id -**Verdict:** `REPRODUCED-on-v4.10.0` — feature gap +**Verdict:** `REPRODUCED-on-v4.10.0` - feature gap `MappingStep` and the extract/load pipeline special-case the literal field name `"Id"` in many places (`mapping_parser.py:171/190/228/241/422`); it always represents the Salesforce Id and lands in an `sf_id` column. There is no mechanism to make a different field (an external-id like `BCM_Unique_Id__c`) act as the row's primary key in the extracted SQLite. The user's example yaml `Id : BCM_Unique_Id__c` is currently interpreted as "extract the SF Id into the column named `BCM_Unique_Id__c`", not "make `BCM_Unique_Id__c` the row primary key". @@ -3054,13 +2912,11 @@ This is closely tied to #3699 (motivated by sortable git diffs of dataset extrac **Recommended pass1: `closed:stale-24mo`.** Reporter hasn't followed up since 2023-11. Workarounds are available (extract Id into a known column and post-process). Could revisit if a v5 effort tackles dataset diff-ability holistically. - - ### #3717: Github automerge feature task not working when running through Github Flow **Verdict**: INCONCLUSIVE-needs-cumulus-actions-workflow **Repro type**: bug -**Method**: Bucket A — code-scan of `cumulusci/core/config/project_config.py` `repo_info` / `repo_branch` and repo-wide grep for GitHub Actions env-var auto-detection. +**Method**: Bucket A - code-scan of `cumulusci/core/config/project_config.py` `repo_info` / `repo_branch` and repo-wide grep for GitHub Actions env-var auto-detection. **Evidence**: @@ -3069,48 +2925,46 @@ The reporter notes that `project_config.repo_branch` and `project_config.project `cumulusci/core/config/project_config.py` shows that cci's only CI auto-detection is for Heroku: ```220:255:cumulusci/core/config/project_config.py - def repo_info(self) -> Dict[str, Any]: - if self._repo_info is not None: - return self._repo_info - - # Detect if we are running in a CI environment and get repo info - # from env vars for the environment instead of .git files - info = {"ci": None} - - # Make sure that the CUMULUSCI_AUTO_DETECT environment variable is - # set before trying to auto-detect anything from the environment - if not os.environ.get("CUMULUSCI_AUTO_DETECT"): - self._repo_info = info - return self._repo_info - - # Heroku CI - heroku_ci = os.environ.get("HEROKU_TEST_RUN_ID") - if heroku_ci: - info = { - "branch": os.environ.get("HEROKU_TEST_RUN_BRANCH"), - "commit": os.environ.get("HEROKU_TEST_RUN_COMMIT_VERSION"), - "ci": "heroku", - "root": "/app", - } - - # Other CI environment implementations can be implemented here... - - self._apply_repo_env_var_overrides(info) + def repo_info(self) -> Dict[str, Any]: + if self._repo_info is not None: + return self._repo_info + + # Detect if we are running in a CI environment and get repo info + # from env vars for the environment instead of .git files + info = {"ci": None} + + # Make sure that the CUMULUSCI_AUTO_DETECT environment variable is + # set before trying to auto-detect anything from the environment + if not os.environ.get("CUMULUSCI_AUTO_DETECT"): + self._repo_info = info + return self._repo_info + + # Heroku CI + heroku_ci = os.environ.get("HEROKU_TEST_RUN_ID") + if heroku_ci: + info = { + "branch": os.environ.get("HEROKU_TEST_RUN_BRANCH"), + "commit": os.environ.get("HEROKU_TEST_RUN_COMMIT_VERSION"), + "ci": "heroku", + "root": "/app", + } + + # Other CI environment implementations can be implemented here... + + self._apply_repo_env_var_overrides(info) ``` -A repo-wide grep (`Grep` over `cumulusci/`) for `GITHUB_REF|GITHUB_HEAD_REF|GITHUB_SHA|GITHUB_ACTIONS` returns **zero matches** — there is no GitHub Actions environment auto-detection in cci. The fallback path in `repo_branch` (line 394-402) calls `current_branch(self.repo_root)` which reads `.git/HEAD`. On a `push`-triggered GHA workflow the standard `actions/checkout@v4` checkout puts the working copy in a detached HEAD state, so `current_branch` returns `None`. On `workflow_dispatch` triggered manually, the action receives a `ref` input that resolves to a named branch checkout, so `current_branch` works. +A repo-wide grep (`Grep` over `cumulusci/`) for `GITHUB_REF|GITHUB_HEAD_REF|GITHUB_SHA|GITHUB_ACTIONS` returns **zero matches** - there is no GitHub Actions environment auto-detection in cci. The fallback path in `repo_branch` (line 394-402) calls `current_branch(self.repo_root)` which reads `.git/HEAD`. On a `push`-triggered GHA workflow the standard `actions/checkout@v4` checkout puts the working copy in a detached HEAD state, so `current_branch` returns `None`. On `workflow_dispatch` triggered manually, the action receives a `ref` input that resolves to a named branch checkout, so `current_branch` works. Net: the reporter's symptom is exactly what cci produces unless the workflow sets `CUMULUSCI_REPO_BRANCH` (and friends) explicitly before invoking `cci flow run`. That responsibility lives in the `cumulus-actions/standard-workflows` YAMLs, not in cci. This matches the precedent established in #3418 (also `INCONCLUSIVE-needs-cumulus-actions-workflow`). **Recommended action**: -- pass1: `unchanged` — issue is at the cci ↔ cumulus-actions boundary; needs investigation in `cumulus-actions/standard-workflows` to confirm/fix `CUMULUSCI_REPO_BRANCH` plumbing for `push`-triggered child-feature merges. +- pass1: `unchanged` - issue is at the cci ↔ cumulus-actions boundary; needs investigation in `cumulus-actions/standard-workflows` to confirm/fix `CUMULUSCI_REPO_BRANCH` plumbing for `push`-triggered child-feature merges. - pass2 labels: `external-config, cumulus-actions, needs-info` > Optional follow-up enhancement (not part of triage): add a `# GitHub Actions` block in `repo_info` parallel to the Heroku block, reading `GITHUB_HEAD_REF` (PR) / `GITHUB_REF_NAME` (push) and `GITHUB_SHA`. Would close a class of "branch=None in CI" reports including this one, but is a behavior-change to a long-stable contract and merits its own design discussion. - - ### #3721: `create_package_version` `version_name` default should be version number, not "Release" **Verdict**: REPRODUCED-on-v4.10.0 @@ -3121,25 +2975,23 @@ Searched for `version_name` defaults in `create_package_version.py` and `package **Evidence**: -- `cumulusci/tasks/create_package_version.py:184` — `version_name=self.options.get("version_name") or "Release"`. Default is still the literal string `"Release"`. -- `cumulusci/cumulusci.yml:684-686` — `upload_production` hard-codes `name: Release`. -- `cumulusci/tasks/salesforce/package_upload.py:147-154` — passes `VersionName` straight through; no jinja2/template support. +- `cumulusci/tasks/create_package_version.py:184` - `version_name=self.options.get("version_name") or "Release"`. Default is still the literal string `"Release"`. +- `cumulusci/cumulusci.yml:684-686` - `upload_production` hard-codes `name: Release`. +- `cumulusci/tasks/salesforce/package_upload.py:147-154` - passes `VersionName` straight through; no jinja2/template support. - `git merge-base --is-ancestor 7aaf348f3 HEAD` returns non-zero. Commit `7aaf348f3` ("Change version naming on PackageUpload task to use the predicted version number and a jinja2 template expression") lives only on the `d2x/*` remotes (muselab-d2x fork), per jlantz's 2024 comment. **Recommended action**: -- pass1: `keep-open` — needs upstream port + design (templating? plain version number? both 1GP and 2GP?). +- pass1: `keep-open` - needs upstream port + design (templating? plain version number? both 1GP and 2GP?). - pass2 labels: `severity:low,area:packaging,area:1gp,area:2gp` --- - - ### #3734: upload_production fails with FIELD_INTEGRITY_EXCEPTION when latest is Beta patch **Verdict**: REPRODUCED-on-v4.10.0 **Repro type**: bug -**Org used**: none (would require a 1GP packaging org with both 6.13 Released and 6.13.1 Beta — too large to fabricate) +**Org used**: none (would require a 1GP packaging org with both 6.13 Released and 6.13.1 Beta - too large to fabricate) **Method**: Read `cumulusci/tasks/salesforce/package_upload.py` `PackageUpload._validate_versions`. The "latest version" SOQL query orders `MajorVersion DESC, MinorVersion DESC, PatchVersion DESC, ReleaseState DESC LIMIT 1`. When the user has the pattern they describe (release 6.13, then create patch 6.13.1 Beta as a safety net), the query returns the patch row with `ReleaseState='Beta'`. @@ -3148,14 +3000,14 @@ Then at line 134-135: ```python if version["ReleaseState"] == "Beta": - self.options["minor_version"] = str(version["MinorVersion"]) + self.options["minor_version"] = str(version["MinorVersion"]) ``` This sets `minor_version=13`, identical to the already-Released minor. The PackageUploadRequest is then created with major=6, minor=13, which Salesforce rejects with `FIELD_INTEGRITY_EXCEPTION: The version number must be greater than the last Managed - Released version number: 6.13`. Exactly the error in the issue. The user's own analysis in their last 3 comments is correct and matches the code. The current `cannot-reproduce`/`awaiting-more-details` labels are stale. -Confirmed via mocked unit test `/tmp/repro/3/tests/repro_3734_upload_production_beta_patch.py`: +Confirmed via mocked unit test `_(repro evidence; see narrative)_`: - With `{Major=6, Minor=13, Patch=1, ReleaseState=Beta}` → `_validate_versions` sets `minor_version='13'` (the bug). - With `{Major=6, Minor=13, Patch=None, ReleaseState=Released}` → `_validate_versions` sets `minor_version='14'` (the desired behavior). @@ -3164,13 +3016,13 @@ git log shows `87b94440e Deploy Major and Minor Version option in upload_product **Evidence**: -- `cumulusci/tasks/salesforce/package_upload.py:80-98` — SOQL query, `ORDER BY MajorVersion DESC, MinorVersion DESC, PatchVersion DESC, ReleaseState DESC LIMIT 1`. -- `cumulusci/tasks/salesforce/package_upload.py:134-137` — Beta branch sets `minor_version` to the same minor. +- `cumulusci/tasks/salesforce/package_upload.py:80-98` - SOQL query, `ORDER BY MajorVersion DESC, MinorVersion DESC, PatchVersion DESC, ReleaseState DESC LIMIT 1`. +- `cumulusci/tasks/salesforce/package_upload.py:134-137` - Beta branch sets `minor_version` to the same minor. - Test passes on v4.10.0 with mocked `_get_one_record`. **Recommended action**: -- pass1: `keep-open` — confirmed real bug; remove the stale `cannot-reproduce`/`awaiting-more-details` labels. +- pass1: `keep-open` - confirmed real bug; remove the stale `cannot-reproduce`/`awaiting-more-details` labels. - pass2 labels: `bug` --- @@ -3178,72 +3030,66 @@ git log shows `87b94440e Deploy Major and Minor Version option in upload_product ## Summary cross-cutting findings 1. **Two feature requests (#3587, #3600)** are easy "good-first-issue" candidates whose semantics are clear from the issue body. Both are independently verifiable with no org needed (`update_package_xml` is local; env-var support is a parser-level concern). -2. **Two real bugs (#3446, #3734)** still reproduce on v4.10.0 with stable, well-understood root causes. #3734 is mislabeled `cannot-reproduce` — that label should be removed in pass2. +2. **Two real bugs (#3446, #3734)** still reproduce on v4.10.0 with stable, well-understood root causes. #3734 is mislabeled `cannot-reproduce` - that label should be removed in pass2. 3. **Two cross-stack issues (#3418, #3542)** point at the boundary between cci and the `cumulus-actions/standard-workflows` repo. They cannot be triaged from cci alone; they need either a workflow-side check or a request to the reporter for the workflow file/SHAs they're using. - - ### #3745: ci_beta and install_managed_beta do not use the latest beta **Verdict:** `NOT-REPRODUCED-on-v4.10.0` (working as designed) -**Evidence:** [`/tmp/repro/4/evidence/3745-source-and-design.txt`](/tmp/repro/4/evidence/3745-source-and-design.txt) +**Evidence:** [`_(repro evidence)_`](_(repro evidence)_) -The `install_managed_beta` task (cumulusci.yml line 408) sets `version: latest_beta`, which `InstallPackageVersion` (lines 96–100 of `cumulusci/tasks/salesforce/install_package_version.py`) resolves via a GitHub Releases lookup using the `include_beta` resolver strategy — NOT a direct DevHub query for the latest `Package2Version`: +The `install_managed_beta` task (cumulusci.yml line 408) sets `version: latest_beta`, which `InstallPackageVersion` (lines 96-100 of `cumulusci/tasks/salesforce/install_package_version.py`) resolves via a GitHub Releases lookup using the `include_beta` resolver strategy - NOT a direct DevHub query for the latest `Package2Version`: ```96:101:cumulusci/tasks/salesforce/install_package_version.py - if version in ["latest", "latest_beta"]: - strategy = "include_beta" if version == "latest_beta" else "production" - dependency = GitHubDynamicDependency(github=github) - dependency.resolve( - self.project_config, get_resolver_stack(self.project_config, strategy) - ) + if version in ["latest", "latest_beta"]: + strategy = "include_beta" if version == "latest_beta" else "production" + dependency = GitHubDynamicDependency(github=github) + dependency.resolve( + self.project_config, get_resolver_stack(self.project_config, strategy) + ) ``` -The reporter (kayla-hager, 2024-02-07) ran `create_package_version` standalone — bypassing `release_2gp_beta` — so no GitHub release with the beta tag was ever created, hence `ci_beta` correctly fell back to the latest production tag (1.27). Comments resolve this as a documentation/usability issue; the reporter accepted the explanation 2024-02-13 and indicated they would close. v4.10.0 has not changed this behavior. +The reporter (kayla-hager, 2024-02-07) ran `create_package_version` standalone - bypassing `release_2gp_beta` - so no GitHub release with the beta tag was ever created, hence `ci_beta` correctly fell back to the latest production tag (1.27). Comments resolve this as a documentation/usability issue; the reporter accepted the explanation 2024-02-13 and indicated they would close. v4.10.0 has not changed this behavior. **Recommendation:** keep `closed:stale-24mo` (rule 1). No code defect. --- - - ### #3746: Deleted Versions used for determining next version **Verdict:** `REPRODUCED-on-v4.10.0` (code-level confirmation) -**Evidence:** [`/tmp/repro/4/evidence/3746-source-soql.txt`](/tmp/repro/4/evidence/3746-source-soql.txt) +**Evidence:** [`_(repro evidence)_`](_(repro evidence)_) -The reporter (yippie, 2024-02-09) flagged that `create_package_version._get_base_version_number()` does not filter `IsDeprecated = true` when picking the highest existing `Package2Version` to increment from. The bug is present verbatim in v4.10.0 source at `cumulusci/tasks/create_package_version.py` lines 535–541: +The reporter (yippie, 2024-02-09) flagged that `create_package_version._get_base_version_number()` does not filter `IsDeprecated = true` when picking the highest existing `Package2Version` to increment from. The bug is present verbatim in v4.10.0 source at `cumulusci/tasks/create_package_version.py` lines 535-541: ```529:545:cumulusci/tasks/create_package_version.py - def _get_base_version_number( - self, version_base: Optional[str], package_id: str - ) -> PackageVersionNumber: - """Determine the "base version" of the package (existing version to be incremented)""" - if version_base is None: - # Default: Get the highest existing version of the package - res = self.tooling.query( - "SELECT MajorVersion, MinorVersion, PatchVersion, BuildNumber, IsReleased " - "FROM Package2Version " - f"WHERE Package2Id='{package_id}' " - "ORDER BY MajorVersion DESC, MinorVersion DESC, PatchVersion DESC, BuildNumber DESC " - "LIMIT 1" - ) - if res["size"]: - return PackageVersionNumber( - **res["records"][0], package_type=PackageType.SECOND_GEN - ) + def _get_base_version_number( + self, version_base: Optional[str], package_id: str + ) -> PackageVersionNumber: + """Determine the "base version" of the package (existing version to be incremented)""" + if version_base is None: + # Default: Get the highest existing version of the package + res = self.tooling.query( + "SELECT MajorVersion, MinorVersion, PatchVersion, BuildNumber, IsReleased " + "FROM Package2Version " + f"WHERE Package2Id='{package_id}' " + "ORDER BY MajorVersion DESC, MinorVersion DESC, PatchVersion DESC, BuildNumber DESC " + "LIMIT 1" + ) + if res["size"]: + return PackageVersionNumber( + **res["records"][0], package_type=PackageType.SECOND_GEN + ) ``` -The same file at line 297 DOES include `IsDeprecated = FALSE` for `Package2` lookups, so the project knows about the column — the omission at line 535 is asymmetric and matches the report exactly. End-to-end repro on a real packaging org would require creating two Package2Version records and deleting one (sf package version delete), which is outside this triage's scope. Code-level confirmation is sufficient. +The same file at line 297 DOES include `IsDeprecated = FALSE` for `Package2` lookups, so the project knows about the column - the omission at line 535 is asymmetric and matches the report exactly. End-to-end repro on a real packaging org would require creating two Package2Version records and deleting one (sf package version delete), which is outside this triage's scope. Code-level confirmation is sufficient. **Recommendation:** flip currently-proposed `closed:stale-24mo` → `kept-open` with `severity:medium`, `area:packaging`, `target:v4-patch`. Trivial 1-line fix (add `AND IsDeprecated = false` to the SOQL WHERE clause). --- - - ### #3754: Enable configuration for cci version update sources **Verdict**: REPRODUCED-on-v4.10.0 @@ -3252,39 +3098,35 @@ The same file at line 297 DOES include `IsDeprecated = FALSE` for `Package2` loo **Evidence**: -- `cumulusci/cli/utils.py:65-79` — `get_latest_final_version` hits `https://pypi.org/pypi/cumulusci/json` literally, no env-var, no kwarg. -- `cumulusci/cli/utils.py:82-101` — `check_latest_version` cannot be disabled via flag/env. Workaround in the comments (touch `~/.cumulusci/cumulus_timestamp` to a far-future epoch) confirmed by inspecting the timestamp logic at lines 38-50, 86-89. +- `cumulusci/cli/utils.py:65-79` - `get_latest_final_version` hits `https://pypi.org/pypi/cumulusci/json` literally, no env-var, no kwarg. +- `cumulusci/cli/utils.py:82-101` - `check_latest_version` cannot be disabled via flag/env. Workaround in the comments (touch `~/.cumulusci/cumulus_timestamp` to a far-future epoch) confirmed by inspecting the timestamp logic at lines 38-50, 86-89. **Recommended action**: -- pass1: `keep-open` — easy add (e.g. `CUMULUSCI_DISABLE_VERSION_CHECK` env), helps offline/restricted environments. +- pass1: `keep-open` - easy add (e.g. `CUMULUSCI_DISABLE_VERSION_CHECK` env), helps offline/restricted environments. - pass2 labels: `enhancement, area:cli` - - ### #3758: Flow `push_upgrade_org` is incorrectly defined **Verdict**: REPRODUCED-on-v4.10.0 **Repro type**: bug **Method**: -Read the `push_upgrade_org` flow in `cumulusci/cumulusci.yml`. Wrote `/tmp/repro/1/tests/test_issue_3758.py` to load the YAML and assert the final step calls `config_managed` (not `config_qa`). +Read the `push_upgrade_org` flow in `cumulusci/cumulusci.yml`. Wrote `cumulusci/tests/triage/test_issue_3758.py` to load the YAML and assert the final step calls `config_managed` (not `config_qa`). **Evidence**: -- `cumulusci/cumulusci.yml:1161-1177` — final step is `flow: config_qa`. The bug report (correctly, in my view) argues this should be `config_managed` because push upgrades target managed-package orgs (UAT sandboxes), not QA scratch orgs. +- `cumulusci/cumulusci.yml:1161-1177` - final step is `flow: config_qa`. The bug report (correctly, in my view) argues this should be `config_managed` because push upgrades target managed-package orgs (UAT sandboxes), not QA scratch orgs. - Repro test FAILS with `config_qa` != `config_managed`. - Both flows currently expand to the same steps (`deploy_post`, `update_admin_profile`, `load_sample_data`), so behavior is equivalent today, but semantics drift over time and the docs link customers to the wrong flow page. **Recommended action**: -- pass1: `keep-open` — single-line YAML fix; great `good-first-issue` candidate. Out of scope for this triage pass per task constraints (do not fix bugs). +- pass1: `keep-open` - single-line YAML fix; great `good-first-issue` candidate. Out of scope for this triage pass per task constraints (do not fix bugs). - pass2 labels: `severity:medium,area:packaging,area:flows,good-first-issue` --- - - ### #3762: `update_admin_profile` task fails on namespaced org with Person Accounts enabled **Verdict**: closed:duplicate-of-#3544 @@ -3296,30 +3138,26 @@ Read both #3762 and (via gh) #3544. The reporter (noahisapilot) explicitly self- The reporter's own analysis even pinpoints the offending code at `update_profile.py` line 238 (in v3.84.3; corresponds to `rt["record_type"] = rt["record_type"].format(**self.namespace_prefixes)` at line 236 in v4.10.0). -#3544 is still OPEN at v4.10.0 with `wi-created` label `W-12589033`. +#3544 is still OPEN at v4.10.0 with `wi-created` label `[internal-ID-redacted]`. **Recommended action**: -- pass1: `close-as-duplicate` — link to #3544. -- pass2 labels: (n/a — duplicate) +- pass1: `close-as-duplicate` - link to #3544. +- pass2 labels: (n/a - duplicate) **Notes**: Per dup-confirm protocol, no live repro performed. --- - - ### #3768: Snowfakery Batch Size and Just Once -**Verdict:** `REPRODUCED-on-v4.10.0` — bug, structural +**Verdict:** `REPRODUCED-on-v4.10.0` - bug, structural -The Snowfakery channel runner architecturally creates a separate working directory per batch via `shutil.copytree(template_path, data_dir)` (`queue_manager.py:322`). Before that copy, `Snowfakery._cleanup_object_tables` (`snowfakery.py:721-730`) drops every non-`sf_ids` table from the template. So when batch 2+ starts, the SQLite database carried in the template only contains `sf_ids` mapping tables — none of the actual `account`-row data created in the initial just_once batch. +The Snowfakery channel runner architecturally creates a separate working directory per batch via `shutil.copytree(template_path, data_dir)` (`queue_manager.py:322`). Before that copy, `Snowfakery._cleanup_object_tables` (`snowfakery.py:721-730`) drops every non-`sf_ids` table from the template. So when batch 2+ starts, the SQLite database carried in the template only contains `sf_ids` mapping tables - none of the actual `account`-row data created in the initial just_once batch. Snowfakery's `random_reference: Account` resolves at generation time against rows in the recipe-local database. Since `just_once: true` means batch 2+ does not regenerate the Accounts, and the carried-over database has no `account` rows (just the `account_sf_ids` map), `random_reference` has nothing to pick from in batch 2+. This matches the user's exact symptom: first 20 contacts (one batch) get the 5 just_once Accounts, the next 430 get nothing (or fall back to NPSP defaults). -Verifying interactively against an org would require provisioning a scratch and running the recipe at `--batch_size 20 --num_records 450` — code-review evidence is conclusive without it. **Recommended pass1: `keep-open`**, severity major. Fix likely requires preserving rows of just_once-referenced objects (not just `_sf_ids`) in the template DB carried to subsequent batches; coordination with the Snowfakery dev branch is probably required. - - +Verifying interactively against an org would require provisioning a scratch and running the recipe at `--batch_size 20 --num_records 450` - code-review evidence is conclusive without it. **Recommended pass1: `keep-open`**, severity major. Fix likely requires preserving rows of just_once-referenced objects (not just `_sf_ids`) in the template DB carried to subsequent batches; coordination with the Snowfakery dev branch is probably required. ### #3771: find_replace transforms on XPath with predicates does not work @@ -3337,7 +3175,7 @@ fork and was never merged into `main`. **Evidence**: -- `cumulusci/core/source_transforms/transforms.py:420-435` — naive +- `cumulusci/core/source_transforms/transforms.py:420-435` - naive predicate handling. - `git log --all --oneline --grep="3772\|3771\|XPath.*predicate"` shows only `2bf6ce6a3 Improve namespace handling in find_replace` on @@ -3349,14 +3187,12 @@ fork and was never merged into `main`. **Recommended action**: -- pass1: keep-open — the leboff PR is a viable starting point; or implement +- pass1: keep-open - the leboff PR is a viable starting point; or implement the reporter's "strip xmlns then re-add" approach for simplicity. - pass2 labels: `severity:medium,area:source-transforms,type:bug,has-pr` --- - - ### #3773: retrieve_profile task seems to be missing some Metadata **Verdict**: REPRODUCED-on-v4.10.0 @@ -3372,9 +3208,9 @@ text. **Evidence**: -- `cumulusci/salesforce_api/retrieve_profile_api.py:164-195` — no +- `cumulusci/salesforce_api/retrieve_profile_api.py:164-195` - no `FieldPermissions` query. -- Greped `FieldPermission|field_permission|fieldPermission` — only the +- Greped `FieldPermission|field_permission|fieldPermission` - only the `update_profile.py`, `permissions.py`, and `mapping_parser.py` files reference field permissions; `retrieve_profile_api.py` does not. - Test output: `test_issue_3773_retrieve_profile_queries_field_permissions` @@ -3390,14 +3226,12 @@ make it into the package.xml requested for retrieve. **Recommended action**: -- pass1: keep-open — needs additional `FieldPermissions` query plus +- pass1: keep-open - needs additional `FieldPermissions` query plus inclusion of those parent SObjectTypes in the `CustomObject` retrieve set. - pass2 labels: `severity:medium,area:retrieve-profile,type:bug` --- - - ### #3852: CumulusCI 4 refresh token error (sarge Capture.flush) **Verdict**: REPRODUCED-on-v4.10.0 @@ -3406,18 +3240,16 @@ make it into the package.xml requested for retrieve. **Evidence**: -- `pyproject.toml:52` — `"sarge"` pinned with no version constraint. +- `pyproject.toml:52` - `"sarge"` pinned with no version constraint. - `uv run python -c "import sarge; print(sarge.__version__)"` → `0.1.7.post1`. - `uv run python -c "import sarge; print(hasattr(sarge.Capture, 'flush'))"` → `False`. The upstream fix (`def flush(self): pass`) sits unreleased on master. -- `cumulusci/core/config/sfdx_org_config.py:200-214` — `refresh_oauth_token` still calls `self.sfdx_info` at line 212. Per the maintainer comment in-thread, on Python 3.13 this triggers the `AttributeError: 'Capture' object has no attribute 'flush'` during interpreter shutdown logging path — cosmetic only, no functional regression. +- `cumulusci/core/config/sfdx_org_config.py:200-214` - `refresh_oauth_token` still calls `self.sfdx_info` at line 212. Per the maintainer comment in-thread, on Python 3.13 this triggers the `AttributeError: 'Capture' object has no attribute 'flush'` during interpreter shutdown logging path - cosmetic only, no functional regression. **Recommended action**: -- pass1: `keep-open` — kept-open per maintainer label; track until sarge 0.1.8 ships or we vendor/swap the dependency. +- pass1: `keep-open` - kept-open per maintainer label; track until sarge 0.1.8 ships or we vendor/swap the dependency. - pass2 labels: `bug, upstream:sarge, py313` - - ### #3854: Issue while Capturing Data (capture_sample_data lookup_key validation) **Verdict**: REPRODUCED-on-v4.10.0 @@ -3426,47 +3258,45 @@ make it into the package.xml requested for retrieve. **Evidence**: -- `cumulusci/tasks/bulkdata/extract.py:367-374` — the offending validation block is intact: - - `if total_mapping_operations != total_rows: raise ConfigError(f"Total mapping operations ({total_mapping_operations}) do not match total non-empty rows ({total_rows}) for lookup_key: {lookup_key}. Mention all related tables for lookup: {lookup_key}")` +- `cumulusci/tasks/bulkdata/extract.py:367-374` - the offending validation block is intact: +- `if total_mapping_operations != total_rows: raise ConfigError(f"Total mapping operations ({total_mapping_operations}) do not match total non-empty rows ({total_rows}) for lookup_key: {lookup_key}. Mention all related tables for lookup: {lookup_key}")` - Error text matches the user's report verbatim. - Per swirkens' comment, this validation was introduced in PR #3741 / commit `2c5d0056e` and remains unchanged in v4.10.0. - Workaround in thread: pin to CCI 3.84.1 (pre-validation). **Recommended action**: -- pass1: `keep-open` — kept-open per maintainer label; real bug for polymorphic-lookup users. +- pass1: `keep-open` - kept-open per maintainer label; real bug for polymorphic-lookup users. - pass2 labels: `bug, area:bulkdata, regression` - - ### #3884: Running a Dev_Org flow goes through re-install of the same package version again **Verdict:** `INCONCLUSIVE-needs-project-with-managed-deps` -**Evidence:** [`/tmp/repro/4/evidence/3884-source-skip-logic.txt`](/tmp/repro/4/evidence/3884-source-skip-logic.txt) +**Evidence:** [`_(repro evidence)_`](_(repro evidence)_) The reporter (dipakparmar, 2025-02-26) describes that re-running `dev_org` reinstalls dependencies that are already installed. CumulusCI itself has no `project__dependencies` block, so end-to-end repro on this very repo is not possible. Source review against v4.10.0 shows that BOTH managed-package install paths in `cumulusci/core/dependencies/dependencies.py` already have a "skip if already at this or newer version" guard: ```458:465:cumulusci/core/dependencies/dependencies.py - if org.has_minimum_package_version( - self.namespace, - version, - ): - context.logger.info( - f"{self} or a newer version is already installed; skipping." - ) - return + if org.has_minimum_package_version( + self.namespace, + version, + ): + context.logger.info( + f"{self} or a newer version is already installed; skipping." + ) + return ``` ```513:520:cumulusci/core/dependencies/dependencies.py - if any( - self.version_id == v.id - for v in itertools.chain(*org.installed_packages.values()) - ): - context.logger.info( - f"{self} or a newer version is already installed; skipping." - ) - return + if any( + self.version_id == v.id + for v in itertools.chain(*org.installed_packages.values()) + ): + context.logger.info( + f"{self} or a newer version is already installed; skipping." + ) + return ``` Likely the reporter conflated "Resolving dependencies..." log noise (which always prints) and the unconditional `deploy_unmanaged` / `config_dev` steps in the dev_org flow with managed-package reinstalls. Without a customer project that has managed deps to reproduce against, we cannot disprove a corner case (e.g., `installed_packages` cache invalidation across a particular path). @@ -3475,8 +3305,6 @@ Likely the reporter conflated "Resolving dependencies..." log noise (which alway --- - - ### #3886: Required Dependencies? **Bucket**: A. **Type**: bug (UX/log-noise). **Verdict**: @@ -3490,11 +3318,11 @@ in the `try/except ImportError`. Two transitive imports both, so **every** `extract_dataset` invocation triggers the warning even when no select strategy is configured. -Behavior introduced in PR #3858 / commit `89a5b5ddb` (W-17427085) and +Behavior introduced in PR #3858 / commit `89a5b5ddb` and unchanged through v4.10.0. The reporter's quoted text mentioned `pipx upgrade cumulusci[select]`; v4.10.0 now uses `get_cci_upgrade_command()` which adapts to the install method (e.g. `pip install --upgrade cumulusci[select]`), -so that part of the message has been polished — but the noise persists. +so that part of the message has been polished - but the noise persists. Recommendation: keep-open. Mitigations to consider: @@ -3505,13 +3333,11 @@ Recommendation: keep-open. Mitigations to consider: - Or downgrade to `logger.debug` and add a one-line `logger.warning` only at the point of need. -Repro: `/tmp/repro/11/tests/test_3886_select_warning.py` (2 tests; all pass). +Repro: `_(repro evidence; see narrative)_` (2 tests; all pass). This issue was double-tagged in `themes.md` (bulkdata + dependencies); classified under dependencies here per bundle instructions. - - ### #3889: Uninstall 2GP task request **Verdict**: REPRODUCED-on-v4.10.0 @@ -3522,38 +3348,34 @@ Listed all `Uninstall*` task definitions in `cumulusci.yml` and inspected `Unins **Evidence**: -- `cumulusci/cumulusci.yml:615-642` — Uninstall tasks: `uninstall_managed`, `uninstall_packaged`, `uninstall_packaged_incremental`, `uninstall_src`, `uninstall_pre`, `uninstall_post`. None take a 04t id. -- `cumulusci/tasks/salesforce/UninstallPackage.py:6-32` — `UninstallPackage` accepts only `namespace` (and `purge_on_delete`). Builds an `UninstallPackageZipBuilder` from the namespace. -- `cumulusci/salesforce_api/package_zip.py:290-301` — `UninstallPackageZipBuilder` writes destructiveChanges referencing `InstalledPackage` by namespace; no 04t code path. +- `cumulusci/cumulusci.yml:615-642` - Uninstall tasks: `uninstall_managed`, `uninstall_packaged`, `uninstall_packaged_incremental`, `uninstall_src`, `uninstall_pre`, `uninstall_post`. None take a 04t id. +- `cumulusci/tasks/salesforce/UninstallPackage.py:6-32` - `UninstallPackage` accepts only `namespace` (and `purge_on_delete`). Builds an `UninstallPackageZipBuilder` from the namespace. +- `cumulusci/salesforce_api/package_zip.py:290-301` - `UninstallPackageZipBuilder` writes destructiveChanges referencing `InstalledPackage` by namespace; no 04t code path. - Tooling API `SubscriberPackageVersion` delete or sf cli `package uninstall -p 04t...` is the underlying API the user wants; not wrapped by any CCI task. **Recommended action**: -- pass1: `keep-open` — needs a new `UninstallPackageVersion` task (or extend `UninstallPackage`) that calls Tooling API directly so it doesn't depend on sf cli stability (per the user's note about sf cli breaking changes). +- pass1: `keep-open` - needs a new `UninstallPackageVersion` task (or extend `UninstallPackage`) that calls Tooling API directly so it doesn't depend on sf cli stability (per the user's note about sf cli breaking changes). - pass2 labels: `severity:medium,area:packaging,area:2gp,area:unlocked-package` - - ### #3899: Exception in task deploy_packaging.unschedule_apex **Verdict:** `INCONCLUSIVE-needs-1gp-packaging-org` -**Evidence:** [`/tmp/repro/4/evidence/3899-task-and-error-analysis.txt`](/tmp/repro/4/evidence/3899-task-and-error-analysis.txt) +**Evidence:** [`_(repro evidence)_`](_(repro evidence)_) -The `unschedule_apex` task (cumulusci/cumulusci.yml lines 646–651) runs one line of trivial Apex via the Tooling API: +The `unschedule_apex` task (cumulusci/cumulusci.yml lines 646-651) runs one line of trivial Apex via the Tooling API: ```650:650:cumulusci/cumulusci.yml - apex: "for (CronTrigger t : [SELECT Id FROM CronTrigger]) { System.abortJob(t.Id); }" + apex: "for (CronTrigger t : [SELECT Id FROM CronTrigger]) { System.abortJob(t.Id); }" ``` -Ran cleanly against scratch org `repro-pkg-b2-dev` ("Anonymous Apex Executed Successfully!"). The reporter's error references Salesforce platform-internal Java classes (`system.scheduler.cron.JobType`, `common.udd.constants.CronJobTypeEnum`) — this is a Salesforce platform NullPointerException inside the scheduler subsystem when looking up a CronTrigger's job-type implementation. CCI sends correct Apex; the platform fails to execute it on certain 1GP packaging org configurations. Provisioning a 1GP packaging org via OAuth connected app is outside the scope of this triage. +Ran cleanly against a scratch org ("Anonymous Apex Executed Successfully!"). The reporter's error references Salesforce platform-internal Java classes (`system.scheduler.cron.JobType`, `common.udd.constants.CronJobTypeEnum`) - this is a Salesforce platform NullPointerException inside the scheduler subsystem when looking up a CronTrigger's job-type implementation. CCI sends correct Apex; the platform fails to execute it on certain 1GP packaging org configurations. Provisioning a 1GP packaging org via OAuth connected app is outside the scope of this triage. **Recommendation:** keep `kept-open`. Add a Pass-2 `external/upstream-salesforce` label (or equivalent) so future triage knows the root cause is upstream. Could also be a candidate for "close as not-our-bug" once a Salesforce known-issue reference is found. --- - - ### #3902: `install_managed` `security_type` not respected with 04t ID **Verdict:** `INCONCLUSIVE-needs-managed-package-04t` @@ -3567,23 +3389,23 @@ User reports that running `install_managed` with `--version '04t…'` and `--sec `InstallPackageVersion._init_options` (cumulusci/tasks/salesforce/install_package_version.py) builds `PackageInstallOptions` from task options including `security_type`: ```148:148:cumulusci/tasks/salesforce/install_package_version.py - self.install_options = PackageInstallOptions.from_task_options(self.options) + self.install_options = PackageInstallOptions.from_task_options(self.options) ``` -`PackageInstallOptions.from_task_options` (cumulusci/salesforce_api/package_install.py:67–92) parses `security_type` into the `SecurityType` enum where `SecurityType.ADMIN = "NONE"`. +`PackageInstallOptions.from_task_options` (cumulusci/salesforce_api/package_install.py:67-92) parses `security_type` into the `SecurityType` enum where `SecurityType.ADMIN = "NONE"`. For 04t versions, `_run_task` routes to `PackageVersionIdDependency.install(...)` which calls `install_package_by_version_id(...)` -> `_install_package_by_version_id(...)`. The latter posts the option to the Tooling API: ```165:175:cumulusci/salesforce_api/package_install.py - request = PackageInstallRequest.create( - { - "EnableRss": options.activate_remote_site_settings, - "NameConflictResolution": options.name_conflict_resolution, - "Password": options.password, - "SecurityType": options.security_type, - ... - } - ) + request = PackageInstallRequest.create( + { + "EnableRss": options.activate_remote_site_settings, + "NameConflictResolution": options.name_conflict_resolution, + "Password": options.password, + "SecurityType": options.security_type, + ... + } + ) ``` Runtime serialization confirmed in the venv: @@ -3593,13 +3415,13 @@ $ uv run python -c "import json; from cumulusci.salesforce_api.package_install i {"SecurityType": "NONE"} ``` -`SecurityType` is a `StrEnum` (cumulusci/core/enums.py) with `__str__ = str.__str__`, so JSON serializes via the string base — `SecurityType.ADMIN` -> `"NONE"`. This was hardened previously in commit `502290b8d` (Dec 2022) for Python 3.11 enum changes and again in `402b890e0` (StrEnum migration). +`SecurityType` is a `StrEnum` (cumulusci/core/enums.py) with `__str__ = str.__str__`, so JSON serializes via the string base - `SecurityType.ADMIN` -> `"NONE"`. This was hardened previously in commit `502290b8d` (Dec 2022) for Python 3.11 enum changes and again in `402b890e0` (StrEnum migration). The 04t and namespace+version paths each correctly pass `security_type` to their respective Salesforce APIs (Tooling API `PackageInstallRequest.SecurityType` for 04t, package install zip header for namespace+version). No defect identified in CumulusCI v4.10.0. ### Why INCONCLUSIVE -We do not have a known reusable managed package 04t Id installable into a CCIDevHub-derived scratch to verify the user's runtime observation. Per spec, this verdict is allowed when the prerequisite cannot be provisioned within budget. +We do not have a known reusable managed package 04t Id installable into a the configured DevHub-derived scratch to verify the user's runtime observation. Per spec, this verdict is allowed when the prerequisite cannot be provisioned within budget. ### Possible non-CumulusCI explanations (worth recording for the issue) @@ -3609,76 +3431,70 @@ We do not have a known reusable managed package 04t Id installable into a CCIDev ### Recommendation -- **Pass 1:** needs-info — request reporter to (a) confirm whether the package was being upgraded vs freshly installed, and (b) inspect Salesforce setup audit trail to see the actual `PackageInstallRequest.SecurityType` value at install time. -- **Pass 2 label:** `needs-managed-package-fixture` — without an internal reusable managed package 04t fixture, this class of issue can never be deterministically validated by maintainers. +- **Pass 1:** needs-info - request reporter to (a) confirm whether the package was being upgraded vs freshly installed, and (b) inspect Salesforce setup audit trail to see the actual `PackageInstallRequest.SecurityType` value at install time. +- **Pass 2 label:** `needs-managed-package-fixture` - without an internal reusable managed package 04t fixture, this class of issue can never be deterministically validated by maintainers. --- - - ### #3929: create_community Loop/Timeout During Community Creation **Verdict:** `NOT-REPRODUCED-on-v4.10.0` -**Evidence:** [`/tmp/repro/4/evidence/3929-create_community.log`](/tmp/repro/4/evidence/3929-create_community.log) +**Evidence:** [`_(repro evidence)_`](_(repro evidence)_) -Ran the exact reproduction command against scratch org `repro-pkg-b2-dev`: +Ran the exact reproduction command against a scratch org: ```bash -uv run cci task run create_community --org repro-pkg-b2-dev \ - -o name "TestWebsite" -o template "Customer Service" -o url_path_prefix "testwebsite" +uv run cci task run create_community --org [scratch-org] \ + -o name "TestWebsite" -o template "Customer Service" -o url_path_prefix "testwebsite" ``` -Community `0DBRK000000QtNR4A0` was created in ~117 seconds with normal polling escalation (1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 seconds) and exited the poll loop cleanly. No 300-second timeout, no retry. This matches the OP-thread comment from dipakparmar (2025-10-22): "This issue is no longer happening" — referring to the upstream SF CLI / Communities API fix tracked at forcedotcom/cli#3419. +Community `0DBRK000000QtNR4A0` was created in ~117 seconds with normal polling escalation (1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 seconds) and exited the poll loop cleanly. No 300-second timeout, no retry. This matches the OP-thread comment from dipakparmar (2025-10-22): "This issue is no longer happening" - referring to the upstream SF CLI / Communities API fix tracked at forcedotcom/cli#3419. **Recommendation:** flip currently-proposed `kept-open` → `closed:not-reproducible-on-v4.10.0` (NEW Pass-1 vocabulary per spec amendment). Confirmed working end-to-end with the very command the reporter said hung. - - ### #3931: Specifying a profile in cumulusci.tasks.salesforce.ProfileGrantAllAccess results in an error **Verdict**: REPRODUCED-on-v4.10.0 **Repro type**: bug -**Org used**: none (Python unit repro is sufficient — code path is purely local XML transform) +**Org used**: none (Python unit repro is sufficient - code path is purely local XML transform) **Method**: Read `cumulusci/tasks/salesforce/update_profile.py`. Spotted the suspect line: ```290:292:cumulusci/tasks/salesforce/update_profile.py - for elem in tree.findall("layoutAssignments"): - if elem.find("recordType").text == rt["record_type"]: - elem.layout.text = layout_option + for elem in tree.findall("layoutAssignments"): + if elem.find("recordType").text == rt["record_type"]: + elem.layout.text = layout_option ``` -`elem.find("recordType")` returns `None` whenever a `layoutAssignments` element has no `recordType` child (which is valid metadata — a layoutAssignments without recordType applies to records lacking a record-type binding). The subsequent `.text` then raises `AttributeError: 'NoneType' object has no attribute 'text'` — exactly the user's reported error. +`elem.find("recordType")` returns `None` whenever a `layoutAssignments` element has no `recordType` child (which is valid metadata - a layoutAssignments without recordType applies to records lacking a record-type binding). The subsequent `.text` then raises `AttributeError: 'NoneType' object has no attribute 'text'` - exactly the user's reported error. -Wrote `/tmp/repro/5/tests/issue-3931/repro_unit.py` that builds an in-memory profile XML matching that shape (one `` with `Account-Account Layout` and no recordType, plus one with both children) and calls `_set_record_types`. Output: +Wrote `_(repro evidence; see narrative)_` that builds an in-memory profile XML matching that shape (one `` with `Account-Account Layout` and no recordType, plus one with both children) and calls `_set_record_types`. Output: ``` Traceback (most recent call last): - File "/tmp/repro/5/tests/issue-3931/repro_unit.py", line 64, in main - task._set_record_types(tree, "Admin") - File "...update_profile.py", line 291, in _set_record_types - if elem.find("recordType").text == rt["record_type"]: - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "_(repro evidence; see narrative)_", line 64, in main + task._set_record_types(tree, "Admin") + File "...update_profile.py", line 291, in _set_record_types + if elem.find("recordType").text == rt["record_type"]: + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AttributeError: 'NoneType' object has no attribute 'text' REPRODUCED: AttributeError raised: 'NoneType' object has no attribute 'text' ``` **Recommended action**: -- pass1: `keep-open` — small, contained fix. +- pass1: `keep-open` - small, contained fix. - pass2 labels: `bug` -**Notes**: Minimal fix at update_profile.py:290-293 — bind `rt_elem = elem.find("recordType")` and check `if rt_elem is not None and rt_elem.text == rt["record_type"]`. Worth a quick scan of sibling code in `_set_record_types` for similar None-deref patterns on optional XML children. +**Notes**: Minimal fix at update_profile.py:290-293 - bind `rt_elem = elem.find("recordType")` and check `if rt_elem is not None and rt_elem.text == rt["record_type"]`. Worth a quick scan of sibling code in `_set_record_types` for similar None-deref patterns on optional XML children. --- - - ### #3936: HTTPSConnectionPool Read timed out (kept-open) -**Verdict:** `INCONCLUSIVE-needs-flaky-network` — but a structural gap is confirmed +**Verdict:** `INCONCLUSIVE-needs-flaky-network` - but a structural gap is confirmed `get_simple_salesforce_connection` in `cumulusci/salesforce_api/utils.py:13-51` constructs `simple_salesforce.Salesforce(...)` with no timeout kwarg and only retries `502/503/504` via `Retry(total=5, backoff_factor=0.3)`. No CCI-side task option, project setting, or env var exposes connect / read timeout for Salesforce REST or Bulk API calls. `cumulusci.yml` has no `timeout` entry. @@ -3686,9 +3502,7 @@ The reported error `Read timed out. (read timeout=None)` with `timeout=None` typ The structural gap (no exposed timeout) is REPRODUCED. The actual flaky behavior is environment-dependent (corporate VPN) and not reproducible in CI without that environment. -This issue is already maintainer-labelled `kept-open`. **Recommended pass1: `unchanged`**. v5 candidacy: yes — add timeout option to `get_simple_salesforce_connection` and to bulk-job polling, plus a documented `cci org refresh` retry path for VPN-induced disconnects. - - +This issue is already maintainer-labelled `kept-open`. **Recommended pass1: `unchanged`**. v5 candidacy: yes - add timeout option to `get_simple_salesforce_connection` and to bulk-job polling, plus a documented `cci org refresh` retry path for VPN-induced disconnects. ### #3938: Rest_Deploy ignores errors @@ -3703,25 +3517,23 @@ and a `componentFailures` list. **Evidence**: -- `cumulusci/salesforce_api/rest_deploy.py:101-120` — +- `cumulusci/salesforce_api/rest_deploy.py:101-120` - `_monitor_deploy_status` logs `componentFailures` then `return`s without raising. -- `cumulusci/salesforce_api/rest_deploy.py:75-85` — `__call__` only logs +- `cumulusci/salesforce_api/rest_deploy.py:75-85` - `__call__` only logs when initial POST is non-201; never raises. - Test output: `test_issue_3938_rest_deploy_failure_does_not_raise` exits the patched call with no exception, confirming the silent-success bug. **Recommended action**: -- pass1: keep-open — CRITICAL severity; should raise `MetadataApiError` / +- pass1: keep-open - CRITICAL severity; should raise `MetadataApiError` / `MetadataComponentFailure` on Failed status, mirroring the SOAP `ApiDeploy` behavior. - pass2 labels: `severity:critical,area:rest-deploy,type:bug,silent-failure` --- - - ### #3939: Deploy task can't parse SOAP Response **Verdict**: REPRODUCED-on-v4.10.0 @@ -3740,9 +3552,9 @@ matches the exact message text in the user report. **Evidence**: -- `cumulusci/salesforce_api/metadata.py:71-76` — wraps every exception +- `cumulusci/salesforce_api/metadata.py:71-76` - wraps every exception thrown inside `_process_response`. -- `cumulusci/salesforce_api/metadata.py:509,520,540,544` — places where +- `cumulusci/salesforce_api/metadata.py:509,520,540,544` - places where intentional MDAPI exceptions are raised inside `_process_response`. - Test output: `test_issue_3939_deploy_apex_test_failure_swallowed` observed final message @@ -3751,71 +3563,67 @@ matches the exact message text in the user report. **Recommended action**: -- pass1: keep-open — the wrapping `except Exception` should re-raise CCI's +- pass1: keep-open - the wrapping `except Exception` should re-raise CCI's own `CumulusCIException` subclasses (`MetadataApiError`, `MetadataComponentFailure`, `ApexTestException`) untouched and only wrap truly unexpected errors. - pass2 labels: `severity:high,area:salesforce-api,type:bug,error-handling` - - ### #3951: set_duplicate_rule_status broken **Verdict**: REPRODUCED-on-v4.10.0 **Repro type**: bug (UX/error-message) -**Org used**: `repro-etl-b-dev` +**Org used**: `[scratch-org]` **Method**: Live repro using the exact CLI from the bug report: ``` -uv run cci task run set_duplicate_rule_status --org repro-etl-b-dev \ - -o api_names "Standard_Rule_for_Leads_with_Duplicate_Contacts" \ - -o active False +uv run cci task run set_duplicate_rule_status --org [scratch-org] \ + -o api_names "Standard_Rule_for_Leads_with_Duplicate_Contacts" \ + -o active False ``` -Result (saved at `/tmp/repro/5/tests/issue-3951/output-no-prefix.txt`): +Result (saved at `_(repro evidence)_`): ``` Error: Cannot find metadata file /var/.../retrieve/duplicateRules/Standard_Rule_for_Leads_with_Duplicate_Contacts.duplicateRule ``` -Identical error wording as the user's report. Then ran the same command with the canonical Metadata API format `Lead.Standard_Rule_for_Leads_with_Duplicate_Contacts` — the task succeeded end-to-end (extract → transform → deploy → Success). The `SetDuplicateRuleStatus` task itself is functional; the bug is the unhelpful error when the user omits the `.` prefix that DuplicateRule API names require. +Identical error wording as the user's report. Then ran the same command with the canonical Metadata API format `Lead.Standard_Rule_for_Leads_with_Duplicate_Contacts` - the task succeeded end-to-end (extract → transform → deploy → Success). The `SetDuplicateRuleStatus` task itself is functional; the bug is the unhelpful error when the user omits the `.` prefix that DuplicateRule API names require. Same root cause as #3613 (api_name format mismatch surfaces as the generic `Cannot find metadata file` from `MetadataSingleEntityTransformTask._transform` base.py:332). **Recommended action**: -- pass1: `improve-error-message` — keep open. +- pass1: `improve-error-message` - keep open. - pass2 labels: `bug`, `good-first-issue`, `documentation` **Notes**: Two improvements: 1. Update the `set_duplicate_rule_status` task option help to call out the `.` format requirement. -2. Same as #3613 — improve the base.py:332 error to list the files actually retrieved. +2. Same as #3613 - improve the base.py:332 error to list the files actually retrieved. The `Cannot find metadata file` error is shared across most `MetadataSingleEntityTransformTask` subclasses, so a single base-class fix would benefit several issues at once. --- - - ### #3953: add_picklist_entries never works through CLI **Verdict**: REPRODUCED-on-v4.10.0 **Repro type**: bug -**Org used**: `repro-etl-b-dev` +**Org used**: `[scratch-org]` **Method**: Live repro using the exact CLI from the bug report: ``` -uv run cci task run add_picklist_entries --org repro-etl-b-dev \ - -o picklists "Account.Status__c" \ - -o entries '[{"fullName": "TestValue", "label": "Test Value"}]' +uv run cci task run add_picklist_entries --org [scratch-org] \ + -o picklists "Account.Status__c" \ + -o entries '[{"fullName": "TestValue", "label": "Test Value"}]' ``` -Result (saved at `/tmp/repro/5/tests/issue-3953/output.txt`): +Result (saved at `_(repro evidence)_`): ``` Error: The 'fullName' key is required on all picklist values. @@ -3825,30 +3633,24 @@ Identical to user's report. Root cause confirmed by reading `cumulusci/tasks/metadata_etl/picklists.py`: -- Line 51: `process_list_arg(self.options["picklists"])` — runs through the list-arg parser. -- Line 68: `if not all(["fullName" in entry for entry in self.options["entries"]])` — iterates `entries` directly without parsing. +- Line 51: `process_list_arg(self.options["picklists"])` - runs through the list-arg parser. +- Line 68: `if not all(["fullName" in entry for entry in self.options["entries"]])` - iterates `entries` directly without parsing. - The CLI passes `entries` through as a JSON string. Iteration walks characters of `'[{"fullName": "TestValue", ...}]'`; none of the characters contain the substring `"fullName"`; `all(...)` returns False; error raised. **Recommended action**: -- pass1: `keep-open` — single-line fix. +- pass1: `keep-open` - single-line fix. - pass2 labels: `bug`, `good-first-issue` **Notes**: Minimal fix in `AddPicklistEntries._init_options`: `if isinstance(self.options.get("entries"), str): self.options["entries"] = json.loads(self.options["entries"])`. Apply same pattern to `record_types` for symmetry. The same class of bug exists in `AddFieldsToPageLayout` (encountered while investigating #3613): `cci task run add_page_layout_fields ... -o fields '[...]'` -> `pydantic.ValidationError: value is not a valid list`. A more general fix would be a helper in the CLI/task-base that auto-parses JSON strings for list-typed options, or schema-driven coercion via the new task_options Pydantic models. --- -## Round 3 (2026-05-13 → 2026-05-14) - -Themes: robotframework (subagent 13), scratch-org-config (subagent 14), auth (subagent 15), keychain (subagent 16), docs (subagent 17), python-modernization (subagent 18). +Themes: robotframework (the triage), scratch-org-config (the triage), auth (the triage), keychain (the triage), docs (the triage), python-modernization (the triage). Scope: 17 issues across 6 themes, all against `origin/dev` @ `1925a3083` (NOT v4.10.0 like Rounds 1+2). -Verdicts: 12 REPRODUCED-on-dev, 5 NOT-REPRODUCED-on-dev. 10 `xfail` tests staged at `/tmp/repro/{13..18}/tests/`. - - +Verdicts: 12 REPRODUCED-on-dev, 5 NOT-REPRODUCED-on-dev. 10 `xfail` tests staged at `_(repro evidence)_`. -# Subagent 13 (rf) — Round 3 robotframework triage - -Worktree: `.worktrees/repro-rf` (`worktree/repro/rf` @ `1925a3083` on `origin/dev`). +Worktree: the triage worktree (the triage worktree @ `1925a3083` on `origin/dev`). 5 issues processed: #3955, #3873, #675, #987, #3602. @@ -3862,14 +3664,14 @@ Worktree: `.worktrees/repro-rf` (`worktree/repro/rf` @ `1925a3083` on `origin/de **Evidence**: -- `cumulusci/robotframework/SalesforcePlaywright.py:106` — `width, height = size.split("x", 1)` returns two `str` values. -- `cumulusci/robotframework/SalesforcePlaywright.py:109-111` — the strings are forwarded directly: +- `cumulusci/robotframework/SalesforcePlaywright.py:106` - `width, height = size.split("x", 1)` returns two `str` values. +- `cumulusci/robotframework/SalesforcePlaywright.py:109-111` - the strings are forwarded directly: - ```python - context_id = self.browser.new_context( - viewport={"width": width, "height": height}, recordVideo=record_video - ) - ``` +```python +context_id = self.browser.new_context( +viewport={"width": width, "height": height}, recordVideo=record_video +) +``` - Playwright contract requires `viewport.width` / `viewport.height` to be `int`, hence the runtime error `viewport.width: expected integer, got string` reported by the user (and confirmed by commenter @rasjani's pointer to lines 106-111). @@ -3877,13 +3679,13 @@ Worktree: `.worktrees/repro-rf` (`worktree/repro/rf` @ `1925a3083` on `origin/de - Approach: cast both fragments to `int` immediately after splitting. - Target: `cumulusci/robotframework/SalesforcePlaywright.py:106` -- Size: small (~1 line) — e.g. `width, height = (int(v) for v in size.split("x", 1))` -- Risk: low — preserves all existing call sites; users were already passing the documented `WxH` string format. +- Size: small (~1 line) - e.g. `width, height = (int(v) for v in size.split("x", 1))` +- Risk: low - preserves all existing call sites; users were already passing the documented `WxH` string format. - API break: no. **Recommended action**: -- pass1: `keep-open` — clear, low-risk, single-line bug fix; great good-first-issue candidate. +- pass1: `keep-open` - clear, low-risk, single-line bug fix; great good-first-issue candidate. - pass2 labels: `bug, robotframework, playwright, good-first-issue` - triage test: `cumulusci/tests/triage/test_issue_3955.py` @@ -3897,8 +3699,8 @@ Worktree: `.worktrees/repro-rf` (`worktree/repro/rf` @ `1925a3083` on `origin/de **Evidence**: -- `cumulusci/robotframework/base_library.py:1-39` — `BaseLibrary` lazily resolves `cumulusci.robotframework.CumulusCI`, `cumulusci.robotframework.Salesforce`, `cumulusci.robotframework.SalesforceAPI` libraries through Robot's `BuiltIn`, which require a CumulusCI project context. -- `cumulusci/robotframework/Salesforce.py:20-28` — imports `cumulusci.robotframework.locator_manager`, `faker_mixin`, `form_handlers`, plus the rest of the cci core that ships in the same package. +- `cumulusci/robotframework/base_library.py:1-39` - `BaseLibrary` lazily resolves `cumulusci.robotframework.CumulusCI`, `cumulusci.robotframework.Salesforce`, `cumulusci.robotframework.SalesforceAPI` libraries through Robot's `BuiltIn`, which require a CumulusCI project context. +- `cumulusci/robotframework/Salesforce.py:20-28` - imports `cumulusci.robotframework.locator_manager`, `faker_mixin`, `form_handlers`, plus the rest of the cci core that ships in the same package. - There is no standalone distribution; the Salesforce/SalesforcePlaywright libraries cannot be installed without the full `cumulusci` wheel and project layout. **Proposed fix sketch**: @@ -3906,14 +3708,14 @@ Worktree: `.worktrees/repro-rf` (`worktree/repro/rf` @ `1925a3083` on `origin/de - Approach: factor a UI-only subset out of `cumulusci.robotframework.*` into a sibling distribution (e.g. `salesforce-robot-library`) that depends only on Selenium/Playwright + the locator dictionaries; have CumulusCI's Robot task consume that subset. - Target: package layout change spanning `cumulusci/robotframework/` and `pyproject.toml`. - Size: large (>100 lines, design change + new distribution). -- Risk: medium — must not break existing tasks/keywords. +- Risk: medium - must not break existing tasks/keywords. - API break: no (additive new distribution). **Recommended action**: -- pass1: `keep-open` — reasonable architectural request, age <24mo, no community PR yet; worth retaining as roadmap signal. +- pass1: `keep-open` - reasonable architectural request, age <24mo, no community PR yet; worth retaining as roadmap signal. - pass2 labels: `enhancement, robotframework, scope-large` -- triage test: n/a — no concrete API to xfail against. +- triage test: n/a - no concrete API to xfail against. --- @@ -3933,14 +3735,14 @@ Worktree: `.worktrees/repro-rf` (`worktree/repro/rf` @ `1925a3083` on `origin/de - Approach: in `Robot._init_options`, default `options.loglevel` to include `TRACE`, OR install a small listener that captures `sys.exc_info()` in keyword-end events and emits a formatted traceback through `robot.api.logger.error`. - Target: `cumulusci/tasks/robotframework/robotframework.py:104` (`_init_options`). - Size: small (~10 lines). -- Risk: low — additive listener; opt-out via options if needed. +- Risk: low - additive listener; opt-out via options if needed. - API break: no. **Recommended action**: -- pass1: `closed:stale-24mo` — issue opened 2018-07, last activity 2018-09, ~8 years inactivity. Two simple workarounds exist (`-o loglevel:TRACE`, `traceback.format_exc()` in keywords). Surface as a tip in docs rather than keep the bug open. +- pass1: `closed:stale-24mo` - issue opened 2018-07, last activity 2018-09, ~8 years inactivity. Two simple workarounds exist (`-o loglevel:TRACE`, `traceback.format_exc()` in keywords). Surface as a tip in docs rather than keep the bug open. - pass2 labels: `cli-usability, robotframework, stale` -- triage test: n/a — observable only in a robot run. +- triage test: n/a - observable only in a robot run. --- @@ -3952,18 +3754,18 @@ Worktree: `.worktrees/repro-rf` (`worktree/repro/rf` @ `1925a3083` on `origin/de **Evidence**: -- Issue specifies Salesforce Spring 19, chromedriver 2.46.628411, chrome 72.0.3626.109 — all extinct. -- Reporter posted on 2019-02-18: _"@davisagli I figured out a work-around. Use firefox with geckodriver. Everything works as intended now."_ — i.e. accepted a working alternative. +- Issue specifies Salesforce Spring 19, chromedriver 2.46.628411, chrome 72.0.3626.109 - all extinct. +- Reporter posted on 2019-02-18: _"@davisagli I figured out a work-around. Use firefox with geckodriver. Everything works as intended now."_ - i.e. accepted a working alternative. - `cumulusci/robotframework/Salesforce.py:154` `click_object_button` still calls `_jsclick`, which has been the workaround pattern for shadow-DOM-aware clicks for years; current Selenium 4 / Salesforce Lightning UI no longer surfaces the original `Cannot read property 'defaultView' of undefined` error in the same form. - Last comment 2022-06 (davidmreed asking if still impacted; no response). -**Proposed fix sketch**: n/a — environment-specific historical bug. +**Proposed fix sketch**: n/a - environment-specific historical bug. **Recommended action**: -- pass1: `closed:stale-24mo` — reporter has a workaround, root cause was Spring 19 specific, 7+ years stale, last activity 2022-06 (still 4 years ago). +- pass1: `closed:stale-24mo` - reporter has a workaround, root cause was Spring 19 specific, 7+ years stale, last activity 2022-06 (still 4 years ago). - pass2 labels: `stale, user-error` -- triage test: n/a — would require a live 2019 org snapshot. +- triage test: n/a - would require a live 2019 org snapshot. --- @@ -3975,8 +3777,8 @@ Worktree: `.worktrees/repro-rf` (`worktree/repro/rf` @ `1925a3083` on `origin/de **Evidence**: -- `cumulusci/robotframework/SalesforcePlaywright.py:60-62` — `def open_test_browser(self, size=None, useralias=None, wait=True, record_video=None):` has no `browser_options`/`extra_options`/`**kwargs` hook. -- `cumulusci/robotframework/Salesforce.robot:103` — Selenium keyword signature `[Arguments] ${size}=... ${alias}=${NONE} ${wait}=True ${useralias}=${NONE}` — same gap. +- `cumulusci/robotframework/SalesforcePlaywright.py:60-62` - `def open_test_browser(self, size=None, useralias=None, wait=True, record_video=None):` has no `browser_options`/`extra_options`/`**kwargs` hook. +- `cumulusci/robotframework/Salesforce.robot:103` - Selenium keyword signature `[Arguments] ${size}=... ${alias}=${NONE} ${wait}=True ${useralias}=${NONE}` - same gap. - `cumulusci/robotframework/Salesforce.robot:157-168` `Get Chrome Options` hard-codes a single `--disable-notifications` argument with no extension hook. - Users cannot load Chrome extensions, switch to incognito, change download directory or accept self-signed certs without a fork of `Salesforce.robot`. @@ -3986,20 +3788,16 @@ Worktree: `.worktrees/repro-rf` (`worktree/repro/rf` @ `1925a3083` on `origin/de - Approach (Selenium): expose a `${EXTRA_CHROME_OPTIONS}` variable / list argument honoured by `Get Chrome Options`; alternatively add an `extra_options` argument to `Open Test Browser` and pipe through to `Create Webdriver With Retry`. - Target: `cumulusci/robotframework/SalesforcePlaywright.py:60-117`; `cumulusci/robotframework/Salesforce.robot:77-168`. - Size: medium (~30-60 lines across both implementations + tests + docs). -- Risk: low — additive parameter with safe default. +- Risk: low - additive parameter with safe default. - API break: no (default `None` preserves current behaviour). **Recommended action**: -- pass1: `keep-open` — reasonable, scoped feature ask; age <36mo; no PR yet; tractable medium-sized contribution. +- pass1: `keep-open` - reasonable, scoped feature ask; age <36mo; no PR yet; tractable medium-sized contribution. - pass2 labels: `enhancement, robotframework, playwright, good-second-issue` - triage test: `cumulusci/tests/triage/test_issue_3602.py` - - -# Subagent 14 — scratch-org-config theme, Round 3 - -Working tree: `.worktrees/repro-scratch` on `worktree/repro/scratch` off `origin/dev` at `1925a3083`. +Working tree: the triage worktree on the triage worktree off `origin/dev` at `1925a3083`. Triaged 3 issues (#3910, #3306, #710). All three remain actionable on dev: #3910 has an open fix PR; #3306 and #710 are never-implemented enhancements. @@ -4015,7 +3813,7 @@ Triaged 3 issues (#3910, #3306, #710). All three remain actionable on dev: #3910 - The actual runtime path (`BaseProjectKeychain.create_scratch_org` at `cumulusci/core/keychain/base_project_keychain.py:74`, then `ScratchOrgConfig._build_org_create_args` at `cumulusci/core/config/scratch_org_config.py:143`) bypasses the Pydantic model via `project_config.lookup`, so booleans set in YAML survive at runtime. The user-visible impact is therefore: editors that consume the JSON schema reject `namespaced: true`/`false` (boolean) in `cumulusci.yml`, and `make schema` regenerates the same incorrect schema until the model is fixed. - Open PR [#3911](https://github.com/SFDO-Tooling/CumulusCI/pull/3911) (base `main`, branch `fix/namespaced-config-value-type-in-schema`) correctly fixes both files. State on 2026-05-14: OPEN, not merged. -**Repro test:** `/tmp/repro/14/tests/test_issue_3910.py` — 4 XFAILs against the schema JSON, the live Pydantic schema, and the model's coercion of booleans. +**Repro test:** `cumulusci/tests/triage/test_issue_3910.py` - 4 XFAILs against the schema JSON, the live Pydantic schema, and the model's coercion of booleans. **Proposed fix sketch** @@ -4033,9 +3831,9 @@ Triaged 3 issues (#3910, #3306, #710). All three remain actionable on dev: #3910 - `cci org scratch` already supports `--release preview|previous` (`cumulusci/cli/org.py:567-579`) and threads it through `BaseProjectKeychain.create_scratch_org` (`cumulusci/core/keychain/base_project_keychain.py:57-84`) to `ScratchOrgConfig._build_org_create_args` (`cumulusci/core/config/scratch_org_config.py:149-150`). - `cci flow run` (`cumulusci/cli/flow.py:119-200`) has no `--release` / `--preview` flag. The flow path also auto-recreates expired scratch orgs in `cumulusci/cli/runtime.py:106-114` without forwarding any release argument. -- Internally tracked as W-11486409; no PR opened in 4 years. +- Internally tracked as [internal-ID-redacted]; no PR opened in 4 years. -No test written — this is a clean enhancement request whose API surface (`--preview` vs `--release` flag, behaviour with non-scratch orgs, behaviour when `release` is already set in YAML) is not yet specced. +No test written - this is a clean enhancement request whose API surface (`--preview` vs `--release` flag, behaviour with non-scratch orgs, behaviour when `release` is already set in YAML) is not yet specced. ### #710: Allow disabling default scratch org configs @@ -4047,7 +3845,7 @@ No test written — this is a clean enhancement request whose API surface (`--pr - `BaseProjectKeychain._load_scratch_orgs` (`cumulusci/core/keychain/base_project_keychain.py:149-159`) iterates every key under `orgs.scratch` and calls `create_scratch_org` unconditionally. - `merge_config` (`cumulusci/core/utils.py:158`) calls `dictmerge`, which drops a `None` value from the project-side override (`{"orgs": {"scratch": {"dev": {"config_file": None}}}}` merged with the universal config still resolves to the universal's `config_file: orgs/dev.json`). The exact syntax proposed by the issue therefore has no effect. -**Repro test:** `/tmp/repro/14/tests/test_issue_710.py` — 2 XFAILs. One asserts that the project-side `config_file: None` override survives `merge_config`; the other asserts the resulting keychain does not load `dev`. +**Repro test:** `cumulusci/tests/triage/test_issue_710.py` - 2 XFAILs. One asserts that the project-side `config_file: None` override survives `merge_config`; the other asserts the resulting keychain does not load `dev`. **Proposed fix sketch** @@ -4057,9 +3855,7 @@ No test written — this is a clean enhancement request whose API surface (`--pr - Risk: low. Existing keys remain compatible; only adds new opt-in behaviour. Needs a docs note (`docs/orgs/scratch.md`) on how to disable inherited defaults. - API break: no (additive). The issue's literal `config_file: None` syntax would NOT be honoured under this proposal; if the team prefers that exact syntax instead, add a `dictmerge` exception so `None` overrides under `orgs.scratch.*` are preserved, then have `_load_scratch_orgs` skip entries with `config_file is None`. Either implementation satisfies the XFAIL test (`dev not in keychain.orgs`). - - -### #2667 — `cci org connect` should output the name of the connected app it is using +### #2667 - `cci org connect` should output the name of the connected app it is using **Theme**: auth · **Bucket**: enhancement (cli-output) · **Verdict**: `NOT-REPRODUCED-on-dev` @@ -4068,21 +3864,21 @@ No test written — this is a clean enhancement request whose API surface (`--pr **Status on `origin/dev` @ `1925a3083`**: Implemented. `cumulusci/cli/org.py` `org_connect` resolves the connected-app name (CLI flag → keychain default) and emits, before initiating OAuth: ```204:209:cumulusci/cli/org.py - click.echo(f"Connecting org using the {connected_app_name} connected app...") - connected_app = runtime.keychain.get_service("connected_app", connected_app_name) - sf_client = setup_client(connected_app, login_url, sandbox) - connect_org_to_keychain( - sf_client, runtime, global_org, org_name, connected_app_name - ) + click.echo(f"Connecting org using the {connected_app_name} connected app...") + connected_app = runtime.keychain.get_service("connected_app", connected_app_name) + sf_client = setup_client(connected_app, login_url, sandbox) + connect_org_to_keychain( + sf_client, runtime, global_org, org_name, connected_app_name + ) ``` The connected_app name is also persisted onto the new `OrgConfig` (`org_config.config["connected_app"] = connected_app`, line 155), addressing davisagli's follow-up that orgs should remember which connected app authorized them. **Implementation history** (via `git log -L`): -- `8fe1910b1` "refactor into separate methods" — split out `connect_org_to_keychain` and `setup_client`. -- `40520bee4` "checkpoint" (2022-01-31) — introduced the `connected_app_name` resolution and the `click.echo` line. This is the commit that closes the loop on this issue. Matches davidmreed's 2022-01-28 comment "Covering in W-9863651". -- `719d40260` "more tests, use the stored connected_app" — added test coverage and passed `connected_app_name` through to `connect_org_to_keychain` so it is stored on the org. +- `8fe1910b1` "refactor into separate methods" - split out `connect_org_to_keychain` and `setup_client`. +- `40520bee4` "checkpoint" (2022-01-31) - introduced the `connected_app_name` resolution and the `click.echo` line. This is the commit that closes the loop on this issue. Matches davidmreed's 2022-01-28 comment "Covering in [internal-ID-redacted]". +- `719d40260` "more tests, use the stored connected_app" - added test coverage and passed `connected_app_name` through to `connect_org_to_keychain` so it is stored on the org. **Test coverage already present**: @@ -4091,17 +3887,13 @@ The connected_app name is also persisted onto the new `OrgConfig` (`org_config.c Both pass on dev (verified locally; 10/10 `test_org_connect*` tests pass). -**Recommendation**: `close-stale` with labels `resolved,implemented`. The exact phrasing differs from the issue's mock-up (`"Connecting org using the X connected app..."` vs `"Using connected_app 'X'"`), but the substantive ask — surfacing the connected-app identity at connection time — is satisfied. davisagli's deeper suggestions (configurable production/sandbox login URLs per connected app; auto-pick connected_app from login URL) are out of scope for this ticket and can be filed separately if still wanted. - - +**Recommendation**: `close-stale` with labels `resolved,implemented`. The exact phrasing differs from the issue's mock-up (`"Connecting org using the X connected app..."` vs `"Using connected_app 'X'"`), but the substantive ask - surfacing the connected-app identity at connection time - is satisfied. davisagli's deeper suggestions (configurable production/sandbox login URLs per connected app; auto-pick connected_app from login URL) are out of scope for this ticket and can be filed separately if still wanted. -# Subagent 16 (keychain) — Round 3 narrative - -Worktree: `.worktrees/repro-keychain` @ `1925a3083` (off `origin/dev`). +Worktree: the triage worktree @ `1925a3083` (off `origin/dev`). Issues processed: 3/3 (#2126, #3407, #3541). Verdict tally: 1 NOT-REPRODUCED (feature/stale), 2 REPRODUCED-on-dev. -### #2126 — Probabilistic-encryption task +### #2126 - Probabilistic-encryption task **Classification**: feature request, theme-mismatched (Shield Platform Encryption, not keychain). @@ -4116,10 +3908,10 @@ in the comments; the issue is 5+ years stale. **Verdict**: `NOT-REPRODUCED-on-dev` (feature scope; no bug to reproduce). **Pass-1 recommendation**: `closed:stale-24mo`. Pass-2 labels: `area/metadata-etl`, -`blocked` (theme correction). No fix sketch — close or hand off to the +`blocked` (theme correction). No fix sketch - close or hand off to the metadata-ETL theme owner with a stale-feature ping. -### #3407 — `set_service(service_config)` annotation lies +### #3407 - `set_service(service_config)` annotation lies **Classification**: typing/API-consistency bug, still present on dev. @@ -4133,9 +3925,9 @@ metadata-ETL theme owner with a stale-feature ping. - `_set_service` (encrypted_file_project_keychain.py:583-605) explicitly short-circuits when `self.key and config_encrypted` and treats `service_config` as the already-serialised payload, so the call is - semantically correct — the annotation is what's wrong. + semantically correct - the annotation is what's wrong. -The two-test repro (`/tmp/repro/16/tests/test_issue_3407.py`) introspects the +The two-test repro (`cumulusci/tests/triage/test_issue_3407.py`) introspects the annotation, confirms a string call site exists in `_load_service_files`, and exercises the runtime path with a string payload via a `BaseProjectKeychain` subclass. Both xfail on dev. @@ -4145,9 +3937,9 @@ subclass. Both xfail on dev. - **Approach**: Widen the annotation. `set_service`'s `service_config` parameter should be `Union[ServiceConfig, str]` (or `ServiceConfig | str | bytes`) and the docstring updated to say "raw encrypted payload when - `config_encrypted=True`". The deeper refactor — splitting the API into + `config_encrypted=True`". The deeper refactor - splitting the API into `set_service` (validated `ServiceConfig`) and `set_encrypted_service` - (raw blob) — is cleaner but breaks the public API and is out of scope + (raw blob) - is cleaner but breaks the public API and is out of scope for this triage pass. - **Target**: `cumulusci/core/keychain/base_project_keychain.py:202-219`. Also add the same widened annotation on the abstract `_set_service` @@ -4160,7 +3952,7 @@ bytes`) and the docstring updated to say "raw encrypted payload when - **API break**: no. Widening a parameter type is non-breaking for callers. -### #3541 — `None__dev` SFDX alias +### #3541 - `None__dev` SFDX alias **Classification**: real bug, mis-labelled `cannot-reproduce`. @@ -4168,11 +3960,11 @@ bytes`) and the docstring updated to say "raw encrypted payload when - `cumulusci/core/keychain/base_project_keychain.py` lines 77-79: - ```python - scratch_config["sfdx_alias"] = ( - f"{self.project_config.project__name}__{org_name}" - ) - ``` +```python +scratch_config["sfdx_alias"] = ( +f"{self.project_config.project__name}__{org_name}" +) +``` - When `project_config.project__name` is None (cumulusci.yml without a `project.name`, or partially-loaded project_config), this f-string @@ -4187,7 +3979,7 @@ bytes`) and the docstring updated to say "raw encrypted payload when target-org={alias}` at `base_project_keychain.py:99`, producing the reporter's symptom. -Two xfail tests in `/tmp/repro/16/tests/test_issue_3541.py` build a +Two xfail tests in `cumulusci/tests/triage/test_issue_3541.py` build a `BaseProjectConfig` without `project.name`, drive both the direct `create_scratch_org` path and the eager-init `_load_scratch_orgs` path, and assert the resulting alias contains no literal `'None'` token. Both fail on @@ -4196,7 +3988,7 @@ dev. **Proposed fix sketch** - **Approach**: Guard the alias construction. Two reasonable options: - (1) raise `CumulusCIException("Cannot build sfdx_alias: project.name is not set in cumulusci.yml")` — surfaces the misconfiguration at the earliest possible moment. + (1) raise `CumulusCIException("Cannot build sfdx_alias: project.name is not set in cumulusci.yml")` - surfaces the misconfiguration at the earliest possible moment. (2) Fall back to `f"{org_name}"` (no prefix) when `project__name` is None, with a `logger.warning`. Less disruptive for existing setups. Option 2 is the safer change; option 1 is the more correct one. Pick based on willingness to break first-run UX. @@ -4215,19 +4007,15 @@ dev. - **API break**: no public API change. The `OrgConfig.sfdx_alias` field shape is preserved; only its derivation logic shifts. -- **Bonus**: remove the `cannot-reproduce` label — the repro here is +- **Bonus**: remove the `cannot-reproduce` label - the repro here is deterministic. - - -# Subagent 17 (docs) — Round 3 narrative - -Worktree: `.worktrees/repro-docs` @ `1925a3083` (off `origin/dev`). +Worktree: the triage worktree @ `1925a3083` (off `origin/dev`). Issues processed: 3/3 (#773, #2500, #3464). Verdict tally: 3 REPRODUCED-on-dev (all pure doc-gaps with code-level testable assertions). -### #773 — Document task return values and results +### #773 - Document task return values and results **Classification**: feature-with-doc-component (needs a small framework hook + matching renderer + the docs themselves). @@ -4242,7 +4030,7 @@ hook + matching renderer + the docs themselves). - `doc_task()` (`cumulusci/utils/__init__.py:354`) walks `task_options` and a free-form `task_docs` string and emits "Description", "Class", "Command Syntax", and "Options" sections. There is no "Return Values" - or "Returns" section — and no plumbing to add one. + or "Returns" section - and no plumbing to add one. - `cci task info ` is implemented by `cumulusci/cli/task.py:99`, which delegates straight to `doc_task`, so it has the same gap. - The docs themselves admit this. `docs/config.md:740-744` includes an @@ -4251,7 +4039,7 @@ hook + matching renderer + the docs themselves). any) requires you to read the source code for the given task."_ So 8 years after the issue was filed, the documented workaround in the -docs is still "read the source". The repro test (`/tmp/repro/17/tests/test_issue_773.py`) +docs is still "read the source". The repro test (`cumulusci/tests/triage/test_issue_773.py`) runs `doc_task` against a real shipping task (`PackageUpload`, whose `_set_return_values()` populates `version_number` / `version_id` / `package_id`) and asserts the rendered RST mentions any of those keys. @@ -4275,7 +4063,7 @@ description (parallel to how `task_options` already works). `task_class.return_values_schema` is non-empty. Update the matching `get_task_*` helpers to surface the schema for web-doc generation. -3. Backfill the schema on tasks that already emit return values — search +3. Backfill the schema on tasks that already emit return values - search for `self.return_values\[` across `cumulusci/tasks/`: at minimum `PackageUpload`, `PromotePackageVersion`, `GithubRelease`, `CreatePackageVersion`, dependency-resolution tasks. Each gets a few @@ -4288,7 +4076,7 @@ Estimated effort: 1-2 day PR for the framework + first wave of tasks; an ongoing "every new task documents its return values" contributor expectation thereafter (enforce in `requesting-code-review` skill). -### #2500 — `ignore_failure` is not documented +### #2500 - `ignore_failure` is not documented **Classification**: pure doc-gap (the feature exists and works; only the docs are missing). @@ -4297,12 +4085,12 @@ docs are missing). - The option exists in three independent places, so it is a stable, public, supported feature: - - `cumulusci/utils/yaml/cumulusci_yml.py:45` — `Step` Pydantic model - declares `ignore_failure: bool = False`. - - `cumulusci/core/flowrunner.py:667` — uses `step_config.get("ignore_failure", False)` - to drive the `allow_failure` flag passed into the step runner. - - `cumulusci/schema/cumulusci.jsonschema.json:149` — exported in the - JSON schema for IDE autocomplete. +- `cumulusci/utils/yaml/cumulusci_yml.py:45` - `Step` Pydantic model + declares `ignore_failure: bool = False`. +- `cumulusci/core/flowrunner.py:667` - uses `step_config.get("ignore_failure", False)` + to drive the `allow_failure` flag passed into the step runner. +- `cumulusci/schema/cumulusci.jsonschema.json:149` - exported in the + JSON schema for IDE autocomplete. - In `docs/`, total mentions are exactly two: a single-line example use inside a release-flow snippet at `docs/config.md:800` (`ignore_failure: True`) and a one-line changelog blurb at @@ -4310,12 +4098,12 @@ docs are missing). - The `## Flow Configurations` chapter (line 294) has subsections for "Add a Custom Flow" (303), "Add a Flow Step" (330), "Skip a Flow Step" (388), "Replace a Flow Step" (414), "Configure Options on Tasks in - Flows" (432) — and there is documentation prose for `when:` at line - 474+ — but no parallel subsection for `ignore_failure`. -- Davidmreed cut GUS W-10908655 on 2022-03-28 to track it; nothing has + Flows" (432) - and there is documentation prose for `when:` at line + 474+ - but no parallel subsection for `ignore_failure`. +- Davidmreed cut GUS [internal-ID-redacted] on 2022-03-28 to track it; nothing has landed in the 4+ years since. -The repro test (`/tmp/repro/17/tests/test_issue_2500.py`) confirms the +The repro test (`cumulusci/tests/triage/test_issue_2500.py`) confirms the option exists in the `Step` model and asserts `docs/config.md` has a heading-level section matching `ignore[ _]failure|ignore a failed|continue.*failure`. The heading assertion xfails today; the existence assertion passes. @@ -4332,7 +4120,7 @@ section. Body should cover: exception raised by that step does not abort the flow; subsequent steps still run. - A minimal YAML example (the existing `release_unlocked_production` - snippet around line 783 already demonstrates it — link to it instead + snippet around line 783 already demonstrates it - link to it instead of duplicating). - Interaction with `^^step.return_value` references: downstream steps that reference a failed step's return values must defend against @@ -4343,10 +4131,10 @@ section. Body should cover: - One sentence on the difference between `ignore_failure` (post hoc: swallow the exception) and `when:` (a priori: skip the step entirely). -This is a tiny, high-leverage docs PR — a strong candidate for a +This is a tiny, high-leverage docs PR - a strong candidate for a `good-first-issue` label. -### #3464 — Concise project-config documentation +### #3464 - Concise project-config documentation **Classification**: doc-gap with structural-fix implications (the most sustainable fix changes how docs are generated, not just what they say). @@ -4358,26 +4146,26 @@ sustainable fix changes how docs are generated, not just what they say). `name`, `package`, `test`, `git`, `dependencies`, `dependency_resolutions`, `dependency_pins`, `source_format`, `custom`. Each of those (except scalars) points at a further sub-model with its - own fields — `Package` has 7, `Git` has 10, `DependencyResolutions` + own fields - `Package` has 7, `Git` has 10, `DependencyResolutions` has 3, `Test` has 1. - `docs/config.md` shows exactly one project-level YAML example at line 281 (NPSP's `project` block) covering `name` + a partial `package`. There is no reference subsection enumerating every `project:` key. - Substring scans of `docs/config.md`: - - `dependency_resolutions` → 0 occurrences. - - `dependency_pins` → 0 occurrences. - - `source_format` → 6 occurrences, all inside flow-step `when:` - clauses, not as a project-level reference. - - `custom` → 29 occurrences but none are about `project.custom`. -- The keys that _are_ documented live in a separate page — `docs/dev.md` +- `dependency_resolutions` → 0 occurrences. +- `dependency_pins` → 0 occurrences. +- `source_format` → 6 occurrences, all inside flow-step `when:` + clauses, not as a project-level reference. +- `custom` → 29 occurrences but none are about `project.custom`. +- The keys that _are_ documented live in a separate page - `docs/dev.md` has `dependency_resolutions` at lines 596, 727 and `dependency_pins` - at lines 499, 509, 535 — which is exactly the _"scattered to the + at lines 499, 509, 535 - which is exactly the _"scattered to the wind"_ complaint in the issue body. jstvz acknowledged the gap in the one comment on the issue ("We've made improvements to the documentation over time, but there is still work to be done to make it easier for users to find what they need"). -The repro test (`/tmp/repro/17/tests/test_issue_3464.py`) enumerates +The repro test (`cumulusci/tests/triage/test_issue_3464.py`) enumerates every field of the `Project` Pydantic model and asserts each name appears at least once in `docs/config.md`. Today it lists the missing keys; xfails. @@ -4401,7 +4189,7 @@ Two-step path: on every Pydantic attribute in `cumulusci_yml.py` and add a Sphinx directive (or a `conf.py` autodoc hook) that emits the reference table directly from the model at docs-build time. This keeps the - reference and the schema in lockstep — the same mechanism powers the + reference and the schema in lockstep - the same mechanism powers the JSON schema (`cumulusci/schema/cumulusci.jsonschema.json`), so the plumbing is straightforward. @@ -4409,24 +4197,20 @@ Step 1 is a single-day effort; step 2 is multi-day but pays back every time a new field is added to `cumulusci.yml`. Recommend keep-open until at least step 1 ships. - - -# Subagent 18 (pymod) — Round 3 narrative - -Worktree: `.worktrees/repro-pymod` @ `worktree/repro/pymod` based on `origin/dev` (`1925a3083`). +Worktree: the triage worktree @ the triage worktree based on `origin/dev` (`1925a3083`). -### #3849 — urllib3 v2 breaks Robot tests on a fresh pip install +### #3849 - urllib3 v2 breaks Robot tests on a fresh pip install **Verdict**: `REPRODUCED-on-dev` → `keep-open`. **Code scan**: -- `pyproject.toml` `[project].dependencies` (lines 26–59) declares no `urllib3` constraint. It still pins `selenium<4` (line 54) and `robotframework-seleniumlibrary<6` (line 50). Both of those pin chains force `selenium==3.141.0`, whose `urllib3` import-time use of the pre-2.0 `Timeout` sentinel object is what produces the user-reported `ValueError: Timeout value connect was `. +- `pyproject.toml` `[project].dependencies` (lines 26-59) declares no `urllib3` constraint. It still pins `selenium<4` (line 54) and `robotframework-seleniumlibrary<6` (line 50). Both of those pin chains force `selenium==3.141.0`, whose `urllib3` import-time use of the pre-2.0 `Timeout` sentinel object is what produces the user-reported `ValueError: Timeout value connect was `. - `requests` (installed as a transitive runtime dep) declares `urllib3<3,>=1.26`, so a fresh `pip install cumulusci` resolves to whatever `urllib3` 2.x is current on PyPI. The local worktree happens to have `urllib3==1.26.20` because `uv sync` consumed `uv.lock`, but the lock is not what pip sees. Confirmed via `uv run python -c "import importlib.metadata as md; print(md.metadata('selenium').get_all('Requires-Dist'))"` → `selenium` declares `urllib3` with no version constraint. - `git log --all --grep urllib3` shows only dependabot lock bumps (e6423311e, 05a904856) that never landed on `dev`. The original 2018 fix referenced in `docs/history.md` (`#832`) is not reflected in the modern dependency list. -- 6+ users have reported reblocking on this in 2024–2025 (Szandor72, dipakparmar, atran-agentsync, JonnyPower, elizabethrichardson-uw, kg345); the documented workaround is still `pip install urllib3==1.26.20` after installing cumulusci. +- 6+ users have reported reblocking on this in 2024-2025 (Szandor72, dipakparmar, atran-agentsync, JonnyPower, elizabethrichardson-uw, kg345); the documented workaround is still `pip install urllib3==1.26.20` after installing cumulusci. -**Repro test**: `/tmp/repro/18/tests/test_issue_3849.py` parses the worktree's `pyproject.toml` (located via `cumulusci.__file__`) and asserts the modernized state — either an explicit `urllib3<…` constraint OR removal of both the `selenium<4` and `robotframework-seleniumlibrary<6` pins. Verified `XFAIL` under `uv run pytest -v -rx` (reason surfaces the docs path). +**Repro test**: `cumulusci/tests/triage/test_issue_3849.py` parses the worktree's `pyproject.toml` (located via `cumulusci.__file__`) and asserts the modernized state - either an explicit `urllib3<…` constraint OR removal of both the `selenium<4` and `robotframework-seleniumlibrary<6` pins. Verified `XFAIL` under `uv run pytest -v -rx` (reason surfaces the docs path). **Proposed fix sketch**: Two acceptable shapes. @@ -4435,30 +4219,30 @@ Worktree: `.worktrees/repro-pymod` @ `worktree/repro/pymod` based on `origin/dev Either way, add a smoke test that imports `SeleniumLibrary` after a fresh resolve to keep the regression caught. -### #3610 — `run_tests` crashes when `ApexTestResult.MethodName` is null +### #3610 - `run_tests` crashes when `ApexTestResult.MethodName` is null **Verdict**: `NOT-REPRODUCED-on-dev` → `closed:fixed-by-pr-#3681`. **Code scan**: -- The original issue points at `cumulusci/tasks/apex/testrunner.py` L417 (sort that explodes on `None`) and L346–348 (dict keyed by `MethodName`). On `origin/dev` today the same module's `_process_test_results` (lines 491–510) explicitly handles `None`: +- The original issue points at `cumulusci/tasks/apex/testrunner.py` L417 (sort that explodes on `None`) and L346-348 (dict keyed by `MethodName`). On `origin/dev` today the same module's `_process_test_results` (lines 491-510) explicitly handles `None`: ```500:510:cumulusci/tasks/apex/testrunner.py - if None in method_names: - class_id = self.classes_by_name[class_name] - self.retry_details.setdefault(class_id, []).append( - self._get_test_methods_for_class(class_name) - ) - del self.results_by_class_name[class_name][None] - self.logger.info( - f"Retrying class with id: {class_id} name:{class_name} due to `None` methodname" - ) - self.counts["Retriable"] += len(self.retry_details[class_id]) - self._attempt_retries() + if None in method_names: + class_id = self.classes_by_name[class_name] + self.retry_details.setdefault(class_id, []).append( + self._get_test_methods_for_class(class_name) + ) + del self.results_by_class_name[class_name][None] + self.logger.info( + f"Retrying class with id: {class_id} name:{class_name} due to `None` methodname" + ) + self.counts["Retriable"] += len(self.retry_details[class_id]) + self._attempt_retries() ``` - This landed in PR #3681 / commit `84389d998b4783ddd2ff062f486a2366709cac27` (“Handling exception when the Tooling API returns a test result with a null method name”), with regression coverage in `cumulusci/tasks/apex/tests/test_apex_tasks.py::test_run_task_None_methodname_fail` and `…_pass`. Both pass on this worktree (`uv run pytest cumulusci/tasks/apex/tests/test_apex_tasks.py -k None_methodname -v` → `2 passed`). -No repro test added — the fix is in place and already has direct unit coverage. Closing the issue is a paperwork action. +No repro test added - the fix is in place and already has direct unit coverage. Closing the issue is a paperwork action. **Proposed fix sketch**: none required. Recommend closing #3610 with a comment that points at PR #3681 and the two `None_methodname` tests. diff --git a/docs/triage/v5/themes.md b/docs/triage/v5/themes.md index 41b6c3a89c..bfff0de43d 100644 --- a/docs/triage/v5/themes.md +++ b/docs/triage/v5/themes.md @@ -1,6 +1,6 @@ # CCI Open-Issue Themes and Duplicate Clusters -Generated by Task 2.5b. Read-only analysis over the 142-issue snapshot +Generated by the reproducibility pass. Read-only analysis over the 142-issue snapshot captured by Task 1. The current proposed-pass1 decisions live in `proposals.md`; this document surfaces information the controller and user can use to refine those decisions before Phase 2 execution. @@ -405,6 +405,8 @@ Recommendation: ## Tranche recommendations +A **tranche** is a release-and-effort grouping for surviving canonical issues - a recommendation for which release window an issue's fix should target. The narrower [Tranche 1 candidate list in `README.md`](./README.md#tranche-1-candidate-list) defines the immediate fix-PR slate against `dev`; the four-tier taxonomy below is the broader recommendation for the 16-issue surviving set. + Surviving canonical set (16 issues): the 15 issues already proposed as `kept-open` plus #3544, promoted by Cluster A. The 126 closure-bound issues are not assigned to a tranche; they remain on their proposed-pass1 @@ -489,7 +491,7 @@ controller's review. - #3938 + #3939 (theme: metadata-etl). Same author, same day, same task family (deploy). #3938 hits the rest_deploy=True code path; #3939 hits the rest_deploy=False (SOAP) code path. Different parsers, kept - as separate Tranche 1 items. + as separate [Tranche 1](../../docs/triage/v5/README.md#tranche-1-candidate-list) items. - #3347 + #3441 (theme: packaging). Both touch release_unlocked_beta + version_base. #3347 (2022-08-29) is a 1-line bug report against the default; #3441 (2023-12-15) is a feature ask