Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 3 additions & 2 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ body:
- type: markdown
attributes:
value: |
Thanks for helping improve Relay. Remove private credentials and proprietary source before posting.
Thanks for helping me improve Relay. A small reproduction makes it much easier for me to understand what happened.
Remove private credentials and proprietary source before posting.
Relay reports are advisory and must not be treated as permission to operate physical machinery.
- type: input
id: version
attributes:
label: Relay version
description: Run `relay --version`.
placeholder: relay 0.1.1
placeholder: relay 0.1.2
validations:
required: true
- type: dropdown
Expand Down
4 changes: 4 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ title: "[Feature]: "
labels:
- enhancement
body:
- type: markdown
attributes:
value: |
I appreciate ideas that explain the real problem first. That context helps me decide whether Relay needs a new rule, better parsing, or clearer documentation.
- type: textarea
id: problem
attributes:
Expand Down
5 changes: 3 additions & 2 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
## Summary

Describe what changed and why.
Tell me what you changed and what led you to it.

## User impact

Explain how this affects findings, compatibility, performance, reports, or documentation.
Explain how this affects findings, compatibility, performance, reports, or documentation. If
nothing changes for users, say that directly.

## Validation

Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## 0.1.2 — 2026-07-29

- Added the personal story behind Relay and a narrative walkthrough of how analysis moves from
source discovery to findings and timing estimates.
- Reworked tutorials, architecture, configuration, timing, limitations, security, support,
contribution, conduct, and roadmap introductions in the maintainer's voice.
- Kept commands, rule definitions, safety boundaries, and compatibility statements concise and
technically unchanged.
- Updated GitHub issue and pull-request guidance to be more welcoming and direct.
- No analyser rules, report schemas, public Python APIs, or CLI behaviour changed in this
documentation-focused release.

## 0.1.1 — 2026-07-29

- Centralized package versioning in `relay.__version__` so CLI and distribution metadata cannot
Expand Down
10 changes: 5 additions & 5 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Code of conduct

Relay contributors must help maintain a welcoming, technically rigorous, and safety-conscious
community.
I want Relay to stay welcoming, technically rigorous, and honest about safety. Everyone
participating in the project shares responsibility for that.

## Expected behaviour

Expand All @@ -19,9 +19,9 @@ disruptive bad-faith behaviour are not accepted.

Report security problems through
[GitHub private security advisories](https://github.com/devkyato/Relay/security/advisories/new).
Report other conduct concerns privately to the repository owner through their GitHub profile.
Maintainers may edit or remove contributions and temporarily or permanently restrict participation
when needed to protect the community.
Report other conduct concerns privately to me through my GitHub profile. I may edit or remove
contributions and temporarily or permanently restrict participation when needed to protect the
community.

Enforcement decisions should be proportionate, documented privately, and focused on community
safety. This code applies in project spaces and when someone publicly represents the project.
7 changes: 7 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Contributing

Thanks for taking a look at Relay. I keep the project intentionally small and reviewable, so a
focused change with a clear reason is more useful than a broad rewrite.

Create a virtual environment, install `python -m pip install -e ".[dev]"`, then run:

```console
Expand All @@ -14,3 +17,7 @@ Rules must keep stable IDs, deterministic ordering, exact-line fixtures, and exp
Add false-positive and malformed-input tests with every detector change. Never execute analysed
source in a test or implementation. Changes involving physical control safety should document
assumptions and avoid claiming proof.

When proposing a new rule, tell me what you noticed in real code, what Relay should report, and
where the heuristic could be wrong. That last part matters: I would rather document uncertainty
than make a confident claim the analyser cannot support.
38 changes: 31 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ Arduino, ESP32, embedded C++, MicroPython, and Python control programs. Version
alpha: useful for review and teaching, but intentionally cautious and not a safety certification.
Analysis never executes, imports, compiles, or uploads the source being inspected.

## Why I built Relay

I kept coming back to one awkward question while reading control code: if this call waits here,
what quietly stops running somewhere else? A plain warning about `delay()` was not enough for me.
I wanted to see the reachable call path, the time involved, and the tasks whose timing contracts
could be missed.

That thought became Relay. I built it as a local-first project because firmware and control code
can be sensitive, and a review tool should not need to upload that source just to be useful.

## Install

Relay supports Python 3.9–3.14.
Expand All @@ -27,7 +37,7 @@ relay --version
On Linux or macOS, activate with `source .venv/bin/activate`. Normal analysis is entirely
offline after installation.

## Five-minute demonstration
## Try it in five minutes

```console
relay check examples
Expand All @@ -38,7 +48,8 @@ relay rules
relay doctor .
```

Typical output:
I usually start with `relay check examples`, then narrow the command to one file once a finding
looks interesting. Typical output looks like this:

```text
HIGH RLY101 blocking_robot.ino:16
Expand All @@ -56,6 +67,17 @@ Exit status is non-zero when a finding reaches `--fail-on` (default: `warning`).
`--suggestions-out relay-suggestions.md` for reviewable patterns; Relay never edits source in
0.1.x and never claims a suggestion is automatically safe for machinery.

## How it works

Relay discovers supported source files, parses their structure without running them, and looks
for blocking or timing-sensitive patterns. It then connects direct calls into an estimated call
graph and compares reachable blocking time with any timing contracts you configured.

Oh—on this part, I deliberately kept facts and estimates separate. A source location is a fact;
an inferred call path or missed-execution count is an estimate. Every finding includes severity,
confidence, evidence, and a suggested direction so you can decide what holds up on the real
target.

## Timing contracts

Copy `relay.toml.example` to `relay.toml`, or run `relay init` (which refuses to overwrite an
Expand Down Expand Up @@ -104,10 +126,12 @@ The public `AnalysisResult`, `Finding`, `Severity`, and `Confidence` models are

## What Relay is not

Relay is not a compiler, hardware simulator, formal-verification system, replacement for tests
on real devices, or a guarantee of real-time behaviour. It cannot see interrupt timing, library
internals, dynamic dispatch, electrical conditions, scheduler details, or worst-case execution
time. Its timeline is a conservative scheduling estimate, never a cycle-accurate simulation.
I thought carefully about this boundary: Relay should explain suspicious timing paths, not pretend
to certify them. It is not a compiler, hardware simulator, formal-verification system,
replacement for tests on real devices, or a guarantee of real-time behaviour. It cannot see
interrupt timing, library internals, dynamic dispatch, electrical conditions, scheduler details,
or worst-case execution time. Its timeline is a conservative scheduling estimate, never a
cycle-accurate simulation.

## Security, contributing, and licence

Expand All @@ -117,4 +141,4 @@ analysed source or a symlink with a report. See [security](docs/security.md), [l
[roadmap](docs/roadmap.md), [support](SUPPORT.md), [contributing](CONTRIBUTING.md), and
[SECURITY.md](SECURITY.md).

Relay is copyright devkyato and available under the [MIT License](LICENSE).
This is a personal open-source project by devkyato, shared under the [MIT License](LICENSE).
6 changes: 3 additions & 3 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Security policy

Relay 0.1.x receives best-effort security fixes. Report vulnerabilities privately through the
GitHub repository's security advisory feature; do not include sensitive source files in a public
issue.
Relay is a personal project, but I still want security reports handled carefully. Relay 0.1.x
receives best-effort security fixes. Report vulnerabilities privately through the GitHub
repository's security advisory feature; do not include sensitive source files in a public issue.

Relay parses untrusted text but does not execute, import, compile, or upload it. Keep analysis
offline. A Relay report is advice, not permission to deploy control code to physical machinery.
11 changes: 7 additions & 4 deletions SUPPORT.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
# Support

Relay is an early open-source project maintained on a best-effort basis.
Relay is a personal open-source project that I maintain on a best-effort basis. I may not answer
immediately, but a small reproducible example gives me the best chance of understanding what you
ran into.

- Read the [README](README.md) and [documentation](docs/) first.
- Use the bug-report form for reproducible crashes or incorrect findings.
- Use the feature-request form for rule, parser, timing, or report proposals.
- Use the bug-report form when Relay crashes or reports something incorrectly.
- Use the feature-request form when you have an idea for a rule, parser, timing, or report change.
- Report vulnerabilities through
[GitHub private security advisories](https://github.com/devkyato/Relay/security/advisories/new).

Include `relay --version`, Python and operating-system versions, the exact command, and a minimal
sanitised source sample. Do not post credentials, private firmware, or machinery control secrets.
sanitised source sample. Oh—and please do not post credentials, private firmware, or machinery
control secrets.
19 changes: 13 additions & 6 deletions docs/architecture.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
# Architecture

`discovery` performs bounded traversal. `lexer` masks C-family comments and strings while
preserving offsets; `parser` adds balanced blocks, calls, loops, functions, and constants.
Python uses `ast.parse` without importing the target. `callgraph` links simple direct calls.
`rules` emits immutable findings, `timing` logic applies contracts, and `reports`/`timeline`
present deterministic results. `analyser.analyse_path` is the public orchestration boundary.
I split Relay into small stages so I can reason about what each stage knows—and, just as
importantly, what it does not know.

No phase invokes a compiler, interpreter, hardware tool, network service, or target source.
1. `discovery` walks the requested path with explicit file-count and size bounds.
2. `lexer` masks C-family comments and strings while preserving source offsets.
3. `parser` identifies balanced blocks, calls, loops, functions, and simple constants. Python
uses `ast.parse` without importing the target.
4. `callgraph` connects simple direct calls, and `rules` emits immutable findings.
5. `timing` compares reachable blocking estimates with configured contracts.
6. `reports` and `timeline` present the result in deterministic order.

`analyser.analyse_path` is the public orchestration boundary. Oh—one design choice I do not want
to blur: no stage invokes a compiler, interpreter, hardware tool, network service, or target
source.
3 changes: 3 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Configuration

I kept configuration explicit and local to the project so a report can be traced back to the
assumptions that produced it.

Relay searches from the analysed path upward for `relay.toml`; `--config FILE` overrides this.
The Python API uses the `RelayConfig` passed by its caller.

Expand Down
3 changes: 3 additions & 0 deletions docs/limitations.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Limitations

This is the page I would want someone to read before treating a finding as a conclusion. Relay is
useful because it is conservative, but that also means context can prove a warning harmless.

Relay's C-family parser is structural, not a complete C++ compiler. Macros, templates, overloads,
function pointers, virtual dispatch, conditional compilation, and calls hidden in libraries can
obscure behaviour. Python dynamic dispatch and monkey-patching are not resolved. Some polling,
Expand Down
48 changes: 48 additions & 0 deletions docs/releases/0.1.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Relay 0.1.2

Relay started with a question I kept asking while reading control code: when a call waits here,
what quietly stops running somewhere else?

Version 0.1.2 tells that story more clearly. I rewrote the public documentation in the voice I
use when explaining the project to another person—direct, personal, and honest about what the
analysis can and cannot prove.

## What changed

- The README now explains why I built Relay and walks through how an analysis works.
- Tutorials connect each command to the reason I would use it during a review.
- Architecture, configuration, timing, and limitation pages explain the decisions behind their
technical details.
- Support, contributing, security, conduct, roadmap, and GitHub templates now sound like a
maintainer speaking directly to a contributor.
- Commands, rule meanings, report formats, and safety boundaries remain precise and unchanged.

Oh—and that last point is important. This release changes how I explain Relay, not what Relay
claims to know. Findings are still conservative review prompts; timing values are still estimates;
and source is still analysed locally without being executed, imported, compiled, or uploaded.

## How Relay works

Relay first discovers supported files within explicit bounds. It parses Python with the standard
AST and C-family sources with a position-preserving structural parser. From there, it identifies
blocking patterns, connects simple direct calls, and compares reachable delays with any timing
contracts you provide. The output keeps source facts, inferred paths, and timing estimates
separate so each conclusion can be reviewed.

## Compatibility

- Python 3.9–3.14
- Arduino, ESP32, embedded C++, MicroPython, and Python sources
- Local and offline operation after installation
- No analyser rule, report schema, Python API, or CLI behaviour changes from 0.1.1

## Install

```console
python -m pip install relay_lint-0.1.2-py3-none-any.whl
relay --version
relay check examples
```

Relay does not guarantee real-time or physical-machine safety. Test every change on the actual
target before deployment.
10 changes: 7 additions & 3 deletions docs/roadmap.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
# Roadmap

Relay 0.1.x establishes the safe, local-first structural analyser and timing-impact model.
Relay 0.1.x is the foundation I wanted first: a safe, local-first structural analyser with an
honest timing-impact model. I am keeping the next steps focused on places where better context
can make the output more useful without making it sound more certain than it is.

Priorities for 0.2.0 are:
For 0.2.0, I am thinking about:

- reduce false positives through context-aware network timeout and polling analysis;
- add source-level suppression directives with auditable reasons;
- improve C++ macro, template, overload, and cross-file resolution;
- prototype optional Clang enrichment without making it a core dependency;
- expand timing contracts and machine-readable schemas without implying cycle accuracy.

Roadmap work is tracked in GitHub issues and may change based on reproducible user feedback.
Each item is tracked in GitHub issues. The order may change when a reproducible example shows
that another problem matters more; that is one of the nice parts of growing this as an open
personal project.
4 changes: 3 additions & 1 deletion docs/rules.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Rule reference

Every rule reports evidence, location, severity, confidence, remediation, and this local reference.
I keep rule IDs stable so reports remain comparable across runs. Every rule reports evidence,
location, severity, confidence, remediation, and this local reference. The short descriptions
below explain what each rule notices; they are review prompts, not proof of unsafe behaviour.

## RLY101
Blocking Arduino `delay()`. **High / high confidence.** Use rollover-safe `millis()` scheduling.
Expand Down
2 changes: 2 additions & 0 deletions docs/security.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Secure analysis

My baseline for Relay is simple: reading a project should not mean running that project.

Relay reads source as bounded UTF-8 text with replacement for malformed bytes. It never imports
analysed Python, invokes a build tool, compiles C++, follows directory symlinks, or makes a
background network request. Default limits are 2 MB per file and 10,000 files.
Expand Down
4 changes: 4 additions & 0 deletions docs/timing-model.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Timing model

The question I want this model to answer is not “exactly how long will the hardware take?” Relay
cannot know that statically. The useful question is “if this visible wait is reachable, which
declared timing expectations could it disrupt?”

Relay evaluates literal durations and simple named numeric constants. A blocking duration is
compared with each reachable task contract. Approximate missed executions are
`floor(block duration / task period)`; latency excess is `block duration - maximum latency`.
Expand Down
11 changes: 9 additions & 2 deletions docs/tutorials.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
# Tutorials

These are the short workflows I use when showing Relay to someone for the first time. Start with
the smallest one that matches what you are reviewing, then follow the evidence back into the
source.

## Review an Arduino sketch

Run `relay check sketch.ino --suggest`. Start with high-confidence RLY101, RLY107, and RLY109
findings, then inspect estimated call paths. Convert one blocking sequence at a time and rerun.
findings, then inspect estimated call paths. I prefer changing one blocking sequence at a time
and rerunning Relay so the effect stays easy to explain.

## Add deadlines

Run `relay init`, map each task name to its actual function, and specify realistic periods or
latency budgets. Use `relay timeline PATH --duration 5s` to communicate the conservative impact.
I thought about making contracts automatic, but explicit names and budgets are easier to audit.

## CI

Use `relay check src --format sarif --output relay.sarif --fail-on high`. A status of 1 means a
finding met the threshold; 2 means invocation or configuration failed.
finding met the threshold; 2 means invocation or configuration failed. This distinction lets CI
separate “Relay found something” from “Relay could not complete the analysis.”
2 changes: 1 addition & 1 deletion src/relay/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@
"Severity",
"analyse_path",
]
__version__ = "0.1.1"
__version__ = "0.1.2"