---
title: 'Moments & History'
description: 'How Agility journals changes as globally-sequential moments, and how moments drive the Hist namespace, versioned asset addresses and asof queries.'
sidebar_label: 'Moments & History'
sidebar_position: 7
tags: ['concepts', 'moment', 'history', 'asof', 'audit']
---

## Overview

Agility does not overwrite data. Changes to assets are journaled, and each
change is stamped with a **moment** — a chronologically increasing integer.

A few attributes are exceptions: rank order (`Order`) changes, for example, are not
journaled at all — an asset's history never shows a rank move. There is no way to
discover through the API which attributes are tracked.

A moment is the unit of time in the Agility data model. It is what makes the
`Hist` namespace, versioned asset addresses and `asof` queries possible, and it is
the single concept you must understand before you can read history correctly.

## Moments Are Global, Not per-Asset

This is the detail that trips up most integrations.

Moment numbers are **sequential for the entire Agility instance**, not for an
individual asset. Any change to any asset, by any member, consumes the next moment
number in the system.

Consider three changes made in this order:

| Order | Change                            | Moment |
| ----- | --------------------------------- | ------ |
| 1     | A Story is created                | 203    |
| 2     | That Story's `ToDo` is updated    | 204    |
| 3     | An unrelated Member's `Name` is updated | 205 |

The Story now has two entries in its own history — moment 203 and moment 204 — and
the next change anywhere in the system will be moment 206.

:::warning[Do not assume a contiguous sequence]

Because moments are handed out globally, an individual asset's moments are almost
always **sparse**. A Story might have moments 203, 204, 818, 874 and 903. The gaps
are other people's changes to other assets.

Never compute "the previous version" by subtracting 1 from a moment, and never
treat the count of moments between two versions as a measure of elapsed time or of
how much changed. To move through an asset's versions, read its history and use the
moments it actually reports.

:::

## Addressing a Version

An asset is identified by its asset type and integer ID:

```text
Member:20
```

A *past version* of an asset is identified by asset type, ID **and** moment:

```text
Member:20:563
```

That reads as "the Member asset with ID 20, as it was at moment 563". The same
three parts appear in the URL of a versioned asset, in the `Moment` path segment:

```text
/VersionOne/rest-1.v1/Data/Member/20/563
```

Omit the moment and you address the asset as it is **now**:

```text
/VersionOne/rest-1.v1/Data/Member/20
```

Relations follow the same rule. A relation attribute on a past version refers to
the *past version* of its target asset, so a historical query gives you an
internally consistent snapshot rather than old attributes stitched onto current
related assets.

## Reading History: The `Hist` Namespace

`rest-1.v1` exposes two query namespaces, and they differ only in whether you get
one record or all of them:

| Namespace | Returns                                                          | Root element |
| --------- | ---------------------------------------------------------------- | ------------ |
| `Data`    | The current version of each matching asset                       | `Assets`     |
| `Hist`    | Every historical version of each matching asset                  | `History`    |

So this returns one Member:

```text
GET /VersionOne/rest-1.v1/Data/Member/20
```

and this returns every version that Member has ever had:

```text
GET /VersionOne/rest-1.v1/Hist/Member/20
```

Each `Asset` element in a `History` response carries an `href` that includes the
moment, giving you a direct, permanent address for that exact version.

History works at attribute granularity too. Asking for the history of a single
attribute returns one record per change to *that* attribute, each with an `href`
pointing at the attribute and an `of` pointing at the owning asset version:

```text
GET /VersionOne/rest-1.v1/Hist/Member/20/Email
```

All of the ordinary query parameters — attribute selection, filtering, sorting,
paging and text search — work against `Hist` in the same way they do against
`Data`, subject to the same rule that list-oriented parameters only take effect on
list-shaped requests. See the [query grammar
reference](/reference/query-grammar) for the applicability matrix.

:::tip[`ChangeDate` is maintained by history]

`ChangeDate` is populated by the history subsystem and records the wall-clock time
at which a version was written. Select it whenever you need to correlate moments
with real time, because a moment number on its own tells you ordering but not when.

:::

## Reading History as a Relation

The [`Hist` namespace](#reading-history-the-hist-namespace) is not the only way to
reach history, and often not the most convenient. Every asset type also exposes
history through **ordinary relations**, which means you can traverse it with the
[attribute-path syntax](/reference/query-grammar/attribute-paths) from any surface
— including [`query.v1`](/apis/query-v1) and the [Bulk API](/apis/asset-bulk),
neither of which has a `Hist` namespace of its own.

| Attribute | Type | From | Gives you |
| --- | --- | --- | --- |
| `History` | Relation, **multi-value** | a current asset | every version of it |
| `Now` | Relation | a version | the current asset — the reciprocal of `History` |
| `Prior` | Relation | a version | the version immediately before it |
| `ChangedBy` | Relation | a version | the Member who made the change |
| `ChangeDate` | Date | a version | when the change happened |
| `ChangeComment` | Text | a version | the comment supplied with the change |
| `Moment` | Opaque | a version | the moment itself |

All seven are read-only **as history attributes** — you read them, you do not
select them to write. `ChangeComment` is the exception worth knowing: you cannot
set it by selecting it, but you *can* supply it at write time — `?comment=` on
[`rest-1.v1`](/apis/rest-1#recording-why-a-change-was-made) or a `ChangeComment`
key on [`api/asset`](/apis/asset-bulk/updating-assets#recording-a-change-comment)
— and it then appears here.

`Prior` is what makes before-and-after comparison possible in a single query:
within one history row, `Description` is the value **at** that moment and
`Prior.Description` is the value **immediately before** it. `Now.Description`
reaches past both to the current value.

:::tip `Now.` is the `query.v1` equivalent of the `#` operator

On `rest-1.v1` you write `Parent#.Name` to mean "the *current* value, not the
value at this moment" — and you must
[percent-encode the `#`](/reference/query-grammar/attribute-paths) or lose it.

`Now.` does the same job as a plain relation traversal, so it needs no escaping
and works anywhere attribute paths work.

:::

### Finding What Changed

Query an asset's history as a nested result set, selecting both the value at each
moment and the value before it:

```json
{
  "from": "Defect",
  "select": [
    {
      "from": "History",
      "select": ["Now.Name", "Prior.Description", "Description", "ChangedBy.Name"]
    }
  ],
  "filter": "Number=$Numbers",
  "with": { "$Numbers": ["D-14519", "D-16384"] },
  "page": { "start": 0, "size": 2 }
}
```

Each row where `Prior.Description` differs from `Description` is a change to that
attribute, attributed to `ChangedBy.Name`.

### Restoring a Previous Value

There is no "revert" operation. Reading history and writing the old value back is
the supported approach: find the moment where the attribute changed, take
`Prior.<Attribute>`, and update the asset with it.

:::danger Strip the moment before you write

OID tokens in history results carry a **moment suffix** — `Defect:1234:5678`, not
`Defect:1234`. That third segment identifies a *version*, and passing it as the
`from` of an update targets a historical row rather than the live asset.

Take the first two segments only:

```json
{ "from": "Defect:1234", "update": { "Description": "<the prior value>" } }
```

See [addressing a version](#addressing-a-version).

:::

## Point-in-Time Queries: `asof`

Moments are precise but opaque — you rarely know the moment number you want. The
`asof` query parameter lets you ask the question in terms of wall-clock time
instead:

```text
GET /VersionOne/rest-1.v1/Hist/Story/1364?asof=2005-08-03T17:30:00.00&sel=Name,ToDo,ChangeDate
```

Two rules govern the result:

1. **`asof` returns the last historical record on or before the given time.** It
   does not require a change to have happened at that instant. In the example
   above, the Story was last changed at 13:09:05.983 on 2005-08-03; that is the
   version returned for an `asof` of 17:30, because nothing changed in between.
2. **`asof` overrides an explicit moment.** If you supply both a `Moment` path
   segment and an `asof` parameter, the moment is ignored. Use one or the other,
   not both.

`asof` applies to single-attribute, single-asset and multi-asset historical
queries alike, so you can reconstruct a whole project as it stood on a given day.

:::note[What `asof` accepts]

`asof` takes either an integer **moment** or a datetime in invariant culture, for
example `2005-08-03T17:30:00.00` — the same format `ChangeDate` returns. The full
syntax of `asof` and of the other query string parameters is covered in the [query
grammar reference](/reference/query-grammar).

:::

## Practical Consequences

- **Audit trails come for free.** You do not need to build change tracking on top
  of Agility; ask `Hist` for the asset and select `ChangeDate` alongside the
  attributes you care about.
- **Trend and burndown data is a series of `asof` queries.** To chart remaining
  effort over a sprint, issue one `asof` query per point on the x-axis rather than
  trying to reduce the raw history yourself.
- **Cache versioned URLs, not current ones.** A URL containing a moment is
  immutable and safe to cache indefinitely. A URL without one is not.
- **Moments are not timestamps.** Two changes made in the same second get
  different moments; moments from different Agility instances are unrelated and
  must never be compared.
- **History is voluminous.** A `Hist` query with no filter returns every version of
  every matching asset. Page it, and select only the attributes you need.

## Related Topics

- [Information model](/apis/rest-1/information-model) — the authoritative
  definition of asset type, attribute definition, asset, attribute and moment.
- [Query examples](/apis/rest-1/query-examples) — worked `Hist` and `asof` queries
  with real response payloads.
- [REST API (rest-1.v1)](/apis/rest-1) — the endpoint surface that exposes all of
  this.
- [Query grammar](/reference/query-grammar) — the syntax of `asof`, `sel`, `where`,
  `sort` and `page`.
