Skip to content

Add reusable gateway workflow harness with mock LLM server - #762

Merged
ilblackdragon merged 5 commits into
split/github-tool-migrationfrom
split/testing-framework-mock-llm
Mar 10, 2026
Merged

ilblackdragon merged 5 commits into
split/github-tool-migrationfrom
split/testing-framework-mock-llm

Conversation

@ilblackdragon

Copy link
Copy Markdown
Member

Summary

  • add reusable in-process OpenAI-compatible mock LLM server for integration tests
  • add gateway workflow harness for chat + routine + webhook end-to-end testing
  • add integration test exercising webhook workflow through gateway/status APIs

Validation

  • cargo test --test gateway_workflow_integration --features libsql

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the testing infrastructure by introducing a robust framework for end-to-end integration tests. It provides a mock OpenAI server to simulate LLM interactions and a comprehensive gateway workflow harness, enabling thorough validation of chat functionalities, routine creation and execution, and webhook processing within the system.

Highlights

  • Mock LLM Server: Added a reusable in-process OpenAI-compatible mock LLM server for integration tests, allowing controlled simulation of LLM interactions.
  • Gateway Workflow Harness: Introduced a comprehensive gateway workflow harness designed for end-to-end testing of chat, routine creation, and webhook functionalities.
  • Integration Test: Implemented a new integration test that thoroughly exercises webhook workflows through the gateway and status APIs, validating the full system path.
Changelog
  • tests/gateway_workflow_integration.rs
    • Added a new integration test to validate the end-to-end workflow involving chat, routine creation, event emission, and webhook processing using the new harness and mock LLM server.
  • tests/support/gateway_workflow_harness.rs
    • Added a new module defining GatewayWorkflowHarness, a utility for setting up a full gateway environment with an agent, database, and webhook server for testing purposes.
    • Included a MockGithubWebhookTool to simulate GitHub webhook events within the harness.
  • tests/support/mock_openai_server.rs
    • Added a new module implementing MockOpenAiServer, an in-process server that mimics the OpenAI API for chat completions, allowing controlled responses for testing.
  • tests/support/mod.rs
    • Updated the module to expose the newly added gateway_workflow_harness and mock_openai_server modules.
Activity
  • No human activity has been recorded on this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@github-actions github-actions Bot added risk: low Changes to docs, tests, or low-risk modules contributor: core 20+ merged PRs labels Mar 9, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a comprehensive integration test harness for gateway workflows, including a mock OpenAI-compatible server. The changes are well-structured and provide valuable end-to-end testing capabilities. I've identified a couple of minor areas for improvement to enhance test robustness and code clarity.

Comment thread tests/gateway_workflow_integration.rs Outdated
Comment on lines +124 to +133
tokio::time::sleep(Duration::from_millis(500)).await;
let runs_after = harness.routine_runs(routine_id).await;
let after_count = runs_after["runs"]
.as_array()
.map(|a| a.len())
.unwrap_or_default();
assert!(
after_count > before_count,
"expected routine runs to increase after webhook; before={before_count}, after={after_count}"
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using a fixed tokio::time::sleep can lead to flaky tests if the asynchronous operation takes longer than the specified duration. It's better to use a polling loop with a timeout to wait for the expected state change. This will make the test more robust.

Suggested change
tokio::time::sleep(Duration::from_millis(500)).await;
let runs_after = harness.routine_runs(routine_id).await;
let after_count = runs_after["runs"]
.as_array()
.map(|a| a.len())
.unwrap_or_default();
assert!(
after_count > before_count,
"expected routine runs to increase after webhook; before={before_count}, after={after_count}"
);
let mut after_count = before_count;
for _ in 0..50 { // 5-second timeout
let runs_after = harness.routine_runs(routine_id).await;
after_count = runs_after["runs"]
.as_array()
.map(|a| a.len())
.unwrap_or_default();
if after_count > before_count {
break;
}
tokio::time::sleep(Duration::from_millis(100)).await;
}
assert!(
after_count > before_count,
"expected routine runs to increase after webhook; before={before_count}, after={after_count}"
);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in e642e53 — replaced the fixed sleep(500ms) with a polling loop (up to 50 iterations × 100ms), matching the wait_for_turns() pattern already used elsewhere in the test.

Arc::new(tokio::sync::RwLock::new(None));

if let (Some(db_arc), Some(ws)) = (&components.db, &components.workspace) {
let (notify_tx, _notify_rx) = tokio::sync::mpsc::channel(16);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The _notify_rx variable is unused. It's good practice to rename it to _ to signify that it's intentionally unused and to avoid compiler warnings.

Suggested change
let (notify_tx, _notify_rx) = tokio::sync::mpsc::channel(16);
let (notify_tx, _) = tokio::sync::mpsc::channel(16);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in e642e53 — removed the entire redundant RoutineEngine block (Agent::run() creates its own), so this variable no longer exists.

@zmanian zmanian left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: Gateway Workflow Harness + Mock LLM Server

Overall this is solid test infrastructure. The mock OpenAI server is well-designed with a clean builder pattern, the rule-matching system is intuitive, and the harness provides good helper methods for common gateway operations. A few issues to address:

Duplicate TestChannelHandle

gateway_workflow_harness.rs defines its own TestChannelHandle (lines 34-89) that is nearly identical to the one in test_rig.rs (lines 41-96). The only difference is the harness version returns "gateway" from name() instead of delegating to self.inner.name(). This should be extracted into a shared helper in test_channel.rs -- perhaps TestChannel::into_channel_handle(name: &str) or a generic TestChannelHandle that accepts a name override. ~55 lines of pure boilerplate duplication.

Redundant RoutineEngine creation

In gateway_workflow_harness.rs lines 241-253, a temporary RoutineEngine is created with RoutineConfig::default() and passed to register_routine_tools(). But Agent::run() (in agent_loop.rs:442-454) creates its own RoutineEngine with the actual config and re-registers the routine tools, overwriting these registrations. This means:

  1. The temporary engine is created and immediately becomes dead weight.
  2. _notify_rx is dropped immediately, making the temporary engine's notification channel broken.
  3. The config used is RoutineConfig::default() rather than the config.routines that was carefully set up above -- an inconsistency that would matter if the engine weren't replaced.

Consider removing this block entirely (the agent's run() handles it), or add a comment explaining it's needed for some pre-run() setup reason I'm not seeing.

Flaky sleep pattern (agree with Gemini's comment)

Line 130 of the test:

tokio::time::sleep(Duration::from_millis(500)).await;

followed by a single check is a flake risk. The Gemini bot's suggestion to use a polling loop with timeout is correct. The test already has wait_for_turns() which demonstrates the right pattern -- apply the same approach here.

register_job_tools passes a fresh ContextManager

Line 224-232: A new ContextManager is created (ctx_mgr) and passed to register_job_tools, but then components.context_manager (a different instance from AppBuilder) is passed to Agent::new() at line 331. This means job tools reference a different context manager than the agent. If any job tool reads/writes context state, it will be invisible to the agent. Either use components.context_manager for both, or document why the separation is intentional.

Minor items

  • #![allow(dead_code)] at file level: Fine for test support modules, but consider scoping it more narrowly if most of the API is actually used. The #[allow(dead_code)] at the top of both files suppresses warnings for genuinely unused code that might indicate over-engineering.

  • Error handling in test helpers: Methods like create_thread(), send_chat(), etc. use .expect() chains which is fine for test code. Good pattern.

  • Mock server Drop impl: Both MockOpenAiServer and GatewayWorkflowHarness have proper Drop impls that abort spawned tasks -- good defensive design to prevent test leaks.

  • ToolOutput::success vs ToolOutput::text: The MockGithubWebhookTool uses ToolOutput::success() -- verify this matches the real GitHub tool's output format so the routine engine processes it correctly (the emit_events key in the output must be parsed somewhere upstream).

Design feedback

The harness is 572 lines for what is essentially "start a gateway + agent + webhook server with a mock LLM." That's a lot of wiring. Some of this complexity is inherent (the real main.rs startup is similarly complex), but it suggests AppBuilder could benefit from a build_test_harness() convenience method that handles the GatewayState/channel/agent wiring internally. Not a blocker for this PR, but worth considering as a follow-up to keep test infrastructure maintainable.

@zmanian zmanian left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: Gateway Workflow Harness + Mock LLM Server

Overall this is solid test infrastructure. The mock OpenAI server is well-designed with a clean builder pattern, the rule-matching system is intuitive, and the harness provides good helper methods for common gateway operations. A few issues to address:

Duplicate TestChannelHandle

gateway_workflow_harness.rs defines its own TestChannelHandle (lines 34-89) that is nearly identical to the one in test_rig.rs (lines 41-96). The only difference is the harness version returns "gateway" from name() instead of delegating to self.inner.name(). This should be extracted into a shared helper in test_channel.rs -- perhaps TestChannel::into_channel_handle(name) or a generic TestChannelHandle that accepts a name override. ~55 lines of pure boilerplate duplication.

Redundant RoutineEngine creation

In gateway_workflow_harness.rs lines 241-253, a temporary RoutineEngine is created with RoutineConfig::default() and passed to register_routine_tools(). But Agent::run() (in agent_loop.rs:442-454) creates its own RoutineEngine with the actual config and re-registers the routine tools, overwriting these registrations. This means:

  1. The temporary engine is created and immediately becomes dead weight
  2. _notify_rx is dropped immediately, making the temporary engine's notification channel broken
  3. The config used is RoutineConfig::default() rather than the config.routines that was carefully set up above

Consider removing this block entirely (the agent's run() handles it), or add a comment explaining why it is needed for some pre-run() setup reason.

Flaky sleep pattern

Line 130 of the test uses tokio::time::sleep(Duration::from_millis(500)).await followed by a single check -- this is a flake risk. The test already has wait_for_turns() which demonstrates the right polling-with-timeout pattern. Apply the same approach for waiting on routine run counts.

register_job_tools passes a fresh ContextManager

A new ContextManager is created (ctx_mgr) and passed to register_job_tools, but then components.context_manager (a different instance from AppBuilder) is passed to Agent::new(). This means job tools reference a different context manager than the agent. If any job tool reads/writes context state, it will be invisible to the agent. Either use components.context_manager for both, or document why the separation is intentional.

Minor items

  • Mock server Drop impls on both MockOpenAiServer and GatewayWorkflowHarness properly abort spawned tasks -- good defensive design
  • Error handling via .expect() chains in test helpers is fine and appropriate for test code
  • MockGithubWebhookTool uses ToolOutput::success() -- verify the emit_events key in the output matches what the real webhook tool produces so the routine engine processes it correctly
  • The harness is 572 lines of wiring. Some complexity is inherent, but it suggests AppBuilder could benefit from a build_test_harness() convenience method as a follow-up

None of these are critical blockers, but the duplicate TestChannelHandle and the redundant RoutineEngine creation should be cleaned up before merge to keep the test infrastructure maintainable.

@github-actions github-actions Bot added scope: agent Agent core (agent loop, router, scheduler) risk: medium Business logic, config, or moderate-risk modules and removed risk: low Changes to docs, tests, or low-risk modules labels Mar 9, 2026
- Extract shared TestChannelHandle into test_channel.rs with name override
  support, eliminating ~55 lines of duplication between test_rig.rs and
  gateway_workflow_harness.rs
- Remove redundant RoutineEngine creation that was immediately overwritten
  by Agent::run()
- Replace flaky sleep(500ms) with polling loop for routine run count check
- Use components.context_manager instead of creating a fresh ContextManager
  for job tools, ensuring agent and tools share the same instance

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ilblackdragon

Copy link
Copy Markdown
Member Author

All review feedback addressed in e642e53:

  1. Duplicate TestChannelHandle — Extracted into test_channel.rs as a shared TestChannelHandle with with_name() constructor for name overrides. Both test_rig.rs and gateway_workflow_harness.rs now import it. Net -65 lines.

  2. Redundant RoutineEngine creation — Removed the entire block (lines 240-253). Confirmed that Agent::run() creates its own RoutineEngine, calls register_routine_tools(), and populates the routine_engine_slot — the harness block was pure dead weight.

  3. Flaky sleep pattern — Replaced sleep(500ms) + single check with a polling loop (50 iterations × 100ms = 5s timeout), matching the wait_for_turns() pattern.

  4. Fresh ContextManager — Now uses components.context_manager instead of creating a separate instance, so job tools and agent share the same context.

  5. build_test_harness() follow-up — Good idea, noted for a future PR.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ilblackdragon
ilblackdragon merged commit 2d8c7db into split/github-tool-migration Mar 10, 2026
20 checks passed
@ilblackdragon
ilblackdragon deleted the split/testing-framework-mock-llm branch March 10, 2026 02:11
ilblackdragon added a commit that referenced this pull request Mar 12, 2026
* Add event-triggered routines and workflow skill templates

* Add generic host-verified webhook ingress for tools

* Migrate GitHub webhook normalization into github tool

* Bump github tool registry version

* Stabilize trace E2E test rig and approval behavior

* Add reusable gateway workflow harness with mock LLM server (#762)

* Add reusable gateway workflow test harness with mock LLM server

* Fix clippy issues in workflow harness

* Stabilize trace E2E test rig and approval behavior

* Address PR review feedback on gateway workflow harness

- Extract shared TestChannelHandle into test_channel.rs with name override
  support, eliminating ~55 lines of duplication between test_rig.rs and
  gateway_workflow_harness.rs
- Remove redundant RoutineEngine creation that was immediately overwritten
  by Agent::run()
- Replace flaky sleep(500ms) with polling loop for routine run count check
- Use components.context_manager instead of creating a fresh ContextManager
  for job tools, ensuring agent and tools share the same instance

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix import ordering in gateway_workflow_harness

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* Address PR #758 review feedback

- Fix header_value to use fully case-insensitive lookup (iterate with
  to_ascii_lowercase) instead of checking only exact/lower/upper variants
- Change comment_id from u32 to u64 to handle GitHub's billion-range IDs
- Remove handle_webhook from LLM-facing JSON schema to prevent direct
  invocation bypassing HMAC verification
- Rename enrichment keys from repository/sender to repository_name/
  sender_login to preserve original JSON objects in webhook payloads
- Remove put_string_normalized helper (no longer needed)
- Replace no-op tests (test_validate_event_in_create_pr_review,
  test_validate_merge_method) with test_header_value_case_insensitive
- Add README docs for 6 undocumented actions (list_issue_comments,
  create_issue_comment, list_pull_request_comments,
  reply_pull_request_comment, get_pull_request_reviews,
  get_combined_status)
- Add comment explaining max_tool_calls <= 8 bound in e2e test
- Fix gateway workflow harness: add webhook_capability with secret auth
  to MockGithubWebhookTool, matching staging's hardened webhook security
- Fix merge artifacts: remove duplicate test function, orphaned code
  fragment in e2e_routine_heartbeat

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix formatting in gateway workflow harness

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Address Copilot review: filter keys, pr_number fallback, feature gate, version alignment

- Update SKILL.md and workflow-routines.md templates to use `repository_name`
  and `sender_login` (matching enriched payload field names)
- Mark webhook HMAC secret as required in SKILL.md prerequisites
- Fall back to `/issue/number` for `pr_number` on issue_comment PR webhooks
- Gate `gateway_workflow_harness` module behind `#[cfg(feature = "libsql")]`
- Align tool version to 0.2.1 in Cargo.toml and capabilities.json

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
bkutasi pushed a commit to bkutasi/ironclaw that referenced this pull request Mar 28, 2026
* Add event-triggered routines and workflow skill templates

* Add generic host-verified webhook ingress for tools

* Migrate GitHub webhook normalization into github tool

* Bump github tool registry version

* Stabilize trace E2E test rig and approval behavior

* Add reusable gateway workflow harness with mock LLM server (nearai#762)

* Add reusable gateway workflow test harness with mock LLM server

* Fix clippy issues in workflow harness

* Stabilize trace E2E test rig and approval behavior

* Address PR review feedback on gateway workflow harness

- Extract shared TestChannelHandle into test_channel.rs with name override
  support, eliminating ~55 lines of duplication between test_rig.rs and
  gateway_workflow_harness.rs
- Remove redundant RoutineEngine creation that was immediately overwritten
  by Agent::run()
- Replace flaky sleep(500ms) with polling loop for routine run count check
- Use components.context_manager instead of creating a fresh ContextManager
  for job tools, ensuring agent and tools share the same instance

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix import ordering in gateway_workflow_harness

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* Address PR nearai#758 review feedback

- Fix header_value to use fully case-insensitive lookup (iterate with
  to_ascii_lowercase) instead of checking only exact/lower/upper variants
- Change comment_id from u32 to u64 to handle GitHub's billion-range IDs
- Remove handle_webhook from LLM-facing JSON schema to prevent direct
  invocation bypassing HMAC verification
- Rename enrichment keys from repository/sender to repository_name/
  sender_login to preserve original JSON objects in webhook payloads
- Remove put_string_normalized helper (no longer needed)
- Replace no-op tests (test_validate_event_in_create_pr_review,
  test_validate_merge_method) with test_header_value_case_insensitive
- Add README docs for 6 undocumented actions (list_issue_comments,
  create_issue_comment, list_pull_request_comments,
  reply_pull_request_comment, get_pull_request_reviews,
  get_combined_status)
- Add comment explaining max_tool_calls <= 8 bound in e2e test
- Fix gateway workflow harness: add webhook_capability with secret auth
  to MockGithubWebhookTool, matching staging's hardened webhook security
- Fix merge artifacts: remove duplicate test function, orphaned code
  fragment in e2e_routine_heartbeat

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix formatting in gateway workflow harness

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Address Copilot review: filter keys, pr_number fallback, feature gate, version alignment

- Update SKILL.md and workflow-routines.md templates to use `repository_name`
  and `sender_login` (matching enriched payload field names)
- Mark webhook HMAC secret as required in SKILL.md prerequisites
- Fall back to `/issue/number` for `pr_number` on issue_comment PR webhooks
- Gate `gateway_workflow_harness` module behind `#[cfg(feature = "libsql")]`
- Align tool version to 0.2.1 in Cargo.toml and capabilities.json

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
drchirag1991 pushed a commit to drchirag1991/ironclaw that referenced this pull request Apr 8, 2026
* Add event-triggered routines and workflow skill templates

* Add generic host-verified webhook ingress for tools

* Migrate GitHub webhook normalization into github tool

* Bump github tool registry version

* Stabilize trace E2E test rig and approval behavior

* Add reusable gateway workflow harness with mock LLM server (nearai#762)

* Add reusable gateway workflow test harness with mock LLM server

* Fix clippy issues in workflow harness

* Stabilize trace E2E test rig and approval behavior

* Address PR review feedback on gateway workflow harness

- Extract shared TestChannelHandle into test_channel.rs with name override
  support, eliminating ~55 lines of duplication between test_rig.rs and
  gateway_workflow_harness.rs
- Remove redundant RoutineEngine creation that was immediately overwritten
  by Agent::run()
- Replace flaky sleep(500ms) with polling loop for routine run count check
- Use components.context_manager instead of creating a fresh ContextManager
  for job tools, ensuring agent and tools share the same instance

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix import ordering in gateway_workflow_harness

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* Address PR nearai#758 review feedback

- Fix header_value to use fully case-insensitive lookup (iterate with
  to_ascii_lowercase) instead of checking only exact/lower/upper variants
- Change comment_id from u32 to u64 to handle GitHub's billion-range IDs
- Remove handle_webhook from LLM-facing JSON schema to prevent direct
  invocation bypassing HMAC verification
- Rename enrichment keys from repository/sender to repository_name/
  sender_login to preserve original JSON objects in webhook payloads
- Remove put_string_normalized helper (no longer needed)
- Replace no-op tests (test_validate_event_in_create_pr_review,
  test_validate_merge_method) with test_header_value_case_insensitive
- Add README docs for 6 undocumented actions (list_issue_comments,
  create_issue_comment, list_pull_request_comments,
  reply_pull_request_comment, get_pull_request_reviews,
  get_combined_status)
- Add comment explaining max_tool_calls <= 8 bound in e2e test
- Fix gateway workflow harness: add webhook_capability with secret auth
  to MockGithubWebhookTool, matching staging's hardened webhook security
- Fix merge artifacts: remove duplicate test function, orphaned code
  fragment in e2e_routine_heartbeat

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix formatting in gateway workflow harness

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Address Copilot review: filter keys, pr_number fallback, feature gate, version alignment

- Update SKILL.md and workflow-routines.md templates to use `repository_name`
  and `sender_login` (matching enriched payload field names)
- Mark webhook HMAC secret as required in SKILL.md prerequisites
- Fall back to `/issue/number` for `pr_number` on issue_comment PR webhooks
- Gate `gateway_workflow_harness` module behind `#[cfg(feature = "libsql")]`
- Align tool version to 0.2.1 in Cargo.toml and capabilities.json

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor: core 20+ merged PRs risk: medium Business logic, config, or moderate-risk modules scope: agent Agent core (agent loop, router, scheduler) size: XL 500+ changed lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants