Build
Code style
Arcane JavaScript, HTML, CSS, naming, and automated style contracts.
Status: Review draft. This Standard Operating Procedure (SOP) defines the coding style for human developers, artificial-intelligence (AI) agents, reviewers, formatters, and lint processes working in Arcane OS.
Table of contents
- Purpose
- How to use this SOP
- Normative language
- Scope and precedence
- Shared rules
- JavaScript
- C#
- CSS
- HTML
- Linter contract
- Human and AI review checklist
- Exceptions
- Definition of done
Purpose
This SOP makes Arcane source code predictable to read, review, generate, and validate. It preserves the character of the original Arcane code while defining sufficiently precise rules for automated enforcement.
The goals are:
- make source code easy for a human to scan and change;
- make AI-generated code look native to the repository;
- reduce formatting-only review noise;
- give linters stable rule identifiers and severities;
- keep structure, accessibility, security, theme behavior, and runtime contracts visible;
- distinguish source code from generated, vendored, and minified artifacts.
Style does not override correctness, security, accessibility, the app-building SOP, the debugging SOP, or a documented public contract.
How to use this SOP
Human developers
Read the shared rules and the section for every language changed. Run the applicable formatter, linter, focused tests, and repository checks before requesting review. Do not reformat unrelated files in a behavioral change.
AI agents
Before editing, inspect nearby first-party code and the applicable contracts. Generate code that conforms to this SOP without waiting for a formatter to repair it. Preserve the behavior and established public surface of existing code. Do not copy an inconsistent local pattern when this SOP gives an explicit rule.
When an AI agent changes code, its handoff must identify:
- the language sections applied;
- automated checks run;
- manual review performed for rules that a linter cannot prove;
- any exception, including its scope and reason.
Reviewers
Review behavior first, then use stable rule IDs from this document for style findings. Prefer comments such as JS-012: split the compound statement over subjective wording. A style-only preference that is not represented here is not a blocking repository rule.
Linter and formatter authors
Use the rule IDs in this document as the durable contract. A tool may expose its own internal rule name, but its report should map back to the Arcane rule ID. Autofix must not change runtime behavior.
Normative language
The words must, must not, should, should not, and may are normative:
- Must / must not: required; a violation fails review unless an exception is documented.
- Should / should not: expected; a deviation needs a local reason but does not automatically fail lint.
- May: optional and context-dependent.
Scope and precedence
This SOP applies to first-party .js, .mjs, .cs, .css, and .html files.
When rules conflict, use this order:
- correctness, security, accessibility, and explicit public contracts;
- Arcane architecture and debugging SOPs;
- a narrower documented tool or platform requirement;
- this SOP;
- the style of nearby first-party code.
The following are excluded from style enforcement unless they are deliberately being replaced or regenerated:
- files in
node_modules/; - third-party source copied into the repository;
- files identified as generated by their header, build contract, or source generator;
- minified files such as
*.min.jsand*.min.css; - build output under
dist/or a staging directory.
Generated output must be changed through its source or generator. A linter should report the source file when that relationship is known.
Shared rules
| Rule | Requirement | Enforcement |
|---|---|---|
GEN-001 |
Text files must use UTF-8. | error, automated |
GEN-002 |
Source indentation must use four spaces. Tabs must not indent source. | error, autofixable |
GEN-003 |
Files must use one consistent line-ending convention and end with one newline. | error, autofixable |
GEN-004 |
Trailing whitespace is prohibited. | error, autofixable |
GEN-005 |
Names must describe purpose in the domain of the owning layer. Avoid unexplained abbreviations. | review |
GEN-006 |
Comments must explain intent, constraints, risk, or a non-obvious decision. They must not narrate obvious syntax. | review |
GEN-007 |
Dead, commented-out, debug, and placeholder code must not be committed without a tracked and documented purpose. | error, review |
GEN-008 |
A change must not include unrelated mass reformatting. | error, review |
GEN-009 |
A file should perform one coherent responsibility and must follow the shared-core/app-adapter boundary in the app-building SOP. | review |
GEN-010 |
Public contracts, failure behavior, asynchronous readiness, security boundaries, and accessibility behavior must be explicit where applicable. | review |
GEN-011 |
Secrets, credentials, private tokens, and environment-specific absolute paths must not be embedded in source. | error, automated plus review |
GEN-012 |
Bracket cuddling is prohibited where the language permits line breaks. A nested structured argument must open on its own line, and nested multiline constructs must not share closing-delimiter lines with their parent. | error, automated by language parser |
GEN-013 |
Every function, callback, handler, delegate, or other callable must have a stable, descriptive name. Anonymous callables are prohibited because names must appear in traces, stack errors, profiles, and debugging output. | error, automated by language parser |
Blank lines should separate imports, declarations, logical stages, and top-level definitions. Repeated blank lines must be collapsed unless a language construct requires them.
JavaScript
The JavaScript baseline is adapted from original Arcane entity and module sources such as arcane/entities/File.js and arcane/entities/User.js: four-space indentation, semicolons, deliberate blank lines, explicit names, and vertically readable control flow.
JavaScript rule catalog
| Rule | Requirement | Enforcement |
|---|---|---|
JS-001 |
Use ECMAScript modules. Static dependencies must use import and export. |
error, automated |
JS-002 |
Use single quotes for ordinary strings. Use template literals for interpolation or purposeful multiline text. | error, autofixable |
JS-003 |
Terminate statements with semicolons. | error, autofixable |
JS-004 |
Put one space around binary and assignment operators and after commas. Do not add spaces immediately inside parentheses, brackets, or braces. | error, autofixable |
JS-005 |
Put an opening brace on the same line as a function, class, method, loop, or condition, separated from the preceding token by one space. Forms such as ){ are prohibited. |
error, autofixable |
JS-006 |
Use braces for multi-line control-flow bodies. A single short guard clause may remain on one line when it has one action and remains unambiguous. | error, partially automated |
JS-007 |
Prefer const; use let only for a binding that is reassigned. Do not use var. |
error, automated |
JS-008 |
Use camelCase for variables and functions, PascalCase for classes, and UPPER_SNAKE_CASE only for genuine module-level constants. |
error, partially automated |
JS-009 |
Private class fields must use #camelCase. Do not simulate privacy with naming alone when language-level privacy is appropriate. |
review |
JS-010 |
Use strict equality (=== and !==) unless coercion is the documented intent. |
error, automated |
JS-011 |
Do not swallow an error silently. A catch without handling is allowed only for an explicitly best-effort operation whose failure is safe and expected. |
error, review |
JS-012 |
Put each logical statement on its own line. Do not compress multiple state changes, awaits, or branches onto one line. | error, partially automated |
JS-013 |
Use async and await for asynchronous control flow when it improves the visible sequence. Await or deliberately return promises; do not create accidental floating promises. |
error, partially automated |
JS-014 |
Validate data at trust and public-contract boundaries. Do not scatter duplicate validation through internal code. | review |
JS-015 |
DOM queries used more than once should be assigned a descriptive binding. Event names and CustomEvent.detail shapes must be stable and documented when public. |
review |
JS-016 |
Browser globals must be accessed deliberately. Prefer globalThis in shared modules; use window or document when the code specifically requires a browser document. |
review |
JS-017 |
Do not mutate function arguments unless mutation is the documented contract. | error, partially automated |
JS-018 |
Export the smallest useful public surface. Helpers used only by one module should remain private to that module. | review |
JS-019 |
Bracket cuddling is prohibited. A nested object, array, callback, call, or other structured expression passed to another construct must open on its own line. Do not place its opening delimiter beside the parent's opening delimiter or after another argument on the same line. In a multiline construct, child and parent closing delimiters must also occupy separate lines. | error, automated |
JS-020 |
Format exception handling as try {, } catch (err) {, and } finally {. catch and finally remain on the closing line of the preceding block, with one space on each side of the keyword. The block must not be compressed onto one line. |
error, autofixable |
JS-021 |
JavaScript must not contain arrow functions or anonymous function expressions. Use a function declaration, a named method, an explicitly named function expression, or a reference to an already named function. This applies to callbacks, event handlers, promise executors, timers, and iterator functions. | error, automated |
JavaScript layout example
Adapted from the original FileEntity pattern:
const MIME_TYPES = {
json: 'application/json',
md: 'text/markdown;charset=utf-8',
txt: 'text/plain;charset=utf-8'
};
class FileEntity {
#tableName = '';
#fileName = '';
constructor(fileName = '', tableName = '') {
if (tableName) {
this.#tableName = tableName;
}
if (fileName) {
this.#fileName = fileName;
}
}
async open() {
const file = await dbopfs.readFile(
this.#tableName,
this.#fileName
);
const extension = this.#fileName
.slice(this.#fileName.lastIndexOf('.') + 1)
.toLowerCase();
file.mime = MIME_TYPES[extension] || 'application/octet-stream';
return file;
}
}
export default FileEntity;
Do not cuddle the opening brackets of a call and a structured argument:
// Forbidden.
a({
b: 1
});
// Required.
a(
{
b: 1
}
);
Every structured argument must begin on its own line. It must not share a line with the preceding argument:
// Forbidden.
myFunction(
'aaaaa', {
a: 1
}
);
// Required.
myFunction(
'aaaaa',
{
a: 1
}
);
The same rule applies to arrays, callbacks, nested calls, and similar structured arguments. A linter must enforce the syntax-tree relationship rather than merely searching for delimiter character sequences.
Format try, catch, and finally blocks consistently:
try {
await performOperation();
} catch (err) {
reportError(err);
} finally {
releaseResources();
}
Do not cuddle the catch block's parentheses and opening brace or move catch
to a separate line:
// Forbidden.
try {
await performOperation();
} catch (err){
reportError(err);
}
// Also forbidden.
try {
await performOperation();
}
catch (err) {
reportError(err);
}
Every callback must be named so its name survives in traces and stack errors. Passing a named function reference is preferred:
function formatItem(item) {
return item.label.trim();
}
const formattedItems = items.map(formatItem);
An inline callback is permitted only as an explicitly named function expression:
button.addEventListener(
'click',
function handleButtonClick(event) {
event.preventDefault();
openSettings();
}
);
Arrow functions and anonymous function expressions are forbidden:
// Forbidden: arrow callbacks do not declare a function name.
items.map(
(item) => item.label
);
// Forbidden: the function expression is anonymous.
button.addEventListener(
'click',
function (event) {
openSettings();
}
);
Avoid compressed compound statements:
// Avoid: several decisions and side effects are hidden on one line.
if (!file) return null; await save(file); emit('saved');
// Use:
if (!file) {
return null;
}
await save(file);
emit('saved');
JavaScript documentation
Use JSDoc when it adds information the signature cannot express, especially for public object shapes, callbacks, events, side effects, and thrown errors. Do not add boilerplate JSDoc that merely repeats a name and primitive type.
C#
The C# baseline is adapted from the Arcane Microsoft NT host sources: four-space indentation, Allman braces, explicit access modifiers, PascalCase types and members, and narrow exception handling around operating-system boundaries.
C# rule catalog
| Rule | Requirement | Enforcement |
|---|---|---|
CS-001 |
Use four spaces and Allman braces. Opening and closing braces must occupy their own lines. | error, autofixable |
CS-002 |
Use PascalCase for namespaces, types, methods, properties, events, and constants. |
error, automated |
CS-003 |
Use camelCase for parameters and local variables. Private fields use camelCase to match the existing host code; do not introduce a second underscore-prefixed convention. |
error, automated |
CS-004 |
State access modifiers explicitly except where the language requires or the generated contract controls them. | error, automated |
CS-005 |
Use one declaration per line. Group using directives by framework, platform condition, and external dependency; remove unused directives. |
error, autofixable |
CS-006 |
Prefer explicit types where platform, numeric width, nullability, or API shape matters. var may be used when the assigned type is obvious and repeating it harms readability. |
warning, review |
CS-007 |
Use braces for multi-line control flow. A one-line guard is permitted only when it contains one simple action and does not hide cleanup, logging, or failure behavior. | error, partially automated |
CS-008 |
Catch the narrowest useful exception. Empty catch blocks require a comment explaining why failure is safely ignored. |
error, review |
CS-009 |
Dispose IDisposable resources deterministically with using, using declarations, or a proven ownership boundary. |
error, automated plus review |
CS-010 |
Asynchronous methods should end in Async, except event handlers or framework-mandated signatures. Do not block async work with .Wait() or .Result where deadlock is possible. |
error, automated |
CS-011 |
Use String.Equals with an explicit StringComparison for security-sensitive, identity, path, protocol, and invariant comparisons. |
error, review |
CS-012 |
Interop declarations, privilege boundaries, filesystem operations, and process launches must make validation and failure handling visible. | review |
CS-013 |
Keep preprocessor regions narrow. Each conditional compilation branch must remain independently buildable and reviewable. | review |
CS-014 |
Public or cross-boundary members must document non-obvious inputs, outputs, exceptions, ownership, and thread requirements. | review |
CS-015 |
Apply GEN-012 to method arguments, object and collection initializers, named local functions, nested calls, and other structured expressions. Do not place a structured argument's opening delimiter beside the parent call or after a preceding argument. |
error, automated |
CS-016 |
Apply GEN-013 to C# callbacks and delegates. Use a named method or named local function instead of a lambda or anonymous delegate so traces and debugging output identify the operation. |
error, automated |
C# layout example
Adapted from the original host startup and watchdog patterns:
internal static class Watchdog
{
private const string WatchdogArgument = "--arcane-shell-watchdog";
private static Process watchdogProcess;
internal static bool TryRun(string[] args)
{
if (args == null || args.Length == 0)
{
return false;
}
if (!String.Equals(args[0], WatchdogArgument, StringComparison.Ordinal))
{
return false;
}
Run(args);
return true;
}
}
Avoid hiding failures:
// Avoid: the reason for ignoring every exception is unknowable.
try { process.Kill(); } catch { }
// Use a narrow best-effort boundary and explain it.
try
{
process.Kill();
}
catch (InvalidOperationException)
{
// The process exited between the state check and the kill request.
}
Use named methods for callbacks and event handlers:
timer.Elapsed += HandleTimerElapsed;
private static void HandleTimerElapsed(object sender, ElapsedEventArgs eventArgs)
{
RecordHeartbeat(eventArgs.SignalTime);
}
Do not use an unnamed lambda or anonymous delegate:
// Forbidden.
timer.Elapsed += (sender, eventArgs) => RecordHeartbeat(eventArgs.SignalTime);
// Also forbidden.
timer.Elapsed += delegate
{
RecordHeartbeat(DateTime.UtcNow);
};
CSS
The CSS baseline descends from the original hand-written Lifeline and Nelson PWA styles, together with current Arcane shared styles such as arcane/css/layout.css and the theme contract in arcane/css/theme.css: expanded declarations, four-space indentation, a clear broad-to-specific source order, one canonical home for each selector, readable selector groups, Arcane variables, and explicit state styling.
The historical structural reference is pwa/nelson/css/layout.css in the Lifeline repository. Preserve its useful qualities: concise named sections, foundations before components, component and state rules in a readable sequence, and consolidated responsive and theme sections. Current Arcane formatting, theme, accessibility, and selector-ownership rules supersede any compressed declarations or duplicated legacy selectors in historical sources.
CSS rule catalog
| Rule | Requirement | Enforcement |
|---|---|---|
CSS-001 |
Put one selector per line when a rule has multiple selectors. Put the opening brace after the final selector. | error, autofixable |
CSS-002 |
Put one declaration per line, indented four spaces, with one space after the colon and a trailing semicolon. | error, autofixable |
CSS-003 |
Use lowercase property names and lowercase kebab-case class names. IDs used by JavaScript may use the established contract name. | error, automated |
CSS-004 |
Prefer class selectors. Do not increase specificity with an ID, element chain, or !important unless the cascade contract requires it and the reason is documented. |
error, partially automated |
CSS-005 |
Every app must load arcane/css/theme.css and arcane/modules/ThemeBootstrap.js. Shared primitives and app or component CSS must follow the theme base. |
error, automated across HTML and CSS |
CSS-006 |
Use an existing Arcane theme variable when it represents the concept. New semantic variables must derive from Arcane variables when an equivalent base exists. | error, review |
CSS-007 |
New literal colors must use rgb(...) or rgba(...), not hexadecimal, HSL, named colors, or bare channel lists. |
error, automated |
CSS-008 |
Interactive controls must define a visible :focus-visible state. Hover must not be the only indication of state or action. |
error, review |
CSS-009 |
Layout must tolerate text zoom, narrow viewports, and content growth. Avoid fixed heights for text containers unless overflow behavior is intentional. | review |
CSS-010 |
Motion must respect the shared reduced-motion behavior. Do not locally defeat the user's motion preference. | error, review |
CSS-011 |
Organize declarations consistently within a rule: custom properties, layout and positioning, box model, typography, visual treatment, interaction, then animation. | warning, autofixable where configured |
CSS-012 |
Media queries should remain near the rules they modify or form a clearly labeled responsive section. Use relative units for content-driven breakpoints. | review |
CSS-013 |
Do not use inline style attributes for application styling. JavaScript may set a narrow dynamic value or custom property when state cannot be represented by a class. | error, partially automated |
CSS-014 |
Shared CSS must remain domain-neutral and must not depend on app-specific markup. | review |
CSS-015 |
Give each selector one canonical base rule. Merge duplicate blocks in the same cascade context. Repeat a selector only for a state, feature query, cascade layer, or breakpoint, and include only the declarations that change there. | error, review |
CSS-016 |
Order styles from broad to specific: theme extensions, document and page layout, components in document order, child elements, states, then responsive or feature overrides. Group identical media conditions and remove selectors already covered by another selector in the same group. | error, review |
CSS-017 |
Use concise section comments in substantial stylesheets to identify major areas and ownership. Comments should explain purpose or structure, not narrate obvious declarations. | warning, review |
CSS organization and selector ownership
A stylesheet should explain the interface from top to bottom. A maintainer should be able to find a selector's base definition in one predictable place and then find its intentional state or responsive changes without searching through competing copies.
Use these organization rules:
- Keep theme extensions and document-level defaults first.
- Use short section comments when a stylesheet spans multiple conceptual areas.
- Follow with page layout and components in document order.
- Place child-element rules immediately after their owning component.
- Place interactive states after the base component they modify.
- Consolidate identical media conditions into one responsive section when that makes the affected layout easier to read.
- Never list a selector that is already matched by another selector in the same group.
- Do not use duplicated selectors or
!importantas a substitute for understanding source order and specificity. - If the same selector must appear again, limit the later rule to changed declarations and make the reason clear from its state, media query, feature query, or cascade layer.
Avoid overlapping selectors and repeated breakpoint blocks:
/* Avoid. */
@media (max-width: 48rem) {
main.profile > section,
main > section,
main section {
border-left: 0 !important;
border-right: 0 !important;
}
}
@media (max-width: 48rem) {
main > section {
border-radius: 0 !important;
}
}
Give the layout and its direct children one clear responsive definition:
/* Use. */
@media (max-width: 48rem) {
main.profile {
display: block;
overflow: visible;
}
main.profile > section {
border: 0;
border-top: 1px solid var(--border-color);
border-radius: 0;
}
}
CSS layout example
Adapted from the original shared layout style while applying the Arcane theme rules:
:root {
--panel-accent: var(--focus-color);
}
.settings-panel {
display: grid;
gap: 1rem;
padding: 1rem;
border: 1px solid var(--border-color);
border-radius: 0.8rem;
background: var(--modal-background);
color: var(--text-color);
}
.settings-panel:focus-within {
border-color: var(--panel-accent);
}
@media (max-width: 48rem) {
.settings-panel {
padding: 0.75rem;
}
}
Avoid compressed rules and fixed app palettes:
/* Avoid. */
.card{background:#050a09;color:#e7f3eb;padding:1rem}
/* Use. */
.card {
padding: 1rem;
background: var(--modal-background);
color: var(--text-color);
}
HTML
The HTML baseline is adapted from original Arcane pages and component documents: a complete document preamble, four-space nesting, semantic regions, descriptive accessibility attributes, and scripts loaded as modules.
HTML rule catalog
| Rule | Requirement | Enforcement |
|---|---|---|
HTML-001 |
Full documents must begin with <!doctype html> and set the root language with <html lang="...">. |
error, automated |
HTML-002 |
Use lowercase element and attribute names and double quotes around attribute values. | error, autofixable |
HTML-003 |
Keep html, head, and body at column zero. Indent their contents and all other nested elements four spaces per level. |
error, autofixable |
HTML-004 |
Void elements must not use XML self-closing syntax. | error, autofixable |
HTML-005 |
Use semantic landmarks and native elements before generic div or span elements. |
warning, review |
HTML-006 |
Every form control must have an accessible name. Images must have purposeful alt text or alt="" when decorative. Icon-only controls must have an accessible name. |
error, automated plus review |
HTML-007 |
Buttons must declare type="button", type="submit", or type="reset". Do not nest a button inside a link or a link inside a button. |
error, automated |
HTML-008 |
IDs must be unique in a document. Use IDs for stable behavior and accessibility relationships, not as the primary styling mechanism. | error, automated |
HTML-009 |
Apps must load the Arcane theme before shared primitives and app styles, and must load ThemeBootstrap.js as a module. |
error, automated |
HTML-010 |
First-party JavaScript belongs in module files. Inline module code is allowed in self-contained shared component documents when that component system requires it. | error, review |
HTML-011 |
External links that open a new browsing context must use safe rel values. Do not add target="_blank" without a user-experience reason. |
error, automated |
HTML-012 |
Use data-* attributes for declarative state or configuration. Do not encode structured application data in class names. |
review |
HTML-013 |
Preserve a logical heading hierarchy. Do not choose heading levels for appearance. | error, review |
HTML-014 |
Load scripts intentionally. Use type="module"; add async or defer only when its execution order is understood and compatible with the readiness contract. |
error, review |
HTML-015 |
User-visible text must be concise and specific. Expand abbreviations on first use unless the abbreviation is the product's established name. | review |
HTML layout example
Adapted from the original application document structure and updated to the required theme order:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Manage Arcane application settings.">
<title>Arcane Settings</title>
<link rel="stylesheet" href="./arcane/css/theme.css?v=1">
<link rel="stylesheet" href="./arcane/css/primitives.css?v=1">
<link rel="stylesheet" href="./apps/settings/settings.css?v=1">
<script type="module" src="./arcane/modules/ThemeBootstrap.js?v=1"></script>
</head>
<body>
<header class="app-header">
<h1>Settings</h1>
</header>
<main>
<section aria-labelledby="appearance-heading">
<h2 id="appearance-heading">Appearance</h2>
<button type="button" aria-label="Open appearance settings">
Configure
</button>
</section>
</main>
<script type="module" src="./apps/settings/modules/SettingsApp.js?v=1"></script>
</body>
</html>
Linter contract
Finding shape
A lint process should emit enough information for a human, AI agent, or editor integration to act without guessing:
{
"ruleId": "JS-003",
"severity": "error",
"file": "arcane/entities/File.js",
"line": 12,
"column": 28,
"message": "Terminate the statement with a semicolon.",
"fixable": true
}
Required fields are ruleId, severity, file, line, column, and message. fixable should be included when known.
Severity
error: violates a must or must not rule and fails the style gate.warning: violates a should or should not rule and requires review.info: reports a review opportunity without failing the gate.
Autofix boundary
Autofix may change whitespace, quote representation, semicolons, declaration ordering, and equivalent syntax only when behavior is preserved. Autofix must not:
- rename a public symbol;
- reorder side effects, imports with side effects, or asynchronous work;
- add or remove error handling;
- change selector specificity or cascade behavior;
- alter DOM meaning, accessibility relationships, or script loading order;
- modify generated output instead of its source.
Recommended tool mapping
The implementation may combine tools rather than forcing one parser to understand every concern:
| Concern | Suggested mechanism |
|---|---|
| JavaScript syntax and safety | ESLint rules plus Arcane custom rules |
| C# syntax and naming | .editorconfig, Roslyn analyzers, and dotnet format where supported |
| CSS syntax and order | Stylelint plus Arcane custom rules |
| HTML syntax and accessibility | HTMLHint or an equivalent parser plus an accessibility checker |
| Cross-file Arcane contracts | Repository scripts or Node test files under test/ |
| Generated/vendor exclusions | Shared ignore configuration consumed by every lint entry point |
The first linter implementation should encode unambiguous automated rules before attempting subjective checks. Review-only rules must not be approximated by noisy heuristics and presented as proven violations.
Human and AI review checklist
- The change follows every applicable
GEN-*rule. - JavaScript changes follow
JS-*rules and expose asynchronous failures deliberately. - C# changes follow
CS-*rules and make native, privilege, resource, and process boundaries visible. - CSS changes follow
CSS-*rules, consume Arcane variables, usergb(...)orrgba(...)for new literal colors, and preserve focus and reduced-motion behavior. - HTML changes follow
HTML-*rules, use semantic and accessible markup, and load the Arcane theme in the required order. - Generated, vendored, and minified files were excluded or changed through their source.
- Automated fixes did not change behavior.
- No unrelated file was reformatted.
- Focused tests and the broadest practical repository check passed.
- Any exception is narrow, documented, and reviewable.
Exceptions
An exception must be the smallest possible scope: one line, rule, file, generated family, or platform boundary. It must record:
- the rule ID;
- why compliance would reduce correctness, security, accessibility, compatibility, or clarity;
- the affected scope;
- whether and when the exception can be removed;
- the approving reviewer when approval is required.
Use the linter's narrow disable mechanism when one exists. A file-wide or project-wide disable requires a stronger explanation than a line-level exception. Convenience, speed, existing inconsistency, and generated AI output are not sufficient reasons.
Definition of done
A code change is style-complete when:
- applicable automated rules pass;
- the relevant language checklist has been reviewed;
- formatting changes are limited to the work's real scope;
- architecture, theme, accessibility, readiness, and failure contracts remain intact;
- exceptions are documented next to the narrowest affected scope;
- verification is reported with the change.
This SOP is the style contract. Tool configuration implements it; tool defaults do not silently redefine it.