- **ALWAYS** end your written contributions with `Written by AI agent working for @jtmorris. Model: <MODEL NAME>.`. Replace `<MODEL NAME>` with the LLM model, version, and, if relevant, number of parameters. For example: `Claude Sonnet 4.7`, `Grok 4.3`, `Qwen 3.6 27B`.
### 1. Only Store or Cache State When It Serves a Purpose
**Never store or cache state unless doing so meets at least one of:**
1. It is the authoritative source of truth owned by this component.
2. It delivers actionable feedback that meaningfully improves the user experience or a decision.
3. It provides a demonstrable and reasonably argued security or performance improvement (the burden of proof is on the proposer).
4. The information cannot be obtained at the moment it is needed and keeping it produces a clear net benefit.
Storing state creates a potential disconnect with reality. Managing that disconnect requires extra tests, defensive checks, and cognitive overhead. State should be added only when the benefit is obvious and defensible.
**Textbook Example (this repository – issue #11)**
Proposal: run `which tailscale` at startup, set a `binaryAvailable` boolean, and guard every `tailscale` invocation behind it.
**Why this was harmful**
1. Wrong solution to the actual problem. This project is a GUI wrapper around the `tailscale` binary. If the binary doesn’t exist, there is nothing to do except surface an error. Storing a flag and guarding UI actions adds state for no gain.
2. Creates a new class of edge cases that must be tested: the binary existed when the flag was set but later disappears. The code must now defend against both “flag is false” and “flag is wrong.”
3. Unreliable guard for a failure the code must handle anyway. A missing binary produces a clear exit-code failure on the real command. Checking the flag *and* handling the failure duplicates work.
### 1. **NEVER** Write Conditional and Loop Blocks Without Curly Braces
**ALWAYS** use curly braces, `{}`, for if, else, while, and for blocks, even when they contain only a single statement. This ensures that any future additions to the block remain within the intended control flow. Reference: `CVE-2014-1266`.
Rationale: Semicolons make intent explicit, eliminate ASI surprises, improve readability, and produce clearer diffs and tooling output.
Scope:
- Applies to all JavaScript statements — inside signal handlers (onClicked: { ... }), custom methods (function foo() { ... }), arrow function bodies, standalone .js files, and test files.
- Does NOT apply to QML declarative property bindings (width: 100, text: "foo", anchors.centerIn: parent, model: myModel, etc.). These are not statements; adding ; after them is either a syntax error or non-idiomatic in QML.
- When multiple QML bindings are written on a single line for compactness, ; is used only as a separator between bindings (Qt/QML convention), not as a statement terminator.