Design: age-based time (RFC 9171 Bundle Age), seq in identity hash
This commit is contained in:
@@ -98,9 +98,11 @@ plus a policy.
|
|||||||
|
|
||||||
```
|
```
|
||||||
Observation {
|
Observation {
|
||||||
id: ObservationId // content-derived hash of the fields below
|
id: ObservationId // content-derived hash (see below)
|
||||||
observer: NodeId // who saw it
|
observer: NodeId // who saw it
|
||||||
time: Timestamp // when they saw it (observer's clock)
|
seq: u64 // observer-local, never repeats
|
||||||
|
age_ms: u64 // time since observed; mutable, grows per hop
|
||||||
|
observed_at: Option<u64> // absolute ms since epoch, if observer had a clock
|
||||||
topic: Topic // key for grouping/trimming, e.g. "door/3"
|
topic: Topic // key for grouping/trimming, e.g. "door/3"
|
||||||
payload: bytes // opaque to tines
|
payload: bytes // opaque to tines
|
||||||
}
|
}
|
||||||
@@ -108,7 +110,7 @@ Observation {
|
|||||||
|
|
||||||
Decisions:
|
Decisions:
|
||||||
|
|
||||||
- `id` is a hash over `(observer, time, topic, payload)`. Two robots that
|
- `id` is a hash over `(observer, seq, topic, payload)`. Two robots that
|
||||||
observe the same thing produce two observations; de-duplication is
|
observe the same thing produce two observations; de-duplication is
|
||||||
by identity, not by meaning. Union is therefore idempotent and
|
by identity, not by meaning. Union is therefore idempotent and
|
||||||
order-independent. An observation is an *event*, not a fact: the same
|
order-independent. An observation is an *event*, not a fact: the same
|
||||||
@@ -119,13 +121,20 @@ Decisions:
|
|||||||
core does not provision or persist it. Adapters may derive it from a
|
core does not provision or persist it. Adapters may derive it from a
|
||||||
hardware unique ID (MCU chip UID, Jetson serial) or read it from
|
hardware unique ID (MCU chip UID, Jetson serial) or read it from
|
||||||
config. *(My call.)*
|
config. *(My call.)*
|
||||||
- `time` is the observer's local clock, as `u64` milliseconds since the
|
- `time` is carried as **age, not a timestamp**, following RFC 9171's
|
||||||
Unix epoch, plus a `ClockQuality` tag: `Synced` (GPS/NTP), `FreeRunning`
|
Bundle Age Block. Every observation carries `age_ms: u64`, the elapsed
|
||||||
(set once, drifting), or `BootRelative` (no RTC; ms since boot). The
|
time since it was observed. Each holder increments it by its own
|
||||||
tag travels with the observation so the memory layer can decide how
|
holding time (monotonic tick; every target has one) before forwarding.
|
||||||
much to trust cross-observer recency. `tines` does not attempt clock
|
An observer that has a real clock may additionally set
|
||||||
sync. *(My call: the tag is the minimum needed to make a
|
`observed_at: Option<u64>` (ms since Unix epoch). A receiver with a
|
||||||
`BootRelative` MCU observation honest rather than silently wrong.)*
|
clock can pin a clockless observation at `now − age_ms`. Precision
|
||||||
|
degrades by each hop's tick error; `tines` does not attempt clock
|
||||||
|
sync. *(Kyle's suggestion; the RFC mapping and the optional absolute
|
||||||
|
field are my call.)*
|
||||||
|
- Because `age_ms` is mutable, it is **not** in the identity hash. The
|
||||||
|
hash covers `(observer, seq, topic, payload)` where `seq` is an
|
||||||
|
observer-local monotonic counter that must not repeat across reboots
|
||||||
|
(persisted, or `boot_count << 32 | counter`). *(My call.)*
|
||||||
- `topic` is a short byte string. Its structure (hierarchy, separators)
|
- `topic` is a short byte string. Its structure (hierarchy, separators)
|
||||||
is application-defined but `tines` supports prefix matching for
|
is application-defined but `tines` supports prefix matching for
|
||||||
trimming and queries.
|
trimming and queries.
|
||||||
|
|||||||
Reference in New Issue
Block a user