@consiliency/agent-board-schema 1.64.0 → 1.74.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/README.md +19 -0
  2. package/fixtures/already-applied.json +44 -4
  3. package/migrations/20261015000100_agent_board_session_provenance.sql +367 -0
  4. package/migrations/20261015000200_agent_board_request_preserve_removed.sql +87 -0
  5. package/migrations/20261015000300_agent_board_rls_correlation.sql +132 -0
  6. package/migrations/20261015000400_agent_board_resolution_authority.sql +146 -0
  7. package/migrations/20261026000100_agent_board_thread_association.sql +1287 -0
  8. package/migrations/20261101000100_agent_board_session_measured_mint.sql +145 -0
  9. package/migrations/20261104065658_agent_board_reply_delivery.sql +659 -0
  10. package/migrations/20261104170000_agent_board_tasking_replay_scope.sql +320 -0
  11. package/migrations/20261104180000_agent_board_delivery_writer_execute.sql +51 -0
  12. package/migrations/20261104190000_agent_board_message_replay_scope.sql +373 -0
  13. package/package.json +1 -1
  14. package/schema-manifest.json +93 -3
  15. package/src/deployment-drift-main.test.mjs +156 -0
  16. package/src/deployment-drift-script.test.mjs +14 -1
  17. package/src/policy-comment.test.mjs +17 -0
  18. package/src/tooling.test.mjs +12 -2
  19. package/tests/agent_board_661_reply_delivery.test.sql +185 -0
  20. package/tests/agent_board_667_boundary.test.sql +162 -0
  21. package/tests/agent_board_667_conversion_branches.test.sql +91 -0
  22. package/tests/agent_board_667_conversion_profile.test.sql +112 -0
  23. package/tests/agent_board_667_history_class.test.sql +785 -0
  24. package/tests/agent_board_667_native_cast_effect.test.sql +88 -0
  25. package/tests/agent_board_667_realtime_apply_behavior.test.sql +117 -0
  26. package/tests/agent_board_667_realtime_apply_controls.test.sql +143 -0
  27. package/tests/agent_board_667_realtime_apply_profile.test.sql +61 -0
  28. package/tests/agent_board_667_retention.test.sql +201 -0
  29. package/tests/agent_board_667_routing.test.sql +294 -0
  30. package/tests/agent_board_667_sender_effects.test.sql +100 -0
  31. package/tests/agent_board_667_sender_profile_controls.test.sql +29 -0
  32. package/tests/agent_board_667_storage_delimiter_behavior.test.sql +84 -0
  33. package/tests/agent_board_667_storage_delimiter_controls.test.sql +23 -0
  34. package/tests/agent_board_667_storage_delimiter_profile.test.sql +61 -0
  35. package/tests/agent_board_667_storage_search_behavior.test.sql +93 -0
  36. package/tests/agent_board_667_storage_search_controls.test.sql +22 -0
  37. package/tests/agent_board_667_storage_search_profile.test.sql +60 -0
  38. package/tests/agent_board_667_storage_timestamp_behavior.test.sql +58 -0
  39. package/tests/agent_board_667_storage_timestamp_controls.test.sql +22 -0
  40. package/tests/agent_board_667_storage_timestamp_profile.test.sql +54 -0
  41. package/tests/agent_board_667_writers.test.sql +281 -0
  42. package/tests/agent_board_717_message_replay_scope.test.sql +828 -0
  43. package/tests/agent_board_717_tasking_replay_scope.test.sql +661 -0
  44. package/tests/agent_board_addressing.test.sql +8 -5
  45. package/tests/agent_board_claim_subject_gate.test.sql +7 -3
  46. package/tests/agent_board_claimpolicy_race.test.sql +39 -11
  47. package/tests/agent_board_consent_gating.test.sql +4 -4
  48. package/tests/agent_board_delegate_role_class.test.sql +33 -15
  49. package/tests/agent_board_delivery_writer_execute.test.sql +371 -0
  50. package/tests/agent_board_fk_lock_edges.test.sql +3 -0
  51. package/tests/agent_board_gatenull_membstate.test.sql +7 -4
  52. package/tests/agent_board_hosted_delegates.test.sql +5 -2
  53. package/tests/agent_board_inbox_rpcs.test.sql +5 -3
  54. package/tests/agent_board_obsgate.test.sql +8 -4
  55. package/tests/agent_board_obsgate4.test.sql +2 -2
  56. package/tests/agent_board_outbox_wake_ordering.test.sql +25 -2
  57. package/tests/agent_board_own_post_not_delivered.test.sql +11 -9
  58. package/tests/agent_board_policy_correlation.test.sql +189 -0
  59. package/tests/agent_board_request_removed.test.sql +96 -0
  60. package/tests/agent_board_resolution_authority.test.sql +190 -0
  61. package/tests/agent_board_session_identity_behavior_classes.test.sql +2 -2
  62. package/tests/agent_board_session_identity_limits.test.sql +1 -1
  63. package/tests/agent_board_session_identity_measured_mint.test.sql +342 -0
  64. package/tests/agent_board_session_identity_predicate_isolation.test.sql +146 -0
  65. package/tests/agent_board_session_provenance.test.sql +106 -0
  66. package/tests/agent_board_sidserver_authority.test.sql +69 -0
  67. package/tests/agent_board_sidserver_catalog.test.sql +47 -0
  68. package/tests/agent_board_signed_write_gateway.test.sql +4 -2
  69. package/tests/agent_board_task_thread_lock_order.test.sql +67 -42
  70. package/tests/agent_board_v2_invariants.test.sql +5 -2
  71. package/tests/agent_board_write_enforcement_class.test.sql +3 -3
  72. package/tests/catalog/function_execute_privileges.json +43 -7
  73. package/tests/catalog/p_metadata_parameters.json +16 -0
  74. package/tests/fixtures/agent_board_667_apply_rls_guard.sql +195 -0
  75. package/tests/fixtures/agent_board_667_apply_rls_provenance.md +125 -0
  76. package/tests/fixtures/agent_board_667_apply_rls_reference.sql +1903 -0
  77. package/tests/fixtures/agent_board_667_conversion_guard.sql +162 -0
  78. package/tests/fixtures/agent_board_667_conversion_reference.md +23 -0
  79. package/tests/fixtures/agent_board_667_conversion_reference.sql +5325 -0
  80. package/tests/fixtures/agent_board_667_delimiter_guard.sql +92 -0
  81. package/tests/fixtures/agent_board_667_delimiter_provenance.md +116 -0
  82. package/tests/fixtures/agent_board_667_delimiter_reference.sql +10150 -0
  83. package/tests/fixtures/agent_board_667_search_guard.sql +92 -0
  84. package/tests/fixtures/agent_board_667_search_provenance.md +141 -0
  85. package/tests/fixtures/agent_board_667_search_reference.sql +4779 -0
  86. package/tests/fixtures/agent_board_667_sender_guard.sql +102 -0
  87. package/tests/fixtures/agent_board_667_sender_reference.md +20 -0
  88. package/tests/fixtures/agent_board_667_sender_reference.sql +875 -0
  89. package/tests/fixtures/agent_board_667_timestamp_graph.sql +84 -0
  90. package/tests/fixtures/agent_board_667_timestamp_guard.sql +94 -0
  91. package/tests/fixtures/agent_board_667_timestamp_provenance.md +99 -0
  92. package/tests/fixtures/agent_board_667_timestamp_reference.sql +2938 -0
  93. package/tests/isolation/expected/association_artifact_anchor_order.out +108 -0
  94. package/tests/isolation/expected/association_board_vs_board.out +71 -0
  95. package/tests/isolation/expected/association_post_wait_authority.out +77 -0
  96. package/tests/isolation/expected/association_strong_history_writers.out +203 -0
  97. package/tests/isolation/expected/association_strong_isolation.out +185 -0
  98. package/tests/isolation/expected/association_vs_artifact_claim_escalation.out +199 -0
  99. package/tests/isolation/expected/association_vs_heartbeat.out +78 -0
  100. package/tests/isolation/expected/association_vs_multi_anchor_artifact.out +67 -0
  101. package/tests/isolation/expected/association_vs_private_message.out +67 -0
  102. package/tests/isolation/expected/association_vs_task_and_conflict.out +133 -0
  103. package/tests/isolation/expected/association_vs_taskful_cross_thread.out +133 -0
  104. package/tests/isolation/expected/consent_approval_lock.out +1 -1
  105. package/tests/isolation/expected/message_replay_scope.out +209 -0
  106. package/tests/isolation/expected/tasking_replay_scope.out +125 -0
  107. package/tests/isolation/specs/association_artifact_anchor_order.spec +46 -0
  108. package/tests/isolation/specs/association_board_vs_board.spec +37 -0
  109. package/tests/isolation/specs/association_post_wait_authority.spec +48 -0
  110. package/tests/isolation/specs/association_strong_history_writers.spec +61 -0
  111. package/tests/isolation/specs/association_strong_isolation.spec +50 -0
  112. package/tests/isolation/specs/association_vs_artifact_claim_escalation.spec +41 -0
  113. package/tests/isolation/specs/association_vs_heartbeat.spec +47 -0
  114. package/tests/isolation/specs/association_vs_multi_anchor_artifact.spec +38 -0
  115. package/tests/isolation/specs/association_vs_private_message.spec +33 -0
  116. package/tests/isolation/specs/association_vs_task_and_conflict.spec +38 -0
  117. package/tests/isolation/specs/association_vs_taskful_cross_thread.spec +42 -0
  118. package/tests/isolation/specs/consent_approval_lock.spec +13 -7
  119. package/tests/isolation/specs/message_replay_scope.spec +77 -0
  120. package/tests/isolation/specs/tasking_replay_scope.spec +72 -0
  121. package/tests/mutations/717-f1/M0_prefix_main_acl_and_comments.sql +11 -0
  122. package/tests/mutations/717-f1/M10_wrapper_stops_delegating.sql +7 -0
  123. package/tests/mutations/717-f1/M11_transitive_recipient_content.sql +8 -0
  124. package/tests/mutations/717-f1/M12_transitive_recipient_visibility.sql +8 -0
  125. package/tests/mutations/717-f1/M13_transitive_worker_content.sql +15 -0
  126. package/tests/mutations/717-f1/M1a_regrant_upsert_delivery_recipient.sql +1 -0
  127. package/tests/mutations/717-f1/M1b_regrant_upsert_inbox_item.sql +1 -0
  128. package/tests/mutations/717-f1/M1c_regrant_queue_inbox_callbacks.sql +1 -0
  129. package/tests/mutations/717-f1/M1d_regrant_queue_board_post_callbacks.sql +1 -0
  130. package/tests/mutations/717-f1/M1e_regrant_next_thread_message_sequence.sql +1 -0
  131. package/tests/mutations/717-f1/M2_blanket_schema_grant.sql +1 -0
  132. package/tests/mutations/717-f1/M3_new_overload_of_sink.sql +10 -0
  133. package/tests/mutations/717-f1/M4_new_route_calling_sink.sql +7 -0
  134. package/tests/mutations/717-f1/M5_actor_trusts_supplied_id.sql +5 -0
  135. package/tests/mutations/717-f1/M6_signed_route_granted_to_authenticated.sql +1 -0
  136. package/tests/mutations/717-f1/M7_worker_granted_to_authenticated.sql +1 -0
  137. package/tests/mutations/717-f1/M8_recipient_state_rewrites_visibility.sql +5 -0
  138. package/tests/mutations/717-f1/M9_public_route_revoked_from_service_role.sql +1 -0
  139. package/tests/mutations/717-f1/outbox_wake_ordering/W1_regrant_queue_inbox_callbacks.sql +1 -0
  140. package/tests/mutations/717-f1/outbox_wake_ordering/W2_revoke_worker_from_service_role.sql +1 -0
  141. package/tests/mutations/717-f1/outbox_wake_ordering/W3_invoker_caller_of_sink.sql +1 -0
  142. package/tests/mutations/717-f1/outbox_wake_ordering/W4_public_regrant_board_post_sink.sql +1 -0
  143. package/tests/mutations/717-f1/run.sh +17 -0
  144. package/tests/mutations/717-f2b/C1_new_delivery_route.sql +4 -0
  145. package/tests/mutations/717-f2b/C2_new_replay_lookup.sql +3 -0
  146. package/tests/mutations/717-f2b/C3_internal_regranted.sql +2 -0
  147. package/tests/mutations/717-f2b/C4_wrapper_writes_delivery.sql +9 -0
  148. package/tests/mutations/717-f2b/C5_class_member_dynamic_sql.sql +9 -0
  149. package/tests/mutations/717-f2b/C6_drop_board_scope_constraint.sql +2 -0
  150. package/tests/mutations/717-f2b/C7_state_private_helper_content.sql +14 -0
  151. package/tests/mutations/717-f2b/L1_dm_lock_split_by_recipient.sql +8 -0
  152. package/tests/mutations/717-f2b/L2_dm_lock_removed.sql +12 -0
  153. package/tests/mutations/717-f2b/L3_mc_lock_split_by_recipients.sql +8 -0
  154. package/tests/mutations/717-f2b/L4_mc_lock_removed.sql +12 -0
  155. package/tests/mutations/717-f2b/M0_prefix_definitions.sql +17 -0
  156. package/tests/mutations/717-f2b/M10_mc_lookup_any_author.sql +15 -0
  157. package/tests/mutations/717-f2b/M11_dm_swallow_refusal.sql +8 -0
  158. package/tests/mutations/717-f2b/M12_mc_swallow_refusal.sql +8 -0
  159. package/tests/mutations/717-f2b/M13_signed_dm_swallows_refusal.sql +32 -0
  160. package/tests/mutations/717-f2b/M14_signed_mc_swallows_refusal.sql +20 -0
  161. package/tests/mutations/717-f2b/M15_mc_any_source.sql +7 -0
  162. package/tests/mutations/717-f2b/M1_dm_drop_recipient_proof.sql +16 -0
  163. package/tests/mutations/717-f2b/M2_mc_drop_recipient_proof.sql +16 -0
  164. package/tests/mutations/717-f2b/M3_dm_metadata_as_proof.sql +12 -0
  165. package/tests/mutations/717-f2b/M4_mc_metadata_as_proof.sql +16 -0
  166. package/tests/mutations/717-f2b/M5_dm_any_mode.sql +11 -0
  167. package/tests/mutations/717-f2b/M6_dm_board_delivery_counts.sql +11 -0
  168. package/tests/mutations/717-f2b/M7_mc_any_mode.sql +11 -0
  169. package/tests/mutations/717-f2b/M8_dm_thread_stamp_as_proof.sql +12 -0
  170. package/tests/mutations/717-f2b/M9_dm_lookup_any_author.sql +15 -0
  171. package/tests/mutations/717-f2b/run.sh +82 -0
@@ -0,0 +1,145 @@
1
+ -- SIDSERVER blocker fix (Consiliency/message-board#653 panel BLOCKs 1 and 2; owner decision
2
+ -- 2026-11-01 "Fix + new replay round", shape "Measured overload" -- a separate strict function
3
+ -- the relay calls exclusively; named distinctly by exec decision so that every frozen
4
+ -- one-row-per-name contract (SIDCLIENT) keeps holding).
5
+ --
6
+ -- The seven-argument mint_fleet_agent_session is the SIDSCHEMA "trusted caller" form: it gates
7
+ -- on the STORED current/approved digests and lets a lapsed Claude identity bind any unseen
8
+ -- session id. Frozen SIDSCHEMA tests pin both behaviours, so that form is left byte-identical.
9
+ -- The relay must instead call this measured function, which receives the PoP-verified binding's
10
+ -- measured fingerprint, continuity and predecessor and:
11
+ --
12
+ -- 1. records the measured reading after the challenge is validated and consumed, and on a
13
+ -- changed risky digest durably freezes the identity and RETURNS a refusal row (raising
14
+ -- would roll the freeze back; the refused session row is revoked in the same transaction);
15
+ -- 2. binds a NEW alias on a lapsed reclaim only for continuity preserved_uuids whose
16
+ -- predecessor is this identity; any other unfamiliar alias refuses identity_continuity_refused;
17
+ -- 3. stores the CLAIMANT'S presented holder secret when it claims or reclaims (generating one
18
+ -- only when none is presented), so a claim whose response is lost is recovered in place: the
19
+ -- retry re-presents that secret and refreshes the claimant's own live lease (#653 re-panel
20
+ -- BLOCK B). On a live lease the identical bound session id refuses duplicate_live_session
21
+ -- whatever secret it presents, then a wrong secret refuses identity_lease_not_held, so every
22
+ -- OTHER claimant is still refused while the lease is live.
23
+ --
24
+ -- The residual -- a service_role caller can still choose the seven-argument trusted form -- is
25
+ -- pre-existing and recorded on Consiliency/message-board#722.
26
+ create function agent_board.mint_fleet_agent_session_measured(
27
+ p_challenge_id uuid, p_nonce text, p_signing_key_id uuid, p_agent_id uuid,
28
+ p_max_ttl_seconds integer, p_holder_secret text, p_session_id text,
29
+ p_fingerprint jsonb, p_continuity text, p_predecessor_agent_id uuid
30
+ ) returns table(session_id text, expires_at timestamptz, identity_lease_epoch bigint, holder_secret text, refusal text)
31
+ language plpgsql security definer set search_path = agent_board, public as $$
32
+ declare v_identity agent_board.session_identities%rowtype; v_session record; v_new_secret text; v_alias uuid;
33
+ v_ancestor_expires timestamptz; v_grant_expires timestamptz; v_state text;
34
+ v_risky text := nullif(p_fingerprint ->> 'risky_digest', '');
35
+ v_recorded jsonb;
36
+ begin
37
+ if not agent_board._is_service_role() then raise exception 'session mint is service_role-only' using errcode = '42501'; end if;
38
+ if p_fingerprint is null or jsonb_typeof(p_fingerprint) <> 'object'
39
+ or coalesce(p_fingerprint ->> 'resolution', '') not in ('resolved', 'unresolved')
40
+ or jsonb_typeof(coalesce(p_fingerprint -> 'recorded', '{}'::jsonb)) <> 'object' then
41
+ raise exception 'invalid identity fingerprint reading' using errcode = '22023';
42
+ end if;
43
+ v_recorded := coalesce(p_fingerprint -> 'recorded', '{}'::jsonb) || jsonb_build_object('resolution', p_fingerprint ->> 'resolution');
44
+ if p_holder_secret is not null and p_holder_secret !~ '^[0-9a-f]{64}$' then
45
+ raise exception 'invalid holder secret' using errcode = '22023';
46
+ end if;
47
+ if p_session_id is null or length(p_session_id) = 0
48
+ or p_continuity is null or p_continuity not in ('same_alias', 'preserved_uuids', 'new', 'fork', 'ambiguous_fork') then
49
+ raise exception 'invalid measured session binding' using errcode = '22023';
50
+ end if;
51
+ -- The predecessor is the measured continuity evidence: preserved UUIDs name this identity,
52
+ -- every other class names none at a token mint.
53
+ if p_continuity = 'preserved_uuids' and p_predecessor_agent_id is distinct from p_agent_id
54
+ or p_continuity <> 'preserved_uuids' and p_predecessor_agent_id is not null then
55
+ raise exception 'identity_continuity_refused' using errcode = '42501';
56
+ end if;
57
+ -- Same challenge-before-principal and identity/alias-before-key order as the trusted form.
58
+ perform 1 from agent_board.agent_signing_key_challenges where id = p_challenge_id for update;
59
+ perform 1 from agent_board.agents where id = (
60
+ select root_agent_id from agent_board.session_identities where agent_id = p_agent_id
61
+ ) for no key update;
62
+ select * into v_identity from agent_board.session_identities where agent_id = p_agent_id for update;
63
+ perform 1 from agent_board.session_id_aliases where identity_agent_id = p_agent_id order by id for update;
64
+ if v_identity.tombstoned_at is not null then raise exception 'identity_tombstoned' using errcode = '42501'; end if;
65
+ if v_identity.agent_id is null or v_identity.identity_kind <> 'session' then
66
+ raise exception 'measured mint requires a session identity' using errcode = '22023';
67
+ end if;
68
+ if not exists (select 1 from agent_board.agent_signing_keys k where k.id = p_signing_key_id
69
+ and k.agent_id = p_agent_id and k.proof_state = 'proven') then
70
+ raise exception 'key_unproven: session key requires proof' using errcode = '42501';
71
+ end if;
72
+ -- Validates and consumes the challenge (and the key/principal/grant gates) BEFORE the reading
73
+ -- is stored, so only a reading bound to a proven, single-use challenge can be recorded.
74
+ select * into v_session from agent_board._mint_fleet_agent_session_legacy(p_challenge_id, p_nonce, p_signing_key_id, p_agent_id, p_max_ttl_seconds);
75
+ v_state := case
76
+ when p_fingerprint ->> 'resolution' is distinct from 'resolved' or v_risky is null
77
+ or v_identity.approved_risky_digest is null then 'frozen'
78
+ when v_risky is distinct from v_identity.approved_risky_digest or v_identity.resolution_state = 'frozen' then 'frozen'
79
+ else 'active' end;
80
+ update agent_board.session_identities
81
+ set current_risky_digest = v_risky, recorded_fingerprint = v_recorded, resolution_state = v_state, updated_at = now()
82
+ where agent_id = p_agent_id;
83
+ if v_state = 'frozen' or exists (
84
+ with recursive ancestry(id, parent_agent_id) as (
85
+ select id, parent_agent_id from agent_board.agents where id = p_agent_id
86
+ union all
87
+ select a.id, a.parent_agent_id from agent_board.agents a join ancestry c on a.id = c.parent_agent_id
88
+ )
89
+ select 1 from ancestry a join agent_board.session_identities si on si.agent_id = a.id
90
+ where si.resolution_state = 'frozen'
91
+ ) then
92
+ -- Return, never raise: the recorded reading and freeze must commit with this refusal.
93
+ update agent_board.nonfleet_sessions s set revoked_at = now() where s.session_id = v_session.session_id;
94
+ return query select null::text, null::timestamptz, null::bigint, null::text, 'identity_fingerprint_unapproved'::text; return;
95
+ end if;
96
+ v_ancestor_expires := agent_board._session_identity_ancestor_ceiling(v_identity.parent_agent_id);
97
+ if not agent_board._session_identity_lease_live(p_agent_id) then
98
+ perform agent_board._session_identity_check_limits(v_identity.root_agent_id, v_identity.parent_agent_id, p_agent_id);
99
+ end if;
100
+ select g.grant_expires_at into v_grant_expires from agent_board.delegation_grants g where g.child_agent_id = p_agent_id;
101
+ v_session.expires_at := least(v_session.expires_at, v_ancestor_expires, v_grant_expires);
102
+ update agent_board.nonfleet_sessions s set expires_at = v_session.expires_at where s.session_id = v_session.session_id;
103
+ if v_identity.holder_secret_hash is not null and v_identity.last_heartbeat > now() - interval '180 seconds' then
104
+ if p_holder_secret is not null and extensions.digest(p_holder_secret, 'sha256') = v_identity.holder_secret_hash then
105
+ return query select v_session.session_id, v_session.expires_at, v_identity.credential_epoch, null::text, null::text; return;
106
+ end if;
107
+ if exists (select 1 from agent_board.session_id_aliases a where a.id = v_identity.lease_alias_id and a.session_id = p_session_id) then
108
+ raise exception 'duplicate_live_session' using errcode = '42501';
109
+ end if;
110
+ if p_holder_secret is not null then raise exception 'identity_lease_not_held' using errcode = '42501'; end if;
111
+ raise exception 'identity_lease_live' using errcode = '42501';
112
+ end if;
113
+ select a.id into v_alias from agent_board.session_id_aliases a
114
+ where a.identity_agent_id = p_agent_id and a.session_id = p_session_id;
115
+ if v_identity.holder_secret_hash is null then
116
+ if v_alias is null or v_alias is distinct from v_identity.lease_alias_id then raise exception 'identity_continuity_refused' using errcode = '42501'; end if;
117
+ elsif v_alias is null then
118
+ -- A lapsed reclaim may bind an unseen session id only as measured preserved-UUID continuity
119
+ -- (Claude resume; the predecessor = this identity rule is enforced once, above). Same-alias,
120
+ -- new and fork claims never mint a new alias.
121
+ if v_identity.harness <> 'claude' or p_continuity <> 'preserved_uuids' then
122
+ raise exception 'identity_continuity_refused' using errcode = '42501';
123
+ end if;
124
+ if exists (select 1 from agent_board.session_id_aliases a where a.root_agent_id = v_identity.root_agent_id
125
+ and a.harness = v_identity.harness and a.session_id = p_session_id) then
126
+ raise exception 'identity_continuity_refused' using errcode = '42501';
127
+ end if;
128
+ insert into agent_board.session_id_aliases(identity_agent_id, root_agent_id, harness, session_id)
129
+ values (p_agent_id, v_identity.root_agent_id, v_identity.harness, p_session_id) returning id into v_alias;
130
+ end if;
131
+ -- The claimant's own presented secret becomes the lease secret (the relay admits only 64 lower
132
+ -- hex); a claimant presenting none gets a generated one, as in the trusted form.
133
+ v_new_secret := coalesce(p_holder_secret, encode(extensions.gen_random_bytes(32), 'hex'));
134
+ update agent_board.session_identities
135
+ set holder_secret_hash = extensions.digest(v_new_secret, 'sha256'), lease_alias_id = v_alias,
136
+ credential_epoch = case when holder_secret_hash is null then credential_epoch else credential_epoch + 1 end,
137
+ last_heartbeat = now(), updated_at = now()
138
+ where agent_id = p_agent_id
139
+ returning credential_epoch into identity_lease_epoch;
140
+ return query select v_session.session_id, v_session.expires_at, identity_lease_epoch, v_new_secret, null::text;
141
+ end;
142
+ $$;
143
+ revoke all on function agent_board.mint_fleet_agent_session_measured(uuid, text, uuid, uuid, integer, text, text, jsonb, text, uuid) from public, anon, authenticated, service_role;
144
+ grant execute on function agent_board.mint_fleet_agent_session_measured(uuid, text, uuid, uuid, integer, text, text, jsonb, text, uuid) to service_role;
145
+ comment on function agent_board.mint_fleet_agent_session_measured(uuid, text, uuid, uuid, integer, text, text, jsonb, text, uuid) is 'Service-role MEASURED session-identity PoP mint, the only session-identity mint the /session relay calls. It enforces every gate of the seven-argument mint_fleet_agent_session trusted form (pgTAP SIDSERVER-MM-PARITY-*) plus measured-reading and continuity gates. Fingerprint, continuity and predecessor come from the PoP-verified session binding. After the challenge is validated and consumed it records the measured reading; a changed or unresolved risky digest (or any frozen ancestor) durably freezes and RETURNS refusal identity_fingerprint_unapproved instead of raising, so the freeze commits and the refused session row is revoked. A lapsed reclaim binds an unseen alias only for preserved_uuids continuity naming this identity; otherwise identity_continuity_refused. A claim or reclaim stores the claimant-presented holder secret (generated only when none is presented), so a claim whose response was lost refreshes on retry; on a live lease the bound session id refuses duplicate_live_session before a wrong secret refuses identity_lease_not_held. Epoch rotation matches the seven-argument trusted form, which remains for SIDSCHEMA callers (residual: Consiliency/message-board#722).';