diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 0000000..9a2ffbe --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,20 @@ +name: Bug +description: A crash, an error on a file that should read, or anything else that does not work. +labels: ["bug"] +body: + - type: textarea + id: what + attributes: + label: What happened + description: The command, its output, and what you expected. + validations: + required: true + - type: textarea + id: file + attributes: + label: The input + description: A synthetic file or scene that reproduces it (never a file you are not free to share). + - type: input + id: version + attributes: + label: luxpath version or commit diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..0e32f4c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: Security vulnerability + url: https://github.com/Erry91/luxpath/security/advisories/new + about: Report a vulnerability privately (crafted files that crash, hang or exploit luxpath). diff --git a/.github/ISSUE_TEMPLATE/wrong-result.yml b/.github/ISSUE_TEMPLATE/wrong-result.yml new file mode 100644 index 0000000..5cd6939 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/wrong-result.yml @@ -0,0 +1,29 @@ +name: Wrong result +description: luxpath computed a value or a verdict you believe is wrong. These are treated as the most serious bugs. +labels: ["wrong-result"] +body: + - type: markdown + attributes: + value: | + Please do not attach manufacturers' photometric files or real building plans unless you are free to share + them. A synthetic scene or file that shows the problem is ideal. + - type: textarea + id: what + attributes: + label: What luxpath reported, and what you expected + description: The values (lux, ratios, verdicts) and, if you compared with another tool, which one and its version. + validations: + required: true + - type: textarea + id: input + attributes: + label: How to reproduce + description: The scene (TOML) and the command; or a description of the luminaire and the geometry. + render: toml + validations: + required: true + - type: input + id: version + attributes: + label: luxpath version or commit + description: "`luxpath --version`, or the commit you built" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 75afcdb..e538953 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,3 +30,10 @@ jobs: targets: wasm32-unknown-unknown - uses: Swatinem/rust-cache@v2 - run: cargo xtask ci + + licences: + name: licences and advisories (cargo deny) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: EmbarkStudios/cargo-deny-action@v2 diff --git a/CLAUDE.md b/CLAUDE.md index 9aa8524..158abe5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -44,7 +44,7 @@ iterating: `cargo test -p luxpath-calc`. ## Commits and PRs `main` is the integration branch. Branch as `/` (`feat/`, `fix/`, `docs/`, `chore/`, `refactor/`), one task id per commit (e.g. `M1.2: EULUMDAT reader`), commit only green states, open a PR using -`.github/pull_request_template.md`, merge when CI is green. +`.github/pull_request_template.md`, merge when CI is green. `cargo deny check` for dependency changes. ## Running - `cargo run -p luxpath-cli -- --help` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..5870ebc --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,34 @@ +# Contributing to luxpath + +Thank you for helping. luxpath computes emergency lighting, a life-safety subject, so a few rules come before +everything else. They are in [AGENTS.md](AGENTS.md) (they bind people and AI agents alike); the short version: + +- **Never commit a standard's text, tables or figures** (EN 1838, EN 50172, IES, CIE…). Requirement values may be + encoded with their clause and edition, in our own words (`docs/standards-parity.md`). +- **Clean-room with respect to other lighting software.** Compare results with DIALux, Relux and others on your own + synthetic scenes; never decompile them, and never copy their luminaire databases, artwork or sample projects. +- **No GPL or AGPL code**, not even as a dependency (`cargo deny check` enforces the licences). +- **Never commit manufacturers' photometric files or real building plans.** Test fixtures are synthetic and listed + with their source in a `README.md` next to them. +- **A wrong "pass" is the worst bug.** Missing or ambiguous data gives "cannot verify". Requirement checks are + tested on both sides of every threshold. +- **Never panic on input.** No `unwrap`, indexing or unchecked arithmetic on anything read from a file. + +## Where help is most useful + +- Photometric files that luxpath reads wrongly or refuses (gaps 12 and 15 in `docs/gaps.md`): a description, or a + synthetic file reproducing the quirk. +- Comparing luxpath's results with DIALux evo or Relux on synthetic scenes (milestone M6, `docs/roadmap.md`). +- National editions and rules around EN 1838 (`docs/standards-parity.md`). +- The work list: `docs/gaps.md`, top rows first. + +## How to work + +1. Read `docs/status.md`, `docs/gaps.md` and `docs/architecture.md`; `CLAUDE.md` describes the day-to-day workflow. +2. Branch as `/` (`feat/`, `fix/`, `docs/`, `chore/`, `refactor/`). +3. Run `cargo xtask ci` (format, clippy, tests, the performance budget, the WASM build, layers, the feature + checklist) and, for licence changes, `cargo deny check`. +4. Open a pull request with the template; record what changed in `parity/features.toml`, `docs/status.md`, + `docs/gaps.md` and the `ROADMAP.md` log. + +By contributing, you agree that your contributions are licensed under the project's licence, MIT OR Apache-2.0. diff --git a/Cargo.toml b/Cargo.toml index 954c53e..e1483d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,8 @@ edition = "2024" license = "MIT OR Apache-2.0" rust-version = "1.95" repository = "https://github.com/Erry91/luxpath" +# Nothing is published to crates.io until the owner decides (docs/publishing.md). +publish = false [workspace.dependencies] # internal (layer order: see docs/architecture.md and `cargo xtask layers`) diff --git a/README.md b/README.md index 23bb3ec..578ae3e 100644 --- a/README.md +++ b/README.md @@ -40,9 +40,11 @@ cargo xtask parity # feature progress by milestone | [docs/gaps.md](docs/gaps.md) | Every known shortfall, ranked: the work list | | [docs/status.md](docs/status.md) | Where work stands right now, blockers, open questions | | [docs/architecture.md](docs/architecture.md) | Crates, layers, data flow, design decisions | +| [docs/scene-format.md](docs/scene-format.md) | The scene file format that `luxpath check` reads | | [docs/standards-parity.md](docs/standards-parity.md) | EN 1838:2024 requirements and their implementation status | | [docs/research.md](docs/research.md) | Market and standards research behind the project | | [parity/features.toml](parity/features.toml) | Machine-readable feature checklist (`cargo xtask parity`) | +| [CONTRIBUTING.md](CONTRIBUTING.md) / [SECURITY.md](SECURITY.md) | How to help, and how to report wrong results and vulnerabilities | | [AGENTS.md](AGENTS.md) / [CLAUDE.md](CLAUDE.md) | Rules and working instructions for contributors and agents | ## Disclaimer diff --git a/ROADMAP.md b/ROADMAP.md index c99c11f..7ba58d9 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -32,6 +32,7 @@ luxpath's one-page summary. Details live in: | Date | Change | |---|---| +| 2026-10-21 | Publishing prepared (docs/publishing.md): history scanned clean, `cargo deny` with a CI job, SECURITY.md, CONTRIBUTING.md, issue templates (wrong result, bug), `publish = false` until a crates.io decision. | | 2026-10-21 | M3: scene format version 1 (docs/scene-format.md: photometry with emergency output, luminaires, routes, open and high-risk areas, points of emphasis; unknown fields refused, errors with line and column); `luxpath check` with exit codes 0/1/2/3, results per element with their assumptions, "cannot verify" when an emergency output is missing; three example scenes with synthetic photometry. | | 2026-10-21 | M2: luminaires with heading and tilt (IES tilt factors applied), illuminance on any surface, area and full-width route grids summed over luminaires, statistics that are unverifiable when any point is; isotropic and Lambertian cases within 1e-6; 100 luminaires × 10,000 points in about 55 ms (release, in `cargo xtask ci`); photometry plausibility warnings. | | 2026-10-21 | M1: IES LM-63 (1986–2019) and EULUMDAT readers, symmetry expansion, tilt data, emergency flux, located errors, property tests, a 10-minute fuzz run (22.8 million inputs) without a panic; `luxpath photometry`. Existing crates evaluated first: none usable (docs/architecture.md). | diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..42a839f --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,25 @@ +# Security and safety reports + +luxpath reads untrusted files (photometric files, scenes, IFC models) and computes values used in life-safety +design. Two kinds of report matter most: + +1. **A wrong result that could make a design look safe when it is not**, for example illuminance computed too + high, a requirement reported as met that is not, or missing data treated as present. These are the most serious + bugs this project can have (AGENTS.md §2). +2. **A crash, hang or excessive memory use on some input file.** Every input must give a result or an error + (AGENTS.md §3). + +## How to report + +- For anything that could be exploited (a crafted file that runs code, reads files, or exhausts a machine), use + GitHub's **private vulnerability reporting** (Security tab, "Report a vulnerability"). Please do not open a + public issue for these. +- For wrong results and crashes on ordinary files, open an issue with the **wrong result** or **bug** template. + Do not attach manufacturers' photometric files or real building plans unless you are free to share them; + a description or a synthetic file that reproduces the problem is enough. + +We aim to acknowledge reports within a week. There is no bug bounty. + +## Supported versions + +luxpath is pre-alpha: only the latest `main` is supported, and nothing is yet released. diff --git a/apps/luxpath-cli/Cargo.toml b/apps/luxpath-cli/Cargo.toml index e56458d..a18a0cd 100644 --- a/apps/luxpath-cli/Cargo.toml +++ b/apps/luxpath-cli/Cargo.toml @@ -6,6 +6,7 @@ edition.workspace = true license.workspace = true rust-version.workspace = true repository.workspace = true +publish.workspace = true [[bin]] name = "luxpath" diff --git a/crates/calc/Cargo.toml b/crates/calc/Cargo.toml index af8b245..e66acd7 100644 --- a/crates/calc/Cargo.toml +++ b/crates/calc/Cargo.toml @@ -6,6 +6,7 @@ edition.workspace = true license.workspace = true rust-version.workspace = true repository.workspace = true +publish.workspace = true [dependencies] luxpath-geom.workspace = true diff --git a/crates/geom/Cargo.toml b/crates/geom/Cargo.toml index 42efc95..f798e10 100644 --- a/crates/geom/Cargo.toml +++ b/crates/geom/Cargo.toml @@ -6,6 +6,7 @@ edition.workspace = true license.workspace = true rust-version.workspace = true repository.workspace = true +publish.workspace = true [lints] workspace = true diff --git a/crates/ifc/Cargo.toml b/crates/ifc/Cargo.toml index aeeaea3..a1b3051 100644 --- a/crates/ifc/Cargo.toml +++ b/crates/ifc/Cargo.toml @@ -6,6 +6,7 @@ edition.workspace = true license.workspace = true rust-version.workspace = true repository.workspace = true +publish.workspace = true [dependencies] ifc-lite-core.workspace = true diff --git a/crates/photometry/Cargo.toml b/crates/photometry/Cargo.toml index baa0ed4..60a3970 100644 --- a/crates/photometry/Cargo.toml +++ b/crates/photometry/Cargo.toml @@ -6,6 +6,7 @@ edition.workspace = true license.workspace = true rust-version.workspace = true repository.workspace = true +publish.workspace = true [dependencies] luxpath-geom.workspace = true diff --git a/crates/report/Cargo.toml b/crates/report/Cargo.toml index a1f6680..67252c1 100644 --- a/crates/report/Cargo.toml +++ b/crates/report/Cargo.toml @@ -6,6 +6,7 @@ edition.workspace = true license.workspace = true rust-version.workspace = true repository.workspace = true +publish.workspace = true [dependencies] luxpath-scene.workspace = true diff --git a/crates/rules/Cargo.toml b/crates/rules/Cargo.toml index a044e19..beb6cc0 100644 --- a/crates/rules/Cargo.toml +++ b/crates/rules/Cargo.toml @@ -6,6 +6,7 @@ edition.workspace = true license.workspace = true rust-version.workspace = true repository.workspace = true +publish.workspace = true [dependencies] luxpath-scene.workspace = true diff --git a/crates/scene/Cargo.toml b/crates/scene/Cargo.toml index a0ea26b..f1b778a 100644 --- a/crates/scene/Cargo.toml +++ b/crates/scene/Cargo.toml @@ -6,6 +6,7 @@ edition.workspace = true license.workspace = true rust-version.workspace = true repository.workspace = true +publish.workspace = true [dependencies] luxpath-geom.workspace = true diff --git a/deny.toml b/deny.toml new file mode 100644 index 0000000..466210e --- /dev/null +++ b/deny.toml @@ -0,0 +1,20 @@ +# `cargo deny check`: licences, advisories and sources (AGENTS.md §1.2: no GPL/AGPL). CI runs it; locally: +# cargo install cargo-deny. + +[graph] +targets = ["x86_64-unknown-linux-gnu", "aarch64-apple-darwin", "x86_64-apple-darwin", "x86_64-pc-windows-msvc", "wasm32-unknown-unknown"] + +[licenses] +# Permissive licences only; MPL-2.0 as an unmodified dependency (ifc-lite-core). +allow = ["MIT", "Apache-2.0", "Apache-2.0 WITH LLVM-exception", "BSD-2-Clause", "BSD-3-Clause", "ISC", "Zlib", "Unicode-3.0", "MPL-2.0", "CC0-1.0", "BSL-1.0"] +confidence-threshold = 0.9 + +[advisories] +yanked = "deny" + +[bans] +multiple-versions = "allow" + +[sources] +unknown-registry = "deny" +unknown-git = "deny" diff --git a/docs/publishing.md b/docs/publishing.md new file mode 100644 index 0000000..845c483 --- /dev/null +++ b/docs/publishing.md @@ -0,0 +1,50 @@ +# Publishing checklist + +> **Last updated:** 2026-10-21 · **Change:** prepared after M3 + +What has to be true before the repository goes public, and the switches the owner flips. Decision recorded +2026-10-21: go public after M3, as a clearly labelled pre-alpha. + +## Done in the repository + +| Item | State | Where | +|---|---|---| +| History scanned: no secrets, keys, tokens, local paths or private notes | clean (2026-10-21) | every commit before this checklist; only synthetic photometry in history | +| No manufacturers' photometric files, real plans, standard texts or IFC samples committed | clean | `plan/` is git-ignored; fixtures listed in their `README.md`s | +| Licence files and `license` metadata | MIT OR Apache-2.0 | `LICENSE-MIT`, `LICENSE-APACHE`, `Cargo.toml` | +| Dependency licences and advisories checked | `cargo deny check` passes | `deny.toml`; a CI job | +| README states the stage and that nothing is validated yet | done | `README.md` | +| Every report says it is a calculation, not a certificate | done | `luxpath-report` | +| How to report vulnerabilities and wrong results | done | `SECURITY.md` | +| How to contribute, with the provenance and safety rules | done | `CONTRIBUTING.md`, `AGENTS.md` | +| Issue templates (wrong result, bug) and the PR template | done | `.github/` | +| Accidental `cargo publish` blocked | `publish = false` in every crate | `Cargo.toml` | +| Hosted CI ready (gates on Linux, macOS, Windows; cargo deny) | ready, unused while private | `.github/workflows/ci.yml` | + +## The owner's switches, in order + +1. **Read the history once more yourself:** `git log -p` (eight commits). Commit authorship shows + `enrico.sita@gmail.com`; it is already public on your other open-source contributions. To use GitHub's + no-reply address for future commits instead, set it in the repository's git config before the next commit + (history keeps the old address unless rewritten, which is not worth it). +2. **Make the repository public:** Settings → General → Danger Zone → Change visibility. +3. **Turn on private vulnerability reporting:** Settings → Code security → Private vulnerability reporting + (`SECURITY.md` points to it). +4. **Protect `main`:** Settings → Branches → require a pull request and the CI checks (`gates (ubuntu-latest)`, + `gates (macos-latest)`, `gates (windows-latest)`, `licences and advisories`). Public repositories get Actions + minutes free, so hosted CI resumes; the first run tells us whether Windows needs fixes. +5. **Description and topics:** "Open, scriptable emergency-lighting calculations (EN 1838) in Rust"; topics such + as `lighting`, `emergency-lighting`, `en1838`, `photometry`, `ies`, `eulumdat`, `rust`, `bim`. +6. **Code of conduct (optional):** Insights → Community → Code of conduct → Contributor Covenant, generated by + GitHub in one click. +7. **Discussions (optional):** useful for practitioners who want to ask rather than file issues. + +## Decisions for later + +- **crates.io:** the `luxpath` name was free on 2026-10-16. Reserving it means publishing a version (a placeholder + or the current pre-alpha library); then `publish = false` comes off the crates to publish. Publishing a + life-safety library before M4 and M6 invites use before validation, so the suggestion is to wait for alpha and + watch the name meanwhile. +- **Announcement:** wait for alpha (M4 checks and M6 validation). Before it, share the repository directly with + people who can help: designers with DIALux or Relux licences for M6, people with real photometric files. +- **Ashlar's plugin (R2.9)** builds on the public library from then on. diff --git a/docs/status.md b/docs/status.md index 3f3182c..56301cf 100644 --- a/docs/status.md +++ b/docs/status.md @@ -38,7 +38,7 @@ FireExit flags. Luminaires collapse into few types (410 → 5), so a photometry - **B. IFC scene:** read luminaire positions and space outlines (geometry) and define the mapping file (type name or product code → photometric file, emergency yes/no). - **C. Obstruction** (gap 16): walls in the scene block light; an alpha blocker before M4's checks. -- **E. Going public:** the publishing checklist (`docs/publishing.md`). +- **E. Going public:** the repository side is ready; the owner's switches are in `docs/publishing.md`. - **D. Real files:** photometric files of luminaires the owner's practice uses, privately in `plan/` (gap 12). ## Blockers