openapi: 3.2.0 info: description: emem is shared memory for AI agents working together in the real world. license: name: Apache-2.0 title: emem Change Attribution API version: 2.4.0 x-emem-surface-asymmetry: memory_notes: MCP only reach_them_at: POST /mcp, method tools/call read_side_is_here: - /v1/memory/search - /v1/memory/sse - /memories/{path} tools: - emem_memory_create - emem_memory_view - emem_memory_delete - emem_memory_rename - emem_memory_str_replace - emem_memory_supersede why_not_here: These write the agent correspondence plane, which is prose and untrusted-by-declaration. It is deliberately not part of the REST fact surface, and the two planes are kept apart rather than merged for convenience. servers: - description: Hosted instance (HTTPS-only) url: https://emem.dev tags: - name: Change Attribution paths: /v1/change_attribution: post: description: 'The first runnable surface of the change decomposition Δz = Δ_env + Δ_sensor + Δ_geo + Δ_encoder + ε: a per-term evidence LEDGER for the readout change at a cell, with NO numeric split. `observed` carries the Tessera year-over-year embedding change. `terms.env` carries label-free index pairs (NDVI, NBR, NDWI) with raw deltas and both fact cids, evidence a future estimator would read. `terms.sensor` records what each visit was observed through (source scheme and scene id per band) and whether that path changed. `terms.geo` is declared not estimated (no registration-residual surface exists). `terms.encoder` is pinned by construction: both vintages are slices of one signed multi-year fact under one recipe, named by fn_key. `terms.noise` reports the S2 scene-classification class per visit, so a cloud flip is visible. `split` is null and `attribution_note` says why: splitting a delta numerically needs a calibrated cross-encoder, cross-sensor stability model this responder does not have, and inventing magnitudes would fabricate the exact confusion the decomposition exists to prevent. The ledger persists: each run stores itself as a derivative fact (band change_attribution.ledger, parents = every fact read) and the response returns its own emem:fact: token under ledger_fact, so an attribution is cited and dereferenced like any reading. The receipt binds every input fact cid plus the stored ledger cid. Bands read cold may materialize, so this signs and persists facts. When to use: Call when a change surface (emem_diff, emem_state_diff, emem_triple_consensus, did_change) reported that a place''s readout moved and the question is WHY: world, instrument, pixels, model, or noise. Read the per-term evidence and cite its fact cids; do not expect a numeric split (`split` is null by design, see `attribution_note`). Bands with fewer than two distinct tslots at the cell appear under evidence_absent with a typed reason rather than a fabricated pair. For the raw delta itself use emem_diff; for the multi-encoder change vote use emem_triple_consensus.' operationId: emem_change_attribution requestBody: content: application/json: schema: properties: cell: description: cell64 or place name type: string required: - cell type: object required: true responses: '200': content: application/json: schema: type: object description: ok default: content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' description: 'error, the emem.error.v1 envelope. Branch on the stable `code` (see GET /v1/errors), not the message. A malformed or missing-field request body returns `code: invalid_argument` with the offending field named in `message`.' summary: 'The attribution ledger for a readout change at a cell: per-term evidence for Δz…' tags: - Change Attribution components: schemas: ErrorEnvelope: description: The `emem.error.v1` failure envelope returned by every endpoint on a 4xx/5xx. Branch on the stable `code` (not the human `message`). See GET /v1/errors for the full code catalog. properties: code: description: Stable machine-readable error code. One of the codes in GET /v1/errors. example: invalid_argument type: string details: description: Optional structured recovery hints; present on errors that ship machine-readable next-steps. type: object message: description: Human-readable detail. For invalid_argument this names the offending field (e.g. "missing field `q`"). type: string path: description: Request path that produced the error. example: /v1/ask type: string schema: const: emem.error.v1 type: string required: - code - message - schema type: object