Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
6fdfc5f
Search every part source at once and merge the results
gs-salitronic Aug 6, 2026
c650b03
Report which objects each ERC violation is about
gs-salitronic Aug 6, 2026
c73a563
Convert EasyEDA and KiCad parts into Altium library parts
gs-salitronic Aug 6, 2026
e6f713d
Add a minimal toolset for clients that cannot hold 396 tools
gs-salitronic Aug 6, 2026
8e5e0dd
Upgrade repair ports to wire stubs where the space allows
gs-salitronic Aug 6, 2026
20d283c
Warn when text cannot survive the bridge instead of corrupting it
gs-salitronic Aug 6, 2026
6d501f4
Report the steps that quietly failed instead of returning success
gs-salitronic Aug 6, 2026
36f2466
Check the KiCad reader against the shipped standard library
gs-salitronic Aug 6, 2026
3649290
Fail the build when the docs and the code disagree
gs-salitronic Aug 6, 2026
2fb957d
Release 0.5.0 and document the part and import tooling
gs-salitronic Aug 6, 2026
dd3ef37
Stop two part provider tests depending on a local KiCad install
gs-salitronic Aug 6, 2026
7796605
Probe kicad_local with a real query so the skip guard works
gs-salitronic Aug 6, 2026
29d58bd
Grow via plating inward from the drill wall
gs-salitronic Aug 8, 2026
02d3eda
Set mechanical layer kinds, and sweep libraries in one call
gs-salitronic Aug 8, 2026
058c2ea
Drive the EasyEDA backend against a live editor, and fix what it found
gs-salitronic Aug 8, 2026
d6823d5
Move the reference material out of the README
gs-salitronic Aug 9, 2026
93141c6
Merge upstream improvements through d6823d5
Rouniy Aug 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Closes #

- [ ] `pytest` passes locally
- [ ] Pascal cross-validation passes (if Pascal touched)
- [ ] Manually exercised in Altium (if behaviour requires it) describe
- [ ] Manually exercised in Altium (if behaviour requires it): describe
what you ran below

Notes:
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,15 @@ jobs:
# but there is no reason to certify a platform we never run on.
runs-on: windows-latest
steps:
# fetch-depth: 0 brings the tags along. The default shallow fetch
# brings none, and tests/test_version_is_unreleased.py compares the
# declared version against the tags: with no tags it has nothing to
# compare and passes vacuously. That would leave the one check that
# catches a release number which has already shipped inert in CI,
# which is the only place it runs unattended.
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: actions/setup-python@v5
with:
Expand Down
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,10 @@ tests/integration/fixtures/schematic_snapshot.*

# Atomic-write temp leftovers (editors / Dropbox)
*.tmp.*

# Built EasyEDA extension entry point; produced by
# extensions/easyeda/build.py, same treatment as the Altium bundle.
extensions/easyeda/dist/

extensions/easyeda/verified.json
extensions/easyeda/*.eext
80 changes: 69 additions & 11 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,42 +46,100 @@ Pascal side; the workspace pointer lives at

## Tests

- `pytest` runs the Python suite
- `pytest` runs the offline suite, and is safe with Altium open
- `EDA_AGENT_INTEGRATION=1 pytest` adds the live-Altium tests
- `python tests/test_cross_validate.py` runs the offline Pascal validator
(requires Free Pascal in PATH)

**A plain `pytest` does not touch a running Altium.** The nine tests
under `tests/integration/` drive a real session, and they are skipped at
COLLECTION unless `EDA_AGENT_INTEGRATION=1`, so no fixture runs, no
bridge is built and no request file is written.

That gate is recent. Before it, those tests reached the skip only after
`real_bridge` had already pinged, and `fixture_project_loaded` called
`project.open` with no skip in front of it at all, so running the suite
against a healthy polling loop would have opened the fixture project in
whatever Altium you had in front of you.
`tests/test_integration_tests_are_opt_in.py` holds the line, and checks
it end to end by running the directory in a subprocess with the
workspace redirected and asserting nothing was written there.

Once you opt in, those tests still only read: they open and compile a
project and query it, and send no command that changes the design. A
test that would is rejected by
`tests/test_integration_suite_is_non_destructive.py`. Verification that
has to modify something belongs in `docs/RELEASE_VERIFICATION.md`.

The Pascal scripts cannot be fully unit-tested without a running Altium
instance cross-validation runs the same logic compiled by `fpc` against
instance; cross-validation runs the same logic compiled by `fpc` against
mocked Altium objects and is the only honest pre-Altium check.

### Writing a guard

A good part of this suite is guards: tests that compare a fact stated in
one place against the code that decides it, because the two drift and
nothing else notices. If you add one, four things have caught real
mistakes here and are worth copying.

**Mutate the defect it exists to catch.** A guard that has never failed
has not been tested. Break the thing on purpose, confirm the guard
fails, put it back. Several guards in this suite passed on their first
run while checking nothing, and only mutation found that.

**Assert the check found something.** If the guard parses a table, a
document or a registry, assert the parse was non-empty and roughly the
expected size. A renamed heading otherwise turns the guard into a test
that passes because it read zero rows. Existing examples:
`test_the_scan_sees_what_it_claims_to`,
`test_the_widened_scan_actually_sees_something`,
`test_the_check_can_actually_fail`.

**Do not let the guard match its own explanation.** If it searches for a
literal and a nearby comment names that literal, the comment satisfies
the search. `tests/test_no_em_dashes.py` builds its characters with
`chr()` for this reason, and the CI check in
`tests/test_version_is_unreleased.py` ignores comment lines because its
own rationale contains the string it looks for.

**Prefer behaviour to literals, and remember a count cannot see a name.**
`tests/test_unit_conversions_agree.py` converts values rather than
comparing constants, because keeping the constant and flipping the
operation is the likelier mistake. `tests/test_readme_names_real_tools.py`
exists because the count guard beside it cannot tell a correct total
from a table naming a tool nobody wrote.

## Pull requests

- Keep PRs focused. One concern per PR.
- Include a clear description of the problem and the chosen approach.
- If you touch Pascal: remember that Altium caches scripts. Reviewers will
need to restart Altium to see your changes in effect.
- Add or update tests when behaviour changes.
- Run `pytest` locally before requesting review.
- Run `pytest --ignore=tests/integration` locally before requesting review.

## Commit messages

Use the conventional-commit style already present in the repository:
Write the subject as a plain imperative sentence saying what the commit
changes, wrapping the body at ~72 columns:

```
type(scope): short summary
Keep the test suite away from the machine-global workspace pointer

Longer body if needed, wrapped at ~72 columns.
Longer body if needed: what was wrong, and why this is the fix.
```

Common types: `feat`, `fix`, `refactor`, `docs`, `test`, `chore`, `revert`.
Scopes used in this repo include `pcb`, `sch`, `design`, `altium`,
`bridge`, `installer`.
Do not use a `type(scope):` prefix. This file previously documented that
convention; the repository no longer uses it.

Do not write housekeeping messages. Mechanical tidying goes into the
commit that makes the substantive change, and is not mentioned in it.

## Reporting bugs

See [`.github/ISSUE_TEMPLATE/bug_report.md`](.github/ISSUE_TEMPLATE/bug_report.md).
Include the Altium version, the `eda-agent --version` output, and if you
can the contents of the workspace `response.json` from the failing call.
Include the Altium version, the `eda-agent --version` output, and, if you
can, the contents of the workspace `response.json` from the failing call.

## Suggesting features

Expand Down
Loading
Loading