# NEURALAN GR-01 事件接口与数据流程

版本：neuralan-events/1.0，2026-11-15。报告沿用neuralan-report/1.0及03文档，回执使用neuralan-receipt/1.0。

## 一、项目交付与启用

本接口供设备向停车场提交事件报告，属于项目对接规范。现有静态网站提供产品资料，不提供事件接收API、推送或后台队列。实际项目需确认接收责任方、真实地址、授权设备、项目令牌、通知岗位及保管规则，完成联调后启用。本文不创建服务，也不以规范文本表示某个项目已接通。

检测发生在道闸附近车辆短暂停稳时，不要求发动机重启，日常不依赖摄像头或OBD。接口只传递设备报告与提醒，不提供复检、维修、转介或预约，不控制道闸，不作安全放行决定。

采用HTTPS POST，文档地址为https://parking.example.com/neuralan/events。交付时替换成双方核实的接收地址，不向示例域名发送实际设备数据。example.com由IANA保留用于文档说明，不能依赖其运行生产服务。[IANA示例域名](https://www.iana.org/help/example-domains)

## 二、编码、鉴权与收妥边界

请求使用Content-Type: application/json和Accept: application/json，正文为UTF-8 JSON，不带字节顺序标记，不使用注释、尾逗号、NaN或Infinity，对象不允许重复键。单次提交一份完整报告，消息上限1 MiB，超限返回413。原始波形不要求塞入消息；未随附的测量值留空。[RFC 8259](https://www.rfc-editor.org/rfc/rfc8259)

鉴权使用每项目独立共享令牌，通过X-NEURALAN-Token请求头传递。令牌在项目实施时产生，授权到明确场地和设备；不放进报告、查询参数或公开页面，日志不记录原文。无效令牌返回401；令牌有效但场地或设备越权返回403。示例值EXAMPLE_NOT_A_VALID_TOKEN不可用，不是实际凭据。本版本不另引入签名算法；共享令牌也不承担事件去重功能。

接收端先鉴权和校验，再将完整报告、版本关联及接收记录一起持久化。只有提交成功、能按编号取回时，才返回201或200加persisted=true。仅进入进程内存、临时缓存或排队不算收妥。发送端核对HTTP状态、回执版本及eventId/reportId/reportRevision后，才结束该版本待传。

本协议不采用202异步受理。202、204、HTML登录页或缺少有效回执的2xx都不视为收妥，保留待传并登记协议异常。HTTP成功不等于人员已查看，也不等于通知已送达、车主已获知或车辆已修复。持久化语义是本接口明确约定，不是HTTP自动保证的业务结果。[RFC 9110](https://www.rfc-editor.org/rfc/rfc9110)

## 三、时序与记录责任

~~~text
设备侧               停车场接收端               事件岗位
  | 生成报告并本地保存     |                        |
  | POST完整报告版本 ---->| 鉴权、格式与状态检查     |
  |                       | 持久化报告与接收记录     |
  |<----201/200及回执------|                        |
  | 核对后结束待传        | 按配置进入事件/告警列表  |
  |                       |----------------------->| 查看
  |                       |<-----------------------| 操作记录
  | 无回执保留重试        | 诊断与处理状态分开保存   |
~~~

设备负责事件编号、完整报告、原观察时间与本地待传记录；接收端负责授权、版本保存、幂等判断及接收时间；人员是否查看由操作记录证明。observed是观察与质量，classification是适用性和参考比较，diagnosis是部位与原因。通信成功不能把未运行或质量不足改成正常，也不能把诊断文字写成磁场原始值。

## 四、核心字段对照

| 字段 | 接口含义及处理 |
|---|---|
| interfaceVersion | 信封版本neuralan-events/1.0，与报告版本分开 |
| transport.requestId | 每次发送的请求号，重试可变化，不是事件数量 |
| transport.attempt / sentAt / replayed | 尝试序号、发送时间及补传标记，不覆盖观察时间 |
| report.schemaVersion | 仍为neuralan-report/1.0；完整字段沿用03和四报告 |
| report.eventId | 一次停稳事件，修订、重试、补传保持不变 |
| report.reportId / reportRevision | 报告稳定编号和正整数版本；一事件关联一个reportId |
| report.device / site | 设备和场地须符合项目授权，不能静默改归属 |
| report.timing | 观察、窗口、生成时间分列，不以发送时间替换 |
| report.vehicle / engine | 无来源的车辆ID、VIN、牌号、里程、出厂发动机号为null |
| report.classification / diagnosis | 分类与故障条目符合状态约束，空条目不是自动正常 |
| report.alert | 保留not_dispatched及pending，不随收妥改成已通知 |
| report.delivery | 报告生成时的链路记录，当前发送状态放transport |
| receipt.persistedAt | 该版本首次持久化时间，不写回原报告 |
| receipt.latestReportRevision | 当前已保存最高版本，识别历史版本补到 |

时间采用含Z或时区偏移的RFC 3339格式。窗口结束不早于开始，报告生成不早于窗口结束。时钟异常保留clockStatus，不擅改观察时间。设备与接收端可能存在时钟偏差，不强求接收时间数值晚于设备生成时间。[RFC 3339](https://www.rfc-editor.org/rfc/rfc3339)

版本从1开始，任何报告内容变更均须增加reportRevision，不覆盖历史；eventId和reportId保持不变。仅重发只改传输信封，原报告中的receivedAt=null和消息状态也保持不变。实际收妥时间由接收端回执和业务视图保存，否则补传每次改正文就会与同版本内容校验冲突。

## 五、请求与响应示例

以下为接口报文示例，不是实际传输记录。完整请求沿用报告01，其观察时间为11月14日，信封发送时间为11月15日，说明补传不能被算作新的观察。HTTP头与正文分别列出，正文均为合法JSON。

~~~http
POST /neuralan/events HTTP/1.1
Host: parking.example.com
Content-Type: application/json
Accept: application/json
X-NEURALAN-Token: EXAMPLE_NOT_A_VALID_TOKEN
~~~

### 示例一：完整请求正文

~~~json
{
  "interfaceVersion": "neuralan-events/1.0",
  "transport": {
    "requestId": "NR-SEND-20261115-0001",
    "attempt": 1,
    "sentAt": "2026-11-15T08:30:00+08:00",
    "replayed": true
  },
  "report": {
    "schemaVersion": "neuralan-report/1.0",
    "reportId": "NR-RPT-20261114-01",
    "eventId": "NR-EVT-20261114-01",
    "reportRevision": 1,
    "reportStatus": "generated",
    "taskType": "engine_state_screening",
    "product": {
      "name": "NEURALAN GR-01",
      "scenario": "停车场道闸车辆短暂停稳时的发动机磁场状态筛查；不要求发动机重启"
    },
    "provenance": {
      "kind": "event_analysis_record",
      "sourceId": "NR-REC-20261114-01",
      "coverage": "本报告提供事件、分类和诊断摘要，未附原始磁场数值文件。",
      "externalIdentifiers": "none",
      "availableRecords": [],
      "valuePolicy": "无随附原始数值时磁场测量明细为null；时间字段采用+08:00。"
    },
    "site": {
      "city": "北京市门头沟区",
      "name": "门头沟社区停车场出口",
      "siteId": "NR-SITE-MTG-01",
      "laneId": "NR-LANE-EXIT-01",
      "installationLocation": "出口道闸外侧独立检测终端"
    },
    "device": {
      "deviceId": "NR-GR01-UNIT-01",
      "configurationVersion": "NR-CONFIG-20261114-A"
    },
    "timing": {
      "observedAt": "2026-11-14T21:00:00+08:00",
      "windowStart": "2026-11-14T21:00:00+08:00",
      "windowEnd": "2026-11-14T21:00:08+08:00",
      "generatedAt": "2026-11-14T21:00:09+08:00",
      "receivedAt": null,
      "clockStatus": "synchronized"
    },
    "vehicle": {
      "vehicleId": null,
      "identityStatus": "anonymous_event_only",
      "linkageSource": "none",
      "vehicleModel": {
        "label": "VEH-SEDAN-ICE-A",
        "source": "vehicle_family_classification"
      },
      "powertrainType": "ice",
      "vin": null,
      "licensePlate": null,
      "odometerKm": null,
      "identityLimit": "仅关联本事件；未提供外部车辆标识，不判断跨事件同车身份"
    },
    "engine": {
      "model": "ENG-L4-A",
      "modelSource": "engine_feature_classifier",
      "modelLibraryVersion": "NR-MODEL-LIB-20261114-A",
      "archiveId": "NR-ENG-ARCHIVE-01",
      "factorySerialNumber": null,
      "factorySerialSource": "none",
      "runningStatus": "running",
      "runningStatusBasis": "本次运行状态分析记录为发动机运行"
    },
    "observed": {
      "vehicleMotion": {
        "status": "stationary",
        "source": "event_state_record"
      },
      "magneticMeasurementValues": null,
      "rawEvidence": {
        "available": false,
        "source": "not_attached"
      },
      "featureDescriptions": [
        {
          "label": "参考一致性",
          "description": "本次特征与ENG-L4-A正常参考档案一致。",
          "source": "feature_analysis_record"
        },
        {
          "label": "周期稳定性",
          "description": "本次记录未见目标周期异常。",
          "source": "feature_analysis_record"
        }
      ],
      "signalQuality": {
        "status": "pass",
        "reasons": [
          "车辆已停稳",
          "目标与参考通道有效",
          "未见影响本次比较的共同干扰"
        ]
      },
      "engineStateEvidence": {
        "source": "engine_state_analysis_record"
      }
    },
    "classification": {
      "result": "valid_reference_match",
      "modelMatchStatus": "matched_family",
      "referenceId": "NR-REF-L4-A-NORMAL-01",
      "summary": "发动机运行，采集条件有效，本次特征处于参考模式内。"
    },
    "diagnosis": {
      "status": "no_target_anomaly",
      "findings": [],
      "resultScope": [
        "发动机状态筛查",
        "不包含制动、轮胎、动力电池与整车其它系统",
        "不作为道闸自动拦车或安全放行指令"
      ]
    },
    "alert": {
      "category": "none",
      "severity": "informational",
      "title": "检测完成：参考模式内",
      "message": "事件NR-EVT-20261114-01已完成本次发动机状态比较，未发现目标异常；报告进入事件列表，不推送车辆异常。",
      "recipientRole": "停车场事件值班岗",
      "deliveryStatus": "not_dispatched",
      "deduplication": {
        "key": "NR-EVT-20261114-01",
        "scope": "same_event_only",
        "crossEventVehicleMerge": false
      },
      "acknowledgment": {
        "status": "pending",
        "meaning": "接收待处理；查看或关闭通知不代表车辆故障已修复"
      }
    },
    "delivery": {
      "connectionState": "online",
      "replayed": false,
      "dispatchMode": "not_enabled"
    },
    "retentionPolicy": "按停车场已约定的数据保管与删除规则执行；本记录不指定固定保留天数。"
  }
}
~~~

### 示例二：首次持久化，HTTP 201

~~~json
{
  "interfaceVersion": "neuralan-receipt/1.0",
  "receiptId": "NR-RCPT-20261115-0001",
  "eventId": "NR-EVT-20261114-01",
  "reportId": "NR-RPT-20261114-01",
  "reportRevision": 1,
  "persisted": true,
  "persistedAt": "2026-11-15T08:30:01+08:00",
  "disposition": "created",
  "latestReportRevision": 1,
  "notificationState": "not_dispatched",
  "humanAcknowledgment": "pending"
}
~~~

### 示例三：同版本同内容重收，HTTP 200

~~~json
{
  "interfaceVersion": "neuralan-receipt/1.0",
  "receiptId": "NR-RCPT-20261115-0001",
  "eventId": "NR-EVT-20261114-01",
  "reportId": "NR-RPT-20261114-01",
  "reportRevision": 1,
  "persisted": true,
  "persistedAt": "2026-11-15T08:30:01+08:00",
  "disposition": "duplicate",
  "latestReportRevision": 1,
  "notificationState": "not_dispatched",
  "humanAcknowledgment": "pending"
}
~~~

duplicate保持首次receiptId和persistedAt，不是新事件或新诊断。notificationState和humanAcknowledgment是接收端消息状态，不回写覆盖原报告。

### 示例四：同版本不同内容，HTTP 409

~~~json
{
  "interfaceVersion": "neuralan-receipt/1.0",
  "persisted": false,
  "error": {
    "code": "REVISION_CONTENT_CONFLICT",
    "message": "同一版本已存在不同内容。",
    "retryable": false
  },
  "eventId": "NR-EVT-20261114-01",
  "reportId": "NR-RPT-20261114-01",
  "reportRevision": 1
}
~~~

### 示例五：状态矛盾，HTTP 422

~~~json
{
  "interfaceVersion": "neuralan-receipt/1.0",
  "persisted": false,
  "error": {
    "code": "STATE_COMBINATION_INVALID",
    "message": "发动机未运行时不得附故障条目。",
    "field": "report.diagnosis.findings",
    "retryable": false
  },
  "eventId": "NR-EVT-20261114-03",
  "reportId": "NR-RPT-20261114-03",
  "reportRevision": 1
}
~~~

409应查明同一版本为何出现两份内容，确需修订用新版本，不换事件号绕过。422按业务问题修正：发动机未运行不能附故障条目，不能为通过校验就把未运行强改成运行。

## 六、幂等、修订、乱序与归档

幂等键为项目范围内的deviceId、eventId、reportId和reportRevision，接收端建立唯一约束，并校验同一事件的reportId稳定。不同设备的相同编号不直接合并，匿名跨事件也不按同车去重。

同键同内容返回原接收记录与duplicate，不再通知；同键内容不同返回409且不覆盖存档。内容按JSON值比较：对象键顺序及空白不影响，数组顺序有效，null不同于缺失，字符串区分大小写，数字按精确十进制值比较，不以有损浮点近似比较。只比较report，不把每次改变的transport算入。发送端应优先原样重发本地保存的报告。

高版本先到可以保存，无须等齐低版本。低版本后来补到仍保留历史，但不降低latestReportRevision，不覆盖当前视图，也不触发历史异常。例如版本3先收妥，版本2后到，新增的是历史档案，不是第二次车辆异常。设备或场地归属冲突须由接入人员核对，不靠报告修订静默换项目。

版本关联型号库、参考档案和可用附件。文件确实存在才写索引，缺附件为空清单，不拼接不存在的下载链接。发动机档案ID关联资料，不等于物理出厂号；多条报告使用相同参考不能作为同车证据。

通知按项目、设备、事件和findingId去重，同一故障条目跨版本保持findingId。重复传输或历史版本补到不通知；当前新版本更新相同条目时更新详情，不产生第二条首次提醒；新增findingId可形成新增条目提醒。移除条目保留修订与旧记录，不写成维修完成。接收端同时保存通知去重记录，进程重启也不能重复发送。

## 七、离线、失败和重试

发送前先持久化报告。超时或回执丢失无法证明接收端未保存，应重发相同版本，由幂等处理确认结果，不重新生成事件号。单次超时30秒，失败后按5、15、60、300秒间隔重试，随后每300秒加0—30秒随机延迟。这是项目接口参数，不是实际运行日志。

| 响应或状态 | 含义 | 发送端处理 |
|---|---|---|
| 201及有效persisted=true | 新版本已持久化 | 保存回执，结束该版本待传 |
| 200及duplicate、persisted=true | 同版本先前已收妥 | 结束待传，不新增通知 |
| 202、204或其它不合约定2xx | 无有效持久化确认 | 保留待传，登记协议异常 |
| 400 / 415 | JSON格式或媒体类型错误 | 停止该条自动重试，修正格式 |
| 401 / 403 | 令牌无效或权限不足 | 保留记录，暂停同凭据发送并核对 |
| 409 | 版本内容或编号关联冲突 | 核对原版与修订，不换编号绕过 |
| 413 / 422 | 过大或业务状态非法 | 修正内容，按版本规则重交 |
| 429 | 限流 | 按Retry-After等待，无值用本地时间表 |
| 5xx、连接失败或超时 | 无法确认收妥 | 相同版本重试 |
| 3xx | 地址不符合交付配置 | 不带令牌自动跳转，核对接收地址 |

Retry-After接受HTTP日期或非负整数秒，不能解释时用本地时间表，不立即循环重发。格式或权限错误须接入人员处理，多次失败不删除报告。存储到达交付容量限制时生成容量告警，按已确认保管规则归档，不静默丢弃旧异常。

离线保留报告和尝试状态，恢复后分批补传。发送顺序只减少乱序，不能替代接收端版本检查。设备重启从持久化待传记录恢复，不依赖进程内存记住已发送项目；有效回执到达后保存索引。原始report.delivery反映生成时情况，补传标记放信封，避免为了记录断网而篡改旧版本。

## 八、状态一致性

| 结果 | 分类与诊断约束 | 提醒 |
|---|---|---|
| 正常有效 | valid_reference_match / no_target_anomaly，findings=[] | 无车辆异常 |
| 发动机异常 | valid_abnormal_pattern / fault_diagnosis，含部位原因条目 | vehicle_anomaly |
| 发动机未运行 | engine_not_running / not_performed_engine_not_running，findings=[] | 无车辆异常 |
| 纯电不适用 | not_applicable_bev / not_performed_out_of_scope，findings=[] | 无车辆异常 |
| 质量不足 | 扩展状态quality_insufficient / not_performed_quality_insufficient，findings=[] | 仅设备原因形成设备告警 |
| 未知型号 | 扩展状态unknown_model / not_performed_unknown_model，findings=[] | 型号待建档，不发车辆故障 |

后两行是本接口对03业务状态的明确枚举扩展，仍使用现有字段；项目接入必须显式支持，不能将不认识的状态退回正常。四份报告原枚举保持不变。发动机未运行、纯电不适用和质量不足都不得存在故障条目，违反时整条拒收，保留待传与错误原因。

## 九、集成常见问题

### I01. HTTP成功是否表示停车场已经看过？

不是。201或200加有效回执只确认接收端持久化。人员查看、提醒发送和故障解除分别需要对应记录。例如回执已保存而岗位尚未登录，humanAcknowledgment仍为pending，不能改成已查看。接口成功不能直接映射为车主已获知，更不能映射为车辆已修复，接收端应保留这些独立状态。

### I02. 超时重新上报会重复计算车辆吗？

不按请求次数计算车辆。同一报告保持事件号和版本，只有信封请求号及发送时间变化。首次写入成功但回包丢失，第二次收到duplicate即可确认已存，不形成第二条异常。匿名记录只能统计事件，不因同型号就合并为同车，也不因重复请求算成多辆车；这两种误差都由稳定编号和范围规则避免。

### I03. 为什么不在补传时填报告接收时间？

发送端不知道对方实际保存时间，改写正文还会造成同版本冲突。原报告保持receivedAt=null，接收端另存回执时间，业务视图可以同时展示。例如旧报告第二天补到，观察时间不变，接收时间显示第二天；单纯补传不增加修订号，也不把旧事件放进当天新观察数量。确实修改结论才形成新版本。

### I04. 无结果记录能否填故障条目让字段齐全？

不能。未运行使用相应未执行状态，纯电使用范围外状态，质量不足记录质量退出，findings均为空。完整是状态和来源完整，不是每栏都有具体数值。例如无VIN、车牌、里程、出厂发动机号时均为null，不能用系统档案号或零值顶替。接收端应拒绝矛盾组合，不擅自把状态改成运行以容纳故障条目。

### I05. 修订后是否重新推送同一异常？

先看事件与findingId。补充说明、重复传输、历史版本补到不产生第二条首次提醒；当前版本更新详情，新增条目才可按新findingId提醒。移除条目留下修订记录，不自动写维修完成。接收端保存通知去重状态，重启后继续使用；人员关闭待办也不应使同一报文再次到达时重新创建通知。

### I06. 本文是否意味着静态网站可以接设备？

不是。现有网站展示资料，实际项目需部署或接入停车场服务，确认真实地址、令牌、授权和岗位，再按报文及失败情形联调。不能向示例域名或自行拼出的站点路径发送。交付完成只启用约定的报告与提醒，不扩展为维修、转介或预约。对接文件说明字段与回执语义，实际开通由项目配置和联调结果证明。

