Closes#274 (WS-A2). Unifies every wall-clock instant on the proto boundary to google.protobuf.Timestamp and every duration to google.protobuf.Duration, replacing the prior mix of unix-seconds and unix-nanoseconds int64/uint64 scalars.
Added prost-types as a workspace dependency (only to nuncio-proto, since it re-exports Timestamp/Duration via a new nuncio_proto::time module so downstream crates don't need their own dependency).
nuncio_proto::time is the single conversion point between the store's native integer instants (unix-seconds i64/u64, or unix-nanoseconds for the WORM audit ledger) and the wire types: timestamp_from_unix_secs/timestamp_to_unix_secs, timestamp_from_unix_nanos/timestamp_to_unix_nanos (lossless split/join of the audit ledger's sub-second precision), duration_from_secs/duration_to_secs, duration_from_micros/duration_to_micros.
nunciod::grpc's mappers now go through these helpers at the proto boundary; core/store models are unchanged (still native seconds/ns integers).
nuncio-cli's runner.rs renders Timestamp fields as RFC 3339 strings (format_timestamp) for both human and --json output, and Duration fields as their original seconds/microseconds units for output-shape continuity. The audit ledger's --json output keeps both a human timestamp (RFC 3339) and an exact timestamp_ns field.
Added round-trip tests: nuncio_proto::time's own unit tests (seconds/nanos/micros round trips, including a negative pre-epoch nanos regression), plus nunciod::grpc's map_email_to_proto_round_trips_received_at_exactly, map_audit_record_to_proto_preserves_nanosecond_precision, and account_sync_interval_round_trips_through_duration.
cargo test -p nuncio-proto — 32 unit tests incl. contract_stability::descriptor_matches_committed_golden
cargo test -p nunciod — lib + all e2e suites green, including the new mapper round-trip tests
cargo test -p nuncio-cli — lib + doctest green, including updated JSON rendering assertions
Full workspace gate (fmt/clippy/test) green via the local pre-commit hook
## Summary
Closes #274 (WS-A2). Unifies every wall-clock instant on the proto boundary to `google.protobuf.Timestamp` and every duration to `google.protobuf.Duration`, replacing the prior mix of unix-seconds and unix-nanoseconds `int64`/`uint64` scalars.
**Fields converted (Timestamp):**
- `Message.received_at`
- `CalendarEvent.start_time` / `end_time`
- `CalendarSyncRequest.start_window` / `end_window`
- `ListEventsRequest.start_window` / `end_window`
- `FilterRule.created_at` / `updated_at`
- `FilterExecutionLog.matched_at`
- `AuditRecord.timestamp_ns` -> renamed `timestamp` (nanosecond precision preserved losslessly)
**Fields converted (Duration):**
- `AccountConfig.sync_interval_secs` -> renamed `sync_interval`
- `PreviewRuleResponse.execution_time_us` -> renamed `execution_time`
**Implementation:**
- Added `prost-types` as a workspace dependency (only to `nuncio-proto`, since it re-exports `Timestamp`/`Duration` via a new `nuncio_proto::time` module so downstream crates don't need their own dependency).
- `nuncio_proto::time` is the single conversion point between the store's native integer instants (unix-seconds `i64`/`u64`, or unix-nanoseconds for the WORM audit ledger) and the wire types: `timestamp_from_unix_secs`/`timestamp_to_unix_secs`, `timestamp_from_unix_nanos`/`timestamp_to_unix_nanos` (lossless split/join of the audit ledger's sub-second precision), `duration_from_secs`/`duration_to_secs`, `duration_from_micros`/`duration_to_micros`.
- `nunciod::grpc`'s mappers now go through these helpers at the proto boundary; core/store models are unchanged (still native seconds/ns integers).
- `nuncio-cli`'s `runner.rs` renders `Timestamp` fields as RFC 3339 strings (`format_timestamp`) for both human and `--json` output, and `Duration` fields as their original seconds/microseconds units for output-shape continuity. The audit ledger's `--json` output keeps both a human `timestamp` (RFC 3339) and an exact `timestamp_ns` field.
- Regenerated `crates/nuncio-proto/proto/nuncio/v1/descriptor.bin`; `contract_stability::descriptor_matches_committed_golden` passes.
- Added round-trip tests: `nuncio_proto::time`'s own unit tests (seconds/nanos/micros round trips, including a negative pre-epoch nanos regression), plus `nunciod::grpc`'s `map_email_to_proto_round_trips_received_at_exactly`, `map_audit_record_to_proto_preserves_nanosecond_precision`, and `account_sync_interval_round_trips_through_duration`.
## Gate output
```
cargo fmt --all -- --check -> clean
cargo check-all -> clean (clippy --all-targets --workspace -D warnings)
cargo test-all -> 498 passed; 0 failed; 0 ignored (workspace total)
```
## Test plan
- [x] `cargo test -p nuncio-proto` — 32 unit tests incl. `contract_stability::descriptor_matches_committed_golden`
- [x] `cargo test -p nunciod` — lib + all e2e suites green, including the new mapper round-trip tests
- [x] `cargo test -p nuncio-cli` — lib + doctest green, including updated JSON rendering assertions
- [x] Full workspace gate (fmt/clippy/test) green via the local pre-commit hook
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Closes #274 (WS-A2). Unifies every wall-clock instant on the proto boundary to
google.protobuf.Timestampand every duration togoogle.protobuf.Duration, replacing the prior mix of unix-seconds and unix-nanosecondsint64/uint64scalars.Fields converted (Timestamp):
Message.received_atCalendarEvent.start_time/end_timeCalendarSyncRequest.start_window/end_windowListEventsRequest.start_window/end_windowFilterRule.created_at/updated_atFilterExecutionLog.matched_atAuditRecord.timestamp_ns-> renamedtimestamp(nanosecond precision preserved losslessly)Fields converted (Duration):
AccountConfig.sync_interval_secs-> renamedsync_intervalPreviewRuleResponse.execution_time_us-> renamedexecution_timeImplementation:
prost-typesas a workspace dependency (only tonuncio-proto, since it re-exportsTimestamp/Durationvia a newnuncio_proto::timemodule so downstream crates don't need their own dependency).nuncio_proto::timeis the single conversion point between the store's native integer instants (unix-secondsi64/u64, or unix-nanoseconds for the WORM audit ledger) and the wire types:timestamp_from_unix_secs/timestamp_to_unix_secs,timestamp_from_unix_nanos/timestamp_to_unix_nanos(lossless split/join of the audit ledger's sub-second precision),duration_from_secs/duration_to_secs,duration_from_micros/duration_to_micros.nunciod::grpc's mappers now go through these helpers at the proto boundary; core/store models are unchanged (still native seconds/ns integers).nuncio-cli'srunner.rsrendersTimestampfields as RFC 3339 strings (format_timestamp) for both human and--jsonoutput, andDurationfields as their original seconds/microseconds units for output-shape continuity. The audit ledger's--jsonoutput keeps both a humantimestamp(RFC 3339) and an exacttimestamp_nsfield.crates/nuncio-proto/proto/nuncio/v1/descriptor.bin;contract_stability::descriptor_matches_committed_goldenpasses.nuncio_proto::time's own unit tests (seconds/nanos/micros round trips, including a negative pre-epoch nanos regression), plusnunciod::grpc'smap_email_to_proto_round_trips_received_at_exactly,map_audit_record_to_proto_preserves_nanosecond_precision, andaccount_sync_interval_round_trips_through_duration.Gate output
Test plan
cargo test -p nuncio-proto— 32 unit tests incl.contract_stability::descriptor_matches_committed_goldencargo test -p nunciod— lib + all e2e suites green, including the new mapper round-trip testscargo test -p nuncio-cli— lib + doctest green, including updated JSON rendering assertions