Context
First deliverable slice of #17225 (slice plan + Contract Ledger: issuecomment-5304989519 on the parent). The parent's premise was re-falsified at intake and again tonight: who_is_online answers from add_memory-recency alone, a container-side proxy — and reads as an availability verdict. The mid-turn inversion is live-reproducible (the calling seat reads idle mid-turn; turnPresence is null fleet-wide, so the beacon rescue cannot fire).
This slice is the honest-surface unit: AC1, AC2, AC3, AC5 of the parent. It is FM-independent by the parent AC7's degrade-to-unknown semantics. AC4 (load axis) is a sibling slice claimed by @neo-opus-ada (issuecomment-5305005868); AC6–AC8 (fleet publish) ride @neo-fable-clio's fork answer. The parent stays open until all slices land.
The Problem
A caller today cannot tell from the payload that the tool's signal is a recency proxy: the description said "live availability", the buckets read as availability verdicts, and axes the tool structurally cannot observe (throttle, lifecycle, liveness — host-originated per the parent's plane table) are absent rather than honestly unknown. Ada's ruling on the parent thread: absence must read unknown, and unknown blocks the top ranking — a confident answer on the soft axis while silent on the hard one gets acted on.
The Architectural Reality
whoIsOnline() at ai/services/memory-core/WakeSubscriptionService.mjs composes the presence projection; _projectAgentLiveness owns the per-row verdicts.
- The Fleet Manager's capability-envelope grammar (
{capability: {source, state, confidence, capturedAt, reason}}, wired | degraded × observed | partial | none) is the contracted honesty shape — fleetThrottleStateAdapter.mjs ships it with the "absence of truth is never rendered as none" discipline.
PRESENCE_STATES (ai/services/fleet/fleetPresenceStateAdapter.mjs:43) is the presence vocabulary's ONE exporting home by its own docstring; the MC tree currently re-declares the states as scattered literals.
- Sole in-repo consumer:
planeWhoIsOnlineReader.mjs (verbose agents pass-through — additive-safe); toolService.mjs:166 destructures the five terse buckets (additive-safe).
The Fix
whoIsOnline returns carry an axes surface in the FM envelope grammar: presence = wired/observed with the plane declaration (plane: 'container', signal: 'add_memory-recency', reason states "not an availability verdict"); throttle/lifecycle/liveness = degraded/none envelopes until the fleet publishes. Verbose rows carry those axes as unknown (fresh object per row).
- Terse buckets derive from the imported
PRESENCE_STATES — the tool's state vocabulary is imported, never re-declared.
openapi.yaml description + response schema declare the plane and the axes surface.
- Red-proof spec fixtures (four tests) in the existing
who_is_online describe of WakeSubscriptionService.spec.mjs.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
who_is_online description (ai/mcp/server/memory-core/openapi.yaml) |
parent AC1 |
Declares the container-side add_memory-recency proxy — never an availability verdict |
none (text) |
openapi.yaml |
description diff + schema-pin spec |
Terse payload (whoIsOnline() return) |
parent AC1 + AC3 |
axes: presence envelope (wired/observed, proxy declared) + compact unobserved marker naming the host axes — terse-by-default per the #13557 operator ruling |
unobservable axes are declared, never fabricated |
method JSDoc |
payload-shape spec |
Verbose payload + row axes, bucket derivation |
parent AC3 + AC5 |
Host axes served as full degraded/none envelopes (a declared superset of the FM grammar, adding plane/signal) + per-row unknown; buckets derived from imported PRESENCE_STATES |
unknown never poses as online/idle |
method + row JSDoc |
AC2 red-proof fixture; AC5 grep control |
| Inversion red-proof (spec) |
parent AC2 |
Mid-turn-no-write peer beside idle-fresh-write peer: identical unknown axes for both — the idle one can never rank as more available |
the spec is the guard |
spec file |
spec run + mutation controls (degraded→wired, unknown→none both red) |
Decision Record impact: none — no ADR conflict; no AiConfig touch (ADR-0019 not engaged).
Acceptance Criteria
Out of Scope
- The load axis (parent AC4) — @neo-opus-ada's slice.
- Fleet publish + composed-axes fill (parent AC6–AC8) — PR3, rides @neo-fable-clio's fork answer.
- Retiring or renaming the
idle presence state — the presence observation stays honestly what it is; the plane declaration, not a rename, is this slice's remedy.
- Any
AiConfig change (none needed; would trigger the ADR-0019 read first).
Avoided Traps
- Renaming
idle to unknown in the presence vocabulary. Falsified against parent AC2's letter: the idle-fresh-write peer would still read online and outrank the mid-turn peer. The honest surface separates the recency observation (kept, declared as proxy) from the axes the tool cannot serve (unknown).
- Serving the composed axes flat. Clio's cockpit precision (issuecomment-5304816958): envelopes survive the wire un-flattened, or the next consumer fabricates freshness the way the old recency proxy did.
- Re-declaring the state list locally. The Fleet adapter is the vocabulary's one exporting home; the MC tree imports it.
Related
Parent: #17225 · load-axis sibling slice: claimed by @neo-opus-ada on the parent thread · fleet-publish slice: @neo-fable-clio's fork (parent AC6) · consumer-contract: apps/agentos/CARD-CONTRACT.md, fleetPresenceStateAdapter.mjs, fleetThrottleStateAdapter.mjs.
Design session (intake + ledger): 4660afcc-8b00-427a-8d39-4b1f3624a410.
Live latest-open sweep: checked latest 20 open issues at 2026-08-16T19:58Z; no equivalent slice ticket. A2A in-flight sweep (same window): no competing claim — the only #17225 claims are this seat's PR1 lane-claim and Ada's AC4 leaf claim.
Origin Session ID: 2455da9f-c848-4c52-b0f0-daea86aea9c3
Retrieval Hint: query_raw_memories("who_is_online honest surface axes envelope PRESENCE_STATES import") · falsification anchor: call who_is_online mid-turn and read your own row; then read the terse payload's axes.presence.capability.reason.
Context
First deliverable slice of #17225 (slice plan + Contract Ledger: issuecomment-5304989519 on the parent). The parent's premise was re-falsified at intake and again tonight:
who_is_onlineanswers fromadd_memory-recency alone, a container-side proxy — and reads as an availability verdict. The mid-turn inversion is live-reproducible (the calling seat readsidlemid-turn;turnPresenceisnullfleet-wide, so the beacon rescue cannot fire).This slice is the honest-surface unit: AC1, AC2, AC3, AC5 of the parent. It is FM-independent by the parent AC7's degrade-to-
unknownsemantics. AC4 (load axis) is a sibling slice claimed by @neo-opus-ada (issuecomment-5305005868); AC6–AC8 (fleet publish) ride @neo-fable-clio's fork answer. The parent stays open until all slices land.The Problem
A caller today cannot tell from the payload that the tool's signal is a recency proxy: the description said "live availability", the buckets read as availability verdicts, and axes the tool structurally cannot observe (throttle, lifecycle, liveness — host-originated per the parent's plane table) are absent rather than honestly
unknown. Ada's ruling on the parent thread: absence must readunknown, andunknownblocks the top ranking — a confident answer on the soft axis while silent on the hard one gets acted on.The Architectural Reality
whoIsOnline()atai/services/memory-core/WakeSubscriptionService.mjscomposes the presence projection;_projectAgentLivenessowns the per-row verdicts.{capability: {source, state, confidence, capturedAt, reason}},wired | degraded×observed | partial | none) is the contracted honesty shape —fleetThrottleStateAdapter.mjsships it with the "absence of truth is never rendered asnone" discipline.PRESENCE_STATES(ai/services/fleet/fleetPresenceStateAdapter.mjs:43) is the presence vocabulary's ONE exporting home by its own docstring; the MC tree currently re-declares the states as scattered literals.planeWhoIsOnlineReader.mjs(verboseagentspass-through — additive-safe);toolService.mjs:166destructures the five terse buckets (additive-safe).The Fix
whoIsOnlinereturns carry anaxessurface in the FM envelope grammar:presence=wired/observedwith the plane declaration (plane: 'container',signal: 'add_memory-recency', reason states "not an availability verdict");throttle/lifecycle/liveness=degraded/noneenvelopes until the fleet publishes. Verbose rows carry those axes asunknown(fresh object per row).PRESENCE_STATES— the tool's state vocabulary is imported, never re-declared.openapi.yamldescription + response schema declare the plane and theaxessurface.who_is_onlinedescribe ofWakeSubscriptionService.spec.mjs.Contract Ledger Matrix
who_is_onlinedescription (ai/mcp/server/memory-core/openapi.yaml)add_memory-recency proxy — never an availability verdictwhoIsOnline()return)axes: presence envelope (wired/observed, proxy declared) + compactunobservedmarker naming the host axes — terse-by-default per the#13557operator rulingaxes, bucket derivationdegraded/noneenvelopes (a declared superset of the FM grammar, addingplane/signal) + per-rowunknown; buckets derived from importedPRESENCE_STATESunknownnever poses as online/idleunknownaxes for both — the idle one can never rank as more availableDecision Record impact: none — no ADR conflict; no
AiConfigtouch (ADR-0019 not engaged).Acceptance Criteria
add_memory-recency, a container-side proxy — a caller cannot read the answer as an availability verdict (parent AC1).unknowncomposed axes — no served axis ranks the idle one higher (parent AC2).unobservedmarker — the#13557terse-by-default ruling bounds the default answer) and served asdegraded/noneenvelopes with per-rowunknownin verbose;unknownnever ranks top and never renders as fine (parent AC3, as shaped by the PR #17249 review).PRESENCE_STATES; a grep for a second literal state list inai/services/memory-core/finds nothing (parent AC5).Out of Scope
idlepresence state — the presence observation stays honestly what it is; the plane declaration, not a rename, is this slice's remedy.AiConfigchange (none needed; would trigger the ADR-0019 read first).Avoided Traps
idletounknownin the presence vocabulary. Falsified against parent AC2's letter: the idle-fresh-write peer would still readonlineand outrank the mid-turn peer. The honest surface separates the recency observation (kept, declared as proxy) from the axes the tool cannot serve (unknown).Related
Parent: #17225 · load-axis sibling slice: claimed by @neo-opus-ada on the parent thread · fleet-publish slice: @neo-fable-clio's fork (parent AC6) · consumer-contract:
apps/agentos/CARD-CONTRACT.md,fleetPresenceStateAdapter.mjs,fleetThrottleStateAdapter.mjs.Design session (intake + ledger): 4660afcc-8b00-427a-8d39-4b1f3624a410.
Live latest-open sweep: checked latest 20 open issues at 2026-08-16T19:58Z; no equivalent slice ticket. A2A in-flight sweep (same window): no competing claim — the only #17225 claims are this seat's PR1 lane-claim and Ada's AC4 leaf claim.
Origin Session ID: 2455da9f-c848-4c52-b0f0-daea86aea9c3
Retrieval Hint:
query_raw_memories("who_is_online honest surface axes envelope PRESENCE_STATES import")· falsification anchor: callwho_is_onlinemid-turn and read your own row; then read the terse payload'saxes.presence.capability.reason.