Close COMPLIANCE.md gap: Documentation (S1F19-F22)
tests / build-and-test (push) Failing after 32s

Adds the GEM "Documentation" Fundamental capability: the equipment now
self-reports which GEM capabilities it supports, and the host can
discover the DVID namelist with the same shape used for SVIDs.

Catalog (data/messages.yaml -> generated messages.hpp)

  S1F19 W   header-only                Get GEM Compliance Request
  S1F20     <L,3 <A SOFTREV>
                 <A EQPTYP>
                 <L,a <L,2 <U1 CCODE> <A CDESC>>>>
                                       Get GEM Compliance Data
  S1F21 W   <L,n <U4 VID>>             DVID Namelist Request (n=0 = all)
  S1F22     <L,n <L,3 <U4 VID>
                       <A VNAME>
                       <A UNITS>>>     DVID Namelist Data

  Codegen emits CapabilityEntry and GemCompliance structs.  S1F22 reuses
  S1F12's StatusName struct (same wire shape; dedup avoids redefinition).

Equipment data dictionary (data/equipment.yaml)

  device:                              Adds `equipment_type: "EQUIPMENT"`
                                       for the S1F20 EQPTYP field.

  capabilities:                        New section.  List of
    - {code, name}                     (CCODE, CDESC) pairs honestly
                                       reflecting what the codebase
                                       implements: 1, 2, 3, 5, 6, 7, 8,
                                       9, 11, 12, 14 (partial), 15.

  dvids:                               New section, same schema as
                                       svids:.  Demo populates two:
    - WaferCounter      (U4, units wafer)
    - ChamberPressure   (F4, units Torr)

Loader (src/config/loader.cpp + include/secsgem/config/loader.hpp)

  EquipmentDescriptor gains equipment_type and capabilities (vector of
  (uint8_t, string) pairs).  load_equipment now reads `capabilities:`
  into the descriptor and `dvids:` into model.dvids.

Server (apps/secs_server.cpp)

  router.on(1, 19) returns S1F20 with desc.software_rev,
  desc.equipment_type, and desc.capabilities converted to
  vector<CapabilityEntry>.
  router.on(1, 21) returns S1F22 built from model.dvids.all().

Client (apps/secs_client.cpp)

  Two new demo steps after Request Online and before SVID discovery:
    S1F19 -> S1F20: logs SOFTREV, EQPTYP, and every (CCODE, CDESC)
                    the equipment claims.
    S1F21 -> S1F22: logs each DVID with units.

Tests

  tests/test_messages.cpp   Round-trip S1F19/F20 with a 3-entry
                            capability list; round-trip S1F22 with two
                            DVIDs.

  tests/test_loader.cpp     Asserts equipment_type, the capabilities
                            list contains CCODE 14 (Spooling), and the
                            two DVIDs land in model.dvids.

COMPLIANCE.md

  "Documentation" Fundamental moves from  to .
  S1F19/F20 + S1F21/F22 rows in the coverage matrix flip to .
  The "what would it take" list drops the documentation-messages bullet.

Verified

  - Tests: 77 cases / 444 assertions pass.
  - Demo: client logs the full capability list received from the
    equipment, including CCODE 14 "Spooling (partial; S2F43/F44 +
    S6F23/F24)" — the equipment honestly reports its partial
    implementation rather than overclaiming.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-07 00:30:43 +02:00
parent 547fd2116b
commit 813e011409
9 changed files with 217 additions and 5 deletions
+61
View File
@@ -130,6 +130,67 @@ messages:
builder: s1f18_online_ack
body: {kind: scalar, item_type: BINARY_BYTE, enum: OnlineAck, param: ack}
# S1F19 / S1F20 — Get GEM Compliance. Host asks the equipment which GEM
# capabilities it supports; equipment replies with its SOFTREV, an
# implementer-defined equipment-type string, and a (CCODE, CDESC) list
# per E30 Appendix A. Closes the "Documentation" Fundamental capability
# by letting the equipment self-report its own COMPLIANCE.md status.
- id: S1F19
stream: 1
function: 19
w: true
builder: s1f19_get_gem_compliance_request
- id: S1F20
stream: 1
function: 20
builder: s1f20_get_gem_compliance_data
parser: parse_s1f20
body:
kind: list
struct_name: GemCompliance
fields:
- {name: softrev, shape: {kind: scalar, item_type: ASCII}}
- {name: equipment_type, shape: {kind: scalar, item_type: ASCII}}
- name: capabilities
shape:
kind: list_of
element:
kind: list
struct_name: CapabilityEntry
fields:
- {name: ccode, shape: {kind: scalar, item_type: U1}}
- {name: cdesc, shape: {kind: scalar, item_type: ASCII}}
# S1F21 / S1F22 — Data Variable Namelist (same wire shape as S1F11/F12
# but for DVIDs). Reuses the StatusName struct emitted by S1F12.
- id: S1F21
stream: 1
function: 21
w: true
builder: s1f21_data_variable_namelist_request
parser: parse_s1f21
body:
kind: list_of
element: {kind: scalar, item_type: U4}
name: vids
- id: S1F22
stream: 1
function: 22
builder: s1f22_data_variable_namelist_data
parser: parse_s1f22
body:
kind: list_of
name: items
element:
kind: list
struct_name: StatusName
fields:
- {name: id, shape: {kind: scalar, item_type: U4}}
- {name: name, shape: {kind: scalar, item_type: ASCII}}
- {name: units, shape: {kind: scalar, item_type: ASCII}}
# =====================================================================
# S2 — Equipment control + reports
# =====================================================================