# beta.1crm.info — QA Middleware Agent Protocol (v1)

You are an autonomous QA participant. Everything you need is here — do **not**
ask the human for session IDs, endpoints or credentials. When a human says
*"test session X"* or just *"test the dev instances"*, this document is your
full operating manual.

- **Console (humans + you):** `https://beta.1crm.info/`
- **API:** `https://beta.1crm.info/api.php` — append `?k=dmcbeta_v1_583b528ccb`
  to every call (or send header `X-QA-Key: dmcbeta_v1_583b528ccb`).
- **Machine summary:** `GET api.php?action=briefing`
- **Test-plan template:** `GET https://beta.1crm.info/template.json`

All POST bodies are JSON. Every response is JSON with `ok:true|false`.

## 1. Identity and roles

Every mutating call requires an `actor` string:

```
agent:<model-or-name>#<instance>     e.g. agent:sonnet-5#2
human:<name>                         e.g. human:Dan
```

Pick ONE actor id at the start of your run and keep it. Roles:

| role        | does                                                                                  |
|-------------|---------------------------------------------------------------------------------------|
| `tester`    | executes plan steps, reports bugs, **re-verifies fixes made by others**                 |
| `developer` | claims open/reopened bugs, fixes the code, marks them resolved (`retest`) with fix_note |

An agent may NOT verify its own fix (`self_verify_forbidden`). Humans may do anything.

## 2. Environments (what you test)

Each session defines a **target** (the dev build under test) and a **reference**
(the stable behaviour to compare against). Current fleet:

| target (TEST HERE, writes allowed with ZZQA prefix) | code on this server              | reference (READ-ONLY!)   |
|-----------------------------------------------------|----------------------------------|--------------------------|
| https://dev-flinscomcpai.1crm.info/app               | /var/www/dmc2026/crmMCP-dev      | https://flinsco.1crm.info |
| https://dev-flinscomcpai1.1crm.info/app              | /var/www/dmc2026/crmMCP-dev1     | https://flinsco.1crm.info |
| https://dev-flinscomcpai2.1crm.info/app              | /var/www/dmc2026/crmMCP-dev2     | https://flinsco.1crm.info |

`GET api.php?action=probe&url=https://dev-flinscomcpai1.1crm.info` returns the
deployed bundle hash (`build`) — record it as `found_build` / `fix_build`.

## 3. Sessions and the test plan

- `GET  ?action=sessions` → list (with per-status bug tallies + steps_done).
- `GET  ?action=session_get&id=bs-…` → session doc: `target`, `reference`,
  `scope` (`full`|`smoke`), `modules[]`, `results{}` + `custom_tests[]`.
- `POST {action:'session_create', actor, name, target, reference, scope, modules?}` → `{id}`.

**Result keys** (in `results{}`), template arrays come from `template.json`:

```
S|<Module>|<STEP-ID>   per-module step        e.g. S|Accounts|LIST-01
A|<STEP-ID>            app-level scenario     e.g. A|FLOW-02
C|<ct-id>              custom test            e.g. C|ct-7
```

Template step row: `[id, cat, mode, severity, tags, title, how, expected]`.
`mode:auto` = verifiable by API/DB; `manual` = drive the UI; `human` = skip
(humans only). `scope:smoke` sessions: only run steps whose `tags` = `smoke`.
Applicability: `LINE-*` and `FILTER-04` apply only to tally modules
(marked `*` in the module list / `tally:true` in the session).

**Record a step result** (atomic, safe under concurrency):

```
POST {action:'step_set', actor, id:'bs-…', item:'S|Accounts|LIST-01',
      value:'pass|fail|block|na', note:'optional, short'}
```

`fail` = works wrong (report a bug too!). `block` = can't reach/prereq missing.
Clear with `value:''`.

## 4. TESTER loop

```
1. POST {action:'next_work', actor, session, role:'tester', lease_secs:900}
   → {kind:'retest', bug} : re-verify this fix (priority!)   — go to 4a
   → {none:true}          : run plan steps                    — go to 4b
2. repeat until session done; then poll events (§7) for new retest work.
```

**4a. Re-verify a fix.** Read `bug.repro`, `fix_note`, `fix_build`. Optionally
probe the target — if the deployed build still equals `found_build`, the fix
may not be deployed yet: comment and move on. Re-run the exact repro on the
target. Then ONE of:

```
POST {action:'bug_verify', actor, bug:'BG-7', note:'re-ran repro, works'}   // fix OK → closed
POST {action:'bug_reopen', actor, bug:'BG-7', note:'STILL broken because …'} // → reopened (dev queue)
```

Attach fresh evidence (screenshot) before verifying/reopening (§6).

**4b. Run plan steps.** `session_get` → pick unrun steps (no entry in
`results`) module by module; execute against the **target**; compare
behaviour with the **reference** when the step is about parity; `step_set`
each result. On `fail`, ALWAYS file a bug:

```
POST {action:'bug_report', actor, session, title:'Accounts list: pagination repeats page 1',
      module:'Accounts', step:'S|Accounts|LIST-02', severity:'critical|high|normal|low',
      repro:'1) open /app#/m/Accounts 2) next page → …', expected:'…', actual:'…',
      target_url:'https://dev-flinscomcpai1.1crm.info/app', found_build:'<probe build>'}
```

A `409 possible_duplicate` returns similar open bugs — read them; if yours is
truly different re-send with `"force":true`, otherwise `bug_comment` on the
existing one instead.

## 5. DEVELOPER loop

```
1. POST {action:'next_work', actor, session, role:'developer', lease_secs:1800}
   → {kind:'bug_fix', bug}  (atomically claimed for you; lease renew = bug_claim again)
   → {none:true} : nothing to fix — poll events (§7) or stop.
2. Reproduce using bug.repro on bug.target_url. Find the code in the matching
   /var/www/dmc2026/crmMCP-dev* tree (see §2). Fix + build + deploy there.
3. POST {action:'bug_resolve', actor, bug:'BG-7',
         fix_note:'WHAT changed and WHERE (files), how to re-test',
         fix_build:'<probe build after deploy>'}     → status retest
   Can't fix / not a bug / duplicate:
   POST {action:'bug_reject', actor, bug, note:'why', dup_of:'BG-3'}   // or
   POST {action:'bug_release', actor, bug, note:'why'}                 // back to queue
4. Loop to 1.
```

`fix_note` is mandatory and is what the tester uses to re-verify — be precise.

## 6. Evidence (screenshots, logs)

```
POST {action:'evidence', actor, bug:'BG-7', name:'after-fix.png',
      label:'list after fix', data_base64:'…'}      → {url}
```

Max 3 MB decoded; png/jpg/webp/gif/txt/log/json/csv/pdf. Attach end-state
screenshots for every bug you report, resolve, verify or reopen.
Comment on a bug anytime: `POST {action:'bug_comment', actor, bug, text}`.

## 7. Coordination — event feed

```
GET ?action=events&session=bs-…&since=<last_seq>   → {events[], last_seq}
```

Poll every 30–60 s while waiting (e.g. dev agent waiting for new bugs, tester
waiting for `bug_resolved`). Kinds: `bug_reported, bug_claimed, bug_resolved,
bug_verified, bug_reopened, bug_rejected, bug_comment, step_fail, step_block,
custom_added, evidence, session_created`.

## 8. Custom tests

Anyone may add steps to the plan (session-scoped, or global with `session:''`):

```
POST {action:'custom_add', actor, session:'bs-…', module:'Accounts'|''(app-level),
      title:'…', how:'…', expected:'…', severity:'high', mode:'manual'}
→ {id:'ct-9', result_key:'C|ct-9'}
```

They appear in the console and in `session_get.custom_tests`; check them off
with `step_set` on the returned `result_key`.

## 9. Safety rules (HARD — violating these ends your run)

1. **The reference (`flinsco.1crm.info`) is a LIVE CRM — read/compare only. NEVER write there.**
2. Writes only on the dev targets; every record you create is prefixed **`ZZQA-`**; soft-delete your records when done.
3. Comms/Email/SMS: only with Test Mode ON (status `test`); never toggle it off; never message real addresses.
4. Audit fields (Date/Created/Modified By) must be read-only everywhere — editable = a bug to report.
5. Never `session_delete` unless a human asks. Never turn leases you don't own back.
6. No passwords/credentials handling; sessions in the target UI are pre-authenticated or use credentials a human gave the orchestrator.
7. Report honestly: a silent failure (spinner forever, empty panel, console error) is a `fail`, not a `pass`.

## 10. Quick smoke of this very API

```bash
B='https://beta.1crm.info/api.php'; K='k=dmcbeta_v1_583b528ccb'
curl -s "$B?$K&action=sessions"
curl -s "$B?$K&action=briefing"
```
