Skip to content

AMPR-323 #737: Observed interface + FreshnessProbe : Probe<Observed> with per-Probe max age - #749

Merged
wow-miley merged 2 commits into
mainfrom
miley/ampr-323-observed-timestamp-interface-freshnessprobe-probeobserved
Sep 3, 2026
Merged

AMPR-323 #737: Observed interface + FreshnessProbe : Probe<Observed> with per-Probe max age#749
wow-miley merged 2 commits into
mainfrom
miley/ampr-323-observed-timestamp-interface-freshnessprobe-probeobserved

Conversation

@wow-miley

@wow-miley wow-miley commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Closes #737. Linear: AMPR-323.

What

  • Observed (probe/Observed.kt): one-field interface, observedAt: Instant. Consumers implement it on their own Recall-binding types for canon-external observations; Ampere never imports the concrete type.
  • CanonProvenance : Observed: declaration-only conformance. The field already existed, so no serialization change; CanonSerializationTest is unaffected.
  • FreshnessProbe(maxAge, now) (probe/FreshnessProbe.kt), default id ampere.freshness:
    • age ≤ maxAgeHolds("observed <age> ago")
    • age > maxAgeUndetermined("observed <age> ago, max <maxAge>", STALE) — not Violated
    • observedAt ahead of nowWarn("observedAt is <skew> ahead of now")
  • Registry wiring: ProbeRegistry.registerAmpereProbes(freshnessMaxAge = 24.hours, now = Clock.System::now) now registers FreshnessProbe beside SequenceProbe (from AMPR-322 #736: CanonWorkItem.dependsOn, CanonWorkGraph, SequenceProbe; report batch cycles #750). The max age is a parameter because it is consumer policy, never a fact field.
  • Docs: new docs/concepts/probe.md (where observedAt binds per observation kind; max-age is a Probe parameter), index row, and a matching invariant in domain-canon.md. No changelog entry: main removed CHANGELOG.md in Remove CHANGELOG.md and stop agents from recreating it #753.

Tests

FreshnessProbeTest (commonTest): fresh → Holds; exactly at max age → Holds; one second past → Undetermined(STALE); future → Warn; a plain object : Observed and a CanonProvenance both run through the same Probe (contravariance); suite composition beside a Probe<Any>; registerAmpereProbes lists both shipped Probes.

Validation

  • ./gradlew :ampere-core:ktlintFormat — no changes
  • ./gradlew :ampere-core:jvmTest --tests "*probe*" --tests "*CanonSerializationTest*" — 35 tests, 0 failures
  • ./gradlew :ampere-core:compileTestKotlinIosSimulatorArm64 — green

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown

Concept staleness check — clean. No tracked-source changes need a concept update.

@wow-miley
wow-miley force-pushed the miley/ampr-323-observed-timestamp-interface-freshnessprobe-probeobserved branch from 44a0d3f to c06f953 Compare September 3, 2026 00:54
wow-miley and others added 2 commits September 2, 2026 20:10
… age

Add `Observed` (one field: `observedAt: Instant`) to the probe package and
have `CanonProvenance` implement it — conformance only, no wire change.
Ship `FreshnessProbe : Probe<Observed>`: within `maxAge` → Holds; beyond it
→ Undetermined(STALE), not Violated (convict-but-not-acquit); `observedAt`
ahead of `now` → Warn for clock skew. Max-age lives on the Probe, never on
the fact.

Tests pin the three outcomes against a fixed clock, run the Probe over a
plain `object : Observed` and over a `CanonProvenance` to prove the
contravariance path, and show it listed in a `ProbeRegistry`.

New `docs/concepts/probe.md` records where `observedAt` binds for each
observation kind (Plug perceive, relay fetch, Recall binding) and that
max-age is a Probe parameter; `domain-canon.md` gains the matching
invariant.

Concept-Verified: DomainCanon

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…enceProbe

AMPR-322 landed the sample wiring this ticket's task 3 targets.
`registerAmpereProbes(freshnessMaxAge, now)` takes the tolerance as a
parameter (default 24h) because max-age is consumer policy, not a fact
field. `FreshnessProbe.ID` mirrors `SequenceProbe.ID`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@wow-miley
wow-miley force-pushed the miley/ampr-323-observed-timestamp-interface-freshnessprobe-probeobserved branch from c06f953 to 7bc5c7e Compare September 3, 2026 01:10
@wow-miley
wow-miley merged commit 1606f42 into main Sep 3, 2026
11 checks passed
@wow-miley
wow-miley deleted the miley/ampr-323-observed-timestamp-interface-freshnessprobe-probeobserved branch September 3, 2026 01:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Observed timestamp interface + FreshnessProbe : Probe<Observed> with per-Probe max age; CanonProvenance implements Observed

1 participant