Skip to content

Commit d9a7d9e

Browse files
authored
Merge pull request #467 from AdaWorldAPI/feat/membrane-commit-event
feat(callcenter): LanceMembrane::commit_event — action-commit sole-writer sibling (gate 1)
2 parents e948e91 + 6e6f57f commit d9a7d9e

1 file changed

Lines changed: 44 additions & 0 deletions

File tree

crates/lance-graph-callcenter/src/lance_membrane.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,35 @@ impl LanceMembrane {
292292
self.version.load(Ordering::Acquire)
293293
}
294294

295+
/// Append an externally-built commit row — the **action-commit** sole-writer
296+
/// sibling of [`ExternalMembrane::project`].
297+
///
298+
/// Where `project()` projects a cognitive cycle (`ShaderBus` + `MetaWord`),
299+
/// `commit_event` takes a caller-built [`CognitiveEventRow`] directly. It is
300+
/// the seam the Rubicon `CommitHook` lowers onto: on entering the `Committed`
301+
/// lifecycle state, the binding builds the row from the OGAR
302+
/// `ActionInvocation` and calls this. (See `ractor_actors::state_machine`
303+
/// `CommitHook::on_commit` + `CROSS_SESSION_COORDINATION.md` grill #10.)
304+
///
305+
/// Unlike `project()`, the action commit is the authoritative **audit** event
306+
/// (the Rubicon crossing / rubberstamp), so it ALWAYS ticks the version and
307+
/// fans out — the server filter / gate throttle cognitive-cycle fan-out, not
308+
/// an explicit committed action.
309+
///
310+
/// Returns the new monotonic Lance version (the same counter
311+
/// [`version`](Self::version) reports; Phase D wires it to the Lance dataset
312+
/// version). Kept on the concrete `LanceMembrane`, NOT on the zero-dep
313+
/// `ExternalMembrane` trait, so the contract crate stays zero-dep and the
314+
/// action-commit path never forces the cognitive-cycle `ShaderBus` shape.
315+
pub fn commit_event(&self, row: CognitiveEventRow) -> u64 {
316+
let version = self.version.fetch_add(1, Ordering::AcqRel) + 1;
317+
#[cfg(feature = "realtime")]
318+
self.watcher.bump(row);
319+
#[cfg(not(feature = "realtime"))]
320+
let _ = row; // without realtime there are no subscribers to fan out to
321+
version
322+
}
323+
295324
/// Set the faculty context for the current cycle.
296325
///
297326
/// Called by the orchestration layer (not by `ingest`) when
@@ -519,6 +548,21 @@ mod tests {
519548
);
520549
}
521550

551+
#[test]
552+
fn commit_event_ticks_version_and_returns_new() {
553+
// The action-commit sole-writer sibling: each call ticks the monotonic
554+
// Lance version and returns the new value (the Rubicon crossing's audit
555+
// version). Mirrors the OGAR `CommitHook::on_commit` lowering.
556+
let m = LanceMembrane::new();
557+
assert_eq!(m.version(), 0);
558+
let v1 = m.commit_event(crate::external_intent::CognitiveEventRow::default());
559+
assert_eq!(v1, 1);
560+
assert_eq!(m.version(), 1);
561+
let v2 = m.commit_event(crate::external_intent::CognitiveEventRow::default());
562+
assert_eq!(v2, 2);
563+
assert_eq!(m.version(), 2);
564+
}
565+
522566
#[test]
523567
fn project_emits_scalar_row() {
524568
let m = LanceMembrane::new();

0 commit comments

Comments
 (0)