# Fireflax enquiry-routing starter 1.0.0

A versioned local rules package, with synthetic fixtures and an explicit approval boundary. It runs without network access, an account, API key or package install. It is not an n8n import, CRM connector or production service. Northstar Plumbing and every contact are fictional. Outbound messaging is absent from the code.

## Prerequisite and quick check

Use an existing Node.js installation. Tested with **Node.js 22.23.2** on 8 October 2026; other versions are not part of that test claim. Extract the ZIP into a new folder, open a terminal in `enquiry-routing-starter-v1.0.0`, and run:

```sh
node --version
node verify.mjs
```

Expected: a JSON report with `caseCount: 5`, `passed: 5`, `failed: 0`, followed by full inputs, expectations and observed states. The five cases cover complete intake, missing details, normalized duplicate, repeated approval and failure/recovery. This script intentionally approves synthetic drafts to test rules; it cannot send them. A failing case returns a nonzero exit status. Keep your output with the version/date rather than substituting our retained run for yours.

## Try the manual approval boundary

The CLI stores `sample-state.json` in your **current directory**. Work in the extracted folder so the scope is clear. `init` refuses to overwrite an existing state. One process at a time; no concurrent-write protection is provided.

```sh
node cli.mjs init
node cli.mjs submit fixtures/new-job.json
node cli.mjs show
```

Expected: one `DEMO-001`, owner `Service coordinator`, category `Plumbing enquiry`, status `review`, no approved draft. Inspect the original request and proposed reply. Open `reviewed-reply.txt`, read/edit its fictional text, then explicitly approve:

```sh
node cli.mjs approve DEMO-001 reviewed-reply.txt
node cli.mjs show
```

Expected: `completed`, one record, your reviewed text retained, and a notice that no email was sent. Repeating approval does not add an effect/history entry. Submitting `fixtures/new-job.json` again returns the existing ID without adding a task.

For missing details, reset/init then submit `fixtures/missing-details.json`. The record stays in review until you approve a clarification; after approval it is `awaiting-details`, with area and job detail still missing. Prepare a suitable fictional clarification in your reply file instead of reusing the complete-request text. There is no inbound-reply handler.

## Pause and rehearse a failure

Start from a new local state (`reset`, then `init`) and submit New job. After inspecting the draft/reply file, run:

```sh
node cli.mjs fail DEMO-001 reviewed-reply.txt
node cli.mjs pause
node cli.mjs show
node cli.mjs restore DEMO-001
```

Expected: `blocked` with the approved text retained. Pause prevents submissions, approvals and restores. The attempted restore exits nonzero and leaves the state unchanged. Pause is a CLI wrapper feature; the browser demo does not have this switch. Resume only when ready to rehearse recovery:

```sh
node cli.mjs resume
node cli.mjs restore DEMO-001
node cli.mjs show
```

Expected: one record back in `review`, draft retained, `approvedDraft: null`. Resume does not replay an action. Inspect the request and text again; `node cli.mjs approve DEMO-001 reviewed-reply.txt` records a fresh approval and finishes the sample. Restore is a controlled simulation, not repair of a real connection.

## Field and rule contract

| Input/output              | Meaning                                                                                                                                             |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `customer`                | Required display name, trimmed, at most 80 characters; used in the greeting, not the duplicate key                                                  |
| `email`                   | Valid email-shaped value, at most 160 characters; synthetic examples only                                                                           |
| `area`                    | Trimmed, at most 100 characters; empty accepted but prompts clarification                                                                           |
| `message`                 | Required text, at most 1,200 characters; fewer than 20 characters prompts clarification                                                             |
| Duplicate key             | Normalized email + area + message; lower-case and repeated whitespace collapsed. Only records in this local state are compared                      |
| Category                  | Quote/quotation/estimate words → Quote enquiry; otherwise pipe/plumber/plumbing/tap/leak/drain/toilet → Plumbing enquiry; otherwise General enquiry |
| Priority/owner            | Burst/flooding/flood/urgent/emergency word → Duty manager; otherwise quote → Quotes team; otherwise Service coordinator                             |
| Approval                  | Nonempty reviewed reply, at most 2,000 characters; allowed only in `review`                                                                         |
| Successful sample outcome | `awaiting-details` if missing information remains; otherwise `completed`                                                                            |
| Failed sample outcome     | `blocked`, retains reviewed text. Restore → `review`, clears approval, requires new approval                                                        |

These English word and length rules illustrate a workflow; they do not interpret all requests or establish urgency, coverage or a booking. Twenty records maximum. Reset loses the duplicate memory. Changed message/area may create another task from the same person. No durable identifiers across resets, encryption, authentication, multiuser locking, scheduler or delivery adapter is provided. The CLI's local file is for a rehearsal, not a customer record store. Do not enter real customer details or secrets.

## Adaptation, reset and uninstall

`routing.mjs` bundles the exact Fireflax `portal-demo.ts` rules and Zod validation; source and hashes are recorded in `version.json`, with the readable source in `source/portal-demo.ts`. The other files provide an offline CLI and checks around those rules. Import its exported helpers into your own local script, or change the rules only with corresponding tests. A real connection needs actual field IDs, permissions, an agreed duplicate strategy, external outcome checks and named recovery owners. This package supplies none of those integrations.

`node cli.mjs reset` removes only `sample-state.json` in the current directory. It does not undo external changes. To uninstall, delete your extracted folder and any report copies you created; there is no background process or installed dependency. Keep evidence you need before reset/deletion.

Maintainer for this release: **Fireflax repository maintainers**, via the source project issue tracker. No individual ongoing support assignment or response time is promised. Before adopting or changing this sample, assign an actual maintenance owner and next review date in the handover worksheet. Version 1.0.0 was reviewed 8 October 2026; revalidate after any rule/runtime change.

Licence: MIT for the starter; bundled Zod 4.6.5 is MIT. See `LICENSE` and `THIRD-PARTY-NOTICES.md`. No credentials or live service endpoints are included. The public portal sample and this package are tested separately; local results do not establish production reliability.
