OTA-2070: Return per-operator verdicts from olm-check#43
Conversation
|
@jrangelramos: This pull request references OTA-2070 which is a valid jira issue. DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
d316922 to
922f52f
Compare
|
Test logs using combined evals from jhadvig#2 on top of #34. Run with claude as provider 🔍 Expand: Eval Run Logs$ CLAUDE_CODE_USE_VERTEX=1 \
ANTHROPIC_VERTEX_PROJECT_ID=itpc-gcp-hcm-pe-eng-claude \
ANTHROPIC_MODEL=claude-opus-4-6 \
CLOUD_ML_REGION=us-east5 \
EVAL_HEALTH_TIMEOUT=180 \
bash evals/run.sh -k "product-lifecycle" --timeout=600
Starting provider containers...
claude: port 18080 (container d77ffafd9aca)
Waiting for servers...
claude: ready
Running evals...
/usr/lib/python3.14/site-packages/pytest_asyncio/plugin.py:211: PytestDeprecationWarning: The configuration option "asyncio_default_fixture_loop_scope" is unset.
The event loop scope for asynchronous fixtures will default to the fixture caching scope. Future versions of pytest-asyncio will default the loop scope for asynchronous fixtures to function scope. Set the default fixture loop scope explicitly in order to avoid unexpected behavior in the future. Valid fixture loop scopes are: "function", "class", "module", "package", "session"
warnings.warn(PytestDeprecationWarning(_DEFAULT_FIXTURE_LOOP_SCOPE_UNSET))
=============================================================================================== test session starts ================================================================================================
platform linux -- Python 3.14.3, pytest-8.3.5, pluggy-1.6.0 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /home/jeramos/pixaa/test/test-ocp5/agentic-skills/evals
configfile: pytest.ini
plugins: anyio-4.12.1, asyncio-1.1.0, xdist-3.7.0, timeout-2.4.0
asyncio: mode=Mode.AUTO, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function
timeout: 600.0s
timeout method: signal
timeout func_only: False
collected 228 items / 186 deselected / 42 selected
evals/skills/test_eval.py::test_skill[claude-product-lifecycle-plc_proposal_olm_batch_check] PASSED [ 2%]
evals/skills/test_eval.py::test_skill[claude-product-lifecycle-plc_cluster_logging_supported] PASSED [ 4%]
evals/skills/test_eval.py::test_skill[claude-product-lifecycle-plc_web_terminal_compat_check] PASSED [ 7%]
evals/skills/test_eval.py::test_skill[claude-product-lifecycle-plc_compliance_operator_status] PASSED [ 9%]
evals/skills/test_eval.py::test_skill[claude-product-lifecycle-plc_ocp_platform_status] PASSED [ 11%]
evals/skills/test_eval.py::test_skill[claude-product-lifecycle-plc_ocp_old_version_extended] PASSED [ 14%]
evals/skills/test_eval.py::test_skill[claude-product-lifecycle-plc_batch_known_operators_only] PASSED [ 16%]
evals/skills/test_eval.py::test_skill[gemini-product-lifecycle-plc_proposal_olm_batch_check] SKIPPED (No server for gemini) [ 19%]
evals/skills/test_eval.py::test_skill[gemini-product-lifecycle-plc_cluster_logging_supported] SKIPPED (No server for gemini) [ 21%]
evals/skills/test_eval.py::test_skill[gemini-product-lifecycle-plc_web_terminal_compat_check] SKIPPED (No server for gemini) [ 23%]
evals/skills/test_eval.py::test_skill[gemini-product-lifecycle-plc_compliance_operator_status] SKIPPED (No server for gemini) [ 26%]
evals/skills/test_eval.py::test_skill[gemini-product-lifecycle-plc_ocp_platform_status] SKIPPED (No server for gemini) [ 28%]
evals/skills/test_eval.py::test_skill[gemini-product-lifecycle-plc_ocp_old_version_extended] SKIPPED (No server for gemini) [ 30%]
evals/skills/test_eval.py::test_skill[gemini-product-lifecycle-plc_batch_known_operators_only] SKIPPED (No server for gemini) [ 33%]
evals/skills/test_eval.py::test_skill[openai-product-lifecycle-plc_proposal_olm_batch_check] SKIPPED (No server for openai) [ 35%]
evals/skills/test_eval.py::test_skill[openai-product-lifecycle-plc_cluster_logging_supported] SKIPPED (No server for openai) [ 38%]
evals/skills/test_eval.py::test_skill[openai-product-lifecycle-plc_web_terminal_compat_check] SKIPPED (No server for openai) [ 40%]
evals/skills/test_eval.py::test_skill[openai-product-lifecycle-plc_compliance_operator_status] SKIPPED (No server for openai) [ 42%]
evals/skills/test_eval.py::test_skill[openai-product-lifecycle-plc_ocp_platform_status] SKIPPED (No server for openai) [ 45%]
evals/skills/test_eval.py::test_skill[openai-product-lifecycle-plc_ocp_old_version_extended] SKIPPED (No server for openai) [ 47%]
evals/skills/test_eval.py::test_skill[openai-product-lifecycle-plc_batch_known_operators_only] SKIPPED (No server for openai) [ 50%]
evals/skills/test_eval.py::test_skill[deepagents-claude-product-lifecycle-plc_proposal_olm_batch_check] SKIPPED (No server for deepagents-claude) [ 52%]
evals/skills/test_eval.py::test_skill[deepagents-claude-product-lifecycle-plc_cluster_logging_supported] SKIPPED (No server for deepagents-claude) [ 54%]
evals/skills/test_eval.py::test_skill[deepagents-claude-product-lifecycle-plc_web_terminal_compat_check] SKIPPED (No server for deepagents-claude) [ 57%]
evals/skills/test_eval.py::test_skill[deepagents-claude-product-lifecycle-plc_compliance_operator_status] SKIPPED (No server for deepagents-claude) [ 59%]
evals/skills/test_eval.py::test_skill[deepagents-claude-product-lifecycle-plc_ocp_platform_status] SKIPPED (No server for deepagents-claude) [ 61%]
evals/skills/test_eval.py::test_skill[deepagents-claude-product-lifecycle-plc_ocp_old_version_extended] SKIPPED (No server for deepagents-claude) [ 64%]
evals/skills/test_eval.py::test_skill[deepagents-claude-product-lifecycle-plc_batch_known_operators_only] SKIPPED (No server for deepagents-claude) [ 66%]
evals/skills/test_eval.py::test_skill[deepagents-gemini-product-lifecycle-plc_proposal_olm_batch_check] SKIPPED (No server for deepagents-gemini) [ 69%]
evals/skills/test_eval.py::test_skill[deepagents-gemini-product-lifecycle-plc_cluster_logging_supported] SKIPPED (No server for deepagents-gemini) [ 71%]
evals/skills/test_eval.py::test_skill[deepagents-gemini-product-lifecycle-plc_web_terminal_compat_check] SKIPPED (No server for deepagents-gemini) [ 73%]
evals/skills/test_eval.py::test_skill[deepagents-gemini-product-lifecycle-plc_compliance_operator_status] SKIPPED (No server for deepagents-gemini) [ 76%]
evals/skills/test_eval.py::test_skill[deepagents-gemini-product-lifecycle-plc_ocp_platform_status] SKIPPED (No server for deepagents-gemini) [ 78%]
evals/skills/test_eval.py::test_skill[deepagents-gemini-product-lifecycle-plc_ocp_old_version_extended] SKIPPED (No server for deepagents-gemini) [ 80%]
evals/skills/test_eval.py::test_skill[deepagents-gemini-product-lifecycle-plc_batch_known_operators_only] SKIPPED (No server for deepagents-gemini) [ 83%]
evals/skills/test_eval.py::test_skill[deepagents-openai-product-lifecycle-plc_proposal_olm_batch_check] SKIPPED (No server for deepagents-openai) [ 85%]
evals/skills/test_eval.py::test_skill[deepagents-openai-product-lifecycle-plc_cluster_logging_supported] SKIPPED (No server for deepagents-openai) [ 88%]
evals/skills/test_eval.py::test_skill[deepagents-openai-product-lifecycle-plc_web_terminal_compat_check] SKIPPED (No server for deepagents-openai) [ 90%]
evals/skills/test_eval.py::test_skill[deepagents-openai-product-lifecycle-plc_compliance_operator_status] SKIPPED (No server for deepagents-openai) [ 92%]
evals/skills/test_eval.py::test_skill[deepagents-openai-product-lifecycle-plc_ocp_platform_status] SKIPPED (No server for deepagents-openai) [ 95%]
evals/skills/test_eval.py::test_skill[deepagents-openai-product-lifecycle-plc_ocp_old_version_extended] SKIPPED (No server for deepagents-openai) [ 97%]
evals/skills/test_eval.py::test_skill[deepagents-openai-product-lifecycle-plc_batch_known_operators_only] SKIPPED (No server for deepagents-openai) [100%]
============================================================================ 7 passed, 35 skipped, 186 deselected in 719.06s (0:11:59) =============================================================================
eval-claude🔍 Expand: Container Logs |
|
Test logs using combined evals from jhadvig#2 on top of #34. Run with openai as provider 🔍 Expand: Eval Run Logs$ OPENAI_API_KEY=${OPENAI_API_KEY} \
OPENAI_MODEL=gpt-5.4 \
EVAL_PROVIDERS=openai \
EVAL_HEALTH_TIMEOUT=180 \
CLAUDE_CODE_USE_VERTEX= \
ANTHROPIC_VERTEX_PROJECT_ID= \
GOOGLE_APPLICATION_CREDENTIALS= \
bash evals/run.sh -k "product-lifecycle" --timeout=600
Starting provider containers...
openai: port 18080 (container 5d95caaddb17)
Waiting for servers...
openai: ready
Running evals...
/usr/lib/python3.14/site-packages/pytest_asyncio/plugin.py:211: PytestDeprecationWarning: The configuration option "asyncio_default_fixture_loop_scope" is unset.
The event loop scope for asynchronous fixtures will default to the fixture caching scope. Future versions of pytest-asyncio will default the loop scope for asynchronous fixtures to function scope. Set the default fixture loop scope explicitly in order to avoid unexpected behavior in the future. Valid fixture loop scopes are: "function", "class", "module", "package", "session"
warnings.warn(PytestDeprecationWarning(_DEFAULT_FIXTURE_LOOP_SCOPE_UNSET))
=============================================================================================== test session starts ================================================================================================
platform linux -- Python 3.14.3, pytest-8.3.5, pluggy-1.6.0 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /home/jeramos/pixaa/test/test-ocp5/agentic-skills/evals
configfile: pytest.ini
plugins: anyio-4.12.1, asyncio-1.1.0, xdist-3.7.0, timeout-2.4.0
asyncio: mode=Mode.AUTO, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function
timeout: 600.0s
timeout method: signal
timeout func_only: False
collected 228 items / 186 deselected / 42 selected
evals/skills/test_eval.py::test_skill[claude-product-lifecycle-plc_proposal_olm_batch_check] SKIPPED (No server for claude) [ 2%]
evals/skills/test_eval.py::test_skill[claude-product-lifecycle-plc_cluster_logging_supported] SKIPPED (No server for claude) [ 4%]
evals/skills/test_eval.py::test_skill[claude-product-lifecycle-plc_web_terminal_compat_check] SKIPPED (No server for claude) [ 7%]
evals/skills/test_eval.py::test_skill[claude-product-lifecycle-plc_compliance_operator_status] SKIPPED (No server for claude) [ 9%]
evals/skills/test_eval.py::test_skill[claude-product-lifecycle-plc_ocp_platform_status] SKIPPED (No server for claude) [ 11%]
evals/skills/test_eval.py::test_skill[claude-product-lifecycle-plc_ocp_old_version_extended] SKIPPED (No server for claude) [ 14%]
evals/skills/test_eval.py::test_skill[claude-product-lifecycle-plc_batch_known_operators_only] SKIPPED (No server for claude) [ 16%]
evals/skills/test_eval.py::test_skill[gemini-product-lifecycle-plc_proposal_olm_batch_check] SKIPPED (No server for gemini) [ 19%]
evals/skills/test_eval.py::test_skill[gemini-product-lifecycle-plc_cluster_logging_supported] SKIPPED (No server for gemini) [ 21%]
evals/skills/test_eval.py::test_skill[gemini-product-lifecycle-plc_web_terminal_compat_check] SKIPPED (No server for gemini) [ 23%]
evals/skills/test_eval.py::test_skill[gemini-product-lifecycle-plc_compliance_operator_status] SKIPPED (No server for gemini) [ 26%]
evals/skills/test_eval.py::test_skill[gemini-product-lifecycle-plc_ocp_platform_status] SKIPPED (No server for gemini) [ 28%]
evals/skills/test_eval.py::test_skill[gemini-product-lifecycle-plc_ocp_old_version_extended] SKIPPED (No server for gemini) [ 30%]
evals/skills/test_eval.py::test_skill[gemini-product-lifecycle-plc_batch_known_operators_only] SKIPPED (No server for gemini) [ 33%]
evals/skills/test_eval.py::test_skill[openai-product-lifecycle-plc_proposal_olm_batch_check] PASSED [ 35%]
evals/skills/test_eval.py::test_skill[openai-product-lifecycle-plc_cluster_logging_supported] PASSED [ 38%]
evals/skills/test_eval.py::test_skill[openai-product-lifecycle-plc_web_terminal_compat_check] PASSED [ 40%]
evals/skills/test_eval.py::test_skill[openai-product-lifecycle-plc_compliance_operator_status] PASSED [ 42%]
evals/skills/test_eval.py::test_skill[openai-product-lifecycle-plc_ocp_platform_status] PASSED [ 45%]
evals/skills/test_eval.py::test_skill[openai-product-lifecycle-plc_ocp_old_version_extended] PASSED [ 47%]
evals/skills/test_eval.py::test_skill[openai-product-lifecycle-plc_batch_known_operators_only] PASSED [ 50%]
evals/skills/test_eval.py::test_skill[deepagents-claude-product-lifecycle-plc_proposal_olm_batch_check] SKIPPED (No server for deepagents-claude) [ 52%]
evals/skills/test_eval.py::test_skill[deepagents-claude-product-lifecycle-plc_cluster_logging_supported] SKIPPED (No server for deepagents-claude) [ 54%]
evals/skills/test_eval.py::test_skill[deepagents-claude-product-lifecycle-plc_web_terminal_compat_check] SKIPPED (No server for deepagents-claude) [ 57%]
evals/skills/test_eval.py::test_skill[deepagents-claude-product-lifecycle-plc_compliance_operator_status] SKIPPED (No server for deepagents-claude) [ 59%]
evals/skills/test_eval.py::test_skill[deepagents-claude-product-lifecycle-plc_ocp_platform_status] SKIPPED (No server for deepagents-claude) [ 61%]
evals/skills/test_eval.py::test_skill[deepagents-claude-product-lifecycle-plc_ocp_old_version_extended] SKIPPED (No server for deepagents-claude) [ 64%]
evals/skills/test_eval.py::test_skill[deepagents-claude-product-lifecycle-plc_batch_known_operators_only] SKIPPED (No server for deepagents-claude) [ 66%]
evals/skills/test_eval.py::test_skill[deepagents-gemini-product-lifecycle-plc_proposal_olm_batch_check] SKIPPED (No server for deepagents-gemini) [ 69%]
evals/skills/test_eval.py::test_skill[deepagents-gemini-product-lifecycle-plc_cluster_logging_supported] SKIPPED (No server for deepagents-gemini) [ 71%]
evals/skills/test_eval.py::test_skill[deepagents-gemini-product-lifecycle-plc_web_terminal_compat_check] SKIPPED (No server for deepagents-gemini) [ 73%]
evals/skills/test_eval.py::test_skill[deepagents-gemini-product-lifecycle-plc_compliance_operator_status] SKIPPED (No server for deepagents-gemini) [ 76%]
evals/skills/test_eval.py::test_skill[deepagents-gemini-product-lifecycle-plc_ocp_platform_status] SKIPPED (No server for deepagents-gemini) [ 78%]
evals/skills/test_eval.py::test_skill[deepagents-gemini-product-lifecycle-plc_ocp_old_version_extended] SKIPPED (No server for deepagents-gemini) [ 80%]
evals/skills/test_eval.py::test_skill[deepagents-gemini-product-lifecycle-plc_batch_known_operators_only] SKIPPED (No server for deepagents-gemini) [ 83%]
evals/skills/test_eval.py::test_skill[deepagents-openai-product-lifecycle-plc_proposal_olm_batch_check] SKIPPED (No server for deepagents-openai) [ 85%]
evals/skills/test_eval.py::test_skill[deepagents-openai-product-lifecycle-plc_cluster_logging_supported] SKIPPED (No server for deepagents-openai) [ 88%]
evals/skills/test_eval.py::test_skill[deepagents-openai-product-lifecycle-plc_web_terminal_compat_check] SKIPPED (No server for deepagents-openai) [ 90%]
evals/skills/test_eval.py::test_skill[deepagents-openai-product-lifecycle-plc_compliance_operator_status] SKIPPED (No server for deepagents-openai) [ 92%]
evals/skills/test_eval.py::test_skill[deepagents-openai-product-lifecycle-plc_ocp_platform_status] SKIPPED (No server for deepagents-openai) [ 95%]
evals/skills/test_eval.py::test_skill[deepagents-openai-product-lifecycle-plc_ocp_old_version_extended] SKIPPED (No server for deepagents-openai) [ 97%]
evals/skills/test_eval.py::test_skill[deepagents-openai-product-lifecycle-plc_batch_known_operators_only] SKIPPED (No server for deepagents-openai) [100%]
============================================================================= 7 passed, 35 skipped, 186 deselected in 63.92s (0:01:03) =============================================================================
eval-openai🔍 Expand: Container Logs |
Align plc_proposal_olm_batch_check with the new olm-check output from openshift#43: test the version-aware found/not-found split instead of the old all-versions dump. Changes: - Switch cluster-logging to v6.3.1 (tracked but not OCP 4.21 compatible) - Replace operators_with/without_lifecycle_data with three finer counts: api_tracked (4), version_tracked (3), ocp_compatible (2) - Update query to ask for per-version and compatibility breakdown
922f52f to
9febc34
Compare
harche
left a comment
There was a problem hiding this comment.
Thanks, the per operator verdict approach is a real improvement. I validated this branch against the live API before reviewing: the api_all() switch has value beyond the stated fix, since the old code misses openshift-pipelines-operator-rh entirely while this branch finds it, and the unfiltered endpoint does return all 236 products in one unpaginated response, so that assumption holds. Inline comments follow, one of them is a live crash.
One thing I could not attach inline because the file is not part of this diff: this branch produces the 3/2 split you describe (compliance 1.9, cluster-logging 6.5 and pipelines 1.22 are all tracked today), but the committed eval expects operators_without_lifecycle_data: 3, so it fails even with this fix:
Ground truth drifted since the eval was written (compliance-operator 1.9 got added to the API), so the follow up eval update needs a number change, not just a rerun, and live data drift may keep biting these evals.
Happy to approve once the crash and the lifecycle_unavailable mismatch are addressed, both are small fixes plus test updates.
- Strip leading 'v' prefix in version normalization (v1.16.0 → 1.16) - Match API versions with '.x' suffix (1.8.x matches normalized 1.8) - Guard against missing 'name' key in API version entries to avoid KeyError crash on live data (e.g. skupper-operator) - Derive lifecycle_unavailable from results instead of maintaining a separate list, so the summary always agrees with per-result verdicts - Document both success shapes in SKILL.md (with-version vs no-version) to avoid overpromising fields the no-version path doesn't return Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The olm-check command previously dumped all version entries for every
matched package, leaving the LLM to determine whether the specific
installed version was actually tracked. Claude handled this correctly
but gemini and openai miscounted — they saw data for a package and
assumed lifecycle data was available, even when the installed version
was not tracked (e.g. web-terminal v1.16 is not in the API).
Refactor olm-check to return one result per operator. When a version
is provided, the tool normalizes it to major.minor and matches against
API version names. Use a single `error` string field — present means
failure (self-describing), absent means success — so incoherent states
are impossible.
Also switch from api_search("OpenShift") to api_all() so operators
with non-OpenShift product names (e.g. compliance-operator) are not
missed by the name filter.
c4ec733 to
0b4d49d
Compare
|
/lgtm |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: harche, jrangelramos The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
|
/override ci/prow/evals this is cluster update related skill change, so I will leave final approval to @wking /hold |
|
@harche: /override requires failed status contexts, check run or a prowjob name to operate on.
Only the following failed contexts/checkruns were expected:
If you are trying to override a checkrun that has a space in it, you must put a double quote on the context. DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
|
/override ci/prow/eval |
|
@harche: Overrode contexts on behalf of harche: ci/prow/eval DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
|
@jrangelramos: all tests passed! Full PR test history. Your PR dashboard. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here. |
Summary
olm-checkto return one result per operator with a singleerrorstring field (present = failure, absent = success) instead ofdumping all version entries for matched packages
versionfield to operator input for per-version matchingv1.9.0→1.9): strip leadingv,truncate to major.minor, match
.xsuffixes in API version namesnamekey in API version entries (live API crash)lifecycle_unavailablefrom per-result verdicts so the summaryalways agrees with the details
api_search("OpenShift")toapi_all()to cover alloperators regardless of product name
no-version) and the
errorfield conventionProblem
Based on evals test run from #34 it was possible to verify inconsistencies
between how different models deal with lifecycle data count.
The gemini and openai providers failed
plc_proposal_olm_batch_checkreturning 4/1 instead of the expected 3/2 split. Root cause: the tool
returned all version entries per package, and the LLMs had to infer
whether the installed version was tracked. web-terminal v1.16 is not
in the API (only up to v1.15), but the models saw web-terminal data
and counted it as "has lifecycle data."
Proposal Fix
The tool now answers the question directly. For each operator:
error, withstatus,ocp_compatible,phaseserrorset, withavailable_versionserrorseterrorif the package exists, withproductand
available_versions(nostatus/ocp_compatible/phases)Before / After
CLI call
Before — no way to specify installed version:
python3 plc_lookup.py olm-check --ocp 4.21 \ --operators '[{"package":"cluster-logging"},{"package":"web-terminal"}]'After — optional
versionfield per operator:python3 plc_lookup.py olm-check --ocp 4.21 \ --operators '[{"package":"cluster-logging","version":"6.5.1"},{"package":"web-terminal","version":"1.16.0"}]'Sample output — Before
The old output dumped every version entry for each matched package.
The LLM had to figure out which (if any) matched the installed version:
{ "ocp_target": "4.21", "operators_checked": 2, "lifecycle_unavailable": [], "results": [ { "product": "logging for Red Hat OpenShift", "package": "cluster-logging", "version": "6.5", "status": "Full Support", "ocp_versions": ["4.19", "4.20", "4.21"], "ocp_compatible": true, "phases": [...] }, { "product": "logging for Red Hat OpenShift", "package": "cluster-logging", "version": "5.9", "status": "End of life", "ocp_versions": ["4.13", "4.14", "4.15", "4.16"], "ocp_compatible": false, "phases": [...] }, { "product": "Red Hat OpenShift Web Terminal", "package": "web-terminal", "version": "1.15", "status": "Full Support", "ocp_versions": ["4.19", "4.20", "4.21"], "ocp_compatible": true, "phases": [...] } ] }Sample output — After
One result per operator with a clear verdict.
No
errorfield means success — no ambiguity for the model to resolve:{ "ocp_target": "4.21", "operators_checked": 2, "lifecycle_unavailable": ["web-terminal"], "results": [ { "package": "cluster-logging", "requested_version": "6.5", "product": "logging for Red Hat OpenShift", "status": "Full Support", "ocp_compatible": true, "phases": [...] }, { "package": "web-terminal", "requested_version": "1.16", "error": "version 1.16 not tracked", "available_versions": ["1.15"] } ] }Files changed
cluster-update/product-lifecycle/scripts/plc_lookup.py— core refactorcluster-update/product-lifecycle/SKILL.md— updated documentationcluster-update/product-lifecycle/scripts/tests/test_plc_lookup.py— rewritten testsTest plan
python3 -m pytest cluster-update/product-lifecycle/scripts/tests/ -v)