# Evidence the inventory cannot show

The inventory proves configuration. It cannot prove which writer actually changed a value, whether a dashboard matches its records, or what a role can really read. For every FAIL and every gate WARN, attach one item below and record it in the inventory's `evidence` block. A finding without evidence stays labelled unconfirmed and cannot justify an irreversible change.

All five checks are reads. Runtime tests are a separate, opt-in step at the end.

## 1. Writer sample (FLD-02, FLD-03, LIFE-03, INT-06, INT-07)

- Export property or field history for each critical field over the window (30 days by default): every changed record up to 2,000, otherwise a random 2,000.
  - HubSpot: Export property history with Include Source Information ticked (recipe, wide layout and revision caps in [reading-hubspot.md](reading-hubspot.md)), or `propertiesWithHistory` reads. Map every source, workflow and app ID to an inventory label with `--writer-map`.
  - Salesforce: the object's field history query (`ParentId` or the object ID, `Field`, `DataType`, `NewValue`, `CreatedDate`, `CreatedById`), with a writer map from user IDs to labels. Lookup fields such as Owner can write an ID row and a name row per change (Salesforce does not document this, so check one owner change); the script keeps the ID row. A field without history tracking has no history: record `history_tracked` false.
  - Attio: historic values with `created_by_actor`.
  - Identity fields (email, phone, name): ask for the value column replaced by a one-way hash or a value token before export, or leave identity fields out of the sample. The script compares values for equality only. A field left out stays NOT CHECKED for FLD-02, with its definition findings still shown.
- Run `python3 -I "$SKILL_DIR/scripts/writer_history.py" <file> --format <format> --window-days 30 --as-of <date> --out audit-work/history.json` from the private working folder. A HubSpot export also needs `--field`, `--object` and `--group`.
- Evidence: the writer distribution, records touched by two or more writers, the flip-flop count split into flip-flops between automated writers and reversals of a person's change, the rate, and up to ten sample record IDs. Values are hashed and never printed.
- Pass: observed writers are a subset of permitted writers and there are no flip-flops. Two automated writers with no written precedence rule fail even when they agree today. Without history a field cannot pass FLD-02 or FLD-03.

## 2. Known-record trace (OBJ-02, LIFE-04, AUTO-03, AUTO-07, INT-02)

- Pick one recent record from the population the rule covers, by record ID. Follow it from creation through routing, stage or lifecycle change and every sync.
- Collect: the creation source, property history lines for the critical fields, workflow or flow history entries, and sync log lines from each integration.
- Pass: every step has the expected writer, in the expected order, and the destination system shows the same values.
- Keep the trace to IDs, timestamps, writer labels and field names. Do not paste names, emails or notes into the report.

## 3. Report reconciliation (REP-01 to REP-04)

- For each headline number (pipeline value, new customers, the top-of-funnel metric), export the record IDs and amounts behind it with exactly the same filters, date range and currency.
- Sum or count by record ID, never by name, and never after a join to contacts, products or activities.
- Evidence: the dashboard value, the record-list value, the difference in percent, and the cause when found (grain, population, currency, timezone, a cross filter hidden in the builder).
- Pass: within 1%, or the cause is explained and documented. Never make the numbers agree by changing the report filter.

## 4. Access view (ACC-01, ACC-02, ACC-05)

- Salesforce: the User Access Summary of each integration user, the Field Access Summary of each restricted field, and Sharing Settings (org-wide defaults and sharing rules) for each object holding restricted records.
- HubSpot: each permission set's View access per object (All, Their team's, Their) and, on Enterprise only, the property's access settings for restricted properties. Below Enterprise there is no property-level restriction, so the View access decides who reads restricted values.
- Attio: plan, member access levels, and object and list access for restricted objects and lists.
- Evidence: which grants give access, through which profile, permission set, group, team, org-wide default or sharing rule. Record field results in `access_checks` and object results in `record_access`.
- Pass: grants match the approved list, and every integration identity can read and write exactly the fields it maps. An integration user that lacks field access gets blank values with no error (FM-17); test access as that identity, not as an admin.

## 5. Settings capture (OBJ-03, LIFE-03, INT-02, INT-06, AUTO-08)

- Capture: company auto-association and its shared-domain exclusions; lifecycle automation toggles; integration field rules, direction and default app; the Salesforce inclusion segment; data sync filters; account cleanup; two-factor and SSO enforcement.
- Evidence: a screenshot or copied value with the read time, stored in the private working folder.
- Pass: each setting matches the decision recorded in `decisions.md`.

## Request what the identity cannot read

When the reading identity lacks access, send [../assets/evidence-request-checklist.md](../assets/evidence-request-checklist.md) to the admin. Mark the rule NOT CHECKED until the evidence arrives; never infer a pass from silence.

## Runtime tests (opt-in only)

- No test records, enrolments, sends or sync triggers in production without the user's explicit approval for that specific test.
- Prefer a sandbox. Otherwise use flagged test records (a `test_record` property or an agreed naming rule) that the reporting exclusion already removes.
- List every record a test creates, every message it could send, and every downstream system it reaches, in the change list, with who deletes them afterwards.
- One test proves one hypothesis. Record the expected and the observed result side by side.

## Evidence quality checks before the report goes out

- Every percentage shows numerator, denominator, population, query and read time.
- Every FAIL and gate WARN cites an evidence ID, or says "unconfirmed".
- Every NOT CHECKED rule names the evidence that would close it.
- `audit_crm.py` was re-run after the last edit to `manual_results`, `evidence`, `decisions` or `gate_owners`, and no `<agent` placeholder remains in the report.
- No credential, token, personal name, email or phone number appears anywhere in the report or the working notes that will be shared.
