Skip to content

Schema Governance — wasmagent ↔ evomerge Data Pipeline

Overview

Three repositories exchange data through JSONL files. This document defines the single source of truth for each format and the process for changing it.

Data pipeline layers

wasmagent-js RolloutForkRunner
  │  produces RolloutBranchResult (in-memory)

  ▼  serialized to JSONL
Layer 1: RolloutBranchRecord (rollout-wire.schema.json § RolloutBranchRecord)
  │  fields: rollout_id, task, branch_index, temperature, session_id,
  │          tool_call_sequence, final_answer, objective_score, rank, total_score

  ▼  consumed by evomerge load_rollouts()
  │  OR processed by wasmagent-js toDpoRecord() / toPpoRecords()

Layer 2: DpoRecord / PpoRecord (rollout-wire.schema.json § DpoRecord / PpoRecord)
  │  fields: prompt, chosen/completion, reward, tool_call_sequence, provenance
  │  provenance.source: "wasmagent-rollout"  ← canonical constant
  │  provenance fields: snake_case throughout

  ▼  consumed by evomerge exporter.py to_dpo() / to_ppo()
  │  (rebuilds messages, infers loss_weight, normalizes reward to [0,1])

Layer 3: Training Record (training-record.schema.json)
  │  fields: messages, chosen/reward, loss_weight_tokens, provenance
  │  validated by validate-rlaif.mjs before shipping to training

  ▼  consumed by training framework (Hugging Face Trainer)

Schema files (single source of truth)

Cross-repo schemas are owned by WasmAgent/wasmagent-protocol and consumed here via the versioned @wasmagent/protocol package — never copied or forked.

SchemaCanonical sourceHow this repo consumes it
rollout-wire@wasmagent/protocol (schemas/compliance/rollout-wire.schema.json)import from the package; see scripts/check-rollout-schema.mjs
constraint-ir, constraint-violation, repair-trace, task-spec, compliance-eval-record@wasmagent/protocolmirrored field-for-field by the packages/compliance types, validated against the package
training-record.schema.jsonwasmagent-js/packages/core/src/ranking/schemas/repo-local — single consumer (this repo + trace-pipeline training pipeline), intentionally not centralized

Historical note: rollout-wire and the compliance family used to live in this repo and were mirrored into evomerge/trace-pipeline by hand. That is the drift wasmagent-protocol was created (2026-07-23) to eliminate. They now live only in wasmagent-protocol; this repo depends on the published package.

Schema owner

wasmagent-js is the domain steward for the AEP and compliance schema family: it drives the design, but the canonical JSON lives in wasmagent-protocol. Changes flow through the protocol contract-change process (edit schema + fixtures in wasmagent-protocol, bump the package, then update consumers). training-record.schema.json remains owned outright by this repo.

Change process

Adding a new field (non-breaking)

  1. Update the Zod interface in RolloutExporter.ts (add the field).
  2. Update rollout-wire.schema.json or training-record.schema.json as appropriate.
  3. Run node scripts/check-rollout-schema.mjs locally — must pass.
  4. Open PR in wasmagent-js. CI will verify schema consistency.
  5. After merge, copy updated schema file(s) to evomerge/datafactory/.
  6. Update exporter.py to consume the new field if needed.
  7. Run python scripts/check-schema-fields.py in evomerge — must pass.

Renaming or removing a field (breaking)

Update consumers first, producer last:

  1. Update evomerge/exporter.py to handle both old and new field names (or remove the old name from its reads).
  2. Update bscode/apps/worker/src/rollout-adapter.ts if it references the field.
  3. After both consumer PRs are merged, update the producer (RolloutExporter.ts) and the schema files.
  4. Remove the compatibility shim from consumers.

Changing provenance.source constant

The constant "wasmagent-rollout" appears in:

  • RolloutExporter.ts (TypeScript literal type + runtime value)
  • rollout-wire.schema.json ($.defs.DpoProvenance.properties.source.const)
  • training-record.schema.json ($.defs.Provenance.properties.source.const)
  • evomerge/datafactory/exporter.py (_make_provenance)
  • evomerge/datafactory/validate-rlaif.mjs (read from schema, not hardcoded)

If it must change, update all five locations atomically.

CI enforcement

wasmagent-js (scripts/check-rollout-schema.mjs)

Runs in CI after lint. Checks:

  • RolloutExporter.ts provenance objects use snake_case keys only
  • Schema JSON files are present and valid
  • Schema provenance.source.const is "wasmagent-rollout"

evomerge (scripts/check-schema-fields.py)

Runs in CI under the boundaries job. Checks:

  • exporter.py load_rollouts() reads all fields required by RolloutBranchRecord
  • exporter.py _make_provenance() uses the source constant from the schema
  • Schema JSON files are present and valid
  • All provenance field names in the schema are snake_case

Conventions

  • Field naming: snake_case in all JSONL wire formats and schema files. TypeScript internal identifiers (function parameters, local variables) may use camelCase, but the serialized JSON keys must be snake_case.
  • reward normalization: total_score in Layer 1/2 is raw (may exceed 1.0). Normalization to [0, 1] is evomerge's responsibility (_compute_reward()). Do not normalize in toPpoRecords().
  • n_gram_hash: 16-hex-character SHA-256 prefix of the task string. Computed in toDpoRecord()/toPpoRecords() using node:crypto. Used by the G3 gate in evomerge to detect eval contamination.
  • prompt_messages: Optional field on DpoTrainingRecord (Training Record layer 3), formally declared in training-record.schema.json. Contains the conversation history up to (not including) the final assistant turn, enabling TRL DPOTrainer to receive a distinct prompt and chosen/rejected pair without double-counting prompt tokens in the loss. Generated by evomerge/datafactory/exporter.py _extract_prompt_messages().

Training scripts

ScriptMethodInput
evomerge/scripts/p17_b1_sft.pySFT (supervised fine-tuning)messages JSONL
evomerge/scripts/p18_grpo_train.pyGRPO (group relative policy optimization)PPORecord JSONL from exporter.py

p18_grpo_train.py reads the reward field from PPORecord (already normalized to [0, 1]) and passes it to trl.GRPOTrainer via a reward function. LoRA is on by default (rank 16). Requires pip install trl>=0.9 peft transformers torch.

Three-repo Data Loop Contract

The full contract including producers, consumers, contamination policy, and end-to-end command chain is documented in:

WasmAgent/trace-pipelinedocs/data-loop-contract.md

That document is the binding contract. GOVERNANCE.md (this file) covers how this repo consumes the canonical schemas and its field-naming conventions. The schema JSON itself is owned by wasmagent-protocol, not this repo.

Released under the Apache-2.0 License.