You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(ri-exchange): exchange records never carry a creator, so four-eyes is a no-op and audit attribution is lost #518
internal/server/handler_ri_exchange.go:329exchangeToConfigRecord copies every field except CreatedByUserID, so every production exchange row has a NULL creator.
internal/api/handler_ri_exchange.go:2220-2222 token approval calls TransitionRIExchangeStatus(..., nil), so transitioned_by is NULL. StampRIExchangeApprovedBy is only called on the session path (~2281), so approved_by is never set for token approvals even when a session resolves.
Wrong comments: internal/api/handler_ri_exchange.go:2220 ("no session user"), internal/config/types.go:963-965 ("populated for dashboard-initiated exchanges" although no such writer exists).
Failure scenario
A user creates an exchange, then approves it themselves. Four-eyes does not fire because the stored creator is NULL. Audit rows show no actor for token approvals.
Exchange rows created by a session user store created_by_user_id, four-eyes rejects a self-approval in a test using the real adapter, and token approvals record the resolved actor when one exists.
Status after PR #602 (Refs, in review): leg (c) is met: token-path RI-exchange approvals now record the resolved actor (transitioned_by) and stamp approved_by through a helper shared with the session path (new test fails on main). Still open, needing an owner decision: (a) copying a creator onto exchange rows: cloud-commitments-go pkg/exchange.ExchangeRecord has no creator field and every writer of ri_exchange_history is the scheduler or the ladder (no session-created exchange path exists), so first decide which creator scheduler exchanges should carry (a system user, the config owner, or NULL by design) and whether the exchange library needs a creator field; (b) four-eyes on RI exchanges with a real adapter: requireDifferentRIExchangeApprover (handler_ri_exchange.go ~2423) returns nil when CreatedByUserID is nil, and #233 (NULL-creator policy) is written for purchase executions only, so an RI-exchange counterpart may be needed.
Activity
cristim commentedon Oct 6, 2026
Status after PR #602 (Refs, in review): leg (c) is met: token-path RI-exchange approvals now record the resolved actor (transitioned_by) and stamp approved_by through a helper shared with the session path (new test fails on main). Still open, needing an owner decision: (a) copying a creator onto exchange rows: cloud-commitments-go pkg/exchange.ExchangeRecord has no creator field and every writer of ri_exchange_history is the scheduler or the ladder (no session-created exchange path exists), so first decide which creator scheduler exchanges should carry (a system user, the config owner, or NULL by design) and whether the exchange library needs a creator field; (b) four-eyes on RI exchanges with a real adapter: requireDifferentRIExchangeApprover (handler_ri_exchange.go ~2423) returns nil when CreatedByUserID is nil, and #233 (NULL-creator policy) is written for purchase executions only, so an RI-exchange counterpart may be needed.
test(ri-exchange): skip approver stamp on the token path when executi…
IAmJSD commentedon Oct 16, 2026
Claiming: working on this
fix(ri-exchange): require an identified approver for creator-less exc…