breadkit-lint 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.yamllint +16 -0
  3. data/CHANGELOG.md +30 -2
  4. data/README.md +55 -40
  5. data/action.yml +42 -0
  6. data/config/default.yml +33 -0
  7. data/docs/REFERENCE.md +129 -0
  8. data/docs/rules/Electrical/CapacitorVoltageRating.md +5 -0
  9. data/docs/rules/Electrical/FloatingInput.md +11 -0
  10. data/docs/rules/Electrical/GpioOvercurrent.md +18 -0
  11. data/docs/rules/Electrical/I2CAddressConflict.md +5 -0
  12. data/docs/rules/Electrical/I2CPullupMissing.md +5 -0
  13. data/docs/rules/Electrical/LedOvercurrent.md +5 -0
  14. data/docs/rules/Electrical/MinimumResistance.md +14 -0
  15. data/docs/rules/Electrical/MissingBaseResistor.md +5 -0
  16. data/docs/rules/Electrical/MissingDecouplingCapacitor.md +5 -0
  17. data/docs/rules/Electrical/MissingFlybackDiode.md +18 -0
  18. data/docs/rules/Electrical/MissingPullResistor.md +17 -0
  19. data/docs/rules/Electrical/MissingSeriesResistor.md +3 -1
  20. data/docs/rules/Electrical/NoCommonGround.md +1 -0
  21. data/docs/rules/Electrical/RailPolarityMismatch.md +10 -0
  22. data/docs/rules/Electrical/ResistorPowerRating.md +5 -0
  23. data/docs/rules/Electrical/ReversePolarity.md +1 -1
  24. data/docs/rules/Electrical/SupplyOverload.md +11 -0
  25. data/docs/rules/Electrical/SupplyVoltageRange.md +1 -0
  26. data/docs/rules/Electrical/VoltageDomainMismatch.md +6 -0
  27. data/docs/rules/Intent/ConnectionMismatch.md +3 -1
  28. data/docs/rules/Intent/MeasurementUnavailable.md +10 -0
  29. data/docs/rules/Layout/AmbiguousSupplySource.md +5 -0
  30. data/docs/rules/Layout/BodyOverlap.md +11 -0
  31. data/docs/rules/Layout/HoleCovered.md +11 -0
  32. data/docs/rules/Layout/InvalidColor.md +3 -0
  33. data/docs/rules/Layout/InvalidOption.md +3 -0
  34. data/docs/rules/Layout/InvalidRoute.md +3 -0
  35. data/docs/rules/Layout/InvalidValue.md +3 -0
  36. data/docs/rules/Layout/InvalidWireId.md +3 -0
  37. data/docs/rules/Layout/LeadSpan.md +21 -0
  38. data/docs/rules/Layout/PartOverride.md +3 -0
  39. data/docs/rules/Layout/UnknownSupplySource.md +5 -0
  40. data/docs/rules/Layout/UnmatchedParts.md +3 -0
  41. data/docs/rules/Layout/WireOverIC.md +11 -0
  42. data/docs/rules/Lint/RedundantDisable.md +3 -0
  43. data/docs/rules/Lint/UnknownRuleInDisable.md +5 -0
  44. data/lib/breadkit/lint/baseline.rb +38 -0
  45. data/lib/breadkit/lint/rake_task.rb +22 -0
  46. data/lib/breadkit/lint/rules/electrical.rb +580 -30
  47. data/lib/breadkit/lint/rules/intent.rb +69 -4
  48. data/lib/breadkit/lint/rules/layout.rb +148 -0
  49. data/lib/breadkit/lint/rules/style.rb +36 -7
  50. data/lib/breadkit/lint/rules/support.rb +45 -11
  51. data/lib/breadkit/lint/rules.rb +205 -2
  52. data/lib/breadkit/lint/source_editor.rb +138 -0
  53. data/lib/breadkit/lint/version.rb +1 -1
  54. data/lib/breadkit/lint.rb +422 -59
  55. data/lib/guard/breadkit/templates/Guardfile +7 -0
  56. data/lib/guard/breadkit.rb +26 -0
  57. data/locales/en.yml +82 -0
  58. data/locales/ja.yml +130 -4
  59. data/locales/ko.yml +191 -0
  60. data/locales/zh.yml +191 -0
  61. data/package-lock.json +103 -0
  62. data/package.json +2 -1
  63. data/scripts/action-run.sh +51 -0
  64. data/scripts/build-rule-pages.mjs +87 -0
  65. data/scripts/check-rule-pages.mjs +18 -0
  66. data/scripts/pre-commit +24 -0
  67. data/sig/breadkit/lint.rbs +12 -1
  68. data/site/index.html +9 -6
  69. data/site/schemas/lint-v1.json +71 -0
  70. data/site/styles.css +13 -0
  71. metadata +64 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5ae47ac3ae7217a2a82b7515f278ad803d0784545f85d469cac5bb5256a5d56a
4
- data.tar.gz: 123c596bd7f50e9da23e73d90e4fb6ad2c4ed8d9fe88274ba519497eec420a75
3
+ metadata.gz: ebac8699bf88561bef695f65d6835056ceaa110d0ce63c9c642cea128d61d383
4
+ data.tar.gz: 9131c8a1aed79757a7e53091e9bb21b07db551983ce594ef6f19473405c2764f
5
5
  SHA512:
6
- metadata.gz: e7391a75a996a8068d8c9446c704d6ac6d13d3d44b3ce4adfc3a827ed4e7980868540baecb3c90a4839b06c287a05d3ac8d618e2af120ee784b88b9b02d31799
7
- data.tar.gz: b87c6a614fdad6c4d9392fde335d48fe82db2f364e72237fe578aa571f72511335ec6ecde1c96a1ea10763640617a76809a18797cc00e6ad5ec6bebea903f7a1
6
+ metadata.gz: 27ac3f4e1bd8be7000afac496fa6bd217c40dcd9dfb060dbc9291528e401dad09182b370022f3b3d3aff745af8c624ee4b86afd7581e3e6ace97d1a162ab18ed
7
+ data.tar.gz: fc1daadc9892710325f251a21f1c05003028460b4fea535d8c2c5510ef984b32c07e14d5af12589fe2a12fea02f635a8d30fc03de5518e1c1eb1fc83c525c29f
data/.yamllint ADDED
@@ -0,0 +1,16 @@
1
+ extends: default
2
+ ignore: |
3
+ build/
4
+ node_modules/
5
+ runtime/build/
6
+ tmp/
7
+ **/*.dSYM/**
8
+
9
+ rules:
10
+ comments:
11
+ min-spaces-from-content: 1
12
+ document-start: disable
13
+ line-length:
14
+ max: 200
15
+ truthy:
16
+ check-keys: false
data/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.0 — 2026-09-27
3
+ ## 0.2.0 — 2026-09-28
4
4
 
5
- - Initial release
5
+ ### Electrical and layout checks
6
+
7
+ - Lint declarative YAML and TOML circuits, named multi-board circuits, and version 2 circuit IR.
8
+ - Check I2C pull-ups and address conflicts, supply overloads, voltage domains, GPIO current limits, missing input pull resistors, missing IC decoupling capacitors, direct transistor base drive, and missing flyback diodes when the circuit supplies enough metadata.
9
+ - Check resistor power, capacitor voltage, LED current, zero-ohm potentiometer paths, component lead spans, covered holes, overlapping bodies, and wires crossing DIP bodies.
10
+ - Evaluate connection expectations in named switch states and check declared voltage and current ranges. An explicit switch-state budget reports incomplete exhaustive analysis instead of silently skipping states.
11
+ - Avoid false common-ground and reverse-polarity findings for shared or isolated supplies and intentionally reverse-biased parts.
12
+ - Recognize offboard power outputs and GPIO pin roles from part definitions when checking shorts, current paths, and voltage limits.
13
+
14
+ ### Reports and integrations
15
+
16
+ - Add Markdown, JUnit, Checkstyle, and reviewdog JSON reports; portable baselines; `--diff`; `--watch`; `--stdin`; and short explanations with `--teach`.
17
+ - Publish the lint JSON schema and rule reference, including English, Japanese, Chinese, and Korean messages and guidance.
18
+ - Provide a GitHub Action, Rake task, Guard plugin, and pre-commit hook. The hook checks staged Ruby DSL, YAML, and TOML circuits.
19
+
20
+ ### Diagnostics and fixes
21
+
22
+ - Show accurate source columns and add safe `--fix` edits for unambiguous wire-color typos and unused standalone suppressions.
23
+ - Preserve useful source paths and locations in terminal, GitHub, JSON, and SARIF reports, including evaluation errors.
24
+ - Report invalid circuit values, colors, routes, and part options as layout errors before electrical checks run.
25
+ - Reduce redundant findings from switch states, unused suppressions, unplaced pins, and missing pull resistors.
26
+
27
+ ### Compatibility
28
+
29
+ - Require Breadkit core 0.2.x. Projects using core 0.1.x should remain on breadkit-lint 0.1.0 until they upgrade both gems.
30
+
31
+ ## 0.1.0 — 2026-09-26
32
+
33
+ - Initial release.
data/README.md CHANGED
@@ -1,54 +1,69 @@
1
- # breadkit-lint
1
+ <p align="center">
2
+ <img src="site/favicon.svg" width="72" height="72" alt="">
3
+ </p>
2
4
 
3
- Project site: https://breadkit.github.io/breadkit-lint/
5
+ <h1 align="center">breadkit-lint</h1>
4
6
 
5
- `bklint` checks Breadkit DSL and IR files for layout, electrical, and wiring-intent problems. DSL files execute as Ruby code; inspect only trusted files. Use IR JSON for data-only input. Configuration `require` entries also execute Ruby code, so load only trusted configuration files.
7
+ <p align="center">
8
+ <strong>Catch breadboard wiring mistakes before you build.</strong>
9
+ </p>
6
10
 
7
- Install `breadkit-lint` directly; RubyGems installs its compatible `breadkit` core dependency. Shared circuit examples are in the [breadkit repository](https://github.com/breadkit/breadkit/tree/main/examples).
11
+ <p align="center">
12
+ <a href="https://rubygems.org/gems/breadkit-lint"><img src="https://img.shields.io/gem/v/breadkit-lint.svg" alt="RubyGems version"></a>
13
+ <a href="https://github.com/breadkit/breadkit-lint/actions/workflows/ci.yml"><img src="https://github.com/breadkit/breadkit-lint/actions/workflows/ci.yml/badge.svg" alt="CI status"></a>
14
+ <img src="https://img.shields.io/badge/Ruby-%3E%3D%203.3-CC342D.svg" alt="Ruby 3.3 or newer">
15
+ <a href="LICENSE.txt"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT license"></a>
16
+ </p>
17
+
18
+ `bklint` checks [Breadkit](https://github.com/breadkit/breadkit) circuits for
19
+ placement, electrical, and connection-intent errors. It accepts Ruby DSL,
20
+ YAML, TOML, and JSON IR.
21
+
22
+ ## Quick start
8
23
 
9
24
  ```sh
25
+ gem install breadkit-lint
10
26
  bklint circuit.bk.rb
11
- bklint circuit.bk.rb --only Electrical/ShortCircuit
12
- bklint circuit.bk.rb --format json --out lint.json
13
- bklint circuit.bk.rb --format github
14
27
  bklint circuit.bk.rb --format sarif --out lint.sarif
15
28
  ```
16
29
 
17
- ## Options
30
+ This README follows main (0.2.0), which requires Breadkit core 0.2.x. If the
31
+ published gems are older, run both main branches from sibling checkouts:
32
+
33
+ ```sh
34
+ git clone https://github.com/breadkit/breadkit.git
35
+ git clone https://github.com/breadkit/breadkit-lint.git
36
+ cd breadkit-lint
37
+ bundle install
38
+ bundle exec bklint ../breadkit/examples/01_led_button.bk.rb
39
+ ```
18
40
 
19
- `bklint [options] [FILES...]` accepts `.bk.rb` and Breadkit IR `.json` inputs. Directory arguments are scanned recursively. With no files, it scans visible inputs under the current directory and skips `node_modules`. Each input uses the nearest ancestor `.bklint.yml` unless `--config` is specified.
41
+ ## What it checks
20
42
 
21
- | Option | Description |
43
+ | Area | Example |
22
44
  | --- | --- |
23
- | `-f, --format FORMAT` | `text` (default), `json`, `github`, or `sarif`. |
24
- | `-o, --out PATH` | Write formatter output to a file. |
25
- | `-c, --config PATH` | Load a `.bklint.yml` configuration. |
26
- | `--fail-level LEVEL` | `error`, `warning` (default), or `info`. |
27
- | `--only RULES` / `--except RULES` | Select or skip comma-separated rule IDs. |
28
- | `--switch-states MODE` | Evaluate `none`, `single` (default), or `all` switch states. |
29
- | `--list-rules` | List registered rules. |
30
- | `--explain RULE` | Show rule guidance and an example. |
31
- | `--locale LOCALE` | `ja` or `en` for rule descriptions, messages, and text summary. |
32
-
33
- Exit status is `0` when no offense meets the fail level, `1` when one does, and `2` for invalid input, configuration, or command usage.
34
-
35
- ## Configuration
36
-
37
- ```yaml
38
- inherit_from:
39
- - ./shared/bklint.yml
40
- use_parts:
41
- - ./parts/*.yml
42
-
43
- Electrical/FloatingPin:
44
- Severity: error
45
-
46
- Style/WireColor:
47
- Enabled: true
48
- PositiveColors: [red, orange]
49
- GroundColors: [black, blue]
50
- ```
45
+ | [Layout](docs/rules/Layout/HoleConflict.md) | Conflicting or invalid placements. |
46
+ | [Electrical](docs/rules/Electrical/ShortCircuit.md) | Shorts, polarity, ratings, and missing protection. |
47
+ | [Intent](docs/rules/Intent/ConnectionMismatch.md) | Connections that differ from declared expectations. |
48
+ | [Style](docs/rules/Style/WireColor.md) | Wire colors that conflict with their net role. |
49
+
50
+ Run `bklint --list-rules` to discover rules or `bklint --explain RULE` for
51
+ specific guidance. The [rule reference](https://breadkit.github.io/breadkit-lint/rules/)
52
+ contains the full list.
53
+
54
+ ## Documentation
55
+
56
+ - [Configuration, CLI options, and integrations](docs/REFERENCE.md)
57
+ - [Default configuration](config/default.yml) and [lint JSON schema](https://breadkit.github.io/breadkit-lint/schemas/lint-v1.json)
58
+ - [Core circuit DSL](https://github.com/breadkit/breadkit/blob/main/docs/dsl.md) for named boards and connection expectations
59
+
60
+ Ruby DSL files and configuration `require` entries can execute code. Inspect
61
+ only trusted files; use JSON IR for data-only input.
62
+
63
+ ## Development
64
+
65
+ From the sibling checkout above, run `bundle exec rake` for the local checks.
51
66
 
52
- All built-in rules and defaults are in [`config/default.yml`](config/default.yml). `.bklint.yml` can also set `AllRules.SwitchStates`, `AllRules.FailLevel`, `AllRules.Exclude`, `AllRules.NewRules` (`pending`, `enable`, or `disable`), `AllRules.RequireDisableReason`, and `require` custom rule files. DSL `lint_disable` declarations suppress a rule globally or for one named component, pin, or wire. Unknown rule IDs are errors; set `reason:` when `RequireDisableReason` is enabled.
67
+ ## License
53
68
 
54
- Use `bklint --format json` with `bkrender --annotations` to display offense markers on a diagram. Rule guidance is in [`docs/rules`](docs/rules).
69
+ [MIT](LICENSE.txt).
data/action.yml ADDED
@@ -0,0 +1,42 @@
1
+ name: Breadkit Lint
2
+ description: Check breadboard circuits and publish SARIF or pull request annotations
3
+ inputs:
4
+ path:
5
+ description: Circuit file or directory to inspect
6
+ required: true
7
+ upload-sarif:
8
+ description: Upload results to GitHub code scanning (requires security-events write)
9
+ default: "true"
10
+ fail-level:
11
+ description: Lowest finding severity that fails the job (error, warning, or info)
12
+ default: warning
13
+ outputs:
14
+ sarif-file:
15
+ description: Generated SARIF file path when upload-sarif is true
16
+ value: ${{ steps.lint.outputs['sarif-file'] }}
17
+ runs:
18
+ using: composite
19
+ steps:
20
+ - uses: ruby/setup-ruby@a0102e0972be65f351c307e2d64b9314a57c8073 # v1.324.0
21
+ with:
22
+ ruby-version: "3.4"
23
+ - id: lint
24
+ name: Check circuits
25
+ shell: bash
26
+ env:
27
+ INPUT_PATH: ${{ inputs.path }}
28
+ INPUT_UPLOAD_SARIF: ${{ inputs['upload-sarif'] }}
29
+ INPUT_FAIL_LEVEL: ${{ inputs['fail-level'] }}
30
+ run: bash "$GITHUB_ACTION_PATH/scripts/action-run.sh"
31
+ - name: Upload SARIF
32
+ if: ${{ inputs['upload-sarif'] == 'true' && steps.lint.outputs['sarif-file'] != '' }}
33
+ uses: github/codeql-action/upload-sarif@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4.38.1
34
+ with:
35
+ sarif_file: ${{ steps.lint.outputs['sarif-file'] }}
36
+ category: breadkit-lint
37
+ - name: Fail on findings
38
+ if: ${{ steps.lint.outputs['exit-code'] != '0' }}
39
+ shell: bash
40
+ env:
41
+ BKLINT_EXIT_CODE: ${{ steps.lint.outputs['exit-code'] }}
42
+ run: exit "$BKLINT_EXIT_CODE"
data/config/default.yml CHANGED
@@ -1,34 +1,67 @@
1
1
  AllRules:
2
2
  SwitchStates: single
3
+ StateBudget: 256
3
4
  FailLevel: warning
4
5
  NewRules: pending
5
6
 
7
+ Lint/RedundantDisable: {Enabled: true, Severity: warning}
8
+ Lint/UnknownRuleInDisable: {Enabled: true, Severity: error}
9
+
6
10
  Layout/InvalidHole: {Enabled: true, Severity: error}
7
11
  Layout/UnknownBoard: {Enabled: true, Severity: error}
8
12
  Layout/UnknownPart: {Enabled: true, Severity: error}
9
13
  Layout/UnknownTransistorModel: {Enabled: true, Severity: warning}
10
14
  Layout/UnknownPin: {Enabled: true, Severity: error}
15
+ Layout/UnknownSupplySource: {Enabled: true, Severity: error}
16
+ Layout/AmbiguousSupplySource: {Enabled: true, Severity: error}
11
17
  Layout/UnknownOption: {Enabled: true, Severity: error}
18
+ Layout/InvalidOption: {Enabled: true, Severity: error}
19
+ Layout/InvalidValue: {Enabled: true, Severity: error}
20
+ Layout/InvalidColor: {Enabled: true, Severity: error}
21
+ Layout/InvalidRoute: {Enabled: true, Severity: error}
22
+ Layout/InvalidWireId: {Enabled: true, Severity: error}
23
+ Layout/UnmatchedParts: {Enabled: true, Severity: warning}
24
+ Layout/PartOverride: {Enabled: true, Severity: warning}
12
25
  Layout/UnplacedPin: {Enabled: true, Severity: error}
13
26
  Layout/DuplicateRef: {Enabled: true, Severity: error}
14
27
  Layout/InvalidPlacement: {Enabled: true, Severity: error}
15
28
  Layout/HoleConflict: {Enabled: true, Severity: error}
29
+ Layout/HoleCovered: {Enabled: true, Severity: error}
30
+ Layout/BodyOverlap: {Enabled: true, Severity: error}
31
+ Layout/WireOverIC: {Enabled: true, Severity: info}
32
+ Layout/LeadSpan: {Enabled: true, Severity: error}
16
33
  Layout/NoFreeHole: {Enabled: true, Severity: error}
17
34
  Layout/SplitNetLabel: {Enabled: true, Severity: error}
18
35
  Layout/PinsInSameStrip: {Enabled: true, Severity: error}
19
36
  Electrical/ShortCircuit: {Enabled: true, Severity: error}
20
37
  Electrical/ShortedComponent: {Enabled: true, Severity: warning}
21
38
  Electrical/FloatingPin: {Enabled: true, Severity: warning}
39
+ Electrical/FloatingInput: {Enabled: true, Severity: info}
40
+ Electrical/MissingPullResistor: {Enabled: true, Severity: info}
22
41
  Electrical/DanglingWire: {Enabled: true, Severity: warning}
23
42
  Electrical/SplitRail: {Enabled: true, Severity: warning}
24
43
  Electrical/MissingSeriesResistor: {Enabled: true, Severity: error}
44
+ Electrical/MinimumResistance: {Enabled: true, Severity: warning}
45
+ Electrical/RailPolarityMismatch: {Enabled: true, Severity: warning}
25
46
  Electrical/ReversePolarity: {Enabled: true, Severity: error}
26
47
  Electrical/PowerPinUnconnected: {Enabled: true, Severity: warning}
27
48
  Electrical/SupplyVoltageRange: {Enabled: true, Severity: error}
28
49
  Electrical/NoCommonGround: {Enabled: true, Severity: warning}
29
50
  Electrical/NetLabelConflict: {Enabled: true, Severity: error}
51
+ Electrical/VoltageDomainMismatch: {Enabled: true, Severity: error}
52
+ Electrical/ResistorPowerRating: {Enabled: true, Severity: error}
53
+ Electrical/CapacitorVoltageRating: {Enabled: true, Severity: error}
54
+ Electrical/LedOvercurrent: {Enabled: true, Severity: error}
55
+ Electrical/GpioOvercurrent: {Enabled: true, Severity: error}
56
+ Electrical/SupplyOverload: {Enabled: true, Severity: error}
57
+ Electrical/I2CAddressConflict: {Enabled: true, Severity: error}
58
+ Electrical/I2CPullupMissing: {Enabled: true, Severity: info}
59
+ Electrical/MissingDecouplingCapacitor: {Enabled: true, Severity: info}
60
+ Electrical/MissingBaseResistor: {Enabled: true, Severity: info}
61
+ Electrical/MissingFlybackDiode: {Enabled: true, Severity: warning}
30
62
  Intent/ConnectionMismatch: {Enabled: true, Severity: error}
31
63
  Intent/UnknownNet: {Enabled: true, Severity: error}
64
+ Intent/MeasurementUnavailable: {Enabled: true, Severity: warning}
32
65
  Style/WireColor:
33
66
  Enabled: true
34
67
  Severity: info
data/docs/REFERENCE.md ADDED
@@ -0,0 +1,129 @@
1
+ # breadkit-lint reference
2
+
3
+ Start with the [README](../README.md) for installation and a first lint run.
4
+ For individual checks, use the [rule reference](https://breadkit.github.io/breadkit-lint/rules/).
5
+
6
+ ## Inputs and results
7
+
8
+ `bklint [options] [FILES...]` accepts Ruby DSL (`.bk.rb`), declarative YAML
9
+ and TOML (`.bk.yml`, `.bk.yaml`, `.bk.toml`), and Breadkit JSON IR. It scans
10
+ directories recursively. With no file argument, it scans the current directory.
11
+ Named multi-board circuits and IR v2 are supported; board holes use qualified
12
+ IDs such as `B1.a10`.
13
+
14
+ The nearest `.bklint.yml` configures each file unless `--config` is given.
15
+ Exit status is `0` when no finding reaches the failure level, `1` for
16
+ findings, and `2` for invalid input or configuration. Ruby DSL circuits and
17
+ configuration `require` entries execute code; inspect only trusted files.
18
+ JSON IR is data-only.
19
+
20
+ ## Rules and configuration
21
+
22
+ Run `bklint --list-rules` to discover IDs and
23
+ `bklint --explain Electrical/ShortCircuit` for a rule's guidance. The
24
+ [default configuration](../config/default.yml) lists every rule and setting.
25
+
26
+ Create `.bklint.yml` beside a circuit to override only what you need:
27
+
28
+ ```yaml
29
+ Electrical/FloatingPin:
30
+ Severity: error
31
+ Include: ['circuits/**/*.bk.rb']
32
+ Exclude: ['circuits/legacy/**/*.bk.rb']
33
+
34
+ Style/WireColor:
35
+ Enabled: true
36
+ ```
37
+
38
+ `Include` and `Exclude` match paths relative to the config file; `Exclude`
39
+ wins. `AllRules.Exclude` skips entire files. Use `inherit_from` for shared
40
+ settings and `use_parts` for custom definitions. Unknown rule IDs are errors.
41
+ A circuit can use `lint_disable` with an optional target and reason;
42
+ `AllRules.RequireDisableReason` makes reasons mandatory.
43
+
44
+ Connection expectations may name a switch state. `expect_voltage` and
45
+ `expect_current` check supported DC ranges; unknown operating points produce
46
+ `Intent/MeasurementUnavailable`. See the
47
+ [core DSL reference](https://github.com/breadkit/breadkit/blob/main/docs/dsl.md)
48
+ for declaration syntax.
49
+
50
+ To adopt lint with existing findings:
51
+
52
+ ```sh
53
+ bklint --generate-baseline .bklint-baseline.json
54
+ bklint --baseline .bklint-baseline.json
55
+ bklint --diff origin/main --format github
56
+ ```
57
+
58
+ Baseline entries omit line numbers, so moving known findings does not make
59
+ them new. The [lint JSON schema](https://breadkit.github.io/breadkit-lint/schemas/lint-v1.json)
60
+ describes machine-readable output.
61
+
62
+ ## CLI options
63
+
64
+ | Option | Use |
65
+ | --- | --- |
66
+ | `--format FORMAT` | `text`, `json`, `github`, `sarif`, `markdown`, `junit`, `checkstyle`, or `rdjson`. |
67
+ | `--out PATH` | Write the report to a file. |
68
+ | `--only RULES`, `--except RULES` | Select rule IDs. |
69
+ | `--fail-level LEVEL` | Fail on `error`, `warning` (default), or `info`. |
70
+ | `--switch-states MODE` | Check `none`, `single` (default), or `all` switch states. |
71
+ | `--state-budget COUNT` | Limit exhaustive states (default 256); report incomplete analysis when exceeded. |
72
+ | `--fix-check`, `--fix` | Preview or apply unambiguous Ruby DSL edits. |
73
+ | `--watch` | Rerun when circuit, part, or config files change. |
74
+ | `--stdin PATH` | Read a Ruby, YAML, or TOML circuit from standard input. |
75
+ | `--teach`, `--locale LOCALE` | Show short explanations or select `en`, `ja`, `zh`, or `ko` messages. |
76
+
77
+ Use `bklint --help` for all flags. Fixing currently covers one-character
78
+ wire-color typos and standalone unused suppressions; ambiguous edits and
79
+ declarative/JSON files are left unchanged. Fix modes cannot be combined with
80
+ stdin, diff, baseline, or `--out`.
81
+
82
+ ## GitHub Action
83
+
84
+ The repository root is a composite Action. It installs this source and a
85
+ pinned compatible Breadkit core revision. This push workflow uploads SARIF:
86
+
87
+ ```yaml
88
+ name: Circuit lint
89
+ on: push
90
+ permissions:
91
+ contents: read
92
+ security-events: write
93
+ jobs:
94
+ lint:
95
+ runs-on: ubuntu-latest
96
+ steps:
97
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
98
+ with:
99
+ persist-credentials: false
100
+ - uses: breadkit/breadkit-lint@main
101
+ with:
102
+ path: circuits
103
+ ```
104
+
105
+ Pin the Action to a commit SHA for reproducible runs. `upload-sarif` defaults
106
+ to `true`; the report is uploaded even when findings fail the job. For
107
+ untrusted pull requests, run on `pull_request` with `contents: read`, no
108
+ secrets, and `upload-sarif: "false"` to emit check annotations. Do not run
109
+ proposed Ruby DSL files with a write token or `pull_request_target`.
110
+ The Action does not post PR comments.
111
+
112
+ ## Local integrations
113
+
114
+ A Rakefile can lint selected files:
115
+
116
+ ```ruby
117
+ require "breadkit/lint/rake_task"
118
+
119
+ Breadkit::RakeTask.new(:circuits) do |task|
120
+ task.files = FileList["circuits/**/*.bk.rb"]
121
+ task.options = ["--format", "github"]
122
+ end
123
+ ```
124
+
125
+ The [pre-commit hook](../scripts/pre-commit) reads staged circuit files from
126
+ Git's index. An optional Guard plugin is available as
127
+ `require "guard/breadkit"`; configure watched circuits in your Guardfile.
128
+ Use `bklint --format json` with `bkrender --annotations` to draw findings
129
+ on a diagram.
@@ -0,0 +1,5 @@
1
+ # Electrical/CapacitorVoltageRating
2
+
3
+ Checks electrolytic capacitors with an explicit voltage rating, such as `electrolytic :C1, "10u 16V", plus: "a1", minus: "a2"`. The check uses the highest known voltage across the capacitor, including both endpoints of a ranged supply when connected directly.
4
+
5
+ Use a capacitor rated above the voltage it can see in the circuit.
@@ -0,0 +1,11 @@
1
+ # Electrical/FloatingInput
2
+
3
+ An explicitly typed `input` pin has an electrical connection, but its net has no modeled voltage source, output driver, or fixed resistor path to one. Check whether it needs a pull-up, pull-down, or output connection.
4
+
5
+ ```ruby
6
+ board :half
7
+ ic :U1, "74hc08", at: "e10"
8
+ wire "a10", "a11" # U1.1A is connected to an undriven net
9
+ ```
10
+
11
+ The rule follows chains of fixed resistors to a source, and ignores visual wires and pins marked `unused`. Bare pins are covered by `Electrical/FloatingPin`. Only pins whose part definition has `type: input` are checked. This is informational because firmware or hardware internal pulls are not modeled.
@@ -0,0 +1,18 @@
1
+ # Electrical/GpioOvercurrent
2
+
3
+ A GPIO or output pin with a declared `max_current` carries more current than its rating in the DC model. The limit is in amperes in the part definition. This rule only evaluates a pin that is also an explicit, fixed-voltage `provides` terminal, so the output state and load current are known.
4
+
5
+ ```yaml
6
+ id: fixed_driver
7
+ category: offboard
8
+ placement: offboard
9
+ pins:
10
+ - {num: 1, name: OUT, type: gpio, max_current: 0.01}
11
+ - {num: 2, name: GND, type: ground}
12
+ provides:
13
+ - {positive: OUT, negative: GND, voltage: 5}
14
+ ```
15
+
16
+ Connecting a 100 Ω resistor across `OUT` and `GND` draws 50 mA, which exceeds the 10 mA limit. Increase the load resistance or use a suitable driver.
17
+
18
+ Ordinary GPIO pins without an explicit output state, unrated pins, and circuits whose DC analysis is unsupported are skipped. The check includes source and sink current and reports each rated pin separately.
@@ -0,0 +1,5 @@
1
+ # Electrical/I2CAddressConflict
2
+
3
+ Two devices with the same `address:` share both SDA and SCL nets. Change one device's address or move it to another I2C bus.
4
+
5
+ Only devices with an explicit address and SDA/SCL pins are checked.
@@ -0,0 +1,5 @@
1
+ # Electrical/I2CPullupMissing
2
+
3
+ An addressed component with both `SDA` and `SCL` pins has an externally connected bus line without a modeled positive resistance to a declared supply's positive net. The rule checks each line separately and ignores unconnected or unpowered buses.
4
+
5
+ Add a fixed pull-up resistor from each bus line to the appropriate supply rail. This is an informational advisory: a module may already contain pull-up resistors, or firmware may enable internal pull-ups, and the circuit model cannot currently represent those facts.
@@ -0,0 +1,5 @@
1
+ # Electrical/LedOvercurrent
2
+
3
+ Checks an LED whose part definition declares `max_forward_current`. The DC model estimates its current using the supply, resistors, and that part's optional `forward_voltage` and `on_resistance` values. The rule reports a current above the declared limit.
4
+
5
+ The rule skips circuits with an indeterminate or unsupported DC operating point. Add an explicit series resistor and use a part-specific current rating; a generic LED has no assumed safe current limit.
@@ -0,0 +1,14 @@
1
+ # Electrical/MinimumResistance
2
+
3
+ A potentiometer wiper can reach either end of its resistive track. If it is the only current-limiting element in an LED path, the resistance can approach 0 Ω and the LED may be damaged. This rule checks connected power and GPIO paths at both wiper extremes. It does not flag a pot used only between its two end pins.
4
+
5
+ ```ruby
6
+ supply :P, voltage: 5, plus: "B+1", minus: "B-1"
7
+ pot :VR1, "10k", at: "a5"
8
+ led :D1, anode: "a10", cathode: "a11"
9
+ wire "b5", "B+"
10
+ wire "b6", "b10"
11
+ wire "b11", "B-"
12
+ ```
13
+
14
+ Add a fixed resistor in series with the LED. Its value should keep LED current within the part's rating at the highest supply voltage.
@@ -0,0 +1,5 @@
1
+ # Electrical/MissingBaseResistor
2
+
3
+ A pin explicitly typed `output` shares a conductive net with a part categorized as a transistor's explicit `base` pin. There is no series resistor between those two pins. Add a suitable resistor between the driver output and the transistor base.
4
+
5
+ This is an informational advisory. Bidirectional `gpio` pins, power rails, and resistor bias networks are excluded because their drive state or purpose cannot be inferred from the circuit model. Transistor parts without an explicit `base` pin are also excluded.
@@ -0,0 +1,5 @@
1
+ # Electrical/MissingDecouplingCapacitor
2
+
3
+ A part categorized as an `ic` has explicit power and ground pins connected across a modeled voltage source, but no capacitor bridges those resolved nets. Place a suitable decoupling capacitor across the IC's supply pins.
4
+
5
+ This is an informational advisory. It excludes offboard modules, which may contain their own decoupling, and does not assess capacitor value or physical distance from the IC. Unpowered pins are handled by `Electrical/PowerPinUnconnected` instead.
@@ -0,0 +1,18 @@
1
+ # Electrical/MissingFlybackDiode
2
+
3
+ A part explicitly marked with `flags: [needs_flyback_diode]` has named positive and negative coil pins, but no reverse diode bridges their resolved nets. The rule checks a load only when a modeled supply terminal connects to one side and the other side connects to a modeled supply terminal or a non-diode component pin. A jumper ending on an empty strip is ignored. A protective diode must have its cathode on the coil's positive net and its anode on the negative net.
4
+
5
+ Declare the coil terminals in a custom part definition:
6
+
7
+ ```yaml
8
+ id: relay_coil
9
+ category: relay
10
+ placement: leads
11
+ pins:
12
+ - {num: 1, name: POS}
13
+ - {num: 2, name: NEG}
14
+ polarity: {positive: POS, negative: NEG}
15
+ flags: [needs_flyback_diode]
16
+ ```
17
+
18
+ This warning is opt-in because ordinary parts do not identify an inductive coil. A different protection method, such as an internal clamp or snubber, is not modeled as a diode and can be documented with `lint_disable`.
@@ -0,0 +1,17 @@
1
+ # Electrical/MissingPullResistor
2
+
3
+ An explicitly typed input connects to one side of a switch, and the other side reaches a declared supply terminal. With the switch open, the input has no modeled drive or pull resistor. Add a fixed pull-up or pull-down resistor to a supply terminal so the open state is defined.
4
+
5
+ ```ruby
6
+ board :half
7
+ supply :USB, voltage: 5, plus: "B+1", minus: "B-1"
8
+ ic :U1, "74hc08", at: "e10"
9
+ part :SW1, :slide_switch_spst, pins: %w[a10 a12]
10
+ wire "b12", "B+2"
11
+ resistor :R1, "10k", pins: %w[b10 b13]
12
+ wire "a13", "B-2"
13
+ ```
14
+
15
+ The rule reports an info advisory when the pull resistor is missing. It checks declared `input` pins and switch contacts with an explicit supply on the opposite side. It accepts a direct source, an output driver, or a fixed resistor pull as an anchor. Firmware pull-ups are not modeled, so an intentional internal pull-up can be documented with `lint_disable`.
16
+
17
+ When this rule applies, its specific finding replaces the general `Electrical/FloatingInput` finding for the same pin. Selecting only `Electrical/FloatingInput` still reports the general finding.
@@ -1,6 +1,6 @@
1
1
  # Electrical/MissingSeriesResistor
2
2
 
3
- An LED has a known unprotected path across a supply. This MVP check uses net reachability and is conservative about complex load branches.
3
+ An LED has a known unprotected path across a supply or GPIO output. The check follows conductive diode and transistor paths but cannot prove current through every active device.
4
4
 
5
5
  ```ruby
6
6
  led :D1, anode: "b10", cathode: "g12"
@@ -9,3 +9,5 @@ wire "h12", "B-"
9
9
  ```
10
10
 
11
11
  Add a current-limiting resistor in series with the LED and verify its two pins land on distinct nets.
12
+
13
+ When the part definition declares `forward_voltage` (volts) and `max_forward_current` (amperes), and the LED is directly across one known supply, the report suggests the next E12 resistor value above `(maximum supply voltage - forward voltage) / maximum current`. This is an estimate from the declared values. Check the LED datasheet, tolerances, and resistor power rating before building the circuit. The report omits a number when any input is unknown.
@@ -8,3 +8,4 @@ supply :B, voltage: 3.3, plus: "T+1", minus: "T-1"
8
8
  ```
9
9
 
10
10
  Connect the grounds when the powered circuits exchange signals or current.
11
+ Declare `isolated: true` on a supply that intentionally remains separate.
@@ -0,0 +1,10 @@
1
+ # Electrical/RailPolarityMismatch
2
+
3
+ An explicit voltage source drives both rails opposite their marked polarities: its positive terminal connects to a `−` rail and its negative terminal to a `+` rail. The check follows electrical jumper connections and uses rail polarity from the board definition. It does not infer polarity from wire colors or net labels.
4
+
5
+ ```ruby
6
+ board :half
7
+ supply :USB, voltage: 5, plus: "B-1", minus: "B+1"
8
+ ```
9
+
10
+ This warning reports the reversed pair once for the source. It skips isolated sources, a source tied to only one marked rail, nets that touch both `+` and `−` rails, and rails without declared polarity. Those cases can be valid in bipolar or custom power layouts. In multi-board circuits, the reversed pair must be on the same named board.
@@ -0,0 +1,5 @@
1
+ # Electrical/ResistorPowerRating
2
+
3
+ Checks resistors with an explicit power rating, such as `resistor :R1, "100 1/4W", pins: %w[a1 a2]`. The check uses the voltage across the resistor and the lowest resistance allowed by an optional tolerance (`"100 5% 1/4W"`). A resistor network is evaluated at the nominal supply voltage unless the resistor is directly across a ranged supply.
4
+
5
+ Choose a resistor with a higher power rating or increase its resistance when the estimated dissipation exceeds the rating.
@@ -7,4 +7,4 @@ led :D1, anode: "b10", cathode: "g12"
7
7
  # Connect anode to GND and cathode to VCC.
8
8
  ```
9
9
 
10
- Swap the connections so the positive pin faces the higher potential.
10
+ Swap accidental reverse connections. For an intentional reverse-biased LED, use `bias: :reverse`. Part definitions can declare `max_reverse_voltage`; ordinary diodes are not flagged by this rule.
@@ -0,0 +1,11 @@
1
+ # Electrical/SupplyOverload
2
+
3
+ A supply with `current_limit:` is delivering more current than its declared
4
+ limit. The value is in amperes: `current_limit: 0.02` means 20 mA.
5
+
6
+ This check uses the circuit's nominal DC operating point and runs only when
7
+ the DC solver supports the whole circuit. It cannot account for module loads
8
+ without a DC model. Size the real supply for startup current, tolerances, and
9
+ loads that are not modeled here.
10
+
11
+ Reduce the load or choose a supply with adequate current capacity.
@@ -8,3 +8,4 @@ ic :U1, "NE555", at: "e20" # NE555 requires at least 4.5 V
8
8
  ```
9
9
 
10
10
  Use a valid supply voltage or a part rated for the circuit voltage.
11
+ For a voltage range, both endpoints are checked when the part is connected directly to one source. Resistor networks use the nominal solved potential.
@@ -0,0 +1,6 @@
1
+ # Electrical/VoltageDomainMismatch
2
+
3
+ A signal pin with `max_voltage` metadata is above its allowed voltage relative to the component ground. Add a level shifter or divider, or use a compatible voltage source.
4
+
5
+ Pins without a declared limit are not checked.
6
+ Range endpoints are checked when the signal and ground connect directly to one source. For resistor networks, the check uses the nominal solved potential.
@@ -1,9 +1,11 @@
1
1
  # Intent/ConnectionMismatch
2
2
 
3
3
  Actual connectivity differs from a declared `connected`, `isolated`, or `net` expectation.
4
+ The rule also reports calculated DC voltage or current outside a declared
5
+ `expect_voltage` or `expect_current` range.
4
6
 
5
7
  ```ruby
6
8
  expect { connected "R1.1", "D1.anode" }
7
9
  ```
8
10
 
9
- Correct the wiring or update the expectation to match the intended circuit. `strict: true` also rejects extra pins on a declared net.
11
+ Correct the wiring or update the expectation to match the intended circuit. `strict: true` rejects extra pins on declared nets and pins on nets omitted from the expectation. If the connection is correct but its name differs, add a `net` label at one of its holes.