feat: Rust state machine for investigation workflow (fn-17) - #75

Draft
bordumb wants to merge 18 commits into
mainfrom
fn-17
Draft

feat: Rust state machine for investigation workflow (fn-17)#75
bordumb wants to merge 18 commits into
mainfrom
fn-17

Conversation

@bordumb

Copy link
Copy Markdown
Owner

Summary

Implements a Rust-based investigation state machine with Python bindings, replacing Temporal workflow local variables with a deterministic, versioned state machine.

Key changes:

  • Rust core (core/): Event-sourced state machine with 8 phases, versioned JSON protocol (v1)
  • PyO3 bindings (core/bindings/python/): Panic-free FFI with custom exceptions
  • Python package (python-packages/investigator/): Runtime, security, envelope, and Temporal integration modules
  • Tests: 43 Rust tests + 74 Python integration tests + 7 E2E workflow tests

Architecture:

  • State machine runs inside Temporal activities (not workflow code) for side-effect isolation
  • brain_step activity: pure computation, no side effects
  • Signals/queries for HITL, continue_as_new at step threshold
  • Deny-by-default security with SQL pattern validation

Epic tasks completed: 16/16

Test plan

  • Rust tests: cd core && cargo test (43 tests)
  • Python integration tests: pytest python-packages/investigator/tests/ (74 tests)
  • E2E workflow tests: skippable when Temporal unavailable
  • Manual: just rust-dev then just test

🤖 Generated with Claude Code

bordumband others added 15 commits January 19, 2026 01:50
- Add core/ Rust workspace with dataing_investigator crate
- Add PyO3 bindings crate with maturin configuration
- Set PROTOCOL_VERSION=1 for snapshot versioning
- Add clippy deny rules for panic-free code
- Include .flow/ epic and task tracking for fn-17
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Scope, CallKind, and CallMeta types to dataing_investigator crate:
- Scope: security context with user/tenant IDs and permissions
- CallKind: enum for LLM vs Tool calls
- CallMeta: metadata for pending external calls
Uses BTreeMap for deterministic serialization ordering and
serde(default) for forward compatibility.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add tagged enum types for state machine communication:
- Event: Start, CallResult, UserResponse, Cancel
- Intent: Idle, Call, RequestUser, Finish, Error
Uses serde tagged enum format for JSON wire protocol.
All variants tested with serialization roundtrip tests.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add state module with:
- Phase enum: Init, GatheringContext, GeneratingHypotheses,
EvaluatingHypotheses, AwaitingUser, Synthesizing, Finished, Failed
- State struct: versioned snapshot with sequence/step counters
- generate_id(): unique ID generation with prefix
- BTreeMap for ordered evidence/call storage
Uses serde(default) on optional fields for forward compatibility.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement core state machine in machine.rs:
- Investigator::new(), restore(), snapshot() for lifecycle
- ingest() processes events and returns intents
- apply() handles Start, CallResult, UserResponse, Cancel events
- decide() emits appropriate Intent for each Phase
Key behaviors:
- Strict call_id validation: unexpected IDs trigger Failed phase
- Logical clock (step) incremented on each event
- Call metadata recorded in call_index for debugging
- Full workflow from Init -> GatheringContext -> GeneratingHypotheses
-> EvaluatingHypotheses -> Synthesizing -> Finished
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add PyO3 bindings exposing the Rust state machine to Python:
- Investigator class with new(), restore(), snapshot(), ingest()
- current_phase() and current_step() helper methods
- JSON-based serialization for events and intents
- protocol_version() function
Maturin build verified with `maturin develop --uv`.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ions
Add complete panic-safe Python bindings:
- Custom exceptions: StateError, SerializationError, InvalidTransitionError
- catch_unwind at FFI boundary for panic safety
- Full docstrings for all methods
- is_terminal() helper method
Python API:
- Investigator(): new(), restore(), snapshot(), ingest()
- current_phase(), current_step(), is_terminal()
- Exception hierarchy for error handling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Rust build commands to Justfile:
- rust-check: verify Rust toolchain
- rust-build: cargo build --release
- rust-dev: maturin develop --uv (install to venv)
- rust-test: cargo test
- rust-lint: cargo clippy
- rust-clean: clean target/
Update setup workflow:
- `just setup` now runs `just rust-dev` after uv sync
- `just clean` includes rust-clean
Note: dataing-investigator requires maturin build, cannot be a uv source.
Use `just rust-dev` after `uv sync` to install bindings.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create python-packages/investigator/ wrapping Rust bindings:
- pyproject.toml with hatchling build
- __init__.py re-exporting Investigator, exceptions, protocol_version
- Empty module files: envelope.py, security.py, runtime.py
Added to uv workspace and project dependencies.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Envelope module (fn-17.11):
- Envelope TypedDict for tracing context
- wrap/unwrap for JSON serialization
- create_trace() for new trace IDs
- create_child_envelope() for linked events
Security module (fn-17.12):
- SecurityViolation exception
- validate_tool_call() with deny-by-default
- Tool allowlist validation
- Table permission checks
- Forbidden SQL pattern detection (DROP, DELETE, etc.)
- create_scope() helper
Both modules exported from investigator package.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add runtime.py with:
- run_local() async function for executing investigations
- LocalInvestigator class for fine-grained control
- Security validation before every tool call
- Error handling for all intent types
- Snapshot/restore support
- Max steps limit to prevent infinite loops
Provides local testing without Temporal dependency.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- InvestigatorWorkflow uses Rust Investigator via brain_step activity
- Pure computation in activity, side effects in workflow
- Signal dedup via seen_signal_ids set
- continue_as_new at step threshold (100)
- HITL via user_response signal and get_status query
- Conditional temporal exports (requires temporalio optional)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- test_investigator.py: basics, events, serialization, errors, full cycle
- test_envelope.py: wrap/unwrap, trace IDs, child envelopes
- test_security.py: tool validation, forbidden SQL patterns, scopes
- test_runtime.py: LocalInvestigator and run_local function
- Added pytest and pytest-asyncio as dev dependencies
- 74 tests total, all passing
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Full investigation lifecycle test
- Query status test
- Cancel signal test
- Deterministic replay test
- Brain step activity unit tests
- Signal deduplication test
- Tests skip if Temporal not available (SKIP_TEMPORAL_TESTS=1)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@vercel

vercelBot commented Jan 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentReviewUpdated (UTC)
dataingReadyReadyPreview, CommentJan 19, 2026 8:29pm
dataing-appReadyReadyPreview, CommentJan 19, 2026 8:29pm
dataing-docsReadyReadyPreview, CommentJan 19, 2026 8:29pm

Sign up for freeto 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.

1 participant

@bordumb
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat: Rust state machine for investigation workflow (fn-17) - #75

Draft
bordumb wants to merge 18 commits into
mainfrom
fn-17
Draft

feat: Rust state machine for investigation workflow (fn-17)#75
bordumb wants to merge 18 commits into
mainfrom
fn-17

Conversation

@bordumb

Copy link
Copy Markdown
Owner

Summary

Implements a Rust-based investigation state machine with Python bindings, replacing Temporal workflow local variables with a deterministic, versioned state machine.

Key changes:

  • Rust core (core/): Event-sourced state machine with 8 phases, versioned JSON protocol (v1)
  • PyO3 bindings (core/bindings/python/): Panic-free FFI with custom exceptions
  • Python package (python-packages/investigator/): Runtime, security, envelope, and Temporal integration modules
  • Tests: 43 Rust tests + 74 Python integration tests + 7 E2E workflow tests

Architecture:

  • State machine runs inside Temporal activities (not workflow code) for side-effect isolation
  • brain_step activity: pure computation, no side effects
  • Signals/queries for HITL, continue_as_new at step threshold
  • Deny-by-default security with SQL pattern validation

Epic tasks completed: 16/16

Test plan

  • Rust tests: cd core && cargo test (43 tests)
  • Python integration tests: pytest python-packages/investigator/tests/ (74 tests)
  • E2E workflow tests: skippable when Temporal unavailable
  • Manual: just rust-dev then just test

🤖 Generated with Claude Code

bordumband others added 15 commits January 19, 2026 01:50
- Add core/ Rust workspace with dataing_investigator crate
- Add PyO3 bindings crate with maturin configuration
- Set PROTOCOL_VERSION=1 for snapshot versioning
- Add clippy deny rules for panic-free code
- Include .flow/ epic and task tracking for fn-17
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Scope, CallKind, and CallMeta types to dataing_investigator crate:
- Scope: security context with user/tenant IDs and permissions
- CallKind: enum for LLM vs Tool calls
- CallMeta: metadata for pending external calls
Uses BTreeMap for deterministic serialization ordering and
serde(default) for forward compatibility.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add tagged enum types for state machine communication:
- Event: Start, CallResult, UserResponse, Cancel
- Intent: Idle, Call, RequestUser, Finish, Error
Uses serde tagged enum format for JSON wire protocol.
All variants tested with serialization roundtrip tests.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add state module with:
- Phase enum: Init, GatheringContext, GeneratingHypotheses,
EvaluatingHypotheses, AwaitingUser, Synthesizing, Finished, Failed
- State struct: versioned snapshot with sequence/step counters
- generate_id(): unique ID generation with prefix
- BTreeMap for ordered evidence/call storage
Uses serde(default) on optional fields for forward compatibility.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement core state machine in machine.rs:
- Investigator::new(), restore(), snapshot() for lifecycle
- ingest() processes events and returns intents
- apply() handles Start, CallResult, UserResponse, Cancel events
- decide() emits appropriate Intent for each Phase
Key behaviors:
- Strict call_id validation: unexpected IDs trigger Failed phase
- Logical clock (step) incremented on each event
- Call metadata recorded in call_index for debugging
- Full workflow from Init -> GatheringContext -> GeneratingHypotheses
-> EvaluatingHypotheses -> Synthesizing -> Finished
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add PyO3 bindings exposing the Rust state machine to Python:
- Investigator class with new(), restore(), snapshot(), ingest()
- current_phase() and current_step() helper methods
- JSON-based serialization for events and intents
- protocol_version() function
Maturin build verified with `maturin develop --uv`.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ions
Add complete panic-safe Python bindings:
- Custom exceptions: StateError, SerializationError, InvalidTransitionError
- catch_unwind at FFI boundary for panic safety
- Full docstrings for all methods
- is_terminal() helper method
Python API:
- Investigator(): new(), restore(), snapshot(), ingest()
- current_phase(), current_step(), is_terminal()
- Exception hierarchy for error handling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Rust build commands to Justfile:
- rust-check: verify Rust toolchain
- rust-build: cargo build --release
- rust-dev: maturin develop --uv (install to venv)
- rust-test: cargo test
- rust-lint: cargo clippy
- rust-clean: clean target/
Update setup workflow:
- `just setup` now runs `just rust-dev` after uv sync
- `just clean` includes rust-clean
Note: dataing-investigator requires maturin build, cannot be a uv source.
Use `just rust-dev` after `uv sync` to install bindings.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create python-packages/investigator/ wrapping Rust bindings:
- pyproject.toml with hatchling build
- __init__.py re-exporting Investigator, exceptions, protocol_version
- Empty module files: envelope.py, security.py, runtime.py
Added to uv workspace and project dependencies.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Envelope module (fn-17.11):
- Envelope TypedDict for tracing context
- wrap/unwrap for JSON serialization
- create_trace() for new trace IDs
- create_child_envelope() for linked events
Security module (fn-17.12):
- SecurityViolation exception
- validate_tool_call() with deny-by-default
- Tool allowlist validation
- Table permission checks
- Forbidden SQL pattern detection (DROP, DELETE, etc.)
- create_scope() helper
Both modules exported from investigator package.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add runtime.py with:
- run_local() async function for executing investigations
- LocalInvestigator class for fine-grained control
- Security validation before every tool call
- Error handling for all intent types
- Snapshot/restore support
- Max steps limit to prevent infinite loops
Provides local testing without Temporal dependency.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- InvestigatorWorkflow uses Rust Investigator via brain_step activity
- Pure computation in activity, side effects in workflow
- Signal dedup via seen_signal_ids set
- continue_as_new at step threshold (100)
- HITL via user_response signal and get_status query
- Conditional temporal exports (requires temporalio optional)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- test_investigator.py: basics, events, serialization, errors, full cycle
- test_envelope.py: wrap/unwrap, trace IDs, child envelopes
- test_security.py: tool validation, forbidden SQL patterns, scopes
- test_runtime.py: LocalInvestigator and run_local function
- Added pytest and pytest-asyncio as dev dependencies
- 74 tests total, all passing
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Full investigation lifecycle test
- Query status test
- Cancel signal test
- Deterministic replay test
- Brain step activity unit tests
- Signal deduplication test
- Tests skip if Temporal not available (SKIP_TEMPORAL_TESTS=1)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@vercel

vercelBot commented Jan 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentReviewUpdated (UTC)
dataingReadyReadyPreview, CommentJan 19, 2026 8:29pm
dataing-appReadyReadyPreview, CommentJan 19, 2026 8:29pm
dataing-docsReadyReadyPreview, CommentJan 19, 2026 8:29pm

Sign up for freeto 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.

1 participant

@bordumb
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: Rust state machine for investigation workflow (fn-17) - #75

Draft
bordumb wants to merge 18 commits into
mainfrom
fn-17
Draft

feat: Rust state machine for investigation workflow (fn-17)#75
bordumb wants to merge 18 commits into
mainfrom
fn-17

Conversation

@bordumb

Copy link
Copy Markdown
Owner

Summary

Implements a Rust-based investigation state machine with Python bindings, replacing Temporal workflow local variables with a deterministic, versioned state machine.

Key changes:

  • Rust core (core/): Event-sourced state machine with 8 phases, versioned JSON protocol (v1)
  • PyO3 bindings (core/bindings/python/): Panic-free FFI with custom exceptions
  • Python package (python-packages/investigator/): Runtime, security, envelope, and Temporal integration modules
  • Tests: 43 Rust tests + 74 Python integration tests + 7 E2E workflow tests

Architecture:

  • State machine runs inside Temporal activities (not workflow code) for side-effect isolation
  • brain_step activity: pure computation, no side effects
  • Signals/queries for HITL, continue_as_new at step threshold
  • Deny-by-default security with SQL pattern validation

Epic tasks completed: 16/16

Test plan

  • Rust tests: cd core && cargo test (43 tests)
  • Python integration tests: pytest python-packages/investigator/tests/ (74 tests)
  • E2E workflow tests: skippable when Temporal unavailable
  • Manual: just rust-dev then just test

🤖 Generated with Claude Code

bordumband others added 15 commits January 19, 2026 01:50
- Add core/ Rust workspace with dataing_investigator crate
- Add PyO3 bindings crate with maturin configuration
- Set PROTOCOL_VERSION=1 for snapshot versioning
- Add clippy deny rules for panic-free code
- Include .flow/ epic and task tracking for fn-17
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Scope, CallKind, and CallMeta types to dataing_investigator crate:
- Scope: security context with user/tenant IDs and permissions
- CallKind: enum for LLM vs Tool calls
- CallMeta: metadata for pending external calls
Uses BTreeMap for deterministic serialization ordering and
serde(default) for forward compatibility.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add tagged enum types for state machine communication:
- Event: Start, CallResult, UserResponse, Cancel
- Intent: Idle, Call, RequestUser, Finish, Error
Uses serde tagged enum format for JSON wire protocol.
All variants tested with serialization roundtrip tests.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add state module with:
- Phase enum: Init, GatheringContext, GeneratingHypotheses,
EvaluatingHypotheses, AwaitingUser, Synthesizing, Finished, Failed
- State struct: versioned snapshot with sequence/step counters
- generate_id(): unique ID generation with prefix
- BTreeMap for ordered evidence/call storage
Uses serde(default) on optional fields for forward compatibility.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement core state machine in machine.rs:
- Investigator::new(), restore(), snapshot() for lifecycle
- ingest() processes events and returns intents
- apply() handles Start, CallResult, UserResponse, Cancel events
- decide() emits appropriate Intent for each Phase
Key behaviors:
- Strict call_id validation: unexpected IDs trigger Failed phase
- Logical clock (step) incremented on each event
- Call metadata recorded in call_index for debugging
- Full workflow from Init -> GatheringContext -> GeneratingHypotheses
-> EvaluatingHypotheses -> Synthesizing -> Finished
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add PyO3 bindings exposing the Rust state machine to Python:
- Investigator class with new(), restore(), snapshot(), ingest()
- current_phase() and current_step() helper methods
- JSON-based serialization for events and intents
- protocol_version() function
Maturin build verified with `maturin develop --uv`.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ions
Add complete panic-safe Python bindings:
- Custom exceptions: StateError, SerializationError, InvalidTransitionError
- catch_unwind at FFI boundary for panic safety
- Full docstrings for all methods
- is_terminal() helper method
Python API:
- Investigator(): new(), restore(), snapshot(), ingest()
- current_phase(), current_step(), is_terminal()
- Exception hierarchy for error handling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Rust build commands to Justfile:
- rust-check: verify Rust toolchain
- rust-build: cargo build --release
- rust-dev: maturin develop --uv (install to venv)
- rust-test: cargo test
- rust-lint: cargo clippy
- rust-clean: clean target/
Update setup workflow:
- `just setup` now runs `just rust-dev` after uv sync
- `just clean` includes rust-clean
Note: dataing-investigator requires maturin build, cannot be a uv source.
Use `just rust-dev` after `uv sync` to install bindings.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create python-packages/investigator/ wrapping Rust bindings:
- pyproject.toml with hatchling build
- __init__.py re-exporting Investigator, exceptions, protocol_version
- Empty module files: envelope.py, security.py, runtime.py
Added to uv workspace and project dependencies.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Envelope module (fn-17.11):
- Envelope TypedDict for tracing context
- wrap/unwrap for JSON serialization
- create_trace() for new trace IDs
- create_child_envelope() for linked events
Security module (fn-17.12):
- SecurityViolation exception
- validate_tool_call() with deny-by-default
- Tool allowlist validation
- Table permission checks
- Forbidden SQL pattern detection (DROP, DELETE, etc.)
- create_scope() helper
Both modules exported from investigator package.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add runtime.py with:
- run_local() async function for executing investigations
- LocalInvestigator class for fine-grained control
- Security validation before every tool call
- Error handling for all intent types
- Snapshot/restore support
- Max steps limit to prevent infinite loops
Provides local testing without Temporal dependency.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- InvestigatorWorkflow uses Rust Investigator via brain_step activity
- Pure computation in activity, side effects in workflow
- Signal dedup via seen_signal_ids set
- continue_as_new at step threshold (100)
- HITL via user_response signal and get_status query
- Conditional temporal exports (requires temporalio optional)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- test_investigator.py: basics, events, serialization, errors, full cycle
- test_envelope.py: wrap/unwrap, trace IDs, child envelopes
- test_security.py: tool validation, forbidden SQL patterns, scopes
- test_runtime.py: LocalInvestigator and run_local function
- Added pytest and pytest-asyncio as dev dependencies
- 74 tests total, all passing
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Full investigation lifecycle test
- Query status test
- Cancel signal test
- Deterministic replay test
- Brain step activity unit tests
- Signal deduplication test
- Tests skip if Temporal not available (SKIP_TEMPORAL_TESTS=1)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@vercel

vercelBot commented Jan 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentReviewUpdated (UTC)
dataingReadyReadyPreview, CommentJan 19, 2026 8:29pm
dataing-appReadyReadyPreview, CommentJan 19, 2026 8:29pm
dataing-docsReadyReadyPreview, CommentJan 19, 2026 8:29pm

Sign up for freeto 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.

1 participant

@bordumb
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: Rust state machine for investigation workflow (fn-17) - #75

Draft
bordumb wants to merge 18 commits into
mainfrom
fn-17
Draft

feat: Rust state machine for investigation workflow (fn-17)#75
bordumb wants to merge 18 commits into
mainfrom
fn-17

Conversation

@bordumb

Copy link
Copy Markdown
Owner

Summary

Implements a Rust-based investigation state machine with Python bindings, replacing Temporal workflow local variables with a deterministic, versioned state machine.

Key changes:

  • Rust core (core/): Event-sourced state machine with 8 phases, versioned JSON protocol (v1)
  • PyO3 bindings (core/bindings/python/): Panic-free FFI with custom exceptions
  • Python package (python-packages/investigator/): Runtime, security, envelope, and Temporal integration modules
  • Tests: 43 Rust tests + 74 Python integration tests + 7 E2E workflow tests

Architecture:

  • State machine runs inside Temporal activities (not workflow code) for side-effect isolation
  • brain_step activity: pure computation, no side effects
  • Signals/queries for HITL, continue_as_new at step threshold
  • Deny-by-default security with SQL pattern validation

Epic tasks completed: 16/16

Test plan

  • Rust tests: cd core && cargo test (43 tests)
  • Python integration tests: pytest python-packages/investigator/tests/ (74 tests)
  • E2E workflow tests: skippable when Temporal unavailable
  • Manual: just rust-dev then just test

🤖 Generated with Claude Code

bordumband others added 15 commits January 19, 2026 01:50
- Add core/ Rust workspace with dataing_investigator crate
- Add PyO3 bindings crate with maturin configuration
- Set PROTOCOL_VERSION=1 for snapshot versioning
- Add clippy deny rules for panic-free code
- Include .flow/ epic and task tracking for fn-17
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Scope, CallKind, and CallMeta types to dataing_investigator crate:
- Scope: security context with user/tenant IDs and permissions
- CallKind: enum for LLM vs Tool calls
- CallMeta: metadata for pending external calls
Uses BTreeMap for deterministic serialization ordering and
serde(default) for forward compatibility.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add tagged enum types for state machine communication:
- Event: Start, CallResult, UserResponse, Cancel
- Intent: Idle, Call, RequestUser, Finish, Error
Uses serde tagged enum format for JSON wire protocol.
All variants tested with serialization roundtrip tests.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add state module with:
- Phase enum: Init, GatheringContext, GeneratingHypotheses,
EvaluatingHypotheses, AwaitingUser, Synthesizing, Finished, Failed
- State struct: versioned snapshot with sequence/step counters
- generate_id(): unique ID generation with prefix
- BTreeMap for ordered evidence/call storage
Uses serde(default) on optional fields for forward compatibility.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement core state machine in machine.rs:
- Investigator::new(), restore(), snapshot() for lifecycle
- ingest() processes events and returns intents
- apply() handles Start, CallResult, UserResponse, Cancel events
- decide() emits appropriate Intent for each Phase
Key behaviors:
- Strict call_id validation: unexpected IDs trigger Failed phase
- Logical clock (step) incremented on each event
- Call metadata recorded in call_index for debugging
- Full workflow from Init -> GatheringContext -> GeneratingHypotheses
-> EvaluatingHypotheses -> Synthesizing -> Finished
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add PyO3 bindings exposing the Rust state machine to Python:
- Investigator class with new(), restore(), snapshot(), ingest()
- current_phase() and current_step() helper methods
- JSON-based serialization for events and intents
- protocol_version() function
Maturin build verified with `maturin develop --uv`.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ions
Add complete panic-safe Python bindings:
- Custom exceptions: StateError, SerializationError, InvalidTransitionError
- catch_unwind at FFI boundary for panic safety
- Full docstrings for all methods
- is_terminal() helper method
Python API:
- Investigator(): new(), restore(), snapshot(), ingest()
- current_phase(), current_step(), is_terminal()
- Exception hierarchy for error handling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Rust build commands to Justfile:
- rust-check: verify Rust toolchain
- rust-build: cargo build --release
- rust-dev: maturin develop --uv (install to venv)
- rust-test: cargo test
- rust-lint: cargo clippy
- rust-clean: clean target/
Update setup workflow:
- `just setup` now runs `just rust-dev` after uv sync
- `just clean` includes rust-clean
Note: dataing-investigator requires maturin build, cannot be a uv source.
Use `just rust-dev` after `uv sync` to install bindings.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create python-packages/investigator/ wrapping Rust bindings:
- pyproject.toml with hatchling build
- __init__.py re-exporting Investigator, exceptions, protocol_version
- Empty module files: envelope.py, security.py, runtime.py
Added to uv workspace and project dependencies.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Envelope module (fn-17.11):
- Envelope TypedDict for tracing context
- wrap/unwrap for JSON serialization
- create_trace() for new trace IDs
- create_child_envelope() for linked events
Security module (fn-17.12):
- SecurityViolation exception
- validate_tool_call() with deny-by-default
- Tool allowlist validation
- Table permission checks
- Forbidden SQL pattern detection (DROP, DELETE, etc.)
- create_scope() helper
Both modules exported from investigator package.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add runtime.py with:
- run_local() async function for executing investigations
- LocalInvestigator class for fine-grained control
- Security validation before every tool call
- Error handling for all intent types
- Snapshot/restore support
- Max steps limit to prevent infinite loops
Provides local testing without Temporal dependency.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- InvestigatorWorkflow uses Rust Investigator via brain_step activity
- Pure computation in activity, side effects in workflow
- Signal dedup via seen_signal_ids set
- continue_as_new at step threshold (100)
- HITL via user_response signal and get_status query
- Conditional temporal exports (requires temporalio optional)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- test_investigator.py: basics, events, serialization, errors, full cycle
- test_envelope.py: wrap/unwrap, trace IDs, child envelopes
- test_security.py: tool validation, forbidden SQL patterns, scopes
- test_runtime.py: LocalInvestigator and run_local function
- Added pytest and pytest-asyncio as dev dependencies
- 74 tests total, all passing
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Full investigation lifecycle test
- Query status test
- Cancel signal test
- Deterministic replay test
- Brain step activity unit tests
- Signal deduplication test
- Tests skip if Temporal not available (SKIP_TEMPORAL_TESTS=1)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@vercel

vercelBot commented Jan 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentReviewUpdated (UTC)
dataingReadyReadyPreview, CommentJan 19, 2026 8:29pm
dataing-appReadyReadyPreview, CommentJan 19, 2026 8:29pm
dataing-docsReadyReadyPreview, CommentJan 19, 2026 8:29pm

Sign up for freeto 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.

1 participant

@bordumb
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat: Rust state machine for investigation workflow (fn-17) - #75

Draft
bordumb wants to merge 18 commits into
mainfrom
fn-17
Draft

feat: Rust state machine for investigation workflow (fn-17)#75
bordumb wants to merge 18 commits into
mainfrom
fn-17

Conversation

@bordumb

Copy link
Copy Markdown
Owner

Summary

Implements a Rust-based investigation state machine with Python bindings, replacing Temporal workflow local variables with a deterministic, versioned state machine.

Key changes:

  • Rust core (core/): Event-sourced state machine with 8 phases, versioned JSON protocol (v1)
  • PyO3 bindings (core/bindings/python/): Panic-free FFI with custom exceptions
  • Python package (python-packages/investigator/): Runtime, security, envelope, and Temporal integration modules
  • Tests: 43 Rust tests + 74 Python integration tests + 7 E2E workflow tests

Architecture:

  • State machine runs inside Temporal activities (not workflow code) for side-effect isolation
  • brain_step activity: pure computation, no side effects
  • Signals/queries for HITL, continue_as_new at step threshold
  • Deny-by-default security with SQL pattern validation

Epic tasks completed: 16/16

Test plan

  • Rust tests: cd core && cargo test (43 tests)
  • Python integration tests: pytest python-packages/investigator/tests/ (74 tests)
  • E2E workflow tests: skippable when Temporal unavailable
  • Manual: just rust-dev then just test

🤖 Generated with Claude Code

bordumband others added 15 commits January 19, 2026 01:50
- Add core/ Rust workspace with dataing_investigator crate
- Add PyO3 bindings crate with maturin configuration
- Set PROTOCOL_VERSION=1 for snapshot versioning
- Add clippy deny rules for panic-free code
- Include .flow/ epic and task tracking for fn-17
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Scope, CallKind, and CallMeta types to dataing_investigator crate:
- Scope: security context with user/tenant IDs and permissions
- CallKind: enum for LLM vs Tool calls
- CallMeta: metadata for pending external calls
Uses BTreeMap for deterministic serialization ordering and
serde(default) for forward compatibility.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add tagged enum types for state machine communication:
- Event: Start, CallResult, UserResponse, Cancel
- Intent: Idle, Call, RequestUser, Finish, Error
Uses serde tagged enum format for JSON wire protocol.
All variants tested with serialization roundtrip tests.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add state module with:
- Phase enum: Init, GatheringContext, GeneratingHypotheses,
EvaluatingHypotheses, AwaitingUser, Synthesizing, Finished, Failed
- State struct: versioned snapshot with sequence/step counters
- generate_id(): unique ID generation with prefix
- BTreeMap for ordered evidence/call storage
Uses serde(default) on optional fields for forward compatibility.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement core state machine in machine.rs:
- Investigator::new(), restore(), snapshot() for lifecycle
- ingest() processes events and returns intents
- apply() handles Start, CallResult, UserResponse, Cancel events
- decide() emits appropriate Intent for each Phase
Key behaviors:
- Strict call_id validation: unexpected IDs trigger Failed phase
- Logical clock (step) incremented on each event
- Call metadata recorded in call_index for debugging
- Full workflow from Init -> GatheringContext -> GeneratingHypotheses
-> EvaluatingHypotheses -> Synthesizing -> Finished
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add PyO3 bindings exposing the Rust state machine to Python:
- Investigator class with new(), restore(), snapshot(), ingest()
- current_phase() and current_step() helper methods
- JSON-based serialization for events and intents
- protocol_version() function
Maturin build verified with `maturin develop --uv`.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ions
Add complete panic-safe Python bindings:
- Custom exceptions: StateError, SerializationError, InvalidTransitionError
- catch_unwind at FFI boundary for panic safety
- Full docstrings for all methods
- is_terminal() helper method
Python API:
- Investigator(): new(), restore(), snapshot(), ingest()
- current_phase(), current_step(), is_terminal()
- Exception hierarchy for error handling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Rust build commands to Justfile:
- rust-check: verify Rust toolchain
- rust-build: cargo build --release
- rust-dev: maturin develop --uv (install to venv)
- rust-test: cargo test
- rust-lint: cargo clippy
- rust-clean: clean target/
Update setup workflow:
- `just setup` now runs `just rust-dev` after uv sync
- `just clean` includes rust-clean
Note: dataing-investigator requires maturin build, cannot be a uv source.
Use `just rust-dev` after `uv sync` to install bindings.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create python-packages/investigator/ wrapping Rust bindings:
- pyproject.toml with hatchling build
- __init__.py re-exporting Investigator, exceptions, protocol_version
- Empty module files: envelope.py, security.py, runtime.py
Added to uv workspace and project dependencies.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Envelope module (fn-17.11):
- Envelope TypedDict for tracing context
- wrap/unwrap for JSON serialization
- create_trace() for new trace IDs
- create_child_envelope() for linked events
Security module (fn-17.12):
- SecurityViolation exception
- validate_tool_call() with deny-by-default
- Tool allowlist validation
- Table permission checks
- Forbidden SQL pattern detection (DROP, DELETE, etc.)
- create_scope() helper
Both modules exported from investigator package.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add runtime.py with:
- run_local() async function for executing investigations
- LocalInvestigator class for fine-grained control
- Security validation before every tool call
- Error handling for all intent types
- Snapshot/restore support
- Max steps limit to prevent infinite loops
Provides local testing without Temporal dependency.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- InvestigatorWorkflow uses Rust Investigator via brain_step activity
- Pure computation in activity, side effects in workflow
- Signal dedup via seen_signal_ids set
- continue_as_new at step threshold (100)
- HITL via user_response signal and get_status query
- Conditional temporal exports (requires temporalio optional)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- test_investigator.py: basics, events, serialization, errors, full cycle
- test_envelope.py: wrap/unwrap, trace IDs, child envelopes
- test_security.py: tool validation, forbidden SQL patterns, scopes
- test_runtime.py: LocalInvestigator and run_local function
- Added pytest and pytest-asyncio as dev dependencies
- 74 tests total, all passing
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Full investigation lifecycle test
- Query status test
- Cancel signal test
- Deterministic replay test
- Brain step activity unit tests
- Signal deduplication test
- Tests skip if Temporal not available (SKIP_TEMPORAL_TESTS=1)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@vercel

vercelBot commented Jan 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentReviewUpdated (UTC)
dataingReadyReadyPreview, CommentJan 19, 2026 8:29pm
dataing-appReadyReadyPreview, CommentJan 19, 2026 8:29pm
dataing-docsReadyReadyPreview, CommentJan 19, 2026 8:29pm

Sign up for freeto 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.

1 participant

@bordumb
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: Rust state machine for investigation workflow (fn-17) - #75

Draft
bordumb wants to merge 18 commits into
mainfrom
fn-17
Draft

feat: Rust state machine for investigation workflow (fn-17)#75
bordumb wants to merge 18 commits into
mainfrom
fn-17

Conversation

@bordumb

Copy link
Copy Markdown
Owner

Summary

Implements a Rust-based investigation state machine with Python bindings, replacing Temporal workflow local variables with a deterministic, versioned state machine.

Key changes:

  • Rust core (core/): Event-sourced state machine with 8 phases, versioned JSON protocol (v1)
  • PyO3 bindings (core/bindings/python/): Panic-free FFI with custom exceptions
  • Python package (python-packages/investigator/): Runtime, security, envelope, and Temporal integration modules
  • Tests: 43 Rust tests + 74 Python integration tests + 7 E2E workflow tests

Architecture:

  • State machine runs inside Temporal activities (not workflow code) for side-effect isolation
  • brain_step activity: pure computation, no side effects
  • Signals/queries for HITL, continue_as_new at step threshold
  • Deny-by-default security with SQL pattern validation

Epic tasks completed: 16/16

Test plan

  • Rust tests: cd core && cargo test (43 tests)
  • Python integration tests: pytest python-packages/investigator/tests/ (74 tests)
  • E2E workflow tests: skippable when Temporal unavailable
  • Manual: just rust-dev then just test

🤖 Generated with Claude Code

bordumband others added 15 commits January 19, 2026 01:50
- Add core/ Rust workspace with dataing_investigator crate
- Add PyO3 bindings crate with maturin configuration
- Set PROTOCOL_VERSION=1 for snapshot versioning
- Add clippy deny rules for panic-free code
- Include .flow/ epic and task tracking for fn-17
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Scope, CallKind, and CallMeta types to dataing_investigator crate:
- Scope: security context with user/tenant IDs and permissions
- CallKind: enum for LLM vs Tool calls
- CallMeta: metadata for pending external calls
Uses BTreeMap for deterministic serialization ordering and
serde(default) for forward compatibility.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add tagged enum types for state machine communication:
- Event: Start, CallResult, UserResponse, Cancel
- Intent: Idle, Call, RequestUser, Finish, Error
Uses serde tagged enum format for JSON wire protocol.
All variants tested with serialization roundtrip tests.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add state module with:
- Phase enum: Init, GatheringContext, GeneratingHypotheses,
EvaluatingHypotheses, AwaitingUser, Synthesizing, Finished, Failed
- State struct: versioned snapshot with sequence/step counters
- generate_id(): unique ID generation with prefix
- BTreeMap for ordered evidence/call storage
Uses serde(default) on optional fields for forward compatibility.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement core state machine in machine.rs:
- Investigator::new(), restore(), snapshot() for lifecycle
- ingest() processes events and returns intents
- apply() handles Start, CallResult, UserResponse, Cancel events
- decide() emits appropriate Intent for each Phase
Key behaviors:
- Strict call_id validation: unexpected IDs trigger Failed phase
- Logical clock (step) incremented on each event
- Call metadata recorded in call_index for debugging
- Full workflow from Init -> GatheringContext -> GeneratingHypotheses
-> EvaluatingHypotheses -> Synthesizing -> Finished
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add PyO3 bindings exposing the Rust state machine to Python:
- Investigator class with new(), restore(), snapshot(), ingest()
- current_phase() and current_step() helper methods
- JSON-based serialization for events and intents
- protocol_version() function
Maturin build verified with `maturin develop --uv`.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ions
Add complete panic-safe Python bindings:
- Custom exceptions: StateError, SerializationError, InvalidTransitionError
- catch_unwind at FFI boundary for panic safety
- Full docstrings for all methods
- is_terminal() helper method
Python API:
- Investigator(): new(), restore(), snapshot(), ingest()
- current_phase(), current_step(), is_terminal()
- Exception hierarchy for error handling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Rust build commands to Justfile:
- rust-check: verify Rust toolchain
- rust-build: cargo build --release
- rust-dev: maturin develop --uv (install to venv)
- rust-test: cargo test
- rust-lint: cargo clippy
- rust-clean: clean target/
Update setup workflow:
- `just setup` now runs `just rust-dev` after uv sync
- `just clean` includes rust-clean
Note: dataing-investigator requires maturin build, cannot be a uv source.
Use `just rust-dev` after `uv sync` to install bindings.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create python-packages/investigator/ wrapping Rust bindings:
- pyproject.toml with hatchling build
- __init__.py re-exporting Investigator, exceptions, protocol_version
- Empty module files: envelope.py, security.py, runtime.py
Added to uv workspace and project dependencies.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Envelope module (fn-17.11):
- Envelope TypedDict for tracing context
- wrap/unwrap for JSON serialization
- create_trace() for new trace IDs
- create_child_envelope() for linked events
Security module (fn-17.12):
- SecurityViolation exception
- validate_tool_call() with deny-by-default
- Tool allowlist validation
- Table permission checks
- Forbidden SQL pattern detection (DROP, DELETE, etc.)
- create_scope() helper
Both modules exported from investigator package.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add runtime.py with:
- run_local() async function for executing investigations
- LocalInvestigator class for fine-grained control
- Security validation before every tool call
- Error handling for all intent types
- Snapshot/restore support
- Max steps limit to prevent infinite loops
Provides local testing without Temporal dependency.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- InvestigatorWorkflow uses Rust Investigator via brain_step activity
- Pure computation in activity, side effects in workflow
- Signal dedup via seen_signal_ids set
- continue_as_new at step threshold (100)
- HITL via user_response signal and get_status query
- Conditional temporal exports (requires temporalio optional)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- test_investigator.py: basics, events, serialization, errors, full cycle
- test_envelope.py: wrap/unwrap, trace IDs, child envelopes
- test_security.py: tool validation, forbidden SQL patterns, scopes
- test_runtime.py: LocalInvestigator and run_local function
- Added pytest and pytest-asyncio as dev dependencies
- 74 tests total, all passing
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Full investigation lifecycle test
- Query status test
- Cancel signal test
- Deterministic replay test
- Brain step activity unit tests
- Signal deduplication test
- Tests skip if Temporal not available (SKIP_TEMPORAL_TESTS=1)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@vercel

vercelBot commented Jan 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentReviewUpdated (UTC)
dataingReadyReadyPreview, CommentJan 19, 2026 8:29pm
dataing-appReadyReadyPreview, CommentJan 19, 2026 8:29pm
dataing-docsReadyReadyPreview, CommentJan 19, 2026 8:29pm

Sign up for freeto 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.

1 participant

@bordumb
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: Rust state machine for investigation workflow (fn-17) - #75

Draft
bordumb wants to merge 18 commits into
mainfrom
fn-17
Draft

feat: Rust state machine for investigation workflow (fn-17)#75
bordumb wants to merge 18 commits into
mainfrom
fn-17

Conversation

@bordumb

Copy link
Copy Markdown
Owner

Summary

Implements a Rust-based investigation state machine with Python bindings, replacing Temporal workflow local variables with a deterministic, versioned state machine.

Key changes:

  • Rust core (core/): Event-sourced state machine with 8 phases, versioned JSON protocol (v1)
  • PyO3 bindings (core/bindings/python/): Panic-free FFI with custom exceptions
  • Python package (python-packages/investigator/): Runtime, security, envelope, and Temporal integration modules
  • Tests: 43 Rust tests + 74 Python integration tests + 7 E2E workflow tests

Architecture:

  • State machine runs inside Temporal activities (not workflow code) for side-effect isolation
  • brain_step activity: pure computation, no side effects
  • Signals/queries for HITL, continue_as_new at step threshold
  • Deny-by-default security with SQL pattern validation

Epic tasks completed: 16/16

Test plan

  • Rust tests: cd core && cargo test (43 tests)
  • Python integration tests: pytest python-packages/investigator/tests/ (74 tests)
  • E2E workflow tests: skippable when Temporal unavailable
  • Manual: just rust-dev then just test

🤖 Generated with Claude Code

bordumband others added 15 commits January 19, 2026 01:50
- Add core/ Rust workspace with dataing_investigator crate
- Add PyO3 bindings crate with maturin configuration
- Set PROTOCOL_VERSION=1 for snapshot versioning
- Add clippy deny rules for panic-free code
- Include .flow/ epic and task tracking for fn-17
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Scope, CallKind, and CallMeta types to dataing_investigator crate:
- Scope: security context with user/tenant IDs and permissions
- CallKind: enum for LLM vs Tool calls
- CallMeta: metadata for pending external calls
Uses BTreeMap for deterministic serialization ordering and
serde(default) for forward compatibility.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add tagged enum types for state machine communication:
- Event: Start, CallResult, UserResponse, Cancel
- Intent: Idle, Call, RequestUser, Finish, Error
Uses serde tagged enum format for JSON wire protocol.
All variants tested with serialization roundtrip tests.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add state module with:
- Phase enum: Init, GatheringContext, GeneratingHypotheses,
EvaluatingHypotheses, AwaitingUser, Synthesizing, Finished, Failed
- State struct: versioned snapshot with sequence/step counters
- generate_id(): unique ID generation with prefix
- BTreeMap for ordered evidence/call storage
Uses serde(default) on optional fields for forward compatibility.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement core state machine in machine.rs:
- Investigator::new(), restore(), snapshot() for lifecycle
- ingest() processes events and returns intents
- apply() handles Start, CallResult, UserResponse, Cancel events
- decide() emits appropriate Intent for each Phase
Key behaviors:
- Strict call_id validation: unexpected IDs trigger Failed phase
- Logical clock (step) incremented on each event
- Call metadata recorded in call_index for debugging
- Full workflow from Init -> GatheringContext -> GeneratingHypotheses
-> EvaluatingHypotheses -> Synthesizing -> Finished
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add PyO3 bindings exposing the Rust state machine to Python:
- Investigator class with new(), restore(), snapshot(), ingest()
- current_phase() and current_step() helper methods
- JSON-based serialization for events and intents
- protocol_version() function
Maturin build verified with `maturin develop --uv`.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ions
Add complete panic-safe Python bindings:
- Custom exceptions: StateError, SerializationError, InvalidTransitionError
- catch_unwind at FFI boundary for panic safety
- Full docstrings for all methods
- is_terminal() helper method
Python API:
- Investigator(): new(), restore(), snapshot(), ingest()
- current_phase(), current_step(), is_terminal()
- Exception hierarchy for error handling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Rust build commands to Justfile:
- rust-check: verify Rust toolchain
- rust-build: cargo build --release
- rust-dev: maturin develop --uv (install to venv)
- rust-test: cargo test
- rust-lint: cargo clippy
- rust-clean: clean target/
Update setup workflow:
- `just setup` now runs `just rust-dev` after uv sync
- `just clean` includes rust-clean
Note: dataing-investigator requires maturin build, cannot be a uv source.
Use `just rust-dev` after `uv sync` to install bindings.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create python-packages/investigator/ wrapping Rust bindings:
- pyproject.toml with hatchling build
- __init__.py re-exporting Investigator, exceptions, protocol_version
- Empty module files: envelope.py, security.py, runtime.py
Added to uv workspace and project dependencies.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Envelope module (fn-17.11):
- Envelope TypedDict for tracing context
- wrap/unwrap for JSON serialization
- create_trace() for new trace IDs
- create_child_envelope() for linked events
Security module (fn-17.12):
- SecurityViolation exception
- validate_tool_call() with deny-by-default
- Tool allowlist validation
- Table permission checks
- Forbidden SQL pattern detection (DROP, DELETE, etc.)
- create_scope() helper
Both modules exported from investigator package.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add runtime.py with:
- run_local() async function for executing investigations
- LocalInvestigator class for fine-grained control
- Security validation before every tool call
- Error handling for all intent types
- Snapshot/restore support
- Max steps limit to prevent infinite loops
Provides local testing without Temporal dependency.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- InvestigatorWorkflow uses Rust Investigator via brain_step activity
- Pure computation in activity, side effects in workflow
- Signal dedup via seen_signal_ids set
- continue_as_new at step threshold (100)
- HITL via user_response signal and get_status query
- Conditional temporal exports (requires temporalio optional)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- test_investigator.py: basics, events, serialization, errors, full cycle
- test_envelope.py: wrap/unwrap, trace IDs, child envelopes
- test_security.py: tool validation, forbidden SQL patterns, scopes
- test_runtime.py: LocalInvestigator and run_local function
- Added pytest and pytest-asyncio as dev dependencies
- 74 tests total, all passing
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Full investigation lifecycle test
- Query status test
- Cancel signal test
- Deterministic replay test
- Brain step activity unit tests
- Signal deduplication test
- Tests skip if Temporal not available (SKIP_TEMPORAL_TESTS=1)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@vercel

vercelBot commented Jan 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentReviewUpdated (UTC)
dataingReadyReadyPreview, CommentJan 19, 2026 8:29pm
dataing-appReadyReadyPreview, CommentJan 19, 2026 8:29pm
dataing-docsReadyReadyPreview, CommentJan 19, 2026 8:29pm

Sign up for freeto 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.

1 participant

@bordumb
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat: Rust state machine for investigation workflow (fn-17) - #75

Draft
bordumb wants to merge 18 commits into
mainfrom
fn-17
Draft

feat: Rust state machine for investigation workflow (fn-17)#75
bordumb wants to merge 18 commits into
mainfrom
fn-17

Conversation

@bordumb

Copy link
Copy Markdown
Owner

Summary

Implements a Rust-based investigation state machine with Python bindings, replacing Temporal workflow local variables with a deterministic, versioned state machine.

Key changes:

  • Rust core (core/): Event-sourced state machine with 8 phases, versioned JSON protocol (v1)
  • PyO3 bindings (core/bindings/python/): Panic-free FFI with custom exceptions
  • Python package (python-packages/investigator/): Runtime, security, envelope, and Temporal integration modules
  • Tests: 43 Rust tests + 74 Python integration tests + 7 E2E workflow tests

Architecture:

  • State machine runs inside Temporal activities (not workflow code) for side-effect isolation
  • brain_step activity: pure computation, no side effects
  • Signals/queries for HITL, continue_as_new at step threshold
  • Deny-by-default security with SQL pattern validation

Epic tasks completed: 16/16

Test plan

  • Rust tests: cd core && cargo test (43 tests)
  • Python integration tests: pytest python-packages/investigator/tests/ (74 tests)
  • E2E workflow tests: skippable when Temporal unavailable
  • Manual: just rust-dev then just test

🤖 Generated with Claude Code

bordumband others added 15 commits January 19, 2026 01:50
- Add core/ Rust workspace with dataing_investigator crate
- Add PyO3 bindings crate with maturin configuration
- Set PROTOCOL_VERSION=1 for snapshot versioning
- Add clippy deny rules for panic-free code
- Include .flow/ epic and task tracking for fn-17
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Scope, CallKind, and CallMeta types to dataing_investigator crate:
- Scope: security context with user/tenant IDs and permissions
- CallKind: enum for LLM vs Tool calls
- CallMeta: metadata for pending external calls
Uses BTreeMap for deterministic serialization ordering and
serde(default) for forward compatibility.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add tagged enum types for state machine communication:
- Event: Start, CallResult, UserResponse, Cancel
- Intent: Idle, Call, RequestUser, Finish, Error
Uses serde tagged enum format for JSON wire protocol.
All variants tested with serialization roundtrip tests.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add state module with:
- Phase enum: Init, GatheringContext, GeneratingHypotheses,
EvaluatingHypotheses, AwaitingUser, Synthesizing, Finished, Failed
- State struct: versioned snapshot with sequence/step counters
- generate_id(): unique ID generation with prefix
- BTreeMap for ordered evidence/call storage
Uses serde(default) on optional fields for forward compatibility.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement core state machine in machine.rs:
- Investigator::new(), restore(), snapshot() for lifecycle
- ingest() processes events and returns intents
- apply() handles Start, CallResult, UserResponse, Cancel events
- decide() emits appropriate Intent for each Phase
Key behaviors:
- Strict call_id validation: unexpected IDs trigger Failed phase
- Logical clock (step) incremented on each event
- Call metadata recorded in call_index for debugging
- Full workflow from Init -> GatheringContext -> GeneratingHypotheses
-> EvaluatingHypotheses -> Synthesizing -> Finished
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add PyO3 bindings exposing the Rust state machine to Python:
- Investigator class with new(), restore(), snapshot(), ingest()
- current_phase() and current_step() helper methods
- JSON-based serialization for events and intents
- protocol_version() function
Maturin build verified with `maturin develop --uv`.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ions
Add complete panic-safe Python bindings:
- Custom exceptions: StateError, SerializationError, InvalidTransitionError
- catch_unwind at FFI boundary for panic safety
- Full docstrings for all methods
- is_terminal() helper method
Python API:
- Investigator(): new(), restore(), snapshot(), ingest()
- current_phase(), current_step(), is_terminal()
- Exception hierarchy for error handling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Rust build commands to Justfile:
- rust-check: verify Rust toolchain
- rust-build: cargo build --release
- rust-dev: maturin develop --uv (install to venv)
- rust-test: cargo test
- rust-lint: cargo clippy
- rust-clean: clean target/
Update setup workflow:
- `just setup` now runs `just rust-dev` after uv sync
- `just clean` includes rust-clean
Note: dataing-investigator requires maturin build, cannot be a uv source.
Use `just rust-dev` after `uv sync` to install bindings.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create python-packages/investigator/ wrapping Rust bindings:
- pyproject.toml with hatchling build
- __init__.py re-exporting Investigator, exceptions, protocol_version
- Empty module files: envelope.py, security.py, runtime.py
Added to uv workspace and project dependencies.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Envelope module (fn-17.11):
- Envelope TypedDict for tracing context
- wrap/unwrap for JSON serialization
- create_trace() for new trace IDs
- create_child_envelope() for linked events
Security module (fn-17.12):
- SecurityViolation exception
- validate_tool_call() with deny-by-default
- Tool allowlist validation
- Table permission checks
- Forbidden SQL pattern detection (DROP, DELETE, etc.)
- create_scope() helper
Both modules exported from investigator package.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add runtime.py with:
- run_local() async function for executing investigations
- LocalInvestigator class for fine-grained control
- Security validation before every tool call
- Error handling for all intent types
- Snapshot/restore support
- Max steps limit to prevent infinite loops
Provides local testing without Temporal dependency.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- InvestigatorWorkflow uses Rust Investigator via brain_step activity
- Pure computation in activity, side effects in workflow
- Signal dedup via seen_signal_ids set
- continue_as_new at step threshold (100)
- HITL via user_response signal and get_status query
- Conditional temporal exports (requires temporalio optional)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- test_investigator.py: basics, events, serialization, errors, full cycle
- test_envelope.py: wrap/unwrap, trace IDs, child envelopes
- test_security.py: tool validation, forbidden SQL patterns, scopes
- test_runtime.py: LocalInvestigator and run_local function
- Added pytest and pytest-asyncio as dev dependencies
- 74 tests total, all passing
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Full investigation lifecycle test
- Query status test
- Cancel signal test
- Deterministic replay test
- Brain step activity unit tests
- Signal deduplication test
- Tests skip if Temporal not available (SKIP_TEMPORAL_TESTS=1)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@vercel

vercelBot commented Jan 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentReviewUpdated (UTC)
dataingReadyReadyPreview, CommentJan 19, 2026 8:29pm
dataing-appReadyReadyPreview, CommentJan 19, 2026 8:29pm
dataing-docsReadyReadyPreview, CommentJan 19, 2026 8:29pm

Sign up for freeto 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.

1 participant

@bordumb