|
| 1 | +# Broadside-AI Project Audit Report |
| 2 | + |
| 3 | +**Date:** 2026-04-03 |
| 4 | +**Version Audited:** 0.1.0 (pre-release alpha) |
| 5 | +**Repository:** HuginnIndustries/Broadside-AI |
| 6 | + |
| 7 | +--- |
| 8 | + |
| 9 | +## 1. Executive Summary |
| 10 | + |
| 11 | +Broadside-AI is a CLI-first Python tool for **parallel LLM orchestration using a scatter/gather architecture**. It fans a prompt out to N independent LLM calls, collects the results, and synthesizes them into a single output. The project targets automation and CI/CD scenarios where running a task multiple times and aggregating signal is valuable without the overhead of a full workflow framework. |
| 12 | + |
| 13 | +**Overall Assessment:** The project demonstrates strong engineering fundamentals for an alpha-stage tool. Architecture is clean and intentionally scoped, code quality tooling is strict, security posture is solid, and CI/CD is comprehensive. A handful of minor issues and missing features are noted below. |
| 14 | + |
| 15 | +| Dimension | Rating | Notes | |
| 16 | +|-----------|--------|-------| |
| 17 | +| Architecture | Strong | Clean scatter/gather pipeline, well-separated concerns | |
| 18 | +| Code Quality | Strong | Strict mypy, Ruff, no dead code, consistent patterns | |
| 19 | +| Security | Strong | No hardcoded secrets, safe parsing, validated inputs | |
| 20 | +| Testing | Adequate | 39 tests cover core paths; no coverage reporting | |
| 21 | +| CI/CD | Strong | Multi-platform matrix, smoke tests, package validation | |
| 22 | +| Documentation | Strong | 6 markdown docs, task library, examples | |
| 23 | +| Dependencies | Good | Minimal core deps, optional extras, modern build system | |
| 24 | + |
| 25 | +--- |
| 26 | + |
| 27 | +## 2. Architecture & Design |
| 28 | + |
| 29 | +### Core Pipeline |
| 30 | + |
| 31 | +``` |
| 32 | +Task -> Scatter -> [Agent 1, Agent 2, ..., Agent N] -> Gather -> Synthesize -> Output |
| 33 | +``` |
| 34 | + |
| 35 | +- **Task** (`task.py`, 43 lines) - Pydantic model: prompt + optional context + optional output_schema |
| 36 | +- **Scatter** (`scatter.py`, 120 lines) - Fans task to N independent calls (parallel or sequential) |
| 37 | +- **Gather** (`gather.py`, 74 lines) - Normalizes results, parses JSON, computes stats |
| 38 | +- **Synthesize** (`synthesize.py`, 103 lines) - Merges results via pluggable strategies |
| 39 | +- **Run** (`run.py`, 94 lines) - Convenience orchestrator for the full pipeline |
| 40 | + |
| 41 | +### Design Patterns |
| 42 | + |
| 43 | +| Pattern | Where | Purpose | |
| 44 | +|---------|-------|---------| |
| 45 | +| Strategy | `strategies/` | Pluggable synthesis algorithms (llm, consensus, voting, weighted_merge) | |
| 46 | +| Plugin/Registry | `backends/__init__.py` | Dynamic backend loading with `register()` / `get_backend()` | |
| 47 | +| Stateless Pipeline | Core modules | No shared state between stages or runs | |
| 48 | +| Circuit Breaker | `budget.py` | Token budget enforcement with thread-safe tracking | |
| 49 | + |
| 50 | +### Scope Boundaries (By Design) |
| 51 | + |
| 52 | +The project explicitly excludes: inter-agent messaging, workflow DAGs, persistent state, crew/role hierarchies, and autonomous long-running agents. This is documented in `ARCHITECTURE.md` and enforced in `CONTRIBUTING.md` (what-won't-be-merged section). |
| 53 | + |
| 54 | +### Codebase Size |
| 55 | + |
| 56 | +- **Source:** ~2,400 lines across 24 files in `src/broadside_ai/` |
| 57 | +- **Tests:** ~500 lines across 9 test files + 79-line conftest |
| 58 | +- **Total repository:** Compact and navigable |
| 59 | + |
| 60 | +--- |
| 61 | + |
| 62 | +## 3. Code Quality |
| 63 | + |
| 64 | +### Tooling |
| 65 | + |
| 66 | +| Tool | Configuration | Status | |
| 67 | +|------|--------------|--------| |
| 68 | +| **mypy** | `strict = true`, Python 3.10 target | Enabled, CI-enforced | |
| 69 | +| **Ruff** | Line length 99, select E/F/I/N/W/UP | Enabled, CI-enforced | |
| 70 | +| **Type hints** | Throughout all source files | Consistent | |
| 71 | + |
| 72 | +### Observations |
| 73 | + |
| 74 | +- **No dead code detected.** All modules are used in the pipeline. |
| 75 | +- **No TODO/FIXME/HACK comments** in the source. |
| 76 | +- **No hardcoded secrets** anywhere in the codebase. |
| 77 | +- **Consistent naming conventions** across all modules. |
| 78 | +- **Clean async patterns** using `asyncio.gather()` for parallel execution. |
| 79 | +- **Pydantic validation** with `extra = "forbid"` prevents silent misconfiguration. |
| 80 | +- **Thread-safe budget tracking** using `threading.Lock`. |
| 81 | + |
| 82 | +### Minor Style Notes |
| 83 | + |
| 84 | +- Backend constructors contain long multi-line error messages with shell commands (`backends/anthropic.py:36-41`, `backends/openai.py:37-42`). Functional but could use `textwrap.dedent` for readability. |
| 85 | + |
| 86 | +--- |
| 87 | + |
| 88 | +## 4. Security |
| 89 | + |
| 90 | +### Strengths |
| 91 | + |
| 92 | +| Area | Implementation | Risk | |
| 93 | +|------|---------------|------| |
| 94 | +| API key handling | Environment variables only (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`), never logged | Low | |
| 95 | +| YAML parsing | `yaml.safe_load()` used exclusively (prevents code injection) | Low | |
| 96 | +| Input validation | Pydantic with `extra: forbid`; `n >= 1` enforced; budget limits | Low | |
| 97 | +| Code injection surface | No `eval()`, `exec()`, `pickle`, or shell command construction | Low | |
| 98 | +| HTTP requests | Via httpx and official SDK clients only | Low | |
| 99 | +| Dependency surface | 5 core deps, all well-maintained libraries | Low | |
| 100 | + |
| 101 | +### Minor Observations |
| 102 | + |
| 103 | +1. **Model name path construction** (`cli.py:419`): Model names are sanitized with `.replace(":", "-").replace("/", "-")` before use in directory paths. Adequate for the threat model (CLI user controls input), but a `pathlib` canonicalization would be more defensive. |
| 104 | + |
| 105 | +2. **Prompt injection via task context**: Context is directly interpolated into prompts (`task.py:28-42`). This is expected behavior for a CLI tool where the caller controls all inputs, not a vulnerability. |
| 106 | + |
| 107 | +3. **Conflict detection severity** (`conflicts.py:84-92`): Always returns `severity: "hard"` regardless of LLM classification. Not a security issue, but the feature is incomplete. |
| 108 | + |
| 109 | +--- |
| 110 | + |
| 111 | +## 5. Testing |
| 112 | + |
| 113 | +### Overview |
| 114 | + |
| 115 | +| Metric | Value | |
| 116 | +|--------|-------| |
| 117 | +| Test framework | pytest + pytest-asyncio | |
| 118 | +| Test files | 9 | |
| 119 | +| Test cases | 39 | |
| 120 | +| Test LOC | ~500 | |
| 121 | +| Async mode | Auto | |
| 122 | +| Mock infrastructure | MockBackend, JsonMockBackend in conftest.py | |
| 123 | + |
| 124 | +### Coverage by Module |
| 125 | + |
| 126 | +| Test File | Module Tested | Tests | |
| 127 | +|-----------|--------------|-------| |
| 128 | +| `test_budget.py` | Budget circuit breaker | 4 | |
| 129 | +| `test_cli.py` | CLI commands and output contracts | 4 | |
| 130 | +| `test_execution.py` | Parallel/sequential mode resolution | 5 | |
| 131 | +| `test_gather.py` | Result normalization and stats | 4 | |
| 132 | +| `test_integration.py` | Full scatter-gather-synthesize pipeline | 2 | |
| 133 | +| `test_quality.py` | Early stop and agreement detection | 6 | |
| 134 | +| `test_synthesize.py` | Synthesis strategy routing | 3 | |
| 135 | +| `test_task.py` | Task model validation | 5 | |
| 136 | +| `test_weighted_merge.py` | Weighted merge algorithm | 6 | |
| 137 | + |
| 138 | +### Gaps |
| 139 | + |
| 140 | +- **No coverage reporting** - `pytest-cov` is not in dev dependencies. No way to measure untested paths. |
| 141 | +- **Integration tests are minimal** - Only 2 tests cover the full pipeline. |
| 142 | +- **Backend implementations untested directly** - Covered only via mocks. This is acceptable given they wrap SDK clients, but edge cases (network errors, rate limits) are not exercised. |
| 143 | + |
| 144 | +--- |
| 145 | + |
| 146 | +## 6. CI/CD |
| 147 | + |
| 148 | +### GitHub Actions Workflows |
| 149 | + |
| 150 | +| Workflow | Trigger | Purpose | |
| 151 | +|----------|---------|---------| |
| 152 | +| `ci.yml` | Push to main, all PRs | Full quality gate | |
| 153 | +| `publish.yml` | GitHub Release event | PyPI publication (Trusted Publishing) | |
| 154 | +| `publish-testpypi.yml` | Manual dispatch | TestPyPI dry-run | |
| 155 | + |
| 156 | +### CI Pipeline (`ci.yml`) |
| 157 | + |
| 158 | +1. Checkout code |
| 159 | +2. Setup Python (matrix: **3.10 + 3.13** on **Ubuntu + Windows**) |
| 160 | +3. Install package with dev dependencies |
| 161 | +4. Run pytest |
| 162 | +5. Run Ruff lint + format checks |
| 163 | +6. Run mypy type checking |
| 164 | +7. CLI smoke tests (`--help`, `validate-task`) |
| 165 | +8. Build package with `build` |
| 166 | +9. Validate distribution with `twine check` |
| 167 | +10. Smoke-test built package (Python 3.13 only) |
| 168 | + |
| 169 | +**Assessment:** Comprehensive. Multi-platform matrix catches OS-specific issues (a recent Windows fix confirms this catches real bugs). Package build validation prevents broken releases. |
| 170 | + |
| 171 | +--- |
| 172 | + |
| 173 | +## 7. Documentation |
| 174 | + |
| 175 | +### Files |
| 176 | + |
| 177 | +| File | Size | Purpose | |
| 178 | +|------|------|---------| |
| 179 | +| `README.md` | 10 KB | Install, quickstart, CLI/API examples, dev setup | |
| 180 | +| `ARCHITECTURE.md` | 4.3 KB | Design philosophy, data flow, extension points, non-goals | |
| 181 | +| `CONTRIBUTING.md` | 2.3 KB | Dev setup, contribution rules, what won't be merged | |
| 182 | +| `RELEASE.md` | 2.1 KB | Release process, PyPI Trusted Publishing setup | |
| 183 | +| `ROADMAP.md` | 2.1 KB | v1 priorities, longer-term ideas, non-goals | |
| 184 | +| `SECURITY.md` | 565 B | Security policy, vulnerability reporting | |
| 185 | +| `tasks/README.md` | - | Task library documentation | |
| 186 | +| `benchmarks/README.md` | - | Benchmark documentation | |
| 187 | +| `.github/PULL_REQUEST_TEMPLATE.md` | - | PR template | |
| 188 | + |
| 189 | +**Assessment:** Unusually thorough for an alpha project. Architecture decisions are well-documented, contribution boundaries are explicit, and the release process is step-by-step. |
| 190 | + |
| 191 | +### Missing |
| 192 | + |
| 193 | +- **CHANGELOG.md** - No changelog file. Git history is clean but a changelog is standard practice before public release. |
| 194 | + |
| 195 | +--- |
| 196 | + |
| 197 | +## 8. Dependencies |
| 198 | + |
| 199 | +### Core (Required) |
| 200 | + |
| 201 | +| Package | Version | Purpose | |
| 202 | +|---------|---------|---------| |
| 203 | +| httpx | >=0.27.0 | Async HTTP client (Ollama backend) | |
| 204 | +| pydantic | >=2.0.0 | Data validation and serialization | |
| 205 | +| rich | >=13.0.0 | Terminal formatting | |
| 206 | +| click | >=8.0.0 | CLI framework | |
| 207 | +| pyyaml | >=6.0 | YAML task parsing | |
| 208 | + |
| 209 | +### Optional (Backend Extras) |
| 210 | + |
| 211 | +| Package | Extra | Purpose | |
| 212 | +|---------|-------|---------| |
| 213 | +| anthropic | `[anthropic]` | >=0.40.0, Claude API | |
| 214 | +| openai | `[openai]` | >=1.50.0, OpenAI-compatible APIs | |
| 215 | + |
| 216 | +### Dev |
| 217 | + |
| 218 | +| Package | Purpose | |
| 219 | +|---------|---------| |
| 220 | +| pytest >=8.0.0 | Testing | |
| 221 | +| pytest-asyncio >=0.24.0 | Async test support | |
| 222 | +| ruff >=0.8.0 | Linting and formatting | |
| 223 | +| mypy >=1.13.0 | Static type checking | |
| 224 | +| build >=1.2.2 | Package building | |
| 225 | +| twine >=6.1.0 | Distribution validation | |
| 226 | + |
| 227 | +### Notes |
| 228 | + |
| 229 | +- **No lock file** - Acceptable for a library (applications pin, libraries don't). |
| 230 | +- **Build system:** Hatchling (modern, PEP 517 compliant). |
| 231 | +- **Python support:** 3.10, 3.11, 3.12, 3.13 (tested in CI for 3.10 and 3.13). |
| 232 | + |
| 233 | +--- |
| 234 | + |
| 235 | +## 9. Issues & Recommendations |
| 236 | + |
| 237 | +### Issues Found |
| 238 | + |
| 239 | +| # | Issue | Severity | Location | |
| 240 | +|---|-------|----------|----------| |
| 241 | +| 1 | PDF file checked into repository | Low | Root directory | |
| 242 | +| 2 | Conflict detection incomplete - always returns `severity: "hard"` | Low | `conflicts.py:84-92` | |
| 243 | +| 3 | Voting strategy makes N extra LLM calls for label extraction | Low | `strategies/voting.py:53-62` | |
| 244 | +| 4 | No test coverage reporting configured | Low | `pyproject.toml` | |
| 245 | +| 5 | Benchmark results committed to repo could bloat wheel builds | Low | `benchmarks/results/` | |
| 246 | +| 6 | No CHANGELOG.md | Low | Root directory | |
| 247 | + |
| 248 | +### Recommendations |
| 249 | + |
| 250 | +1. **Add the PDF to `.gitignore`** or move it to an external location. Binary files in Git repos increase clone size permanently. |
| 251 | + |
| 252 | +2. **Add `pytest-cov`** to dev dependencies and configure a coverage target. This provides visibility into untested code paths and can be enforced in CI. |
| 253 | + |
| 254 | +3. **Add a `CHANGELOG.md`** before the first public PyPI release. Even a simple keep-a-changelog format helps users track breaking changes. |
| 255 | + |
| 256 | +4. **Exclude `benchmarks/results/`** from the wheel distribution via `pyproject.toml` build configuration to keep package size minimal. |
| 257 | + |
| 258 | +5. **Consider batching voting label extraction** into a single LLM call to reduce cost and latency of the voting strategy. |
| 259 | + |
| 260 | +6. **Finish or remove conflict detection** (`conflicts.py`). The current implementation is partially functional - it should either be completed with proper severity parsing or explicitly marked as experimental. |
| 261 | + |
| 262 | +--- |
| 263 | + |
| 264 | +## 10. Summary |
| 265 | + |
| 266 | +Broadside-AI is a well-engineered, narrowly-scoped tool that does one thing cleanly: parallel LLM scatter/gather with synthesis. For a v0.1.0 alpha, the project demonstrates mature engineering practices: |
| 267 | + |
| 268 | +- **Architecture** is clean, documented, and deliberately constrained |
| 269 | +- **Code quality** is enforced by strict tooling (mypy strict, Ruff) |
| 270 | +- **Security** posture is solid with no identified vulnerabilities |
| 271 | +- **CI/CD** is comprehensive with multi-platform testing |
| 272 | +- **Documentation** is thorough and includes design rationale |
| 273 | + |
| 274 | +The issues identified are all low-severity and relate to missing features or polish rather than fundamental problems. The project is well-positioned for a public release after addressing the recommendations above. |
0 commit comments