Files
nickol-knx-mcp/.github/workflows/ci.yml
T
Nikolay MiroshnichenkoandClaude Opus 5 ec63bcf106 load_ga_export, entity naming, climate setpoint shift; fix suggest_repairs crash; CI runs every test
Three things found by auditing a TapPlan export, plus one regression found on the way.

load_ga_export(path): new tool. Reads an ETS ga-export/01 XML (ETS "Export Group
Addresses", or the import file a planning tool writes) into a project without
devices, through safe_fromstring, capped at 50 MB and 8 levels of range nesting.
Invalid or duplicate addresses and unknown DPT tokens go to import_warnings, never
silently. Round trip with our own generate_ets_xml is covered by a test.

Entity naming: lights, covers and climates are named after the common word prefix
of their member names, cutting only function words. The first version of the rule
turned "01. <room> - All Blinds - Move" into "01" on a real project, so anything not
in the function vocabulary now stays. On six real projects 214 of 1189 entities got
a shorter name, each rename reviewed, no address mapping changed. Regenerated
packages show different names; noted in the changelog.

Setpoint shift: 9.002 / 6.010 with a shift word maps to setpoint_shift_address,
setpoint_shift_state_address and setpoint_shift_mode (keys checked against the HA
KNX climate docs). It used to become a plain sensor.

Fixed: suggest_repairs raised UnboundLocalError on any project with a missing status
GA. My local rename in the 12.09 typing cleanup left two references to the old name.
test_council_fixes covers it but was not in CI, so it shipped. CI now runs all 21
test files instead of a hand-picked 10; the 11 added ones pass from a clean clone.

Verified: all 21 tests, ruff, mypy with the package installed, corpus guard no drift.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 00:11:45 +02:00

119 lines
3.6 KiB
YAML

name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
# The workflow only reads the tree; nothing here needs a writable token.
permissions:
contents: read
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: "3.12"
cache: pip
- name: Install package and tools
run: |
python -m pip install --upgrade pip
pip install -e . ruff mypy
- name: Lint (ruff — errors only, no style rules)
run: ruff check nickol_knx_mcp tests tools
- name: Types (mypy)
run: mypy
smoke-test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
cache: pip
- name: Install package
run: |
python -m pip install --upgrade pip
pip install -e .
- name: End-to-end smoke test (synthetic 16-GA project)
run: python tests/test_pipeline.py
- name: Device catalog wiring (catalog-exact + recipe fallback)
run: python tests/test_device_catalog.py
- name: App-program parser (synthetic .knxprod round-trip)
run: python tests/test_appprog_parser.py
- name: v0.8 fixes (positional pairing, ref-merge, range names)
run: python tests/test_v08_fixes.py
- name: Cover step/stop pairing stays within the ETS Function (issue #11)
run: python tests/test_cover_pairing.py
- name: RM/Rückmeldung shutter feedback classifies as status, not light (issue #12)
run: python tests/test_rm_status.py
- name: Policy profile — inferred taxonomy, declared profile, project-seeded example (issue #13)
run: python tests/test_policy.py
- name: Structure-first entity suggestions (HA SuggestionProvider prototype)
run: python tests/test_suggest.py
- name: Stable ordering + cursor paging for large tool results
run: python tests/test_paging.py
- name: GA-export intake, entity naming, climate setpoint shift
run: python tests/test_ga_export.py
- name: Repair proposals and council-review fixes
run: python tests/test_council_fixes.py
- name: Domain classifier (name + DPT + range context)
run: python tests/test_domain_classifier.py
- name: explain_ga provenance
run: python tests/test_explain.py
- name: Aggregates carry their evidence
run: python tests/test_explainable_aggregates.py
- name: Device parameter checks
run: python tests/test_param_check.py
- name: Value-status completeness (brightness / position)
run: python tests/test_role_completeness.py
- name: Room template library
run: python tests/test_room_library.py
- name: Root-cause regressions
run: python tests/test_root_cause.py
- name: Hardened archive and XML parsing
run: python tests/test_safexml.py
- name: Theben reference projects
run: python tests/test_theben_corrections.py
- name: Topology limits
run: python tests/test_topology.py
- name: Console script is installed
run: |
python -c "import importlib.metadata as m; print('entry points:', [e.name for e in m.entry_points(group='console_scripts') if e.name == 'nickol-knx-mcp'])"
command -v nickol-knx-mcp