# Radar documentation Radar is a ProcessWire content-intelligence and editorial-operations module. It scans content deterministically, can request optional AI guidance through Squad, and creates reviewable drafts instead of silently changing pages. This file is the practical product and maintenance guide. Update it in the same commit whenever user-visible behavior, configuration, routes, integrations, permissions, CLI commands, or verification steps change. ## Start here 1. Open **Setup → Radar → Dashboard**. 2. Open **Diagnostics** and resolve red checks first. 3. Review **Content Types** and confirm that ProcessWire fields are mapped to Radar properties. 4. Run **Page Scan** for one representative page. 5. Open **Generate content** from Dashboard or **Analysis → Generate** to create a reviewable proposal. Page Scan opportunities also link directly to it. 6. Review the proposed diff, then apply it or send it to **Drafts** for approval. 7. Run **Site Scan** and save the report to establish a site-wide baseline. Radar never changes page content during a scan. Generation creates a preview; content is written only through an explicit apply or approval action. ## Admin workspace ### Dashboard Shows readiness, the latest saved Site Scan score, recent reports, pending drafts, Content Type totals, and the recommended onboarding path. The site score is a dated report snapshot, not a live measurement. Its primary **Generate content** action opens the generator directly; editors do not have to discover it through a completed scan first. The Dashboard keeps one compact source of truth for each metric. Custom override count is included under Content Types, passing checks are included under Readiness, and the former duplicate Content intelligence and Activity panels are removed. Snapshot/readiness context shares one compact row. Recent reports and the four-step onboarding panel size to their own content instead of stretching short panels to the report-list height. Below the live metrics, the first page acts as a module map. **Choose a workflow** routes users by desired outcome—page understanding, site baseline, reviewable generation, or evidence-backed research—and states what each path returns. **What Radar needs** exposes the current Content Type, Squad, and Atlas requirements while explaining that deterministic scans do not require AI. The final safe-workflow panel explains the read-only scan, reviewable preview, and explicit human-review boundary. It also keeps direct reference links to Content Types, Definitions, Diagnostics, and module settings beside recent reports, so technical configuration remains discoverable without dominating the page. Desktop Dashboard groups use equal-height tracks: the score and four metric cards are exactly 108px, every workflow card follows the tallest workflow item, requirements have the same minimum height, and both panels in each two-column row stretch to the same measured height. At phone width these fixed heights are released so translated or wrapped text cannot be clipped. Workflow cards constrain description copy to a consistent two-line measure and align their internal grid content from the top. CSS Grid no longer stretches label/title rows differently when one description happens to fit on one line; the Site Scan card and the other three workflows therefore share the same visible vertical rhythm and bottom spacing. Diagnostics is a first-class workspace pill because it reports Radar runtime readiness rather than configuration. The gear icon opens ProcessWire's native Radar module configuration screen with its information panel initially collapsed (`module/edit?name=Radar&collapse_info=1`). ### Breadcrumbs and page titles Every workspace route uses a task-specific sentence-case H1. Top-level sections sit below **Radar**; Analysis tools sit below **Radar → Analysis**; report, draft, Content Type, and Definition detail/actions sit below their corresponding list page. Error and confirmation states retain the same parent trail, so a user can always return to the relevant queue or configuration list instead of backing out through URL segments. Direct or stale Apply/Queue URLs no longer fall through to a generic ProcessWire 404 headed only “Radar”. They render a safe **Generated preview unavailable** state, confirm that nothing changed, and link back to Generate under the appropriate **Analysis** or **Drafts** breadcrumb parent. ### Module settings The native ProcessWire module screen starts with three direct routes to Dashboard, Content Types, and Diagnostics. Everyday controls are split into **Site behavior** and **History and retention**, with explicit explanations for automatic profile detection, policy eligibility, indefinite retention, and the fact that pending drafts are never cleaned up automatically. Developer JSON is separated into collapsed content-model, editorial-rule, and profile/source sections. Each JSON field reports whether it is empty, how many entries are configured, or why invalid JSON is being ignored. Empty overrides continue using Radar's built-in or workspace configuration. Every developer textarea includes a valid inline placeholder example for its exact shape: Content Types, Schemas, Policies, Goals, Workflows, Site Profiles, and mode-keyed Research Sources. Notes identify required lowercase identifiers, the Site Profile `rules` keys, and the difference between array-based definition lists and the Research Sources object. Placeholder examples never become saved configuration unless an administrator deliberately copies or edits them. Stored empty containers (`[]` or `{}`) are displayed as an empty textarea so the relevant example remains visible; saving that blank value has the same built-in-fallback meaning. Empty multi-selects are never rendered as tiny blank controls. If no Policies exist, **Eligible Policies** becomes an explanatory state with **Create first Policy** and **Open Definitions** actions. Generate applies the same rule to **Radar property**: when no compatible mapped text field exists, only the Field mapping recovery guidance is shown. Radar does not use `InputfieldAsmSelect`: under AdminThemeUikit an unselected AsmSelect can collapse to a tiny control that resembles a broken dropdown. Site Profiles, existing Policies, Content Type templates and Goals, and Generate properties use explicit native checkbox groups with responsive option columns. ### Analysis - **Generate** — selects a page, Content Type, generation task and mapped fields, then creates a before-and-after draft without silently editing the page. With no page selected, it shows the three-step path and only asks for a page first; the full task and mapped-field form appears after **Choose page and continue**. **Generate only empty fields** is an optional safety filter and is off by default, so a normal Generate Field request can propose a reviewed replacement for existing text. When enabled, populated fields are deliberately skipped; the result links directly back to the filter if nothing remains to generate. The default instruction explicitly requests a new, specific value that differs from the current text while preserving known facts. Editors can replace it with a narrower brief whenever tone, audience, keywords, or format matter. If a provider still returns unchanged text, the result links directly to Instruction with **Make instruction more specific** instead of presenting a dead-end status. **AI model** reads Radar's own catalog across every supported provider. Keep **Radar default** to use the provider/model pair configured in Radar settings, or choose any provider and model for this request. Radar never stores provider keys and rejects selections that are not in its current catalog. Squad supplies the matching provider credentials and request transport only. The override also reaches generation-related research and structured taxonomy/relation suggestions. - **Page Scan** — evaluates one page against its resolved Content Type, mapped fields, goals, policies, and optional Squad analysis. When AI analysis is enabled, **AI model** selects the model for that request. - **Research** — exposes the same **AI model** selector for evidence analysis and competitor runs. Deterministic Taxonomy and Relations scans intentionally have no irrelevant model control; their AI-assisted proposals use Generate. - **Template Scan** — ranks pages that use one ProcessWire template. - **Content Type Scan** — compares pages with the same content purpose, even when they use different templates. - **Site Scan** — creates the broad site baseline and can optionally include the internal relation graph. - **Focused Scan** — runs quality, semantic-section, freshness, or accessibility-content checks for one page. - **Conversion** — measures configured goal-property readiness. It does not represent analytics, revenue, or conversion tracking. - **Duplicates** — finds exact normalized duplicates in mapped content. - **Relations** — inspects mapped Page references and links found in rich text. - **Taxonomy** — finds missing classification and duplicate taxonomy terms. The Site Scan result never equates zero rule-level opportunities with a perfect site. Its result status also considers the overall score. The post-scan workspace shows an overall-health summary, the three lowest dimensions with plain-language next steps, a full score breakdown ordered weakest first, site-level findings, and pages ordered by their all-dimension score rather than Completeness alone. Template and Content Type batch results use the same post-action language: group health, page count, opportunity count, weakest shared dimensions, issue mix, and a weakest-first page table with Overall score, Completeness, and a direct page report action. Page and Focused results use the same distinction between Overall health and Completeness, highlight the three lowest dimensions, show the full dimension breakdown, and place evidence-backed opportunities in a clearly labeled action queue before optional AI interpretation. Conversion results separate Goal alignment, mapped goal fields, and complete goal fields. Their priority cards distinguish mapping work from missing content, then show a readiness matrix and a dedicated conversion action queue. Duplicates, Relations, and Taxonomy results now share compact three-metric overviews and named work areas: duplicate decision queue, relation network plus action queue, and taxonomy coverage plus cleanup queue. Tables retain direct links to the affected pages or terms. Successful Research results are an evidence workspace: source, supported-finding, and gap/opportunity totals; a readable evidence brief; and a ledger that keeps every conclusion beside its cited source links. When sources are processed but support no structured conclusion, Research shows `No supported findings`, removes the draft-generation action, and replaces an empty provider summary with guidance to try a more specific authoritative source. All visual score progress indicators expose an accessible name for their page, group, site, goal, or individual dimension value; color and bar length are never the only way the score is communicated. The Dashboard battery is exposed as a `progressbar` named `Site scan score`, with a 0–100 range, numeric current value, and percentage value text. Its visual fill and duplicate percentage are hidden from assistive technology to avoid double announcements. Dashboard metric and activity labels use ProcessWire plural translation for Content Types, custom types, drafts, reports, readiness checks, issues, and recent scans. Diagnostics uses the same mechanism for resolved types and active profiles, so count `1` never receives a plural label. Result panels use a polite live `status` region so post-button outcomes are announced without interrupting the user. Informational notices use `status` and error notices use the assertive `alert` role. Their visible wording remains the primary explanation. Technical/provider messages and raw structured output use one consistent secondary disclosure across Scan, Research, Generation, Apply, Queue, Draft review, Reports, and Diagnostics. The disclosure is collapsed by default, theme-aware, and always follows the plain-language result and recovery action. Dashboard metric cards, onboarding steps, activity links, comparison snapshots, and the Diagnostics icon expose the same theme-aware border and two-pixel focus ring when reached from the keyboard. Focus uses current `--pw-*` colors and does not depend on hover. Primary Radar tabs, nested Analysis modes, and the separate Diagnostics control all expose `aria-current="page"` when active; the selected location is never communicated by color alone. Every responsive table wrapper is keyboard-focusable and exposed as a named region. Its accessible name is generated from the first meaningful column headers, so multiple tables on one result remain distinguishable. Focused table regions use the same two-pixel theme-aware ring and can be scrolled without a pointer. Page and Focused Scan opportunity queues use the same shared table wrapper as every other result, so their Severity/Issue/Details table receives identical UIkit classes, keyboard scrolling, accessible naming, and mobile containment. Every initial scan screen explains what the result will contain and shows a result skeleton before data exists. Empty successful results are explicitly distinguished from missing configuration and provider failures. Primary scan and research submit controls use a dedicated full-row wrapper. ProcessWire renders submit Inputfields as `uk-width-auto` even when a column width is assigned, so Radar explicitly gives these wrappers a 100% flex basis. Mixed 20/30/33/40/50/70% option layouts therefore cannot pull a button into an unfinished column or move it when optional controls appear. Page Scan, Focused Quality, and Duplicates additionally render **Save structured report** as a full-width Inputfield. These forms no longer leave an open 50% column immediately before the primary action, eliminating layout recalculation when ProcessWire initializes checkboxes or restores form state. Unexpected failures from a fieldtype, site hook, database operation, or optional integration are caught by every admin scan. Radar keeps the completed form on screen, states that no page content or incomplete report was saved, links to Diagnostics, and puts the exception message behind Technical details. Page-based actions require a selected page. If no page is selected, Radar links back to the Page field. If a saved link points to a deleted or inaccessible page, Radar explains the permission/existence problem and asks for another page rather than showing a generic error. Template and Content Type batch scans validate the submitted selection against the site's current configuration. Missing selections and stale links to removed items return to the relevant native field with a specific explanation; they are not saved as empty reports. ### Research Research accepts a page, Content Type, research mode, and optional public source URLs. External, SERP, competitor, official, and catalog modes require supplied, configured, or hook-provided sources. Atlas powers knowledge-base retrieval. Squad converts prepared sources into structured, evidence-bound findings. Links from saved reports preserve both the page and research mode, so **Run a current scan** reopens the same Knowledge Base, Competitors, SERP, official, catalog, or external-source workflow instead of resetting the selector. Saved Page, Focused, Conversion, Template, and Research reports also preserve the resolved or explicitly selected Content Type. Rerun links restore it, report scope labels show it, and comparisons do not combine snapshots evaluated against different Content Type schemas. Admin and CLI saves use the same scope format, so a CLI baseline can be compared with a later admin scan only when page/template, mode, and Content Type all match. Enter one complete `http://` or `https://` address per line. Radar identifies malformed entries before calling a provider, removes duplicate lines, and accepts at most 12 distinct sources per run. When no configured or hooked source exists, the result links directly back to the Source URLs field. Source acquisition rejects private-network targets. AI output is editorial guidance and must be reviewed before it becomes page content. ### Reports Enable **Save structured report** on a scan form to preserve a snapshot. Reports record scan type, scope, author, time, and structured result. A report can: - open its page scan when a page is present; - return to the matching current scan through **Run a current scan**; - compare with the previous report having the same scan type and scope; - expose raw JSON behind a disclosure for technical integrations. Comparison shows linked Before/After snapshots, dates, authors, metric deltas, and a plain-language count of improved and declined measurements. Positive score deltas are better; negative opportunity deltas are better. Every compact delta also has a translated accessible label—Better, Worse, No change, or Not comparable—so meaning never depends on green/red styling alone. An opened report begins with snapshot identity cards for scan type, scope, author, and creation time, followed by clearly labelled saved metrics, opportunities, and research sources. Raw structured data remains available in a secondary technical disclosure. Comparison adds a compact overview of improved metrics, declined metrics, and the opportunity-count change before the detailed delta table. Metrics available in only one snapshot are reported as newly tracked or no longer tracked; they are not misclassified as unchanged, improved, or declined. Missing or retained-away report URLs return a Report unavailable workspace instead of a generic 404. Comparison distinguishes a missing snapshot from a pair with different scan types or scopes and explains how to select a compatible pair. Neither recovery path runs a scan or changes content. After a requested save, Radar shows an inline confirmation with a direct link to the new report. If report storage fails, the scan result remains visible and valid for the current request, while a separate warning links to Diagnostics and states clearly that no historical snapshot was created. Successful report persistence is a polite live `status`; storage failure is an assertive `alert`. Both keep their visible explanation and recovery link, and a provider/database exception remains collapsed under Technical details. Expired CSRF tokens on all scan, research, and generation forms return a plain-language `This form expired` result beside the preserved native form. Radar explicitly confirms that nothing was scanned, generated, stored, or changed and asks the editor to submit again with the freshly rendered token; these routes no longer expose a raw security-token exception page. Content Type and reusable Definition saves use the same recovery result while preserving every submitted native field, including advanced JSON. Definition and Content Type override deletion screens keep the override active and return to the confirmation form when their token expires. No configuration write or delete method is called on the expired-token branch. Database repair, immediate Apply, Queue, and queued Approve/Reject decisions also recover inline. Repair returns to refreshed Diagnostics without running a migration. Apply and Queue retain the complete session preview and render fresh controls. Draft decisions remain Pending and show the unchanged diff. No page, queue record, draft status, or database schema is mutated by an expired request. ### Drafts Generated changes can be applied immediately or sent to the persistent review queue. Draft history has Pending, Applied, and Rejected views. Each draft shows its author, reviewer, changed fields, and before/after diff. The selected history filter exposes `aria-current="page"` in addition to its visual primary-button style, so assistive technology receives the same location cue. The post-generation preview begins with counts for proposed fields, actual changes, and page writes. Each field is shown in a separate review card with its Radar property, mapped ProcessWire field, highlighted diff, and expandable full current/proposed values. A final decision section explains Apply now and Ask for review before showing either control. Taxonomy and relation suggestions use the same result overview and count individual suggestions rather than property groups. Queued draft detail uses the same field cards as the generation preview. Its overview identifies the current review status, proposal author, creation time, field count, and reviewer for completed decisions. This keeps Pending review and Applied/Rejected history visually consistent and makes the audit trail readable without opening raw draft data. Missing completed-draft links and drafts whose target page was removed or became inaccessible return a safe Draft unavailable workspace. No review decision or page write is attempted, and a direct action returns the editor to Drafts. Successful immediate Apply returns to a fresh Page Scan with a server-side result stating how many reviewed field values were written and linking to the ProcessWire page editor. Successful Queue returns to Drafts with the number of proposed values, an explicit reminder that the page is unchanged, and a direct link to the queued review. These results use the same one-time session mechanism as configuration saves. Approve and Reject also return to the matching Draft history filter with a full result. It identifies the reviewer, page, and number of decided field values; Reject explicitly confirms that the ProcessWire page stayed unchanged, while Approve confirms the write and links to the immutable historical draft. Queued review explains both decisions beside the controls. An approver must acknowledge that Approve writes the displayed values while Reject changes only the draft status. The visible reject action is labeled **Reject and keep page unchanged**, matching its consequence card instead of relying on the reviewer to infer the effect from surrounding text. The server enforces confirmation; a missing confirmation leaves the draft pending and the page unchanged. The queued-review form also blocks implicit Enter submission from its checkbox or other non-action controls. Keyboard activation still works normally when the reviewer focuses either decision button, so Approve can never be selected merely because it happens to be the first submit control in the form. After any valid Radar form submission, the chosen button changes to the translated **Working…** state and repeat submission is ignored until navigation completes. The control remains a successful submitter internally, so actions distinguished by button name—Apply, Queue, Approve, and Reject—continue to reach the correct server branch. If the browser restores a submitted page from its back/forward cache, Radar removes the stale submitting state and restores the button's original translated label on `pageshow`. A visually hidden polite live region announces the same Working state to assistive technology and is cleared when a history-restored form becomes available again. Each queued decision atomically claims the Pending draft inside a database transaction. A second reviewer cannot apply or reject the same draft again. If page application or final status storage fails, Radar rolls back the transaction, keeps the draft Pending, and explains the safety stop without retaining a partial page update. Stale hashes are checked again before writing. If the original field changed after generation, Radar refuses to overwrite it. Pending drafts are never removed by retention cleanup. ### Diagnostics Diagnostics summarizes Ready, Needs attention, and Blocked checks before four purpose-based groups: **Configuration**, **Runtime**, **Integrations**, and **Storage**. Configuration uses a wide two-column checklist; the smaller groups form a balanced row. Blocked and warning checks sort ahead of ready checks inside their group, so the next action is visible without scanning a long technical table. Database maintenance is separated by its own vertical rhythm and a safe schema explanation stating exactly what the action can and cannot change. After a successful schema repair, the redirected page keeps a complete `Schema ready` result visible instead of relying only on a temporary ProcessWire notice. Failed repair remains inline with technical details and a safe retry path; neither outcome edits page content. The **AI model configuration** section explains Radar's independent default provider/model pair, total selectable models, catalog provider count, and whether Squad has an active key for Radar's chosen provider. A direct action opens Radar settings. Changing Squad's own default provider or model does not change Radar. ### Content Types Successful Content Type and reusable-definition saves return to their list with a full result panel confirming what became active and a direct link back to the saved editor. Successful override deletion uses the same one-time session result to explain what was removed and whether a built-in definition can take over. These results are stored server-side for the redirect and consumed once; URL parameters cannot forge a successful save or deletion message. Stale Edit URLs for removed Content Types or Definitions return an unavailable workspace rather than an empty editor or generic 404. Reopened Delete override URLs report that no deletion is needed. These branches never create a new override, write configuration, or change ProcessWire content. Unknown identifiers are checked against the identifier actually returned by the registry, so its generic `custom` fallback cannot masquerade as the requested Content Type editor. Unknown Definition `kind` values also return a supported-type explanation rather than a GET 404. The only remaining 404 branches are intentional direct-access guards for POST-only Repair, Apply, and Queue endpoints or missing session previews; they cannot be reached through normal Radar links. Radar keeps ProcessWire's native ASMSelect controls. A small admin adapter adds an accessible name and matching tooltip to the visible add selector and icon-only remove links, including items inserted dynamically by the Inputfield. Names are derived from the native Inputfield heading and selected item. The adapter does not change selection or removal behavior. ASMSelect accessibility templates (`Add to %s`, `Remove %s`, and their generic fallbacks) originate in PHP translation calls and are passed to the admin adapter through escaped workspace data attributes. They therefore follow the administrator's ProcessWire language instead of being fixed English strings in JavaScript. A Content Type describes a page's purpose independently of its ProcessWire template. It can define: - applicable templates and reusable schema; - required, optional, section, taxonomy, metadata, and accessibility properties; - ProcessWire field mappings; - validation and scoring rules; - goals, policies, research profile, generation profile, and review workflow; - localization requirements and freshness threshold. Built-in types are safe defaults. Saving a built-in type creates a site-owned override. Deleting an override does not delete pages, fields, content, or the built-in definition. Validation or storage failures keep the Content Type editor open and leave the previous configuration active. Failed override deletion remains on the confirmation screen, reports that nothing was removed, and links to Diagnostics instead of redirecting with a false success state. When an advanced mapping or JSON value is invalid, Radar restores every submitted native Inputfield value, keeps Advanced rules expanded, and links the correction button to the exact mapping, validation, relation, or scoring field. ### Definitions Schemas, Policies, Goals, and Workflows are reusable definitions referenced by Content Types. Their name and description use native fields; definition-specific advanced properties use JSON. Built-ins remain available when a site override is removed. Failed Definition saves keep every submitted field visible, identify the field to correct, and leave the previously saved definition active. A failed override deletion remains on its confirmation screen, states that nothing was removed, and links to Diagnostics instead of reporting false success. Deleting a Definition or Content Type override requires a separate acknowledgement of the exact consequence. The server enforces this confirmation even when browser validation is bypassed; without it, the override remains active. ### Diagnostics Diagnostics checks ProcessWire and PHP compatibility, configuration JSON, database tables, languages, active Site Profiles, Squad, and Atlas. Red means a feature is blocked, yellow means optional or incomplete, and green means ready. For superusers, **Ensure Radar database schema** is an idempotent repair action. If schema repair fails, Radar stays on Diagnostics, refreshes the readiness checks, keeps the repair button available, confirms that page content was not changed, and shows the exception only under Technical details. ## Generation workflow 1. Run Page Scan and open **Generate field draft**, or open the generator from a specific opportunity. 2. Select a generation task and one or more editable mapped properties. 3. Add a precise instruction. Translation also requires a target language. 4. Generate the preview. 5. Review every red removal and green addition. 6. Choose **Apply to the page now** or **Send to review queue**. Immediate Apply requires a separate acknowledgement beneath the preview. The server enforces it even if browser validation is bypassed. Without confirmation, Radar keeps the generated preview and offers Apply or review queue again; no page value is written. Apply also stops when the page, mapped field, language, permissions, or original value changed after generation. A stale preview links to a fresh Page Scan and does not write partial changes. If review-queue storage fails, Radar keeps the full preview on screen and offers Queue, confirmed Apply, and Diagnostics again. Before immediate Apply, the target must still exist and be viewable and editable by the current user. Before Queue, it must still exist and be viewable. A removed or inaccessible target clears the stale session preview, creates no queued draft, changes no content, and returns the user to a fresh Page Scan. Field-oriented tasks require at least one property. Page, taxonomy, and relation tasks may select configured properties automatically. If no usable mapping exists, Radar links directly to the current Content Type's Field mapping. Translation requires ProcessWire Languages support, a selected destination language, and multilingual mapped fields. Radar validates the task and language before contacting Squad. Missing or removed choices link back to the exact form field; a site without Languages support links to Diagnostics. Unexpected exceptions during generation keep the completed form visible and return a safe failure result with Diagnostics and disclosed technical details. Radar does not store a draft or change a ProcessWire page on this path. Supported task families include page and field generation, title, summary, description, CTA, FAQ, metadata, taxonomy, relations, outline, rewrite, expand, shorten, normalize, translate, and refresh. ## Permissions and safety - `radar-use` grants access to the Radar workspace. - `radar-approve` grants permission to approve or reject queued drafts. - ProcessWire view/edit permissions are respected when pages are read or changed. - Mutating admin requests require ProcessWire CSRF tokens. - Draft application validates page, field, language, and stale value hashes. - Admin, trash, and 404 branches are excluded from site-wide content scans. - Destructive definition and Content Type actions remove only site overrides. ## Optional integrations - **Squad** — credentials and request transport for AI interpretation, research analysis, and generation. Radar owns its provider/model selection and catalog; deterministic scans remain available when Squad fails. - **Atlas** — knowledge-base research. - **Context** — may independently describe the live site to an AI agent when a project uses it; Radar does not call Context and builds its own normalized page context from Content Types and mapped fields. - **OpenRouter** — can be configured through Squad as its model provider. Keep credentials in provider/module configuration; Radar does not print API keys. Radar has no hard dependency on these modules for deterministic scanning. Radar's minimum runtime is ProcessWire 3.0.244 and PHP 8.3. Module metadata and Diagnostics enforce the same versions. ## Admin interface localization Radar's source interface is English. The module bundles complete ProcessWire translation imports in `languages/French.csv`, `languages/German.csv`, and `languages/Spanish.csv`. These files translate the Radar workspace, module configuration, forms, post-action results, empty states, Diagnostics, scan messages, and validation feedback; they do not translate stored page content, custom Content Type labels, provider responses, or technical identifiers. When Language Support and at least one non-default ProcessWire language exist, open **Modules → Radar → install translations**. Assign the matching CSV to each language and submit. ProcessWire stores the imported phrases in that language's translation files and automatically renders Radar in the current admin user's language. No Radar-specific language selector is required. `tools/generate-language-catalog.php` scans every translatable PHP source and rebuilds `languages/catalog.json`. `tools/generate-translations.py` preserves existing translations, translates new phrases, protects format placeholders, and applies Radar's reviewed terminology glossary. Regenerate and validate all language files whenever a user-facing source phrase changes. Install the development-only translator with `python3 -m pip install -r tools/requirements-translations.txt`; it is not a runtime dependency of Radar. Use `python3 tools/generate-translations.py --refresh` only when every existing machine-assisted translation should be rebuilt before human review. ## PHP API ```php $radar = $modules->get('Radar'); $context = $radar->pageContext($page); $pageScan = $radar->scanPage($page); $aiScan = $radar->scanPage($page, null, ['ai' => true]); $siteScan = $radar->scanSite(['limit' => 1000, 'relationScan' => true]); $result = $radar->generateField($page, 'introduction', [ 'instruction' => 'Clarify the value proposition.', ]); // Call only after a person has reviewed the returned draft. $radar->applyDraft($page, $result['draft']); ``` Use `generateFields()` for a coherent multi-property draft and `applyDrafts()` to write an already reviewed set in one page save. ## Extension hooks `Radar::opportunities` can append site-specific deterministic opportunities. `Radar::researchSources` can provide results from a dedicated search or source provider. Hook output is normalized before it is merged into Radar results. See `README.md` for payload examples. ## CLI ```bash php index.php --radar-help php index.php --radar-scan-page=123 --radar-ai --radar-save php index.php --radar-scan-template=service --radar-limit=250 --radar-save php index.php --radar-scan-content-type=service_page --radar-limit=250 --radar-save php index.php --radar-scan-conversion=123 --radar-save php index.php --radar-scan-relations --radar-limit=1000 --radar-save php index.php --radar-scan-taxonomy --radar-limit=1000 --radar-save php index.php --radar-scan-site --radar-relations --radar-save ``` CLI commands write JSON to stdout. Errors use stderr and a non-zero exit code. If requested AI analysis fails, deterministic output is retained and the command exits with code `2`. ## Verification Run the repository checks after every implementation change: ```bash php -l Radar.module.php php -l ProcessRadar.module.php bash tests/smoke.sh git diff --check ``` To run ProcessWire CLI smoke tests against an installation: ```bash RADAR_SITE_ROOT=/path/to/processwire ./tests/smoke.sh ``` Set `RADAR_AI=1` for a live Squad request and `RADAR_INTEGRATIONS=1` to require ready Squad and Atlas modules plus a real embedding request. Admin UI changes must also be checked in light theme, dark theme, and at a 400px mobile viewport. Verify both the initial screen and the result reached after submitting each changed form. All count-dependent interface text uses ProcessWire plural translations. This includes Dashboard readiness messages and the action count in result summaries, so singular and plural labels remain grammatical in every installed language. Every data-table column has a visible, translatable header. Columns containing links such as Open report, Create fix, and Open page report are labeled Action; they are not represented by an empty heading that loses meaning for assistive technology or when the table is horizontally scrolled on mobile. At widths below 640px, every shared table panel shows a translated visual hint to swipe sideways for more columns. The focusable table region already exposes a screen-reader label beginning with Scrollable table, so the mobile hint is presentation-only and does not duplicate the accessibility announcement. At the same mobile breakpoint, Draft history filters and compact table action buttons use a minimum 40px touch height. Native Radar form submit buttons, including Generate preview, use the same minimum. Text remains at the native Ichiban/UIkit scale; the larger target comes from layout rather than shrinking or enlarging the label. Repeated table actions also expose a contextual accessible name. A screen-reader link list therefore announces the report number, page title, or property being fixed instead of presenting several indistinguishable Open report or Generate fix links. Draft actions announce both the draft number and its target page, and the Draft queue uses the same visible Action column heading as scan tables. The shared table renderer adds `scope="col"` to every column header before the table is displayed. This applies consistently to reports, diagnostics, scans, draft history, configuration lists, and future tables rendered through the same workspace helper. Saved-report and draft timestamps are formatted through ProcessWire using the translatable `M j, Y, g:i a` display pattern. Dashboard snapshots, history tables, report details, draft details, and comparison cards therefore share one readable localized presentation while stored database values remain unchanged. User-facing record statuses use an explicit ProcessWire translation map rather than mechanically converting stored identifiers. Pending, Applied, Rejected, Ready, Needs attention, Error, and Complete can therefore be translated as full interface terms; unknown integration statuses still receive a readable fallback. External Research evidence always opens in a new tab with `noopener noreferrer`. Its accessible name explicitly announces the new tab; compact numbered evidence links are announced as Open source #N instead of an ambiguous standalone number. Saved-report source titles use the same shared link behavior. Only absolute HTTP and HTTPS URLs with a host become links; unsupported or malformed values remain visible as inert text so legacy and integration data cannot introduce an unsafe navigation scheme. URLs containing embedded user credentials are also inert. When a provider supplies no source title, the saved report displays the domain instead of exposing a long technical URL, then falls back to Source #N. ## Documentation maintenance When changing Radar, update all affected documentation in the same commit: - `DOCUMENTATION.md` for user workflows, behavior, setup, and maintenance; - `README.md` for public API and developer-facing examples; - `CHANGELOG.md` for user-visible release notes. Documentation is part of the definition of done. Do not describe planned behavior as implemented, and remove obsolete instructions when behavior changes. `AGENTS.md` is Radar's Olivia-ready behavioral contract for AI agents. It explains how Radar participates in building a ProcessWire site, lists supported public PHP, hook, storage, and CLI calls, separates read-only work from approved writes, and documents rollback and contribution boundaries. It is guidance, not proof of the current installation: an agent must inspect the live ProcessWire site before relying on templates, fields, modules, permissions, Content Types, models, or credentials described in documentation. Radar does not call a Context module directly. If a site provides Context or a site-level `AGENTS.md`, an agent may use it independently to understand the live architecture, then use `Radar::pageContext()` for Radar's normalized Content Type and mapped-field view of a ProcessWire page. Developer override JSON fields keep their examples available through an `Insert example` action above every textarea. In an empty field the action inserts the complete valid example immediately. When a field already contains JSON, Radar requires a second click on `Replace current JSON?` before replacing it. Inserted examples remain ordinary editable values and are not saved until the module configuration form is submitted. The public `README.md` follows the concise Vox module structure and uses `assets/Radar.png`, copied from the shared neighboring doodles collection, as its repository hero. Detailed API, workflow, and maintenance guidance belongs in this document rather than being duplicated in the README. Dashboard cards use a single accent border on hover. Keyboard focus strengthens that same border inward instead of drawing a second offset rectangle, preserving a visible focus state without the doubled-frame effect. The local `docs/` workspace is intentionally excluded from Git. Public README and documentation links must therefore target tracked files and must not depend on local specification notes under that directory. ## Module source architecture The ProcessWire entrypoints are intentionally thin. `Radar.module.php` declares module metadata, storage properties, and composes the public API from traits in `src/Core/` and `src/Config/`. `ProcessRadar.module.php` declares the admin process and composes route, form, renderer, and UI-support traits from `src/Admin/`. Admin source is grouped by responsibility: - `src/Admin/Routes/` owns ProcessWire execute routes; - `src/Admin/Forms/` owns native Inputfield builders and navigation; - `src/Admin/Rendering/` owns scan, report, and draft result presentation; - `src/Admin/Support/` owns shared UI, labels, failures, and source links. Styles are loaded in order from `assets/css/workspace.css`, `dashboard.css`, `components.css`, `diagnostics.css`, and `responsive.css`. JavaScript lives in `assets/js/`. Keep new behavior in the narrowest matching concern rather than growing either module entrypoint again. Core tests enforce entrypoints below 100 lines and verify that every composed source group remains loaded.